Skip to content
CrazyPhoenix edited this page Jul 12, 2018 · 8 revisions

Introduction

Welcome to the ToS Parser wiki. This wiki aims to document the protocol used by the game.

This is currently a WIP. Due to the lack of demand for this information, it will not be updated very frequently. If there is information you need not currently documented in the wiki, please create an issue.

Network Message Format

The data streams exchanged by the client and server can be partitioned into null-terminated messages. More specifically, a message is comprised of three parts:

  1. A non-null byte identifying the type of the message. The meaning of this byte depends on who sent the message.
  2. A stream of non-null (not 0x00) bytes that store the message's parameters.
  3. A null byte.

Messages that contain only a null byte should be ignored. For this reason, C#0 and S#0 are reserved. The parameters of the message should be parsed according to the way the messages are defined in their respective page. If it's a message sent by the client, refer to the client message types, otherwise, refer to the server message types.

Message Parameter Documentation

The message parameters are documented using a simple format inspired from that used in RFC 5246. Each statement ends in a semicolon and may have leading and trailing whitespace. All number literals in the documentation are written in hexadecimal and prefixed with 0x.

Fixed Value Statement

Messages may sometimes contain values that do not vary. These values are represented using a fixed value statement. These statements are only a number, which indicates what byte must be written in that position. When this statement follows a parameter statement with a literal or array type, the length of that parameter must be the smallest possible for the message to be valid.

Parameter Statement

Parameters are formatted similarly to C# variables. Each parameter is written with a type, whitespace, then a name. The type may be any C# primitive type except object, an enumeration defined in this wiki, a struct defined on the same wiki page, or an array of a legal type. The name may be any sequence of alphanumeric characters, dashes or underscores. The type may be prefixed by keywords, which must be separated using whitespace, including from the type.

In situations where the parameter has a numerical type (numerical primitive type, bool type, any enumeration type, or an array of a numerical type), the value is incremented by 1 over the network. This is because 0x00 signals the end of the message.

Literal Keyword

The literal keyword indicates that the value must be formatted in UTF-8 plaintext instead of using its default format. If the type is an array, the literal keyword must be followed by a number which represents the character separating the elements of the array. In the documentation, whitespace may separate these, e.g.

literal 0x2C GameMode[] gameModes;

Declaring an array as literal additionally requires the array's elements to be formatted under the rules of the literal keyword. The string type is implicitly literal, and explicitly declaring it is identical to not doing so. Declaring a structure as literal does not affect the formatting of the structure.

Switch Statement

Message parameters may sometimes be formatted in different ways for the same message. This is done using notation identical to the C# "switch" statement, except that the notation can be used on all valid non-array types. Inside switches, special control statements "break" and "goto case" can be used and function identically to those in C#, e.g.

bool change;
switch (change) {
    case true:
        Player old;
        goto case false;
    case false:
        Player new;
        break;
}

Structure Statement

Structures are special composite types that behave as one type, making it possible to repeat several values with ease. Structures are defined using identical notation to that in C# (using the struct keyword). Each structure can only be defined once. Formatting a structure consists of formatting all the statements in that structure. Accessing a value stored inside a structure for use in switch statements can be done using the name of the structure, followed by a ., followed by the identifier of the value inside that structure.

Clone this wiki locally