Sync

Everything about the packets that synchronize the game states. In this document, packets are distinguished by their length and command byte. For example a 16BC41 describes the packet with a length of 16 bytes and a command byte with value 0x41 in the header.

When the game is paused, only 16BC31 and 16BC32 packets are sent.

Periodic

16BC41

A simple incremental counter that will increments every time a 16BC41 packet is sent. Packets are transmitted in intervals of 120ms.

def 16BC41
  int32 :network_source_id
  int32 :network_dest_id
  int8 :command
  int8 :option1
  int8 :option2
  int8 :option3
  int32 :individual_counter
end

:network_source_id
Works the same way as outlined in 02-header.md.

:network_dest_id
The destination of the packet. 16BC41 is one of the few packet types, where this value is not set to zero.

:command
Always has the value 0x41.

:option{1-3}
These are options with unknown effects. They work the same way as outlined in 02-header.md.

:individual_counter
The individual counter of the player who sent the packet. It increments by 1 with every 16BC41 sync command. For individual players, this counter starts with values that are 1200 units (two players) or 2000 units (three players, 0x7d0) apart from each other. In the latter example player 1 starts with the value 0x7d0, player 2 with 0xfa0 and player 3 with 0x1770. If the differences between these values is not a multiple of 2000, this indicates a de-sync.

16BC31

Makes sure that the game time of players stays synced. It always receives an answer in form of 16BC32. Packets are transmitted in intervals of 8s.

def 16BC31
  int32 :network_source_id
  int32 :network_dest_id
  int8 :command
  int8 :option1
  int8 :option2
  int8 :option3
  int32 :time_passed
end

:network_source_id
Works the same way as outlined in 02-header.md.

:network_dest_id
The destination of the packet. 16BC31 is one of the few packet types, where this value is not set to zero.

:command
Always has the value 0x31.

:option{1-3}
All 3 options are always zero for this command.

:time_passed
Time passed in milliseconds since the game started for the player. The difference between player 1 and player 2 was roughly 3,220 ms during tests. Note that for 16BC31 packets present in the lobby, this value represents milliseconds since the application started instead.

16BC32

The answer for a 16BC31 packet. Packets are transmitted in intervals of 8s.

def 16BC32
  int32 :network_source_id
  int32 :network_dest_id
  int8 :command
  int8 :option1
  int8 :option2
  int8 :option3
  int32 :time_passed
end

:network_source_id
Works the same way as outlined in 02-header.md.

:network_dest_id
The destination of the packet. 16BC32 is one of the few packet types, where this value is not set to zero.

:command
Always has the value 0x32.

:option{1-3}
They work the same way as outlined in 02-header.md.

:time_passed
Has the exact same value as the 16BC31 packet.

24BC35

Syncing the connection between players in lobby. Packets are transmitted in intervals of 2s.

def 24BC35
  int32 :network_source_id
  int32 :network_dest_id
  int8 :command
  int8 :option1
  int8 :option2
  int8 :option3
  int32 :connecting1
  int32 :unknown
  int32 :connecting2
end

:network_source_id
Works the same way as outlined in 02-header.md.

:network_dest_id
This value is always zero.

:command
Always has the value 0x35.

:option1
0x35 for both host and regular players when initiating the connection. Otherwise it has the value 0x30.

:option2
0x32 for the host and 0xf8 for regular players when initiating the connection. Otherwise it has the value 0x5d.

:option3
0x00 for the host and 0x0a for regular players when initiating the connection. Otherwise it has the value 0x00.

:connecting1
This field is only used to initiate a connection to a lobby. It always has the value 0x32d2a4 for the host and 0x503a87 for regular players when initiating a connection. Once the connecting player has joined the lobby, the value remains zero for all following packets.

:unknown
Field with unknown purpose. The value in here is unique for every player and sent with every packet.

:connecting2
This field is only used to initiate a connection to a lobby. It always has the value 0x5016b5 for the host and 0x32b5c4 for regular players when initiating a connection. Once the connecting player has joined the lobby, the value remains 0xFFFFFFFF for all following packets.

26BC53

Only sent by the host from the lobby and not by other players. Sent in intervals of 3s.

def 26BC53
  byte20 :header
  int16 :unknown1
  int16 :unknown2
  int16 :communication_turn
end

:header
The standard header. Works the same way as outlined in 02-header.md.

:unknown1
A field with unknown purpose. Changes between values of 0x04 and 0x08.

:unknown2
Another field with unknown purpose. Possibly ping.

:communication_turn
The current communication turn as a 16 bit value.

32BC44

Syncs up the communication turns in the game. Packets are transmitted in intervals of 120ms.

def 32BC44
  byte20 :header
  int8 :command2
  int8 :unknown1
  int8 :unknown2
  int8 :unknown3
  int32 :communication_turn_offset
  int8 :ping1
  int8 :ping2
  int8 :unknown4
  int8 :unknown5
end

:header
The standard header. Works the same way as outlined in 02-header.md.

:command2
Always has the value of the command byte from the header 0x44. It is unknown whether this is supposed to be the same as :command or if it has other use cases.

:unknown1
Possibly used to communicate the connection status. The value is different for every player, but consistent for most packets throughout the game. An exception are packets sent at the start of a game. The first 32BC44 packet sent by the lobby host always has the value 0x96 in this field. All other players will have the value 0xce in their first packet.

Sometimes the value of the fields :unknown{1-3} and :unknown5 will be 0x00, but no reason for this behavior could be found.

:unknown2
Like :unknown1 it is probably used to communicate the connection status. Values for the very first 32BC44 packet are 0x98 for the lobby host and 0x32 for all other players.

Sometimes the value of the fields :unknown{1-3} and :unknown5 will be 0x00.

:unknown3
Has the value 0xf7 most of the time.

Sometimes the value of the fields :unknown{1-3} and :unknown5 will be 0x00.

:communication_turn_offset
If the game desyncs, this field indicates the last communication turn where the game was in sync for the player sending this packet. While the game is synced, the value should match up with :communication_turn in the header.

:ping1
The difference between the ping from the current turn and the ping from the previous turn.

:ping2
Average time to receive an answer from the player the packet was sent to. Uses the ping times for the last 10-15 32BC44 packets for calculation.

:unknown4
Byte with unknown purpose. It will have the value 0x4c for the player who was the lobby host and a different value for all other players (one player: 0x48; two players: both 0x47). When :unknown{1-3} and :unknown5 have the value 0x00, the value for :unknown4 will always be 0x32.

:unknown5
Has the value 0xf7 most of the time.

Sometimes the value of the fields :unknown{1-3} and :unknown5 will be 0x00.

56BC4D

Syncs up the communication turns in the game. Seems to check if some values are the same for every player. In every interval, the values of 56BC4D stay the same for all players (except for the last 4 bytes). Packets are transmitted in intervals of 8s - 16s.

def 56BC4D
  byte20 :header
  int32 :unknown1
  int32 :communication_turn_check
  int32 :unknown2
  int32 :unknown3
  int32 :unknown3
  int32 :unknown5
  int32 :unknown6
  int32 :unknown7
  int32 :unknown8
end

:header
The standard header. Works the same way as outlined in 02-header.md.

:communication_turn_check
The communication turn which is validated. Always has the value (:communication_turn - 2).

:unknown{1-7}
These are the same for all players during a given interval. Some of them seem to be counters, while others change values with an unknown pattern.

:unknown8
Different for every interval and every player.

Non-Periodic

24BC51

Utilized after dropping a player due to connection loss or de-sync.

def 24BC51
  byte20 :header
  int32 :unknown3
end

:header
The standard header. Works the same way as outlined in 02-header.md.

:last_synced_communication_turn
The number of the communication turn that the remaining players will continue the game from.

24BC52

Used for readying in the lobby.

def 24BC52
  int32 :network_source_id
  int32 :network_dest_id
  int8 :command
  int8 :option1
  int8 :option2
  int8 :option3
  int8 :unknown
  int8 :player_id
  int8 :unknown2
  int32 :zero
  int32 :unknown3
end

:network_source_id
Works the same way as outlined in 02-header.md.

:network_dest_id
This value is always zero.

:command
Always has the value 0x52.

:option1
Is 0x01 when readying and 0x00 when unreadying.

:option2
Is 0x1e when readying and 0x00 when unreadying.

:option3
Is 0x00 when readying or unreadying.

:unknown
Field with unknown purpose. Always has value 0x01.

:player_id
The ID of the player who is readying. Is 0x00 when player is unreadying.

:unknown2
Field with unknown purpose. Always has value 0x01 when player is readying. Is 0x00 when player is unreadying.

:zero
These 4 bytes are always zero.

:unknown3
Field with unknown purpose. Always has value 0x04 when player is readying. Is 0x00 when player is unreadying.