So if you want to use a binary packet format you are going to need a well defined structure to it. Anything without a fixed size will need an extra field to tell you how long the data is going to be, otherwise you will not be able to read it back.
In terms of your chosen data for each peer you have:
- PeerID (unsure if sized)
- Position X (sized)
- Position Y (sized)
- Direction (sized)
PeerID is somewhat frustrating, I can't tell from the documentation if it's always a fixed length. If it is then we only need 1 size value for the whole packet, but if it isn't then we need one for each peer! I think we will have to assume that it can vary in length.
We will need to store an integer value at the start of our packet that contains the number of peers. Then for each peer we need to store 2 integers ( direction, peer id length ), 2 floats (position x, position y,) and then a string ( peer id ).
For writing strings you will need a second binary data object to write the string into, then copy the contents of that object into the main one. This limitation is due to it being hard to know how many bytes you need to store a string until you try to write it.
Example serialisation
1. First we need to calculate how big the buffer needs to be, we need to loop through each peer and add up the sizes of the data. Let's use uint8 for the integers (max value is 255) and float64 for the fractional values. This gives us the size for each peer (2 x 8) + (2 x 1) + (peerIDByteLength)
then add the size of the peer count ( 1 x 1 )
.
2. Create a new buffer with the calculated size.
3. Write the number of peers as a uint8.
4. Loop through each peer
4a. Write peer ID length as uint8
4b. Write peer direction as uint8
4c. Write peer position X as float64
4d. Write peer position Y as float64
4e. Write peer ID as string
You will have to keep track of the current byte offset while writing the data, you don't want to just keep overwriting the value at index 0. For each uint8 written increate the offset by 1, for float 64 by 8 and for a string the number of characters. Deserialisation is simpler, as we don't have to pre calculate the buffer size. But we will still have to keep track of the byte offset as we read values.
1. Read peer count as u8.
2. Repeat by peer count.
2a. Read peer ID length as uint8
2b. Read peer direction as uint8
2c. Read peer position X as float64
2d. Read peer position Y as float64
2e. Read peer ID as string, using length from step 2a
This technique does make a small assumption that you don't have more than 255 peers... You can use a larger integer size if that's a requirement, but somehow I don't think it will be.