# Packet Structure

Game packets are composed of 3 distinct parts, the packet header, the segment header and a (sometimes) optional IPC header.

{% hint style="info" %}
While 'IPC' is incorrect terminology given the usage, SE calls it IPC so the naming has been preserved.
{% endhint %}

## Packet Header

```cpp
struct FFXIVARR_PACKET_HEADER
{
  uint64_t magic[2];
  uint64_t timestamp;
  uint32_t size;
  uint16_t connectionType;
  uint16_t segmentCount;
  uint8_t unknown_20;
  uint8_t isCompressed;
  uint32_t unknown_24;
};
```

| Field            | Description                                                                                                                                                                                                                |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `magic`          | <p>A magic value that identifies a packet.<br><br>This is <code>FF14ARR</code> if you read it both in its hexadecimal and ASCII representation at the same time.</p>                                                       |
| `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` | <p>The connection type. This will be 1 for zone channel connections and 2 for chat.<br><br>This is only sent on the initial connection now, previously this was sent with every packet but that is no longer the case.</p> |
| `unknown_20`     | Alignment, most likely.                                                                                                                                                                                                    |
| `isCompressed`   | <p>Whether the segments + remaining data is compressed. The header is always uncompressed.<br><br>This data is compressed with zlib and there is no header - default compression settings.</p>                             |
| `unknown_24`     | Alignment, most likely.                                                                                                                                                                                                    |

## Segment Header

```cpp
struct FFXIVARR_PACKET_SEGMENT_HEADER
{
  uint32_t size;
  uint32_t source_actor;
  uint32_t target_actor;
  uint16_t type;
  uint16_t padding;
};
```

| Field          | Description                                                                                                                                                                                              |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `size`         | The size of this segment and its data (if any).                                                                                                                                                          |
| `source_actor` | <p>The actor ID of the actor who effectively caused this packet to be sent.<br><br>For example, if another player casts an action, the <code>source\_actor</code> field will contain their actor ID.</p> |
| `target_actor` | <p>The actor ID of the actor who is affected by the packet.<br><br>This isn't used consistently, but the same logical rules apply as <code>source\_actor</code>.</p>                                     |
| `type`         | <p>The type of segment, see <a href="#segment-types">below for more detail</a>.<br><br>Based on the value of this field indicates what kind of data you'd expect to find after the segment header.</p>   |
| `paddding`     | Alignment.                                                                                                                                                                                               |

### Segment Types

```cpp
enum FFXIVARR_SEGMENT_TYPE
{
  SEGMENTTYPE_SESSIONINIT = 1,
  SEGMENTTYPE_IPC = 3,
  SEGMENTTYPE_KEEPALIVE = 7,
  //SEGMENTTYPE_RESPONSE = 8,
  SEGMENTTYPE_ENCRYPTIONINIT = 9,
};
```

| Type                         | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SEGMENTTYPE_SESSIONINIT`    | <p>Used to login to a world or chat server.<br><br>The packet that has a segment that has a type set to this will contain a correct <code>connectionType</code> set in the <a href="#packet-header">packet header</a>. Use this to record what kind of connection it is.<br><br>Example implementation is in <a href="https://github.com/SapphireServer/Sapphire/blob/399d9b0dcd6d87aa624bd53c58415efa27bb1b1c/src/world/Network/GameConnection.cpp#L430-L452">Sapphire</a>.</p> |
| `SEGMENTTYPE_IPC`            | <p>Used for segments that contain data that should be handled by the packet router for the associated channel.<br><br>Chat messages, using actions and etc. will always be sent via this segment type and there will be a <code>FFXIVARR\_IPC\_HEADER</code> immediately following the segment header.</p>                                                                                                                                                                       |
| `SEGMENTTYPE_KEEPALIVE`      | <p>TODO: can't remember where this is actually used - lobby?<br><br>As a note, world (and chat?) use IPCs to ping/pong. Because reasons.</p>                                                                                                                                                                                                                                                                                                                                     |
| `SEGMENTTYPE_ENCRYPTIONINIT` | <p>Used to initialize Blowfish for the <a href="../channels#lobby">lobby channel</a>.<br><br>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).</p>                                                                                                                                                                                                                                    |

## IPC Header

Only present when the parent segment type is set to `SEGMENTTYPE_IPC`.

```cpp
struct FFXIVARR_IPC_HEADER
{
  uint16_t reserved;
  uint16_t type;
  uint16_t padding;
  uint16_t serverId;
  uint32_t timestamp;
  uint32_t padding1;
};
```

| Field       | Description                                                                                                                               |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `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` | <p>A Unix timestamp in seconds since the epoch.<br><br>Not really sure why this exists here but it does and that's what it has in it.</p> |
| `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:

```
if buf.size < sizeof(FFXIVARR_PACKET_HEADER):
    return

header = &buf[0] as FFXIVARR_PACKET_HEADER:

if buf.size < header.size:
    return

data = slice buf from sizeof(FFXIVARR_PACKET_HEADER) to end of buf

if buf.isCompressed:
    data = zlib_inflate(data)

pos = 0
while true:
    segment = &data[pos] as FFXIVARR_PACKET_SEGMENT_HEADER

    if segment.size >= buf.size
        burn them

    if segment.size >= data.size:
        also burn them

    pos = segment.size

    seg_hdr_size = sizeof(FFXIVARR_PACKET_SEGMENT_HEADER)

    if segment.type == SEGMENTTYPE_IPC:
        ipc_size = segment.size - seg_hdr_size
        ipc_data = slice segment from seg_hdr_size to ipc_size

        ipc_hdr = &ipc_data[0] as FFXIVARR_IPC_HEADER
        ipc_hdr_size = sizeof(FFXIVARR_IPC_HEADER)

        packet_data = slice ipc_data from ipc_hdr_size to remaining size
        process_channel_packet(ipc_hdr.type, packet_data)

    // other segment types depend on the type of channel, but it's more of the same
```

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](https://github.com/SapphireServer/Sapphire/blob/develop/src/common/Network/GamePacket.h) (and some container-level parsing)
* [Packet parsing](https://github.com/SapphireServer/Sapphire/blob/develop/src/common/Network/GamePacketParser.cpp)
