Writing packets
From VbGORE Visual Basic Online RPG Engine
Packets are what is used to communicate between the server and the clients connected to it. The same concept is used for writing both client to server and server to client packets, but of course, the function of each is different, depending on the packet.
Contents |
[edit] Packet structure
Packets contain only two parts you need to worry about in general - the header, and the data. The header is a single byte that represents how to handle the data. These always come at the start of the packet. The header is written like:
DataCode.User_Move
If you sent this from the client to the server, you will be telling the server that the rest of the data in the packet relates to making the user move.
[edit] The data
The data depends on what the header is along with what the packet is trying to accomplish. Each valid DataCode is handled by a sub of the same name that starts with Data_. In our example, this would be:
Sub Data_User_Move
This sub is very important because it will tear the information it needs from the packet, along with it tells you how the packet is constructed at the top of the sub. In our Data_User_Move sub, you will see this:
'***************************************************************** 'Move the user '<Direction(B)> '*****************************************************************
The first line tells you what the packet does. In this case, it is just telling you that it is used to make the user move. The second line is what is most important to us - it tells us how the packet is structured. You will always see it in the format of:
<Short description or variable name (Variable type)>
The variable types are represented as follows:
- (B): Byte (8 bits)
- (I): Integer (16 bits, or 2 bytes)
- (L): Long (32 bits, or 4 bytes)
- (S): String (variable length, from 0 to 255 characters)
- (S-EX): String-EX (variable length, from 0 to 32767 characters)
Some times you will see a structure like this:
'********************************************* 'Set an inventory slot's information 'The information in the () is only sent if the ObjIndex <> 0 '<Slot(B)><OBJIndex(L)>(<OBJName(S)><OBJAmount(L)><Equipted(B)><GrhIndex(L)>) '*********************************************
The tags in the ()'s are not always sent. Some times you will have to dig through the code to find in what conditions they are sent, other times it will just tell you like it does here.
[edit] Using the buffer
Both the client and the server use the same DataBuffer class to pack the packet information. Theres a lot of comments in the code for it, but lets quickly run over all the routines:
- Put_ / Get_
- Puts information into the buffer / reads information out of the buffer. The amount put / grabbed is based on the variable attached to it. You have to use the same Get order as you do Put or else your values will be off.
- Clear
- Clears out the information from the buffer and gets it ready to use again. This must be used every time before the server makes a new conversion with the buffer (more on that later).
- Allocate
- Sets aside a pre-defined amount of bytes for the buffer. Put_ and Get_ will add more room if needed, but if you allocate more than you need then you will end up sending empty information, which I highly recommend avoiding. It is better to not allocate then to send empty information. Allocating serves only one benefit - speed. Its not required, but is good practice if you want to keep the best performance possible. Allocating two bytes is faster then letting Put_Byte allocate the memory for you twice individually. This is only used on Put_ commands.
- PreAllocate
- This combines Clear with Allocate. It will perform both operations, but faster. It is recommend to, whenever possible, use this instead of Clear.
- Get_Buffer
- Used to get the byte array in the data buffer.
- Overflow
- This will break the packet from the Do loop used to read information from the packet. Use this if you ever need to completely drop a packet, such as if invalid offsets were found. Theres often no need to use this. Don't use it unless you know what you are doing. Its not dangerous, but it does completely omit the rest of the packet.
[edit] Making the packet
The way the client and server both build the packets are the same in the end, but require a slightly different approach. The client only has one buffer because it only has one destination - the server. The server, on the other hand, has to send a packet to every client there is connected. Because of this, an individual buffer must be made for each client.
For the client, all you have to do is append (add on to) the buffer sndBuf (send buffer) in the following way:
sndBuf.Allocate 2 'Optional sndBuf.Put_Byte DataCode.User_Walk sndBuf.Put_Byte NORTH
For the server, though, you use the ConBuf to convert to a byte array then send that byte array with Data_Send, such as this:
ConBuf.PreAllocate 3 + Len(NPCList(NPCIndex).Name) ConBuf.Put_Byte DataCode.Server_Message ConBuf.Put_Byte 1 ConBuf.Put_String NPCList(NPCIndex).Name Data_Send ToNPCArea, NPCIndex, ConBuf.Get_Buffer
Notice that we use Allocate in the client but PreAllocate in the server. This is because the client actually uses the sndBuf as the buffer, while the server uses ConBuf just to make the data into a byte array. You never want to use PreAllocate in the client, and always want to (or .Clear) in the Server. Failure to do so in the server will result in packets not being cleared from the buffer, so you'll constantly be repeating packets you sent.



