|
|
|
# JS5 protocol
|
|
|
|
|
|
|
|
The JS5 remote protocol is used by the client to download groups of files from
|
|
|
|
the server as they are required, as well as prefetching certain groups in
|
|
|
|
advance. Groups contain the client's assets and scripts, and are stored in the
|
|
|
|
cache.
|
|
|
|
|
|
|
|
The client opens a connection to the primary game server port and sends the
|
|
|
|
`INIT_JS5REMOTE_CONNECTION` packet, which consists of a single byte opcode
|
|
|
|
(`15`) followed by the client's build number as an integer.
|
|
|
|
|
|
|
|
The server responds with a single `0` byte if the connection attempt is
|
|
|
|
successful. It may also respond with `CLIENT_OUT_OF_DATE` (`6`), `SERVER_FULL`
|
|
|
|
(`7`) or `IP_LIMIT` (`9`), after which the connection will be closed.
|
|
|
|
|
|
|
|
After a successful connection attempt, the connection remains in JS5 mode for
|
|
|
|
the rest of its life.
|
|
|
|
|
|
|
|
JS5 is a request/response protocol with support for pipelining - the 550 client
|
|
|
|
is capable of handling up to 20 prefetch and 20 urgent in-flight requests.
|
|
|
|
|
|
|
|
## Upstream
|
|
|
|
|
|
|
|
| Opcode | Description |
|
|
|
|
|-------:|--------------------------|
|
|
|
|
| 0 | Request group (prefetch) |
|
|
|
|
| 1 | Request group (urgent) |
|
|
|
|
| 2 | Logged in |
|
|
|
|
| 3 | Logged out |
|
|
|
|
| 4 | Rekey |
|
|
|
|
| 6 | Connected |
|
|
|
|
| 7 | Disconnect |
|
|
|
|
|
|
|
|
All upstream packets are exactly 4 bytes long, including the opcode. Unused
|
|
|
|
payload bytes are set to zero.
|
|
|
|
|
|
|
|
### 0 (Request group (prefetch))
|
|
|
|
|
|
|
|
| Data type | Description |
|
|
|
|
|---------------|-------------|
|
|
|
|
| UnsignedByte | Archive ID |
|
|
|
|
| UnsignedShort | Group ID |
|
|
|
|
|
|
|
|
Requests a group. Prefetch requests are used to prepopulate most of the cache
|
|
|
|
in the background.
|
|
|
|
|
|
|
|
### 1 (Request group (urgent))
|
|
|
|
|
|
|
|
| Data type | Description |
|
|
|
|
|---------------|-------------|
|
|
|
|
| UnsignedByte | Archive ID |
|
|
|
|
| UnsignedShort | Group ID |
|
|
|
|
|
|
|
|
Requests a group. Urgent requests have a higher priority than prefetch requests,
|
|
|
|
as the client needs the group immediately.
|
|
|
|
|
|
|
|
### 2 (Logged in)
|
|
|
|
|
|
|
|
Sent whenever the player logs into the game. Consensus in the community is that
|
|
|
|
the logged in/out state is probably used for prioritisation, much like the
|
|
|
|
distinction between prefetch/urgent requests.
|
|
|
|
|
|
|
|
### 3 (Logged out)
|
|
|
|
|
|
|
|
Sent whenever the player logs out of the game.
|
|
|
|
|
|
|
|
### 4 (Rekey)
|
|
|
|
|
|
|
|
| Data type | Description |
|
|
|
|
|---------------|----------------------|
|
|
|
|
| UnsignedByte | Key |
|
|
|
|
| UnsignedShort | Unused (set to zero) |
|
|
|
|
|
|
|
|
Sent to set the encryption key.
|
|
|
|
|
|
|
|
### 6 (Connected)
|
|
|
|
|
|
|
|
| Data type | Description |
|
|
|
|
|----------------|-----------------------------|
|
|
|
|
| UnsignedMedium | Unknown (always set to `3`) |
|
|
|
|
|
|
|
|
Sent immediately after the JS5 connection is established. Its purpose is not
|
|
|
|
known.
|
|
|
|
|
|
|
|
### 7 (Disconnect)
|
|
|
|
|
|
|
|
Requests that the server closes the connection. Sent by the `::serverjs5drop`
|
|
|
|
command.
|
|
|
|
|
|
|
|
## Downstream
|
|
|
|
|
|
|
|
There is only a single type of response packet, and as such, there are no
|
|
|
|
response opcodes. The packet contains a group requested by the client.
|
|
|
|
|
|
|
|
| Data type | Description |
|
|
|
|
|----------------|-----------------------------------------------------------|
|
|
|
|
| UnsignedByte | Archive ID |
|
|
|
|
| UnsignedShort | Group ID |
|
|
|
|
| UnsignedByte | Compression type (ORed with `0x80` for prefetch requests) |
|
|
|
|
| Int | Compressed length |
|
|
|
|
| Int (optional) | Uncompressed length (present iff the group is compressed) |
|
|
|
|
| Byte[] | Compressed data (with `0xFF` markers, see below) |
|
|
|
|
|
|
|
|
If encryption is enabled, all downstream bytes are XORed with the encryption
|
|
|
|
key. The client enables encryption if the checksum of a group does not match the
|
|
|
|
expected checksum in the master index or index.
|
|
|
|
|
|
|
|
The encryption scheme is probably used to defend against middle boxes tampering
|
|
|
|
with the plaintext traffic.
|
|
|
|
|
|
|
|
After the first 512 bytes of a response (including the header), every subsequent
|
|
|
|
block of 511 bytes is prefixed with a single `0xFF` byte.
|