ok, terrible description below
The command format is:
app to server: <cmd> <seq> <parameters>
server to app: 0x80 <seq+1> <response>
Historically, there are two types of commands.
Commands with numbers < 0x80 have raw binary parameters and return value and command number is send as 1 byte.
For other commands, command number is sent as two bytes (command/subcommand) and parameters and response are msgpack-encoded arrays.
Also, server may send:
0x82 <seq+1> <errorstring>
if there was an error (Lua exception) while processing the command.
For map and status updates:
<flags> <status1,status2><extended data><center data><map data>
all the fields are optional and present if corresponding bit of flags is set (0,1,2,3 from the left).
status1/status2 are sent only if changed and are the current game (UI) mode, extended data is msgpack-encoded additional data, sent only if changed. For example, for unit [v]iew mode it will be
24,0 if there's no unit selected and 24,1,unit_name if there's a unit.
center data is sent if the current view centre has been changed on server side (announcement, zoom to unit, following unit, etc.)
map data is current z-level followed by an array of x,y,tile,fg | (bg << 4) bytes
This will be changed in future! First, to support multi-level rendering and creature graphics, and second because currently it supports only maps <= 256x256.
If response is longer than 500 bytes, server will compress it and send:
0x81 <deflate()-compressed original reponse>
Connection sequence:
client connects and sends cmd 238 subcmd 4, parameters: protocol version that the client supports, password hash or empty
server responds with server version and game status - this is to query server status without actually connecting to the game
then, if the server version is supported,
client sends cmd 1 with parameters (in binary): token (4 bytes), protocol version, password hash
server responds with whether_the_token_matched, new token, server version. At this moment server will disconnect the currently connected client, if any, and clear map cache if tokens didn't match.
token is generated randomly in the app and the updated with the server version and is preserved, and is used to track a single session, so that app may disconnect and not need to reload map and some other data next time. if another client connects, this will reset.
then:
app sends <238>,<5> to get map info
app sends <15>,<dimx>,<dimy> to set map view dimensions to render
app sends <30>,<cx>,<cy> to set map center
app sends <238>,<1> to get list of designations
app sends <238>,<2> to get list of building commands
app sends <238>,<3> to get list of labors
app sends <17>,<block_number> to start preloading map for the current z-level and repeats that until server says there are no more blocks. If client does not want to preload map, it needs to send <17>,<255> because server also starts rendering and sending map updates when there are no blocks to preload
Commands/responses are never resent in case of network issues, all messages are sent with Enet's reliable flag and in case of disconnection and reconnection, if the token matched, they must be resent and responses to previous commands will be received. This is to preserve synchronisation of UI state between server and client - if some command is sent, the client will either receive a response and be sure that the server is in an expected state, or the client will disconnect.