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: TODO
Expected response: TODO
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);
    }
                
            


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 TODO
Num parts Int TODO
Part Int TODO
Crc Int TODO
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. And the following ints are all 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:TODO
Recipient:TODO
Message ID:7
Response to: TODO
Expected response: TODO
Argument name Type Note
TODO String Int TODO


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 TODO
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);
    }