Skip to content
Darrin W. Cullop edited this page Feb 24, 2016 · 5 revisions

Client-To-Server Messages

Purpose

The client to server packets are how the client informs the server of how a player is moving, what weapon they are using, what their name is, what their skin is, and other client settings.

Structure

Header

Field Length Notes
Sequence Number Long (4 bytes) This is the packet sequence number.  Each packet from the client has a sequence number one higher than the previous packet.
Last Received
Sequence Number
Long (4 bytes) This is the sequence number of the packet the client last received from the server.  It lets the server know whether or not its last transmission was heard.
QPort Short (2 bytes) This is the unique ID value that is chosen by the client in order to deal with things like proxies and firewalls.
Message Data Variable The message data contains one (or possibly more) client message.  The section below has more information on client messages.

Message Types

There are 5 different message types that client sends to the server. Each message has one byte to identify what message it is, and then the corresponding data for that message (if applicable).

CLC_BAD (0x00)

This is not an actual message type, but is reserved in case there is an error parsing another message.

CLC_NOP (0x01)

NOP = No Operation

This allows the client to send a message, without having to have something meaningful to say. It usually represents a "keep alive".

CLC_MOVE (0x02)

This packet contains the information about how the client's player is moving (velocity, firing weapon, jumping, etc.). The complex structure of this packets data can be found on its own page.

CLC_USERINFO (0x03)

This message lets the client set configuration variables on the server such as "fov", "rate", and "skin".

The only field in this message is a NULL terminated string that contains the variables and the values to which they should be set. The general format for this string is a repeating set of "backslash, variable, backslash, value". Some examples:

  • \fov\90\msg\3\rate\50000\name\Pandora\skin\female/pandora\hand\2
  • \msg\2\rate\35000\name\[DvC]roark\skin\male/grunt

CLC_STRINGCMD (0x04)

This message allows the client to send console commands to the remote server. It contains one NULL terminated string indicating the console command the server is to execute.

Sample Parsing Code

Here is some sample code for how these packets could be parsed.

    // #define for the Client Message Types
    #define CLC_BAD        0
    #define CLC_NOP        1
    #define CLC_MOVE       2
    #define CLC_USERINFO   3
    #define CLC_STRINGCMD  4

    void DecodeClientPacket( QuakePacket* pMsg )
    {
       switch ( pMsg->ReadByte() )
       {
       case CLC_BAD:
           Error("Received Invalid Client Message\n");
           break;
       case CLC_NOP:
           Info("Received NoOp Message\n");
           break;
       case CLC_MOVE:
           ParseMoveMessage( pMsg );
           break;
       case CLC_USERINFO:
           ParseUserInfoMessage( pMsg );
           break;
       case CLC_STRINGCMD:
           ParseCommandMessage( pMsg );
           break;
       default:
           Error("Unknown Message Type\n");
           break;
       }
    }

    void ParseMoveMessage( QuakePacket* pMsg )
    {
       unsigned char  nCheckSum;
       unsigned long  nFrame;
       int            nCount;
       unsigned char  nMask;
       short          nOrientation[3];
       short          nVelocity[3];
       unsigned char  nButtons;
       unsigned char  nImpulse;
       unsigned char  nMSecs;
       unsigned char  nLight;

       nCheckSum = pMsg->ReadByte();
       nFrame = pMsg->ReadLong();
       for (nCount = 0; nCount < 3; nCount++)
       {
           nMask = pMsg->ReadByte();
           if (nMask & 0x01) nOrientation[0] = pMsg->ReadShort();
           if (nMask & 0x02) nOrientation[1] = pMsg->ReadShort();
           if (nMask & 0x04) nOrientation[2] = pMsg->ReadShort();
           if (nMask & 0x08) nVelocity[0] = pMsg->ReadShort();
           if (nMask & 0x10) nVelocity[1] = pMsg->ReadShort();
           if (nMask & 0x20) nVelocity[2] = pMsg->ReadShort();
           if (nMask & 0x40) nButtons = pMsg->ReadByte();
           if (nMask & 0x80) nImpulse = pMsg->ReadByte();
           nMSecs = pMsg->ReadByte();
           nLight = pMsg->ReadByte();
       }
    }

    void ParseUserInfoMessage( QuakePacket* pMsg )
    {
       pMsg->ReadString();
    }

    void ParseCommandMessage( QuakePacket* pMsg )
    {
       pMsg->ReadString();
    }

Extra Information

Here is some extra information about a few of the packet types.

CLC_USERINFO (0x03)

Here are the known variables used in this packet:

`fov` Tells the server what the client's horizontal "Field of View" is
1. `fov` Tells the server what the client's horizontal "Field of View" is 1. `rate` Indicates the maximum number of bytes the client should receive from the server per second 1. `msg` Indicates the minimum priority for SVC_PRINT messages 1. `name` Indicates the player name for the client 1. `skin` Indicates what skin the client is using in the format of "model/skinname" 1. `hand` Indicates the "handedness" of the client (0 = Left, 1 = Right, 2 = None) 1. `password` Specifies the client's password for the current server (must match the one set on the server in order for it to allow a connection)

CLC_STRINGCMD (0x04)

Here are the known commands:

  1. new Used in the handshaking process
  2. configstrings %d %d Used to request server information strings
  3. baselines %d %d Used to request entity information
  4. begin
  5. nextserver UNKNOWN
  6. disconnect Drops the connection from the server
  7. info
  8. download %s Requests the file "%s" from the server
  9. nextdl Requests the next block of a file that was previously requested with "download"

If the server receives a command that is not on the above list, it will pass it along to the .DLL that is running the game. This allows mod authors to create their own custom commands. It is important to remember that commands such as "say", "use", "drop", and "say_team" are all implemented in the DLL, which is why they do not appear on this list.