Packet Structure: Difference between revisions
Created page with "= Packet Structure = All communication between the client and server uses a binary packet format. Each packet consists of a fixed 8 byte header (metadata) followed by a variable length payload. == Packet Layout == <pre> Offset Size Field 0x00 2 checkSerial 0x02 2 checkSum 0x04 2 packetId 0x06 2 dataLength 0x08 n data (payload) </pre> == Header Fields == {| class="wikitable" ! Field ! Size ! Description |- | checkSeri..." |
No edit summary |
||
| (One intermediate revision by the same user not shown) | |||
| Line 9: | Line 9: | ||
<pre> | <pre> | ||
Offset Size Field | Offset Size Field | ||
0x00 2 | 0x00 2 serialnum | ||
0x02 2 | 0x02 2 checksum | ||
0x04 2 | 0x04 2 packet id | ||
0x06 2 | 0x06 2 data length | ||
0x08 n data (payload) | 0x08 n data (payload) | ||
</pre> | </pre> | ||
| Line 23: | Line 23: | ||
! Description | ! Description | ||
|- | |- | ||
| | | serialnum | ||
| 2 bytes | | 2 bytes | ||
| Serial value used by the protocol for packet validation and sequencing. | | Serial value used by the protocol for packet validation and sequencing. | ||
|- | |- | ||
| | | checksum | ||
| 2 bytes | | 2 bytes | ||
| Checksum used by the protocol to verify packet integrity. | | Checksum used by the protocol to verify packet integrity. | ||
|- | |- | ||
| | | packet id | ||
| 2 bytes | | 2 bytes | ||
| Identifier that determines the packet type and how the payload should be interpreted. | | Identifier that determines the packet type and how the payload should be interpreted. | ||
|- | |- | ||
| | | data length | ||
| 2 bytes | | 2 bytes | ||
| Length of the payload (data) in bytes. | | Length of the payload (data) in bytes. | ||
| Line 45: | Line 45: | ||
<pre> | <pre> | ||
data length = number of bytes following the header | |||
</pre> | </pre> | ||
| Line 81: | Line 81: | ||
<pre> | <pre> | ||
B8 79 -> | B8 79 -> serialnum | ||
BF 07 -> | BF 07 -> checksum | ||
3F 18 -> | 3F 18 -> packet id (0x183F) | ||
04 00 -> | 04 00 -> data length (4 bytes) | ||
</pre> | </pre> | ||
| Line 121: | Line 121: | ||
From the packet metadata: | From the packet metadata: | ||
* | * packet id = '''0x183F''' | ||
* payload length = '''4 bytes''' | * payload length = '''4 bytes''' | ||
| Line 162: | Line 162: | ||
String toString(); | String toString(); | ||
// must be implemented by the concrete class for field deserialization | |||
static <T extends IPacket> T fromBytes(byte[] packet) { | |||
throw new UnsupportedOperationException("fromBytes method not implemented"); | |||
} | |||
} | } | ||
| Line 167: | Line 172: | ||
This interface defines the minimal contract required for packet serialization and metadata access. | This interface defines the minimal contract required for packet serialization and metadata access. | ||
<code>fromBytes(payload)</code> is called by the Packet Deserializer, a registered packet class must implement it. | |||
=== Example === | |||
Example implementation for CMSG_AuthLogin (auto-generated). | |||
<syntaxhighlight lang="java"> | |||
public static CMSGAuthLogin fromBytes(byte[] rawData) { | |||
CMSGAuthLogin msg = new CMSGAuthLogin(); | |||
ByteBuffer buffer = ByteBuffer.wrap(rawData).order(ByteOrder.nativeOrder()); | |||
msg.metaData.checkSerial = buffer.getChar(0); | |||
msg.metaData.checkSum = buffer.getChar(2); | |||
msg.metaData.packetId = buffer.getChar(4); | |||
msg.metaData.dataLen = buffer.getChar(6); | |||
msg.data = new byte[msg.metaData.dataLen]; | |||
BitKit.blockCopy(rawData, 8, msg.data, 0, msg.metaData.dataLen); | |||
msg.username = msg.readString(); | |||
msg.token = msg.readFixedString(16); | |||
msg.timestamp = msg.readLong(); | |||
return msg; | |||
} | |||
</syntaxhighlight> | |||
== Packet Schema == | |||
Packet structures themselves are defined using the '''[[Packet Schema (.packet) Format]]'''. | |||
These schema files describe the payload layout for each packet id and are used to generate the corresponding packet classes automatically. | |||
[[Category:Server]] | [[Category:Server]] | ||
[[Category:Protocol]] | [[Category:Protocol]] | ||
Latest revision as of 15:24, 16 March 2026
Packet Structure
All communication between the client and server uses a binary packet format.
Each packet consists of a fixed 8 byte header (metadata) followed by a variable length payload.
Packet Layout
Offset Size Field 0x00 2 serialnum 0x02 2 checksum 0x04 2 packet id 0x06 2 data length 0x08 n data (payload)
Header Fields
| Field | Size | Description |
|---|---|---|
| serialnum | 2 bytes | Serial value used by the protocol for packet validation and sequencing. |
| checksum | 2 bytes | Checksum used by the protocol to verify packet integrity. |
| packet id | 2 bytes | Identifier that determines the packet type and how the payload should be interpreted. |
| data length | 2 bytes | Length of the payload (data) in bytes. |
Payload
The payload immediately follows the header and contains packet specific data.
data length = number of bytes following the header
The structure of the payload depends entirely on the packetId.
The maximum packet size is limited to 16384 bytes.
Since the packet header has a fixed size of 8 bytes, the remaining 16376 bytes are available for payload data.
Maximum packet size : 16384 bytes Header size : 8 bytes Maximum payload : 16376 bytes
Example Packet
The following packet was captured from the server while processing a point update during a match.
2026-03-16 14:57:47,231 [epollEventLoopGroup-3-2] PacketLogger [decode] DEBUG RECV [12 bytes]
CMSGPoint { "id": "0x183F", "len": 4, "data": { "pointsTeam": 1, "unk0": 0, "ballState": 4, "playerPosition": 10 } }
--- Hex Dump ---
B8 79 BF 07 3F 18 04 00 01 00 04 0A
===
The total packet size is 12 bytes:
- 8 bytes header
- 4 bytes payload
Header
B8 79 -> serialnum BF 07 -> checksum 3F 18 -> packet id (0x183F) 04 00 -> data length (4 bytes)
Payload
01 00 04 0A
Which the packet parser interprets as:
| Field | Value | Hex |
|---|---|---|
| pointsTeam | 1 | 01 |
| unk0 | 0 | 00 |
| ballState | 4 | 04 |
| playerPosition | 10 | 0A |
Packet Interpretation
From the packet metadata:
- packet id = 0x183F
- payload length = 4 bytes
The server maps this packetId to the packet type:
CMSGPoint
The payload is then decoded according to the structure defined for that packet type.
Byte Order
All packet fields are encoded using little-endian byte order.
Example:
17 00 -> 0x0017 -> 23
Packet Interface Contract
All packets in the server implementation follow the IPacket interface.
package com.jftse.server.core.protocol;
public interface IPacket {
byte[] toBytes();
char getDataLength();
char getPacketId();
char getCheckSerial();
char getCheckSum();
String toString();
// must be implemented by the concrete class for field deserialization
static <T extends IPacket> T fromBytes(byte[] packet) {
throw new UnsupportedOperationException("fromBytes method not implemented");
}
}
This interface defines the minimal contract required for packet serialization and metadata access.
fromBytes(payload) is called by the Packet Deserializer, a registered packet class must implement it.
Example
Example implementation for CMSG_AuthLogin (auto-generated).
public static CMSGAuthLogin fromBytes(byte[] rawData) {
CMSGAuthLogin msg = new CMSGAuthLogin();
ByteBuffer buffer = ByteBuffer.wrap(rawData).order(ByteOrder.nativeOrder());
msg.metaData.checkSerial = buffer.getChar(0);
msg.metaData.checkSum = buffer.getChar(2);
msg.metaData.packetId = buffer.getChar(4);
msg.metaData.dataLen = buffer.getChar(6);
msg.data = new byte[msg.metaData.dataLen];
BitKit.blockCopy(rawData, 8, msg.data, 0, msg.metaData.dataLen);
msg.username = msg.readString();
msg.token = msg.readFixedString(16);
msg.timestamp = msg.readLong();
return msg;
}
Packet Schema
Packet structures themselves are defined using the Packet Schema (.packet) Format. These schema files describe the payload layout for each packet id and are used to generate the corresponding packet classes automatically.