Unified Network Code
I though it would be best to share a lesson that I've learned while working on the networking aspect of my game.
In my game I use C sockets for network code. The server side is written in Golang. With game networking, you can't really use JSON as a data layer as the performance hits for serializing and deserializing data are too big. So the best option is to write out your data in a "file" struct format.
My game has a few types of structs.
PacketHeader, PlayerPosition, PlayerInit, PlayerQuit, PlayerMessage, ItemPickup, ItemDrop, StatusEffect.
I ran into a problem with writing code to handle players dropping items across all clients.
Sample Struct:
struct ItemDrop { unsigned short itemId; float positionX; float positionY; float positionZ; }
On the Golang side the struct was something like this:
type ItemDrop struct { ItemId uint16 X float32 Y float32 Z float32 }
They look exactly alike!
In C++, sizeof(ItemDrop) => 16.
In Golang, unsafe.Sizeof(ItemDrop) => 16
Everything should be perfect right? No. Notice how there are 3 float32s giving us 12 bytes, a uint16 should only be two bytes. Yet it takes up 32 bits of data.
On network serializing: binary.Size(ItemDrop) => 14.
This means that when the C++ side sends 16 bytes, golang reads 14 bytes, then re-transmits as 14 bytes. There are two problems that occurs. When a client is expecting to read a packet size of 16, it blocks on the read when Golang only sends 14 bytes. This also means that when Golang reads 14 bytes instead of the full 16, it corrupts future packets from that buffer by shifting the data 2 bytes.
So why Golang for the server code? Easier to write. C/C++ networking is a pain. Golang has the native support that C/C++ has, with nice modern libraries built out for it.
Because of situations like this, I will be re-writing the network code for client and server to use golang.
- 2
0 Comments
Recommended Comments