docs/Packet System

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 ByteTypeWire Format
0x00byte0x00 + 1 byte
0x01int32/uint32/float0x01 + 4 bytes LE
0x02string0x02 + int32 len + bytes
0x03array (int)0x03 + int32 count + 4-byte items
0x05struct/raw0x05 + length-prefixed
0x09special0x09 + custom format

Message Types

TypeNameFormatDescription
1WelcomeTextConnection handshake ACK
2TextText (|)Login, chat, dialogs, commands
3Extended TextText (|)Requires bypass flag; join requests, purchases
4BinarySerializedMovement, 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_NAME

Action IDs

Action IDNameDirection
0OnPlayerLeftSrv -> Client
1OnPlayerMovingBoth
2OnSpawnSrv -> Client
3OnRemoveSrv -> Client
4OnSendMapDataSrv -> Client
7OnSendTileUpdateDataBoth
9OnSendTileUpdateDataMultipleSrv -> Client
11OnSendTileDamageBoth
12OnSendPingRequestSrv -> Client
13OnSendPingResponseClient -> Srv
19OnSendInventoryStateSrv -> Client
20OnSendItemDatabaseDataSrv -> Client
21OnSendTileDataSrv -> Client
22OnReconnectSrv -> Client
26OnSendGameModesSrv -> Client
27OnSendPlayerMessageSrv -> 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_create

Bit-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