Difference between revisions of "Network protocol (Worms Armageddon)"

From Worms Knowledge Base

Jump to: navigation, search
m (Map data)
m
 
(37 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{ParentArticle|[[Worms Armageddon]]}}
+
{{ParentArticle|[[Game logic]]}}
 
== General ==
 
== General ==
 
* Sizes and offsets are in bytes
 
* Sizes and offsets are in bytes
Line 5: Line 5:
 
* Word size = 2 bytes
 
* Word size = 2 bytes
 
* DWord size = 4 bytes
 
* DWord size = 4 bytes
* Everything is LSB on the wire
+
* Everything is LSB on the wire (Little Endian)
 +
 
 +
Is it possible to write a bot?
 +
 
 +
It surely is. However the bot doesn't have access to very much information. It cannot tell who won or lost for example. The game relies on all of the clients performing identical simulations. So nothing other than what you get in a replay file is transmitted for each turn. This excludes any win/or loss data or anything like that. Your bot could spectate games, chat, and perform all the lobby actions and that's about it on its own. A bot ''could'' hook into the actual game, but doing so without informing other players is the difference between writing your own AI and cheating with an aimbot.
 +
 
 +
A minimal client with a readline command interface is available here https://github.com/giannitedesco/wabs under the terms of the GPLv3.
  
 
== Message header ==
 
== Message header ==
{| border="1"
+
{| class="wikitable"
!Offset
+
! Offset !! Size !! Value
!Size
+
!Value
+
 
|-
 
|-
|00
+
| 0 || Byte || 1 for frontend messages, 2 for ingame (compression ?)
|Byte
+
|1 for frontend messages, 2 for ingame (compression?)
+
 
|-
 
|-
|01
+
| 1 || Byte || (??) may be ignored
|Byte
+
|(??)
+
 
|-
 
|-
|02
+
| 2 || Word || Message size (max is 0x1414, if larger, the header(s) is(are) sent again)
|Word
+
|Message size (max is 0x1414, if larger, the header(s) is(are) sent again)
+
 
|-
 
|-
|04
+
| 4 || Word || Command
|Word
+
|Command
+
 
|}
 
|}
 
Length: 6
 
Length: 6
 +
 +
For in-game messages where the second byte is set to 2, the structure is slightly different.
 +
{| class="wikitable"
 +
! Offset !! Size !! Value
 +
|-
 +
| 0 || Byte || 2
 +
|-
 +
| 1 || Byte || (??) may be ignored
 +
|-
 +
| 2 || Word || Message size (max is 0x1414, if larger, the header(s) is(are) sent again)
 +
|-
 +
| 4 || Byte || Player ID
 +
|-
 +
| 5 || Word || Flags? Maybe a bitmap? Observed values of 1, 2 and 4.
 +
|-
 +
| 7 || Word || Frame sequence number. Incremented every time a message is sent.
 +
|}
 +
Length:9
 +
 +
== Packet Commands List ==
 +
{| class="wikitable"
 +
! Hex !! Dec !! Description
 +
|-
 +
| 0x00 || 00 || [[#Chat Message|Chat message]]
 +
|-
 +
| 0x01 || 01 || ???????
 +
|-
 +
| 0x02 || 02 || ???????
 +
|-
 +
| 0x03 || 03 || ???????
 +
|-
 +
| 0x04 || 04 || Login from client (completeme)
 +
|-
 +
| 0x05 || 05 || Another login from client (completeme)
 +
|-
 +
| 0x06 || 06 || Client sends password (completeme)
 +
|-
 +
| 0x07 || 07 || Password Required (no data)
 +
|-
 +
| 0x08 || 08 || Sucessfully joined (or password ok) need to figure out what the data means (version of the host ??)
 +
|-
 +
| 0x09 || 09 || Wrong password (no data)
 +
|-
 +
| 0x0A || 10 || Error joining (nickname already used, or missing, or flag missing/incorrect) < need to figure out exact symptoms
 +
|-
 +
| 0x0B || 11 || [[#Player list|Player list]]
 +
|-
 +
| 0x0C || 12 || [[#Team list|Team list]]
 +
|-
 +
| 0x0D || 13 || [[#Custom Scheme data|Custom scheme data]]
 +
|-
 +
| 0x0E || 14 || Player joined (sent to already connected players)
 +
|-
 +
| 0x0F || 15 || [[#Ready signal|Ready signal]]
 +
|-
 +
| 0x10 || 16 || [[#Remove Team|Remove team]]
 +
|-
 +
| 0x11 || 17 || [[#Changing Scheme data|Changing scheme data]] Round Time
 +
|-
 +
| 0x12 || 18 || [[#Changing Scheme data|Changing scheme data]] Turn Time
 +
|-
 +
| 0x13 || 19 || [[#Changing Scheme data|Changing scheme data]] Victories needed
 +
|-
 +
| 0x14 || 20 || [[#Changing Scheme data|Changing scheme data]] Worm Selection
 +
|-
 +
| 0x15 || 21 || [[#Changing Scheme data|Changing scheme data]] Worms HP
 +
|-
 +
| 0x16 || 22 || [[#Change Team|Change team]] - team color
 +
|-
 +
| 0x17 || 23 || [[#Change Team|Change team]] - team handicap
 +
|-
 +
| 0x18 || 24 || [[#Change Team|Change team]] - number of worms
 +
|-
 +
| 0x19 || 25 || Player left the game (sent to connected players)
 +
|-
 +
| 0x1A || 26 || [[#Add Team|Add team]]
 +
|-
 +
| 0x1B || 27 || You have been Kicked (no data)
 +
|-
 +
| 0x1C || 28 || [[#Starting Game|Starting game]]
 +
|-
 +
| 0x1D || 29 || [[#Changing Scheme data|Changing scheme data]] Worm Placment
 +
|-
 +
| 0x1E || 30 || ?????????
 +
|-
 +
| 0x1F || 31 || [[#Default Scheme data|Default scheme data]]
 +
|-
 +
| 0x20 || 32 || Default Maps (like ArtClass) just a String with the map name, 40 bytes long
 +
|-
 +
| 0x22 || 34 || This packet is sent from server when version = 0, very weird.
 +
|-
 +
| 0x23 || 35 || The client sends this after the 0x22 , can't get it to work.
 +
|-
 +
| 0x24 || 36 || Server sends this when a game is over. It seems to be a sort of ping.
 +
|-
 +
| 0x25 || 37 || Client sends this in response to a 0x24. If not the server keeps resending the 0x24 packet and the player appears to have timed out in the post-game lobby area.
 +
|-
 +
| 0x26 || 38 || The client sends this after the 0x22 , can't get it to work. The server also sends this after a game has finished, and after sending the 0x24 packet.
 +
|-
 +
| 0x27 || 39 || Gameid incorrect (or no more place ?)
 +
|-
 +
| 0x2B || 43 || [[#Map|Map]]
 +
|}
 +
 +
== Chat Message ==
 +
{| style="text-align: left"
 +
!Command:
 +
|0x0000
 +
|-
 +
!Direction:
 +
|Both
 +
|-
 +
!Size:
 +
|Variable
 +
|}
 +
Just a String, 00 Terminated.
 +
 +
Type:FromNick:ToNick:Text
 +
 +
Differents Types
 +
 +
Normal Message : GLB
 +
 +
Private Message : PRV
 +
 +
System Message : SYS
 +
 +
Notes :
 +
 +
- ToNick is often set to "ALL" to be sent to everyone (doesn't work for whispers)
 +
 +
- When X types /me Text, it sends this : SYS:X:ALL:X Text
 +
 +
- For systems messages, FromNick can be null, since it's not shown
  
 
== Join ==
 
== Join ==
Line 110: Line 240:
 
Figure out what the rest is.
 
Figure out what the rest is.
  
Considering there can be 7 players, the total length should be 840 bytes.
+
There are 6 bytes of unknown, followed by 7 player structs. The structure for each player is:
Array starts at 06, 08 or 0b?
+
{| class="wikitable"
 +
! Offset !! Size !! Value
 +
|-
 +
| 0 || 17 || name
 +
|-
 +
| 17 || 108 || unknown
 +
|-
 +
| 125 || 2 || prev, signed integer pointing to previous player, set to -1 for first entry
 +
|-
 +
| 127 || 2 || unknown
 +
|-
 +
| 129 || 1 || country code (for flag)
 +
|-
 +
| 130 || 7 || unknown
 +
|}
  
Depending, that leaves 330, 328 or 324 trailing bytes.
+
After that, there is 520 bytes unknown, a 16 byte integer with the total number of valid players and then 2 bytes unknown.
Figure out what follows (or what is before the array).
+
  
 
== Team list ==
 
== Team list ==
Line 128: Line 271:
 
|}
 
|}
  
TODO
+
The structure here is subtly different to the WGT format. Furthermore the [[#Add Team]] message is completely different again. And reverse engineering that is complicated by the fact that the game doesn't appear to scrub the unused bytes in the structure to zero. So it leaks some random heap or stack that way.
  
== Scheme data ==
+
{| class="wikitable"
 +
! Offset !! Size !! Value
 +
|-
 +
| 0 || Word || Unknown
 +
|-
 +
| 2 || Word || Slot number in the teams-list
 +
|-
 +
| 4 || Word || Unknown
 +
|-
 +
| 6 || Byte || Player ID
 +
|-
 +
| 7 || Byte || Color
 +
|-
 +
| 8 || Byte || Unknown
 +
|-
 +
| 9 || 17 || Team name
 +
|-
 +
| 26 || 32 || Soundbankk name
 +
|-
 +
| 58 || Word || Soundbank flags?
 +
|-
 +
| 60 || 30 || Fanfare
 +
|-
 +
| 90 || Byte || Unknown
 +
|-
 +
| 91 || 30 || Fanfare again, why?
 +
|-
 +
| 121 || 41 || Unknown
 +
|-
 +
| 162 || 8 * 17 || Worm names
 +
|-
 +
| 298 || 3160 || Unknown, but some similarities to the WGT file. There's certainly a flag bitmap in there among other things
 +
|}
 +
 
 +
== Custom Scheme data ==
 
{| style="text-align: left"
 
{| style="text-align: left"
 
!Command:
 
!Command:
|0x000d
+
|0x000d (13dec)
 
|-
 
|-
 
!Direction:
 
!Direction:
Line 142: Line 319:
 
|}
 
|}
  
I saw two messages for a single scheme change?
+
{| class="wikitable"
Word at 06 is 0x0000 for the first, 0x0007 for the second.
+
! Offset !! Size !! Value
Otherwise identical.
+
|-
 +
| 0 || Word || (??)
 +
|-
 +
| 2 || DWord || An identifier for the scheme. (-1 for custom, scheme, 1-13 for default (edited) scheme)
 +
|-
 +
| 6 || 292 bytes || Scheme file withouth "SCHM" header
 +
|-
 +
| 298 || DWORD || (?)
 +
|}
  
DWord at 08 is always 0xffffffff?
+
== Default Scheme data ==
Byte at 0xd always 0x00?
+
{| style="text-align: left"
 +
!Command:
 +
|0x001f (31dec)
 +
|-
 +
!Direction:
 +
|To client
 +
|-
 +
!Size:
 +
|12
 +
|}
 +
{| class="wikitable"
 +
! Offset !! Size !! Value
 +
|-
 +
| 0 || Word || (??)
 +
|-
 +
| 2 || DWord || An identifier for the scheme.
 +
|}
 +
{| class="wikitable"
 +
! Identifier !! Scheme
 +
|-
 +
| 1 || Beginner
 +
|-
 +
| 2 || Intermediate
 +
|-
 +
| 3 || Pro
 +
|-
 +
| 6 || Artillery
 +
|-
 +
| 7 || Classic
 +
|-
 +
| 8 || Armageddon
 +
|-
 +
| 9 || The Darkside
 +
|-
 +
| 11 || Retro
 +
|-
 +
| 13 || Strategic
 +
|-
 +
| 14 || Sudden Sinking
 +
|-
 +
| 15 || Tournament
 +
|-
 +
| 16 || Blast Zone
 +
|-
 +
| 17 || The Full Wormage
 +
|}
 +
If you put 0 as Scheme Identifier, it will crash the game.
 +
Any other number that doesn't appear in the list will put Intermediate.
  
(Atleast for version 1 scheme:)
+
== Changing Scheme data ==
Scheme starts at 0e. No SCHM header. No version number?
+
{| style="text-align: left"
79 bytes after, probably 76 extra for scheme version 2.
+
!Command:
Remaining 3 are 0x0046ec?
+
|Depends
 +
|-
 +
!Direction:
 +
|To client
 +
|-
 +
!Size:
 +
|12
 +
|}
  
//edit by Robi//
+
{| class="wikitable"
 +
! Offset !! Size !! Value
 +
|-
 +
| 0 || Word || Always 0x3E (62dec) ?
 +
|-
 +
| 2 || DWord || Value
 +
|}
  
Updating the Scheme :
+
{| class="wikitable"
 
+
! Command !! Command (dec) !! Description
53 63 FF FF FF FF 00 [ .WSC file starting at offset 5 ] FF FF FF
+
|-
 
+
| 0x11 || 17 || Round Time (Positive = Minutes, Negative = Seconds)
The size seems to be always 308, so it is always v2 Scheme, if you put a v1 scheme, it is convertised to v2 (padded with 0's) That's why the version isn't in the packet.
+
|-
 
+
| 0x12 || 18 || Turn Time (FFFFFFFF = Infinite)
Still don't know why it's sent twice though...
+
|-
 
+
| 0x13 || 19 || Victories needed
//end of edit//
+
|-
 +
| 0x14 || 20 || Worm Selection (0 = Disabled ; 1 = Enabled)
 +
|-
 +
| 0x15 || 21 || Worms HP
 +
|-
 +
| 0x1D || 29 || Worm Placment (0 = Disabled ; 1 = Enabled)
 +
|}
  
 
== Ready signal ==
 
== Ready signal ==
Line 178: Line 429:
 
|}
 
|}
  
Word at 06 always 0x736e?
+
{| class="wikitable"
 
+
! Offset !! Size !! Value
DWord at 08 is on/off?
+
|-
DWord at 0b is player number?
+
| 08 || DWord || on/off
 
+
|-
== Map data ==
+
| 0B || DWord || Player number
(Atleast for random generated)
+
|}
  
 +
== Starting Game ==
 
{| style="text-align: left"
 
{| style="text-align: left"
 
!Command:
 
!Command:
|0x002b
+
|0x001c
 
|-
 
|-
 
!Direction:
 
!Direction:
Line 194: Line 446:
 
|-
 
|-
 
!Size:
 
!Size:
|64
+
|20
 
|}
 
|}
  
Using a .BIT file (modified with map editor) : when using this, the size of the packet might change depending of the .BIT file
+
{| class="wikitable"
 +
! Offset !! Size !! Value
 +
|-
 +
| 6 || Word || I guess this is only not important junk and can be anything (need verification)
 +
|-
 +
| 08 || DWord || HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Data\LogicSeed
 +
|-
 +
| 0C || DWord || "GSAW" (this is hardcoded, but i think it can be anything, not important)
 +
|-
 +
| 10 || DWord || Version of the Game (4C for the normal 3.6.28.0)
 +
|}
  
A3 01 5B 00 00 00 00 00 00 00 5B 00 00 00 01 00 00 00 [ .BIT file ]
+
After this, we switch to type-2 packets documented above. All players send loading status reports up to frame number 0x1b. The report for 0x1b contains some sort of magic which is presumably a sort of checksum on the game logic such as worm placement and map generation. If it's not correct then the game notifies of invalid data and won't let the game start. Best bet is to listen for one player to finish and echo his magic number back.
  
Using a .LEV file (random generated) :
+
Here is an example of what is received when 2 other players are in the game:
  
A0 01 2C 00 00 00 00 00 00 00 2C 00 00 00 02 00 00 00 [ .LEV file ]
+
<tt>
 +
Frame: player=0 frame=0x00000001 len=4
 +
| 00000 : ....              c0 0a 00 00
 +
Frame: player=0 frame=0x00000002 len=4
 +
| 00000 : ....              c0 0a 04 00
 +
Frame: player=2 frame=0x00000001 len=4
 +
| 00000 : ....              c0 0a 00 00
 +
Frame: player=2 frame=0x00000002 len=4
 +
| 00000 : ....              c0 0a 04 00
 +
Frame: player=2 frame=0x00000003 len=4
 +
| 00000 : ....              c0 0a 08 00
 +
Frame: player=0 frame=0x00000003 len=4
 +
| 00000 : ....              c0 0a 08 00
 +
Frame: player=0 frame=0x00000004 len=4
 +
| 00000 : ....              c0 0a 0c 00
  
Maybe it's just the same, need to figure out what those mean ...
 
  
Exemple of a multi-packeted BIT-file :
+
snip ...
 +
 
 +
Frame: player=0 frame=0x0000001a len=4
 +
| 00000 : ..d.              c0 0a 64 00
 +
Frame: player=2 frame=0x0000001a len=4
 +
| 00000 : ..d.              c0 0a 64 00
 +
Frame: player=2 frame=0x0200001b len=7
 +
| 00000 : @.GQ{7.          40 09 47 51 7b 37 00
 +
Frame: player=0 frame=0x0200001b len=7
 +
| 00000 : @.GQ{7.          40 09 47 51 7b 37 00
 +
</tt>
 +
 
 +
== Map ==
 +
 
 +
{| style="text-align: left"
 +
!Command:
 +
|0x002b
 +
|-
 +
!Direction:
 +
|To client
 +
|-
 +
!Size:
 +
|64
 +
|}
 +
 
 +
{| class="wikitable"
 +
! Offset !! Size !! Value
 +
|-
 +
| 06 || Byte || (??)
 +
|-
 +
| 07 || Byte || Always 01 ?
 +
|-
 +
| 08 || DWord || File Length
 +
|-
 +
| 0C || DWord || Data Offset
 +
|-
 +
| 10 || DWord || Data Length
 +
|-
 +
| 14 || Data Length || Data
 +
|}
 +
 
 +
Note : A DWord is put at the beginning of the File to tell what type of Map is sent.
  
<01 48 1414 2B00> <A2 01 [E2 34 00 00] [00 00 00 00] [00 14 00 00]> [ 01 00 00 00 { .BIT file DAT } ]
+
1 = .BIT [[Monochrome map (.bit, .lev)]]
  
<01 48 1414 2B00> <A2 01 [E2 34 00 00] [00 14 00 00] [00 14 00 00]> [ { .BIT file DAT } ]
+
2 = .LEV [[Monochrome map (.bit, .lev)]]
  
<01 9C F60C 2B00> <A5 01 [E2 34 00 00] [00 28 00 00] [E2 0C 00 00]> [ { .BIT file DAT } ]
+
3 = .PNG [[Colour map]]
  
<[[Message header]]> <map header : [total DATA lenght] [offset] [lenght of DATA]> { start 01 for BIT 02 for LEV (need to check this!)?? } [ data ]
+
Exemple of a multi-packeted BIT-file (135434(0x34DE)bytes file):
  
size of the .BIT file tested : 13534 bytes = 0x34DE
+
<01 48 1414 2B00> <A2 01 [E2 34 00 00] [00 00 00 00] [00 14 00 00]> [ 01 00 00 00 { .BIT file DATA } ]
  
0x1400 + 0x1400 + 0x0CE2 = 0x34E2
+
<01 48 1414 2B00> <A2 01 [E2 34 00 00] [00 14 00 00] [00 14 00 00]> [ { .BIT file DATA } ]
  
0x34E2 - 0x4 = 0x34DE
+
<01 9C F60C 2B00> <A5 01 [E2 34 00 00] [00 28 00 00] [E2 0C 00 00]> [ { .BIT file DATA } ]

Latest revision as of 22:05, 16 April 2022

(Up to Game logic)

General

  • Sizes and offsets are in bytes
  • All offsets are from the start of the packet's data
  • Word size = 2 bytes
  • DWord size = 4 bytes
  • Everything is LSB on the wire (Little Endian)

Is it possible to write a bot?

It surely is. However the bot doesn't have access to very much information. It cannot tell who won or lost for example. The game relies on all of the clients performing identical simulations. So nothing other than what you get in a replay file is transmitted for each turn. This excludes any win/or loss data or anything like that. Your bot could spectate games, chat, and perform all the lobby actions and that's about it on its own. A bot could hook into the actual game, but doing so without informing other players is the difference between writing your own AI and cheating with an aimbot.

A minimal client with a readline command interface is available here https://github.com/giannitedesco/wabs under the terms of the GPLv3.

Message header

Offset Size Value
0 Byte 1 for frontend messages, 2 for ingame (compression ?)
1 Byte (??) may be ignored
2 Word Message size (max is 0x1414, if larger, the header(s) is(are) sent again)
4 Word Command

Length: 6

For in-game messages where the second byte is set to 2, the structure is slightly different.

Offset Size Value
0 Byte 2
1 Byte (??) may be ignored
2 Word Message size (max is 0x1414, if larger, the header(s) is(are) sent again)
4 Byte Player ID
5 Word Flags? Maybe a bitmap? Observed values of 1, 2 and 4.
7 Word Frame sequence number. Incremented every time a message is sent.

Length:9

Packet Commands List

Hex Dec Description
0x00 00 Chat message
0x01 01  ???????
0x02 02  ???????
0x03 03  ???????
0x04 04 Login from client (completeme)
0x05 05 Another login from client (completeme)
0x06 06 Client sends password (completeme)
0x07 07 Password Required (no data)
0x08 08 Sucessfully joined (or password ok) need to figure out what the data means (version of the host ??)
0x09 09 Wrong password (no data)
0x0A 10 Error joining (nickname already used, or missing, or flag missing/incorrect) < need to figure out exact symptoms
0x0B 11 Player list
0x0C 12 Team list
0x0D 13 Custom scheme data
0x0E 14 Player joined (sent to already connected players)
0x0F 15 Ready signal
0x10 16 Remove team
0x11 17 Changing scheme data Round Time
0x12 18 Changing scheme data Turn Time
0x13 19 Changing scheme data Victories needed
0x14 20 Changing scheme data Worm Selection
0x15 21 Changing scheme data Worms HP
0x16 22 Change team - team color
0x17 23 Change team - team handicap
0x18 24 Change team - number of worms
0x19 25 Player left the game (sent to connected players)
0x1A 26 Add team
0x1B 27 You have been Kicked (no data)
0x1C 28 Starting game
0x1D 29 Changing scheme data Worm Placment
0x1E 30  ?????????
0x1F 31 Default scheme data
0x20 32 Default Maps (like ArtClass) just a String with the map name, 40 bytes long
0x22 34 This packet is sent from server when version = 0, very weird.
0x23 35 The client sends this after the 0x22 , can't get it to work.
0x24 36 Server sends this when a game is over. It seems to be a sort of ping.
0x25 37 Client sends this in response to a 0x24. If not the server keeps resending the 0x24 packet and the player appears to have timed out in the post-game lobby area.
0x26 38 The client sends this after the 0x22 , can't get it to work. The server also sends this after a game has finished, and after sending the 0x24 packet.
0x27 39 Gameid incorrect (or no more place ?)
0x2B 43 Map

Chat Message

Command: 0x0000
Direction: Both
Size: Variable

Just a String, 00 Terminated.

Type:FromNick:ToNick:Text

Differents Types

Normal Message : GLB

Private Message : PRV

System Message : SYS

Notes :

- ToNick is often set to "ALL" to be sent to everyone (doesn't work for whispers)

- When X types /me Text, it sends this : SYS:X:ALL:X Text

- For systems messages, FromNick can be null, since it's not shown

Join

Joining consists of several steps:

Step 1

Command: 0x0004
Direction: From client
Size: 128
  • Nick at 06, null terminated, ends (last place the null could be) at 22.
  • Gameid (ascii) at 23, null string for IP games.
  • Version at 64, composed of 30 24 F4 (hex)

NB : these 3 parameters are sufficient to enter a game. Everything else can be 0 and it's ok. Figure out what follows.

Step 2

Command: 0x0008
Direction: To client
Size: 6

Acknowledgement. Empty message. Figure out error messages. (different commands?)

Step 3

Command: 0x0005
Direction: From client
Size: 114
  • Nick at 06, null terminated.
  • Flag (+1) at 72 (if 13 is France, then to put French flag, you have to put 13+1 = 0x0E)

Figure out what follows.

Step 4

Server sends:

  • Player list, see below.
  • Team list (when not empty), see below.
  • Map data, see below. (Map is not sent when we rejoin?)
  • A message with command 0x001f? What is it?

Figure out how the scheme is sent here when it's not the default Intermediate

Player list

Command: 0x000b
Direction: To client
Size: 1176

This looks like it's sending a raw array of player structures. Each player structure is 120 bytes in size.

Names are limited to 17 characters, and are padded with 0 bytes. (If a name is exactly 17 characters, there will NOT be a null-terminator) Figure out what the rest is.

There are 6 bytes of unknown, followed by 7 player structs. The structure for each player is:

Offset Size Value
0 17 name
17 108 unknown
125 2 prev, signed integer pointing to previous player, set to -1 for first entry
127 2 unknown
129 1 country code (for flag)
130 7 unknown

After that, there is 520 bytes unknown, a 16 byte integer with the total number of valid players and then 2 bytes unknown.

Team list

Command: 0x000c
Direction: To client
Size: ??

The structure here is subtly different to the WGT format. Furthermore the #Add Team message is completely different again. And reverse engineering that is complicated by the fact that the game doesn't appear to scrub the unused bytes in the structure to zero. So it leaks some random heap or stack that way.

Offset Size Value
0 Word Unknown
2 Word Slot number in the teams-list
4 Word Unknown
6 Byte Player ID
7 Byte Color
8 Byte Unknown
9 17 Team name
26 32 Soundbankk name
58 Word Soundbank flags?
60 30 Fanfare
90 Byte Unknown
91 30 Fanfare again, why?
121 41 Unknown
162 8 * 17 Worm names
298 3160 Unknown, but some similarities to the WGT file. There's certainly a flag bitmap in there among other things

Custom Scheme data

Command: 0x000d (13dec)
Direction: To client
Size: 308
Offset Size Value
0 Word (??)
2 DWord An identifier for the scheme. (-1 for custom, scheme, 1-13 for default (edited) scheme)
6 292 bytes Scheme file withouth "SCHM" header
298 DWORD (?)

Default Scheme data

Command: 0x001f (31dec)
Direction: To client
Size: 12
Offset Size Value
0 Word (??)
2 DWord An identifier for the scheme.
Identifier Scheme
1 Beginner
2 Intermediate
3 Pro
6 Artillery
7 Classic
8 Armageddon
9 The Darkside
11 Retro
13 Strategic
14 Sudden Sinking
15 Tournament
16 Blast Zone
17 The Full Wormage

If you put 0 as Scheme Identifier, it will crash the game. Any other number that doesn't appear in the list will put Intermediate.

Changing Scheme data

Command: Depends
Direction: To client
Size: 12
Offset Size Value
0 Word Always 0x3E (62dec) ?
2 DWord Value
Command Command (dec) Description
0x11 17 Round Time (Positive = Minutes, Negative = Seconds)
0x12 18 Turn Time (FFFFFFFF = Infinite)
0x13 19 Victories needed
0x14 20 Worm Selection (0 = Disabled ; 1 = Enabled)
0x15 21 Worms HP
0x1D 29 Worm Placment (0 = Disabled ; 1 = Enabled)

Ready signal

Command: 0x000f
Direction: Both ways
Size: 16
Offset Size Value
08 DWord on/off
0B DWord Player number

Starting Game

Command: 0x001c
Direction: To client
Size: 20
Offset Size Value
6 Word I guess this is only not important junk and can be anything (need verification)
08 DWord HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Data\LogicSeed
0C DWord "GSAW" (this is hardcoded, but i think it can be anything, not important)
10 DWord Version of the Game (4C for the normal 3.6.28.0)

After this, we switch to type-2 packets documented above. All players send loading status reports up to frame number 0x1b. The report for 0x1b contains some sort of magic which is presumably a sort of checksum on the game logic such as worm placement and map generation. If it's not correct then the game notifies of invalid data and won't let the game start. Best bet is to listen for one player to finish and echo his magic number back.

Here is an example of what is received when 2 other players are in the game:

Frame: player=0 frame=0x00000001 len=4
| 00000 : ....              c0 0a 00 00
Frame: player=0 frame=0x00000002 len=4
| 00000 : ....              c0 0a 04 00
Frame: player=2 frame=0x00000001 len=4
| 00000 : ....              c0 0a 00 00
Frame: player=2 frame=0x00000002 len=4
| 00000 : ....              c0 0a 04 00
Frame: player=2 frame=0x00000003 len=4
| 00000 : ....              c0 0a 08 00
Frame: player=0 frame=0x00000003 len=4
| 00000 : ....              c0 0a 08 00
Frame: player=0 frame=0x00000004 len=4
| 00000 : ....              c0 0a 0c 00


snip ...

Frame: player=0 frame=0x0000001a len=4
| 00000 : ..d.              c0 0a 64 00
Frame: player=2 frame=0x0000001a len=4
| 00000 : ..d.              c0 0a 64 00
Frame: player=2 frame=0x0200001b len=7
| 00000 : @.GQ{7.           40 09 47 51 7b 37 00
Frame: player=0 frame=0x0200001b len=7
| 00000 : @.GQ{7.           40 09 47 51 7b 37 00

Map

Command: 0x002b
Direction: To client
Size: 64
Offset Size Value
06 Byte (??)
07 Byte Always 01 ?
08 DWord File Length
0C DWord Data Offset
10 DWord Data Length
14 Data Length Data

Note : A DWord is put at the beginning of the File to tell what type of Map is sent.

1 = .BIT Monochrome map (.bit, .lev)

2 = .LEV Monochrome map (.bit, .lev)

3 = .PNG Colour map

Exemple of a multi-packeted BIT-file (135434(0x34DE)bytes file):

<01 48 1414 2B00> <A2 01 [E2 34 00 00] [00 00 00 00] [00 14 00 00]> [ 01 00 00 00 { .BIT file DATA } ]

<01 48 1414 2B00> <A2 01 [E2 34 00 00] [00 14 00 00] [00 14 00 00]> [ { .BIT file DATA } ]

<01 9C F60C 2B00> <A5 01 [E2 34 00 00] [00 28 00 00] [E2 0C 00 00]> [ { .BIT file DATA } ]

Personal tools