Packet System
gamepacket_t serialization, text vs binary packets, and message IDs
gamepacket_t Structure
The core packet builder used for all type 4 (binary) packets. Uses a large fixed buffer followed by typed data inserts.
class gamepacket_t {
public:
unsigned char buffer[1024 * 256]; // 256KB packet buffer
unsigned int index = 0; // write cursor
int type = 0; // message type
bool encrypted = false;
// Insert methods - typed serialization
void Insert(unsigned char value); // 0x00 type marker
void Insert(int value); // 0x01 int32
void Insert(unsigned int value); // 0x01 uint32
void Insert(float value); // 0x01 float (bit-cast)
void Insert(string value); // 0x02 length + bytes
void Insert(const char* value); // 0x02 C-string
void Insert(vector<int> value); // 0x03 array of ints
void InsertRaw(...); // raw bytes without type marker
};Type Markers (Serialization)
| Marker Byte | Type | Wire Format |
|---|---|---|
| 0x00 | byte | 0x00 + 1 byte |
| 0x01 | int32/uint32/float | 0x01 + 4 bytes LE |
| 0x02 | string | 0x02 + int32 len + bytes |
| 0x03 | array (int) | 0x03 + int32 count + 4-byte items |
| 0x05 | struct/raw | 0x05 + length-prefixed |
| 0x09 | special | 0x09 + custom format |
Message Types
| Type | Name | Format | Description |
|---|---|---|---|
| 1 | Welcome | Text | Connection handshake ACK |
| 2 | Text | Text (|) | Login, chat, dialogs, commands |
| 3 | Extended Text | Text (|) | Requires bypass flag; join requests, purchases |
| 4 | Binary | Serialized | Movement, actions, world, spawn, OSM |
Binary Packet Assembly
// Example: OnSpawn packet (type 4)
gamepacket_t pack;
pack.Insert(4); // message type (binary)
pack.Insert(2); // action type (OnSpawn)
pack.Insert(player->netID); // netID
pack.Insert(player->userID); // userID
pack.Insert(player->characterState); // char state
pack.Insert(player->posX); // int X
pack.Insert(player->posY); // int Y
pack.Insert(player->posX); // float X (for client)
pack.Insert(player->posY); // float Y
pack.Insert(player->flags); // flags
pack.Insert(player->guildID); // guild
pack.Insert(player->guildRank); // guild rank
pack.Insert(player->userName); // string name
pack.Insert(player->userNick); // string nick
pack.Insert(player->clothes); // itemIDs array (7)
pack.Insert(player->hairColor); // int
pack.Insert(player->eyeColor); // int
pack.Insert(player->skinColor); // int
pack.Insert(0); // rain strength
pack.Insert(player->hats); // extra hats
pack.Insert(0); // state
pack.Insert(0); // pose
pack.Insert(player->renderType); // render type
send_raw(peer, pack.buffer, pack.index);Text Packet Format
Text packets use pipe-delimited key-value pairs. Client to Server for type 2/3:
tankIDName|user|tankIDPass|pass|requestedName||f|1|protocol|225|game_version|5.53|fz|23314424|klv|...|hash|...|mac|...|rid|...|country|us|platformID|0,1,1
// Chat message
playerChat|text|Hello world
// Command
action|input|/warp spawn
// Join request (type 3 - bypass)
action|join_request|WORLD_NAMEAction IDs
| Action ID | Name | Direction |
|---|---|---|
| 0 | OnPlayerLeft | Srv -> Client |
| 1 | OnPlayerMoving | Both |
| 2 | OnSpawn | Srv -> Client |
| 3 | OnRemove | Srv -> Client |
| 4 | OnSendMapData | Srv -> Client |
| 7 | OnSendTileUpdateData | Both |
| 9 | OnSendTileUpdateDataMultiple | Srv -> Client |
| 11 | OnSendTileDamage | Both |
| 12 | OnSendPingRequest | Srv -> Client |
| 13 | OnSendPingResponse | Client -> Srv |
| 19 | OnSendInventoryState | Srv -> Client |
| 20 | OnSendItemDatabaseData | Srv -> Client |
| 21 | OnSendTileData | Srv -> Client |
| 22 | OnReconnect | Srv -> Client |
| 26 | OnSendGameModes | Srv -> Client |
| 27 | OnSendPlayerMessage | Srv -> Client |
PlayerMoving Struct
Used for type 4 binary movement packets (action 1):
struct PlayerMoving {
int netID;
int characterState;
int punchX, punchY; // punch target
int posX, posY; // int position (tile-aligned)
float posXf, posYf; // float position (pixel)
int plantedTree; // tree id if planting
int plantSeed; // seed id if planting
int plantFrame; // tree frame
int plantPosX, plantPosY;
int isPunching; // 1 = punching
int isFlag; // extra flags
int isJiggle; // jiggle/anim flag
};Packing/Unpacking Flow
// CLIENT TO SERVER (incoming type 4)
// 1. Validate packet header (61-byte, 4-byte length)
// 2. Decode packed chunks with bit-reading
// 3. Unpack into PlayerMoving fields
// 4. Route to action handler
// SERVER TO CLIENT (outgoing)
// 1. Build gamepacket_t with Insert()
// 2. Pack PlayerMoving fields with bit-writer
// 3. Append to packet buffer
// 4. Send via enet_packet_createBit-packing reduces bandwidth for movement data - integer positions are packed with 4-bit field IDs and signed values use zigzag encoding.
Packet Counters (Anti-Flood)
// Per-peer monitoring (anti-flood)
pInfo(peer)->all_packets++; // total received
pInfo(peer)->pps++; // per-second counter
pInfo(peer)->last_packet = now_ms();
// Send rate tracking
pInfo(peer)->sent_packets++;
pInfo(peer)->sent_bytes += packet->dataLength;
// Limits (disconnect triggers)
all_packets >= 560 -> flood
pps >= 16 -> too many pps