![]() |
Description The bitstream class is a helper class under the namespace RakNet that is used to wrap a dynamic array for the purpose of packing and unpacking bits. Its main three benefits are:
The compression is quite simple and uses the following algorithm: 1. Is the upper half all 0's (1's for unsigned types)? TRUE - Write a 1 FALSE - Write a 0, and the upper half 2. Repeat with the lower half, until we are at half a byte. What this means is you will save bits if your data under half its maximum range. So if you know this is usually the case in advance, you can use WriteCompressed instead of Write and ReadCompressed instead of read. Finally, you can write bits. Most of the time you will not care about this. However, when writing booleans it will automatically only write one bit. This can also be very useful for encryption since your data will no longer be byte aligned. Writing Data Bitstream is templated to take any type of data. If this is a built-in type, such as NetworkIDObject, it uses partial template specialization to write the type more efficiently. If it's a native type, or a structure, it writes the individual bits, similar to memcpy. You can pass structs containing multiple data members to bitstreams. However, you may wish to serialize each individual element to do correct endian swapping (needed for communication between PCs and Macs, for example). Note: if you want to support endian swapping, you should also comment out __BITSTREAM_NATIVE_END in RakNetDefines.h. This is uncommented by default as a speed optimization. struct MyVector { float x,y,z; } myVector; // No endian swapping bitStream.Write(myVector); // With endian swapping #undef __BITSTREAM_NATIVE_END bitStream.Write(myVector.x); bitStream.Write(myVector.y); bitStream.Write(myVector.z); // You can also override operator left shift and right shift RakNet::BitStream& operator << (RakNet::BitStream& out, MyVector& in) { out.WriteNormVector(in.x,in.y,in.z); return out; } RakNet::BitStream& operator >> (RakNet::BitStream& in, MyVector& out) { bool success = in.ReadNormVector(out.x,out.y,out.z); assert(success); return in; } // Read from bitstream myVector << bitStream; // Write to bitstream myVector >> bitStream; Optional - One of the constructor versions takes a length in bytes as a parameter. If you have an idea of the size of your data you can pass this number when creating the bitstream to avoid internal reallocations. See Creating Packets for more details. Reading Data Reading data is equally simple. Create a bitstream, and in the constructor assign it your data. // Assuming we have a Packet * BitStream myBitStream(packet->data, packet->length, false); struct MyVector { float x,y,z; } myVector; // No endian swapping bitStream.Read(myVector); // With endian swapping (__BITSTREAM_NATIVE_END should just be commented in RakNetDefines.h) #undef __BITSTREAM_NATIVE_END #include "BitStream.h" bitStream.Read(myVector.x); bitStream.Read(myVector.y); bitStream.Read(myVector.z); See Receiving Packets for a more complete example. Serializing Data You can have the same function read and write, by using BitStream::Serialize() instead of Read() or Write(). struct MyVector { float x,y,z; // writeToBitstream==true means write, writeToBitstream==false means read void Serialize(bool writeToBitstream, BitStream *bs) { bs->Serialize(writeToBitstream, x); bs->Serialize(writeToBitstream, y); bs->Serialize(writeToBitstream, z); } } myVector; See Receiving Packets for a more complete example. |
![]() |
See BitStream.h for a full list of functions. Write functions |
![]() |
Index Creating Packets Receiving Packets |