Packet Structure
Game packet structures
Game packets are composed of 3 distinct parts, the packet header, the segment header and a (sometimes) optional IPC header.
While 'IPC' is incorrect terminology given the usage, SE calls it IPC so the naming has been preserved.
Packet Header
magic
A magic value that identifies a packet.
This is FF14ARR
if you read it both in its hexadecimal and ASCII representation at the same time.
timestamp
The number of milliseconds since the unix epoch when the packet was sent.
size
The size of the entire packet including its segments and data.
connectionType
The connection type. This will be 1 for zone channel connections and 2 for chat. This is only sent on the initial connection now, previously this was sent with every packet but that is no longer the case.
unknown_20
Alignment, most likely.
isCompressed
Whether the segments + remaining data is compressed. The header is always uncompressed. This data is compressed with zlib and there is no header - default compression settings.
unknown_24
Alignment, most likely.
Segment Header
size
The size of this segment and its data (if any).
source_actor
The actor ID of the actor who effectively caused this packet to be sent.
For example, if another player casts an action, the source_actor
field will contain their actor ID.
target_actor
The actor ID of the actor who is affected by the packet.
This isn't used consistently, but the same logical rules apply as source_actor
.
type
The type of segment, see below for more detail. Based on the value of this field indicates what kind of data you'd expect to find after the segment header.
paddding
Alignment.
Segment Types
SEGMENTTYPE_SESSIONINIT
Used to login to a world or chat server.
The packet that has a segment that has a type set to this will contain a correct connectionType
set in the packet header. Use this to record what kind of connection it is.
Example implementation is in Sapphire.
SEGMENTTYPE_IPC
Used for segments that contain data that should be handled by the packet router for the associated channel.
Chat messages, using actions and etc. will always be sent via this segment type and there will be a FFXIVARR_IPC_HEADER
immediately following the segment header.
SEGMENTTYPE_KEEPALIVE
TODO: can't remember where this is actually used - lobby? As a note, world (and chat?) use IPCs to ping/pong. Because reasons.
SEGMENTTYPE_ENCRYPTIONINIT
Used to initialize Blowfish for the lobby channel. The client sends a packet to lobby with it's key phrase which is then used to """secure""" a lobby session (spoiler alert: it's not secure).
IPC Header
Only present when the parent segment type is set to SEGMENTTYPE_IPC
.
reserved
type
This will contain the opcode of the packet which identifies which hanadler the packet data following this packet should go.
padding
Potentially data here and not padding but it's probably not that important. Right?
serverId
TODO: write about retail server architecture.
timestamp
A Unix timestamp in seconds since the epoch. Not really sure why this exists here but it does and that's what it has in it.
padding1
Alignment.
Decoding Packets
Decoding packets is reasonably simple and assuming you have a buffer that you write data in to for each connection, it's something like the following:
A lot of detail is omitted for brevity, but it's generally pretty straightforward.
A more comprehensive example of packet parsing can be found in Sapphire:
Packet container (and some container-level parsing)
Last updated