Skip to content

Latest commit

 

History

History
397 lines (286 loc) · 16.3 KB

Protocol.md

File metadata and controls

397 lines (286 loc) · 16.3 KB

VSCP Documentation

This is an unofficial documentation of the Virtual Society Server-Client Protocol (VSCP). Most of the content written here are hypotheses from manual packet decoding, therefore it might not be accurate. The interpretations provided here should be considered entirely subjective.

Currently, it is also incomplete as some parts of the protocol lack any viable explaination. If you feel like something could use a better interpretation or you have a hypothesis on how something works, feel free to make a suggestion or a PR.

Overview

The protocol follows a client-server model and uses TCP for sending data between the server and its clients.

The data that it sends is sometimes a mix of binary and "human readable" data, therefore thoughout this documentation, both hexadecimal and string representations are provided where applicable. The strings might include C-like escape sequences.

Glossary

Packet layout

A packet layout is described using a table, split into sections (rows) that follows one another in the exact order of the actual packet itself.

Example:

Section Size Type
Number of cats 4 uint32
Number of dogs 2 uint16
Some data 12 data
Some text ~ string

All of the section sizes provided here are in bytes. Sections with ~ as the size have a varying size.

Types

  • data: Raw (arbitrary) data
  • int8, int16, int32: n-bit signed integer
  • uint8, uint16, uint32: n-bit unsigned integer
  • string: Null-terminated string. Does not have a determined size.
  • int32float: Special type used to store floating point values as 32-bit big-endian signed integers. The float value would be multiplied by 65536 and then casted to a 32-bit signed integer.
    • The original float value is calculated by dividing the integer by 65536.

All other integer types are in little-endian byte order.

Aura

Throughout the documentation, you'll find mentions of a user's "aura". This is used to refer to the Aura system used by the server.

In a nutshell: Each user will have a defined radius where they can be seen; that is their aura. If a user's aura overlaps another user's, then they can "see" each other.

This system is referenced from: Benford, S., & Fahlén, L. (1993). A spatial model of interaction in large virtual environments. In ECSCW 1993: Proceedings of the Third European Conference on Computer Supported Cooperative Work. Kluwer Academic Publishers, Dordrecht, The Netherlands.

The Aura system has influence on what data the client will accept from other users. If a client was sent any message that makes use of the broadcast ID (which also identifies their Aura) from another user that can't be "seen" by it, it will actively ignore the message. The server should also not send any message that are not within their aura.

The hello Packet

To establish a connection to the server, the client first performs a TCP 3-way handshake with the server. If that succeeds, it sends the hello packet to the server:

Hex String
0x68 0x65 0x6c 0x6c 0x6f 0x01 0x01 hello\x01\x01

The server then replies with a matching hello packet, followed by the connection ID:

Section Size Type
Header 13 data
Connection ID 1 uint8

The header data is as follows:

Hex String
0x68 0x65 0x6c 0x6c 0x6f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 hello\0\0\0\0\0\0\0\0

The connection ID is generated by the server and could be used to uniquely identify clients. The original server software supposedly generated this ID by simply incrementing a counter and using the value until it hits 255, then go back to 0.

After receiving the hello packet from the server, the client should immediately follow up with a message packet containing a CMSG_NEW_USER section.

Message Packets

After sending the hello packet, the client and the server can now talk to each other through structured message packets. A packet may contain multiple message sections placed one after another.

A section will always start with the following data:

Section Size Type
Section type 4 uint32

The section type defines how the message section should be interpreted.

Section sizes varies between different section types:

  • For General Message sections: 17 + n bytes (let n be the content size, see below)
  • For Position Update sections: 27 bytes

General Message

Section Size Type
Section type 4 uint32
ID 1 4 uint32
ID 2 4 uint32
Opcode 4 uint32
Content size (n) 1 uint8
Content n data
  • Section type = 0

ID 1 and 2's values are set depending on the type of opcode used and does not necessarily correlate to the current client's IDs.

For client messages: ID 1 is usually set to the connection ID, while ID 2 is usually set to the client ID (see SMSG_CLIENT_ID)

For server messages: ID values varies between each message type and content, check each of them for more details.

It is not important to distinguish between ID 1 and ID 2 (or between the connection ID and the client ID) as long as the server has enough information to identify a client and set unique IDs for each message.

The opcode describes how the content should be interpreted by the receiver.

  • Known opcodes:
    CMSG_NEW_USER     = 0,
    SMSG_CLIENT_ID    = 1,
    SMSG_USER_JOINED  = 2,
    SMSG_USER_LEFT    = 3,
    SMSG_BROADCAST_ID = 4,
    MSG_COMMON        = 6,
    CMSG_STATE_CHANGE = 7,
    SMSG_UNNAMED_1    = 8,
    SMSG_USER_COUNT   = 11

Opcodes prefixed with MSG are used by both the client and the server, while CMSG and SMSG are used exclusively by the client and the server respectively. UNNAMED opcodes are opcodes that have no exact meaning bound to them (yet)

The following subsections describe the data expected in the content section of the message, depending on the opcode:

CMSG_NEW_USER

The first thing that the client sends after receiving the server's hello reply is the CMSG_NEW_USER message, which identifies the user.

Section Size Type
Username ~ string
Avatar path ~ string

The avatar path is a relative path based on where the avatar is located in the current world's directory, which could be a local or a remote directory (served over HTTP and loaded by Netscape). Example: avtwrl/01cat.wrl

After receiving the CMSG_NEW_USER message, the server will proceed to broadcast SMSG_USER_COUNT to all clients connected to it. The server will also send SMSG_CLIENT_ID, SMSG_UNNAMED_1, SMSG_USER_JOINED and SMSG_BROADCAST_ID messages back to the current client.

SMSG_CLIENT_ID

Used to send the client ID. It can be identical to the connection ID.

Section Size Type
Unknown 3 data
Client ID 1 uint8

The unknown bytes are always set to zeroes.

In the original server software, the client ID (which is generated after CMSG_NEW_USER was sent) might differ from the connection ID (which is generated when the socket was first opened). However, it is fine to use the same ID for both.

SMSG_USER_JOINED

Used to announce that someone has joined a user's aura.

Section Size Type
ID 1 Type 2 uint16
Broadcast ID 1 2 uint16
ID 2 Type 2 uint16
Broadcast ID 2 2 uint16
Avatar path ~ string
Username ~ string

Broadcast ID 1 is always set to the broadcast ID of the user that joined the Aura. It is unknown what the second broadcast ID is used for, as it differs between users to users, although setting it to the same ID will work just fine. Both broadcast ID types must be set to 0.

SMSG_USER_LEFT

Used to announce that someone has left a user's aura. This is also sent to other users within their aura when a user leaves the server.

Section Size Type
ID type 2 uint16
Broadcast ID 2 uint16

SMSG_BROADCAST_ID

Used to send the client's broadcast ID, which will be used for messages that are bound to a specific user (position updates, chat, state changes, etc.)

Section Size Type
ID type 2 uint16
Broadcast ID 2 uint16

Type must always be 0. 0xFFFF is a reserved type. The broadcast ID seems to be a randomly generated value from 1 to 0xFFFF (0 is reserved for "no broadcast ID"). Could also be used to uniquely identify a client.

MSG_COMMON

As the name implies, this is the most common opcode and is used for a number of things.

Section Size Type
ID type 2 uint16
Broadcast ID 2 uint16
Type 4 uint32
Subtype 1 uint8
Content ~ data

The type defines what the content contains. Known types:

    APPL_SPECIFIC    = 0x10270000,
    CHAT_SEND        = 0x09000000,
    NAME_CHANGE      = 0x0D000000,
    AVATAR_CHANGE    = 0x0E000000,
    TRANSFORM_UPDATE = 0x02000000,
    CHARACTER_UPDATE = 0x0C000000,
    VOICE_STATE      = 0x12000000,
    UNNAMED_1        = 0x10000000,
    PRIVATE_CHAT     = 0x0F000000

Possible subtype values are 0, 1, 2 and 3. They define what to do with the message.

  • If subtype is 0 or 1, the message should be broadcasted to other clients.
  • If subtype is 2 or 3, the message should be sent back to the client with the broadcast ID specified in the message. Usually, this is the ID of the same user, however some content types might have a different one (such as PRIVATE_CHAT)

Each type usually has a specific subtype. Note that when broadcasting messages to other clients, ID 1 and ID 2 must be set to those of the client being sent to.

The following subsections describe the content data of each type:

APPL_SPECIFIC

  • Subtype = 2 (other values are possible, but deprecated)
Section Size Type
Unknown 1 uint8
Method name ~ string
Argument ~ string
ID type 2 uint16
Broadcast ID 2 uint16

Used to invoke the specified script function. Sent by calling the vs.Vscp.sendApplSpecificMsgWithDist Java API.

The ID type must be set to 0xFFFF and broadcast ID must be set to 0xF1D8 (unknown purpose/unconfirmed). This type of message could also be sent by the client without having a broadcast ID.

CHAT_SEND

  • Subtype = 0

Used to send chat messages.

Section Size Type
Message ~ string

NAME_CHANGE

  • Subtype = 1

Used to announce a name change.

Section Size Type
New name ~ string

AVATAR_CHANGE

  • Subtype = 1

Used to announce an avatar change.

Section Size Type
New avatar ~ string

TRANSFORM_UPDATE

  • Subtype = 1

Used to update the character's transformation matrix and position. The transformation matrix is a 3x3 matrix with 9 int32float values.

Section Size Type
Matrix value 1 4 int32float
...
Matrix value 9 4 int32float
X 4 int32float
Y 4 int32float
Z 4 int32float

Note: Due to how the data is laid out, it's safe to assume that the character's position (or translation) is not contained within the transformation matrix.

CHARACTER_UPDATE

  • Subtype = 1

Used to update the character data. This is also a companion to CMSG_STATE_CHANGE, since it can't actually broadcast the user's state to other players.

Section Size Type
Data ~ string

The data will look something like this: sleep:0 1:000000000000:58:0:

  • The first part (sleep:0) tells whether the character is sleeping or not (1 for true, 0 for false)
  • The second part contains the character data, each part separated by a colon:
    • The first value (1) is the number of the avatar.
    • Next is the body parts's color and scale:
      • Each body part has two values, the first value is the color, the second value is the scale.
      • The amount of values depends on how much body parts the user's avatar has.
    • After that is the minutes spent using that particular avatar (58)
    • The final value is user's medal, which is awarded if they have spent enough time using that avatar (none = 0, happy = 1, lucky = 2, lovely = 3).

VOICE_STATE

Used to update the voice chat state.

Section Size Type
Unknown 4 uint32
Unknown 1 uint8
State 1 uint8

Both unknown values always seem to be set to 1.

A state value of 2 seems to stand for Disabled, while 3 stands for Enabled.

UNNAMED_1

Unknown purpose. Sent by Browser v2.0 alpha 2 or later upon connecting to the server, a bit after sending the CMSG_NEW_USER packet. Probably used for voice chat?

PRIVATE_CHAT

Used to initiate and send private chat messages to other users.

Section Size Type
ID type 2 uint16
Broadcast ID 2 uint16
Message ~ string

Note that the broadcast ID in the header of the message is for the user that the message is being sent to, while the broadcast ID here is for the user that sent the message.

The message may contain special values that starts with %% to communicate with the client application itself. Possible values:

  • %%REQ: Used to initiate a request to chat with another user. Also used as a keep-alive message which is sent periodically.
  • %%RINGING: Let the sender know that the end user is being prompted for the chat request.
  • %%ACCEPT: Accept the chat request.
  • %%REJECT: Reject the chat request.
  • %%OK: Used to reply to a keep-alive %%REQ message.
  • %%END: Used by either clients to end the chat session.

CMSG_STATE_CHANGE

Used to announce a player state change.

Section Size Type
State 1 uint8

Known state values:

  • 0x00: NOT_CONNECTED
  • 0x01: CONNECTING
  • 0x02: CONNECTED
  • 0x03: DISCONNECTING
  • 0x04: ACTIVE
  • 0x05: SLEEP

Active and Sleep can be activated manually by the user. The Disconnecting state is triggered when the Browser is closing itself and will terminate the connection shortly. Other states are used internally by the client and are not sent to the server.

If the state is Active or Sleep, the client will follow up with another packet containing a MSG_COMMON section to send the sleep state.

SMSG_UNNAMED_1

Unknown purpose.

Section Size Type
Value 1 uint8

Value is always set to 1.

SMSG_USER_COUNT

Used to announce the number of users in the server.

Section Size Type
Unknown 4 uint32
User count 1 uint8

The unknown value is always set to 1.

Position Update

Used to update the character's position.

Section Size Type
Section type 4 uint32
ID 1 4 uint32
ID 2 1 uint8
ID type 2 uint16
Broadcast ID 2 uint16
X 4 int32float
Y 4 int32float
Z 4 int32float
Unknown 2 uint16
  • Section type = 2

ID 1 and ID 2 are always set to the connection ID and the client ID of the user, repectively. ID type must always be 0.

The unknown value is always set to 0x100.

The server should broadcast this message to other users that are within the aura of the current user. ID 1 and ID 2 of the broadcasted message must be set to those of the user being sent to.

The server can also send a Position Update message to update any client's own character position.

Limitations

By design, the protocol is limited to 256 concurrent users. This is because, the hello packet that the server sends only uses an uint8 to send the connection ID; effectively limiting its range from 0 to 255, thus limiting it to 256 possible values. However, it is still entirely possible for a server to handle more than that, as TCP doesn't limit the amount of active connections, though it is impractical to do so. This is where WLS comes into use.

Special thanks

This documentation was made possible by the help of these folks:

  • barra: Provided information for the character update data.
  • Twig: Discovered how the character position and rotation values are encoded.

License

This documentation is licensed under CC BY-SA 4.0