Teeworlds 0.6

List of network system messages

There are three types of messages with overlapping message ids:
system messages, game messages and control messages
This list is only covering system messages.

When the client and server exchange packets. An integer field which usually does not exceed one byte. Is indicating which type of message was sent. This field is called the message id. These message ids are defined in src/engine/shared/protocol.h and their payload is defined where they are sent and received. There can be multiple messages in so called chunks in one teeworlds packet.

In the list below you will find those message. With their name, id and payload.


NETMSG_NULL

Message ID:0


NETMSG_INFO

Sender:Client
Recipient:Server
Message ID:1
Response to:NET_CTRLMSG_ACCEPT
Expected response:NETMSG_MAP_CHANGE
Argument name Type Note
Net Version String TODO
Password String TODO
Sent by the client in CClient::SendInfo()
                
    void CClient::SendInfo()
    {
        CMsgPacker Msg(NETMSG_INFO);
        Msg.AddString(GameClient()->NetVersion(), 128);
        Msg.AddString(g_Config.m_Password, 128);
        SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH);
    }
                
            
The server respons to it in CServer::ProcessClientPacket() with NETMSG_MAP_CHANGE in a call to SendMap(ClientID);
                
    void CServer::ProcessClientPacket(CNetChunk *pPacket)
    {
            // [...]

            if(Sys)
            {
                    // system message
                    if(Msg == NETMSG_INFO)
                    {
                            if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State == CClient::STATE_AUTH)
                            {
                                    const char *pVersion = Unpacker.GetString(CUnpacker::SANITIZE_CC);
                                    if(str_comp(pVersion, GameServer()->NetVersion()) != 0)
                                    {
                                            // wrong version
                                            char aReason[256];
                                            str_format(aReason, sizeof(aReason), "Wrong version. Server is running '%s' and client '%s'", GameServer()->NetVersion(), pVersion);
                                            m_NetServer.Drop(ClientID, aReason);
                                            return;
                                    }

                                    const char *pPassword = Unpacker.GetString(CUnpacker::SANITIZE_CC);
                                    if(g_Config.m_Password[0] != 0 && str_comp(g_Config.m_Password, pPassword) != 0)
                                    {
                                            // wrong password
                                            m_NetServer.Drop(ClientID, "Wrong password");
                                            return;
                                    }

                                    m_aClients[ClientID].m_State = CClient::STATE_CONNECTING;
                                    SendMap(ClientID);
                            }
                    }
                
            


NETMSG_MAP_CHANGE

Sender:Server
Recipient:Client
Message ID:2
Response to: TODO
Expected response: TODO
Argument name Type Note
Map name String TODO
Crc Int TODO
Size Int TODO
Sent by the server in CServer::SendMap(int ClientID)
                
    void CServer::SendMap(int ClientID)
    {
        CMsgPacker Msg(NETMSG_MAP_CHANGE);
        Msg.AddString(GetMapName(), 0);
        Msg.AddInt(m_CurrentMapCrc);
        Msg.AddInt(m_CurrentMapSize);
        SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true);
    }
                
            


NETMSG_MAP_DATA

Sender:Server
Recipient:Client
Message ID:3
Response to: TODO
Expected response: TODO
Argument name Type Note
Last Int TODO
Current map crc Int TODO
Chunk Int TODO
Chunk size Int TODO
Data Raw TODO
Sent by the server in CServer::ProcessClientPacket()
                
    CMsgPacker Msg(NETMSG_MAP_DATA);
    Msg.AddInt(Last);
    Msg.AddInt(m_CurrentMapCrc);
    Msg.AddInt(Chunk);
    Msg.AddInt(ChunkSize);
    Msg.AddRaw(&m_pCurrentMapData[Offset], ChunkSize);
    SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true);
                
            


NETMSG_CON_READY

Sender:Server
Recipient:Client
Message ID:4
Response to: TODO
Expected response: TODO
Argument name Type Note
None
Sent by the server in CServer::SendConnectionReady()
                
    void CServer::SendConnectionReady(int ClientID)
    {
        CMsgPacker Msg(NETMSG_CON_READY);
        SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true);
    }
                
            
Unpacked by the client in CClient::ProcessClientPacket()
                
    else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_CON_READY)
    {
        GameClient()->OnConnected();
    }
                
            


NETMSG_SNAP

Sender:Server
Recipient:Client
Message ID:5
Response to: Updates in the world
Expected response: The client acknowledges the Game tick in the message NETMSG_INPUT
Argument name Type Note
Game tick Int TODO
Delta tick Int The base snapshot game tick which the delta was created from. Will be -1 for the first snapshot signaling it is a delta based on the empty snapshot.
Num parts Int Indicates the total amount of parts for this snapshot. The current part is set in the Part field. The client is supposed to collect the payload and concatinate it locally and only if the last part is received it should parse the snapshot. Where last part is defined as Part == Num Parts - 1.

So if Num Parts is set to 2 the first Part will be 0 and the second (last) will be 1.
Part Int 0 based index for Num Parts.
Crc Int The crc (cyclic redundancy check) is used as a checksum verifying the integrity of the snapshot. It is all snapshot item payloads summed together into one 32 bit integer. The reference implementation might overflow the crc and so should you to match the exact value. More details on how to calculate the crc can be seen in the teeframe documentation.

Important to understand is that the crc is not applied to only the snap items sent in this net message but the full snapshot. Every snap msg is just a delta that might add or remove items from a previous snapshot. So if the client already knows about a snapshot with 3 items and then another NETMSG_SNAP comes in with 3 additional items as payload the crc has to be calculated on all 6 items that are now in the fully unpacked snapshot.
Part size Int The size of this part. Meaning the size in bytes of the next raw data field.
Data Raw The partial snapshot data. It should be only processed when all Num parts are assembled together.

The snapshot data. Which is a bunch of packed ints. The first is the amount of removed items. The second is the amount of item deltas. The third a unused zero byte. Then there are "amount of removed items" repeated integers identifying the deleted items. Followed by "amount of item deltas" repeated snap items You can read more about snap items and the structure of this data field in the snap items section.


NETMSG_SNAPEMPTY

Sender:TODO
Recipient:TODO
Message ID:6
Response to: TODO
Expected response: TODO
Argument name Type Note
TODO String Int TODO


NETMSG_SNAPSINGLE

Sender:Server
Recipient:Client
Message ID:7
Response to: Updates in the world
Expected response: The client acknowledges the Game tick in the message NETMSG_INPUT
Argument name Type Note
Game tick Int TODO
Delta tick Int The base snapshot game tick which the delta was created from. Will be -1 for the first snapshot signaling it is a delta based on the empty snapshot.
Crc Int The crc is a checksum. More details here.
Part size Int The size of this part. Meaning the size in bytes of the next raw data field.
Data Raw The snapshot data. Which is a bunch of packed ints. The first is the amount of removed items. The second is the amount of item deltas. The third a unused zero byte. Then there are "amount of removed items" repeated integers identifying the deleted items. Followed by "amount of item deltas" repeated snap items You can read more about snap items and the structure of this data field in the snap items section.
One full snapshot. If it does not fit into one message it will be split into multiple parts and send as NETMSG_SNAP instead.


NETMSG_SNAPSMALL

Sender:TODO
Recipient:TODO
Message ID:8
Response to: TODO
Expected response: TODO
Argument name Type Note
TODO String Int TODO


NETMSG_INPUTTIMING

Sender:Server
Recipient:Client
Message ID:9
Response to: TODO
Expected response: TODO
Argument name Type Note
Intended tick Int TODO
Time left Int TODO
Sent by the server in CServer::ProcessClientPacket()
                
    if(IntendedTick > m_aClients[ClientID].m_LastInputTick)
    {
        int TimeLeft = ((TickStartTime(IntendedTick)-time_get())*1000) / time_freq();

        CMsgPacker Msg(NETMSG_INPUTTIMING);
        Msg.AddInt(IntendedTick);
        Msg.AddInt(TimeLeft);
        SendMsgEx(&Msg, 0, ClientID, true);
    }
                
            
Unpacked by the client in CClient::ProcessServerPacket()
                
    else if(Msg == NETMSG_INPUTTIMING)
    {
        int InputPredTick = Unpacker.GetInt();
        int TimeLeft = Unpacker.GetInt();

        // adjust our prediction time
        int64 Target = 0;
        for(int k = 0; k < 200; k++)
        {
            if(m_aInputs[k].m_Tick == InputPredTick)
            {
                Target = m_aInputs[k].m_PredictedTime + (time_get() - m_aInputs[k].m_Time);
                Target = Target - (int64)(((TimeLeft-PREDICTION_MARGIN)/1000.0f)*time_freq());
                break;
            }
        }

        if(Target)
            m_PredictedTime.Update(&m_InputtimeMarginGraph, Target, TimeLeft, 1);
    }
                
            


NETMSG_RCON_AUTH_STATUS

Sender:Server
Recipient:Client
Message ID:10
Response to: NETMSG_RCON_CMD logout |
NETMSG_RCON_AUTH
Expected response: TODO
Argument name Type Note
Authed Int
  • 0 - off (logout)
  • 1 - on (login)
Cmdlist Int
  • 0 - off (logout)
  • 1 - on (login)
Sent on login and logout by the server to inform the client about its rcon state. The client then activates or deactivates the remote console in the ui.

Sent by the server in CServer::ProcessClientPacket() on successful login.
                
    else if(Msg == NETMSG_RCON_AUTH)
    {
        const char *pPw;
        Unpacker.GetString(); // login name, not used
        pPw = Unpacker.GetString(CUnpacker::SANITIZE_CC);

        if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Error() == 0)
        {
            if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0] == 0)
            {
                SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console.");
            }
            else if(g_Config.m_SvRconPassword[0] && str_comp(pPw, g_Config.m_SvRconPassword) == 0)
            {
                CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
                Msg.AddInt(1);	//authed
                Msg.AddInt(1);	//cmdlist
                SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);

                m_aClients[ClientID].m_Authed = AUTHED_ADMIN;
                int SendRconCmds = Unpacker.GetInt();
                if(Unpacker.Error() == 0 && SendRconCmds)
                    m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_ADMIN, CFGFLAG_SERVER);
                SendRconLine(ClientID, "Admin authentication successful. Full remote console access granted.");
                char aBuf[256];
                str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID);
                Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
            }
            else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0)
            {
                CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
                Msg.AddInt(1);	//authed
                Msg.AddInt(1);	//cmdlist
                SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);

                m_aClients[ClientID].m_Authed = AUTHED_MOD;
                int SendRconCmds = Unpacker.GetInt();
                if(Unpacker.Error() == 0 && SendRconCmds)
                    m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_MOD, CFGFLAG_SERVER);
                SendRconLine(ClientID, "Moderator authentication successful. Limited remote console access granted.");
                char aBuf[256];
                str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID);
                Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
            }
            else if(g_Config.m_SvRconMaxTries)
            {
                m_aClients[ClientID].m_AuthTries++;
                char aBuf[128];
                str_format(aBuf, sizeof(aBuf), "Wrong password %d/%d.", m_aClients[ClientID].m_AuthTries, g_Config.m_SvRconMaxTries);
                SendRconLine(ClientID, aBuf);
                if(m_aClients[ClientID].m_AuthTries >= g_Config.m_SvRconMaxTries)
                {
                    if(!g_Config.m_SvRconBantime)
                        m_NetServer.Drop(ClientID, "Too many remote console authentication tries");
                    else
                        m_ServerBan.BanAddr(m_NetServer.ClientAddr(ClientID), g_Config.m_SvRconBantime*60, "Too many remote console authentication tries");
                }
            }
            else
            {
                SendRconLine(ClientID, "Wrong password.");
            }
        }
    }
                
            
And also send by the server in CServer::ConLogout() when the rcon command logout is executed.
                
    void CServer::ConLogout(IConsole::IResult *pResult, void *pUser)
    {
        CServer *pServer = (CServer *)pUser;

        if(pServer->m_RconClientID >= 0 && pServer->m_RconClientID < MAX_CLIENTS &&
            pServer->m_aClients[pServer->m_RconClientID].m_State != CServer::CClient::STATE_EMPTY)
        {
            CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
            Msg.AddInt(0);	//authed
            Msg.AddInt(0);	//cmdlist
            pServer->SendMsgEx(&Msg, MSGFLAG_VITAL, pServer->m_RconClientID, true);

            pServer->m_aClients[pServer->m_RconClientID].m_Authed = AUTHED_NO;
            pServer->m_aClients[pServer->m_RconClientID].m_AuthTries = 0;
            pServer->m_aClients[pServer->m_RconClientID].m_pRconCmdToSend = 0;
            pServer->SendRconLine(pServer->m_RconClientID, "Logout successful.");
            char aBuf[32];
            str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out", pServer->m_RconClientID);
            pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
        }
    }
                
            
Unpacked by the client in CClient::ProcessServerPacket()
                
    else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_AUTH_STATUS)
    {
        int Result = Unpacker.GetInt();
        if(Unpacker.Error() == 0)
            m_RconAuthed = Result;
        int Old = m_UseTempRconCommands;
        m_UseTempRconCommands = Unpacker.GetInt();
        if(Unpacker.Error() != 0)
            m_UseTempRconCommands = 0;
        if(Old != 0 && m_UseTempRconCommands == 0)
            m_pConsole->DeregisterTempAll();
    }
                
            


NETMSG_RCON_LINE

Sender:Server
Recipient:Client
Message ID:11
Response to: TODO
Expected response: TODO
Argument name Type Note
Line String TODO
Sent by the server in CServer::SendRconLine(int ClientID, const char *pLine)
                
    void CServer::SendRconLine(int ClientID, const char *pLine)
    {
        CMsgPacker Msg(NETMSG_RCON_LINE);
        Msg.AddString(pLine, 512);
        SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
    }
                
            


NETMSG_AUTH_CHALLANGE

Sender:Unused
Recipient:Unused
Message ID:12
Response to: Unused
Expected response: Unused
Argument name Type Note
Unused
This message ID is unused
Note challenge is misspelled (here to optimize search results)


NETMSG_AUTH_RESULT

Sender:unused
Recipient:unused
Message ID:13
Response to: unused
Expected response: unused
Argument name Type Note
Unused
This message ID is unused


NETMSG_READY

Sender:Client
Recipient:Server
Message ID:14
Response to: TODO
Expected response: TODO
Argument name Type Note
None
Sent by the client in CClient::SendReady()
                
    void CClient::SendReady()
    {
        CMsgPacker Msg(NETMSG_READY);
        SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH);
    }
                
            


NETMSG_ENTERGAME

Sender:Client
Recipient:Server
Message ID:15
Response to: TODO
Expected response: TODO
Argument name Type Note
None
Sent by the client in CClient::SendEnterGame()
                
    void CClient::SendEnterGame()
    {
        CMsgPacker Msg(NETMSG_ENTERGAME);
        SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH);
    }
                
            


NETMSG_INPUT

Sender:Client
Recipient:Server
Message ID:16
Response to: TODO
Expected response: TODO
Argument name Type Note
Ack Game Tick Int Informs the server it can now use the snapshot with this game tick as base for new delta snapshots.
Prediction Tick Int TODO
Size Int TODO
[data] Direction Int m_Direction of the CNetObj_PlayerInput struct.
Indicating the direction the tee wants to walk in.
  • -1 is left
  • 1 is right
  • 0 is stop
[data] TargetX Int m_TargetX of the CNetObj_PlayerInput struct.
X coordinate of the tees cursor. The coordinate is not absolute in the world but relative to the tee. The tee being the origin 0,0 and aiming left would be a negative x coordinate and aiming right would be a positive x coordinate.
[data] TargetY Int m_TargetY of the CNetObj_PlayerInput struct.
Y coordinate of the tees cursor. The coordinate is not absolute in the world but relative to the tee. The tee being the origin 0,0 and aiming up would be a negative y coordinate and aiming down would be a positive y coordinate.
[data] Jump Int m_Jump of the CNetObj_PlayerInput struct.
  • 1 to jump while on ground
  • 1 to double jump while in air
  • 0 to stop holding jump
[data] Fire Int m_Fire of the CNetObj_PlayerInput struct.
[data] Hook Int m_Hook of the CNetObj_PlayerInput struct.
  • 1 to hook
  • 0 to stop hooking
[data] PlayerFlags Int m_PlayerFlags of the CNetObj_PlayerInput struct.
[data] WantedWeapon Int m_WantedWeapon of the CNetObj_PlayerInput struct.
[data] NextWeapon Int m_NextWeapon of the CNetObj_PlayerInput struct.
[data] PrevWeapon Int m_PrevWeapon of the CNetObj_PlayerInput struct.
                
    struct CNetObj_PlayerInput
    {
        int m_Direction;
        int m_TargetX;
        int m_TargetY;
        int m_Jump;
        int m_Fire;
        int m_Hook;
        int m_PlayerFlags;
        int m_WantedWeapon;
        int m_NextWeapon;
        int m_PrevWeapon;
    };
                
            


NETMSG_RCON_CMD

Sender:Client
Recipient:Server
Message ID:17
Response to: TODO
Expected response: TODO
Argument name Type Note
Command String The rcon command like for example status or shutdown
Sent by the client in CClient::Rcon(const char *pCmd)
                
    void CClient::Rcon(const char *pCmd)
    {
        CMsgPacker Msg(NETMSG_RCON_CMD);
        Msg.AddString(pCmd, 256);
        SendMsgEx(&Msg, MSGFLAG_VITAL);
    }
                
            
Unpacked by the server in CServer::ProcessClientPacket()
                
    else if(Msg == NETMSG_RCON_CMD)
    {
        const char *pCmd = Unpacker.GetString();

        if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Error() == 0 && m_aClients[ClientID].m_Authed)
        {
            char aBuf[256];
            str_format(aBuf, sizeof(aBuf), "ClientID=%d rcon='%s'", ClientID, pCmd);
            Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf);
            m_RconClientID = ClientID;
            m_RconAuthLevel = m_aClients[ClientID].m_Authed;
            Console()->SetAccessLevel(m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD);
            Console()->ExecuteLineFlag(pCmd, CFGFLAG_SERVER);
            Console()->SetAccessLevel(IConsole::ACCESS_LEVEL_ADMIN);
            m_RconClientID = IServer::RCON_CID_SERV;
            m_RconAuthLevel = AUTHED_ADMIN;
        }
    }
                
            


NETMSG_RCON_AUTH

Sender:Client
Recipient:Server
Message ID:18
Response to: TODO
Expected response: TODO
Argument name Type Note
Name String TODO
Password String TODO
Send rcon commands Int The official vanilla 0.6 clients uses the fixed value 1 at all times for this field. But technically the protocol allows optig out of the rcon command list receival. The server would not send any if this field was set to 0
Sent by the client in CClient::RconAuth()
                
    void CClient::RconAuth(const char *pName, const char *pPassword)
    {
        if(RconAuthed())
            return;

        CMsgPacker Msg(NETMSG_RCON_AUTH);
        Msg.AddString(pName, 32);
        Msg.AddString(pPassword, 32);
        Msg.AddInt(1);
        SendMsgEx(&Msg, MSGFLAG_VITAL);
    }
                
            


NETMSG_REQUEST_MAP_DATA

Sender:Client
Recipient:Server
Message ID:19
Response to: TODO
Expected response: TODO
Argument name Type Note
Chunk Int TODO
Sent by the client in CClient::ProcessServerPacket()
                
    else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAP_DATA)
    {
        int Last = Unpacker.GetInt();
        int MapCRC = Unpacker.GetInt();
        int Chunk = Unpacker.GetInt();
        int Size = Unpacker.GetInt();
        const unsigned char *pData = Unpacker.GetRaw(Size);

        // check fior errors
        if(Unpacker.Error() || Size <= 0 || MapCRC != m_MapdownloadCrc || Chunk != m_MapdownloadChunk || !m_MapdownloadFile)
            return;

        io_write(m_MapdownloadFile, pData, Size);

        m_MapdownloadAmount += Size;

        if(Last)
        {
            // [..]
        }
        else
        {
            // request new chunk
            m_MapdownloadChunk++;

            CMsgPacker Msg(NETMSG_REQUEST_MAP_DATA);
            Msg.AddInt(m_MapdownloadChunk);
            SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH);

            if(g_Config.m_Debug)
            {
                char aBuf[256];
                str_format(aBuf, sizeof(aBuf), "requested chunk %d", m_MapdownloadChunk);
                m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", aBuf);
            }
        }
    }
                
            


NETMSG_AUTH_START

Sender:Unused
Recipient:Unused
Message ID:20
Response to: Unused
Expected response: Unused
Argument name Type Note
None
This message ID is unused


NETMSG_AUTH_RESPONSE

Sender:Unused
Recipient:Unused
Message ID:21
Response to: Unused
Expected response: Unused
Argument name Type Note
None
This message ID is unused


NETMSG_PING

Sender:Client
Recipient:Server
Message ID:22
Response to: TODO
Expected response: TODO
Argument name Type Note
None
Unpacked by the client in CClient::ProcessServerPacket()
                
    else if(Msg == NETMSG_PING)
    {
        CMsgPacker Msg(NETMSG_PING_REPLY);
        SendMsgEx(&Msg, 0);
    }
                
            
Sent by the client via the ping console command
                
    void CClient::Con_Ping(IConsole::IResult *pResult, void *pUserData)
    {
        CClient *pSelf = (CClient *)pUserData;

        CMsgPacker Msg(NETMSG_PING);
        pSelf->SendMsgEx(&Msg, 0);
        pSelf->m_PingStartTime = time_get();
    }
                
            
Unpacked by the server in CServer::ProcessClientPacket()
                
    else if(Msg == NETMSG_PING)
    {
        CMsgPacker Msg(NETMSG_PING_REPLY);
        SendMsgEx(&Msg, 0, ClientID, true);
    }
                
            


NETMSG_PING_REPLY

Sender:Client
Server
Recipient:Client
Message ID:23
Response to: TODO
Expected response: TODO
Argument name Type Note
None
Sent by the server in CServer::ProcessClientPacket()
                
    else if(Msg == NETMSG_PING)
    {
        CMsgPacker Msg(NETMSG_PING_REPLY);
        SendMsgEx(&Msg, 0, ClientID, true);
    }
                
            
Sent by the client in CClient::ProcessServerPacket()
                
    else if(Msg == NETMSG_PING)
    {
        CMsgPacker Msg(NETMSG_PING_REPLY);
        SendMsgEx(&Msg, 0);
    }
                
            
Unpacked in the client side to print the ping in CClient::ProcessServerPacket()
                
    else if(Msg == NETMSG_PING_REPLY)
    {
        char aBuf[256];
        str_format(aBuf, sizeof(aBuf), "latency %.2f", (time_get() - m_PingStartTime)*1000 / (float)time_freq());
        m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client/network", aBuf);
    }
                
            


NETMSG_ERROR

Sender:Unused
Recipient:Unused
Message ID:24
Response to: Unused
Expected response: Unused
Argument name Type Note
None
This message ID is unused


NETMSG_RCON_CMD_ADD

Sender:Server
Recipient:Client
Message ID:25
Response to: TODO
Expected response: TODO
Argument name Type Note
Name String TODO
Help String TODO
Params String TODO
Sent by the server in CServer::SendRconCmdAdd()
                
    void CServer::SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID)
    {
        CMsgPacker Msg(NETMSG_RCON_CMD_ADD);
        Msg.AddString(pCommandInfo->m_pName, IConsole::TEMPCMD_NAME_LENGTH);
        Msg.AddString(pCommandInfo->m_pHelp, IConsole::TEMPCMD_HELP_LENGTH);
        Msg.AddString(pCommandInfo->m_pParams, IConsole::TEMPCMD_PARAMS_LENGTH);
        SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
    }
                
            


NETMSG_RCON_CMD_REM

Sender:Server
Recipient:Client
Message ID:26
Response to: TODO
Expected response: TODO
Argument name Type Note
Name String TODO
Sent by the server in CServer::SendRconCmdAdd()
                
    void CServer::SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID)
    {
        CMsgPacker Msg(NETMSG_RCON_CMD_REM);
        Msg.AddString(pCommandInfo->m_pName, 256);
        SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
    }
                
            
Unpacked by the client in CClient::ProcessServerPacket()
                
    else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_CMD_REM)
    {
        const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
        if(Unpacker.Error() == 0)
            m_pConsole->DeregisterTemp(pName);
    }