Teeworlds 0.6

List of network game messages

There are three types of messages with overlapping message ids:
system messages, game messages and control messages
This list is only covering game 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 generated/protocol.h which is generated by datasrc/network.py which also includes the message payload. There can be multiple messages in so called chunks in one teeworlds packet.
The message names give a hint about who is sending and receiving them. The format is always

                
    NETMSGTYPE_<sender>_<name>
                
            
Where sender can be one of those: In the list below you will find those message. With their name, id and payload.


NETMSG_INVALID

Message ID:0


NETMSGTYPE_SV_MOTD

Sender:Server
Recipient:Client
Message ID:1
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
Message String The message of the day (motd) that will be displayed to clients that connect. (The one with the dark background)


NETMSGTYPE_SV_BROADCAST

Sender:Server
Recipient:Client
Message ID:2
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
Message String The broadcast message.


NETMSGTYPE_SV_CHAT

Sender:Server
Recipient:Client
Message ID:3
Response to: NETMSGTYPE_CL_SAY
Expected response: None
Flags: MSGFLAG_VITAL
Argument name Type Note
Team Int
  • 0 - public chat
  • 1 - team chat
Technically the range from TEAM_SPECTATORS (-1) to TEAM_BLUE (1) are the allowed values. But it is not used like that.

Be careful! the ddracenetwork protocol extended this with their own team values for whisper.
Client ID Int Client ID of the message author.
Message String Message that will be displayed in the chat.


NETMSGTYPE_SV_KILLMSG

Sender:Server
Recipient:Client
Message ID:4
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
Killer Int TODO
Victim Int TODO
Weapon Int TODO
Mode special Int TODO


NETMSGTYPE_SV_SOUNDGLOBAL

Sender:Server
Recipient:Client
Message ID:5
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
Sound ID Int TODO


NETMSGTYPE_SV_TUNEPARAMS

Sender:Server
Recipient:Client
Message ID:6
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
ground_control_speed Int TODO
ground_control_accel Int TODO
ground_friction Int TODO
ground_jump_impulse Int TODO
air_jump_impulse Int TODO
air_control_speed Int TODO
air_control_accel Int TODO
air_friction Int TODO
hook_length Int TODO
hook_fire_speed Int TODO
hook_drag_accel Int TODO
hook_drag_speed Int TODO
gravity Int TODO
velramp_start Int TODO
velramp_range Int TODO
velramp_curvature Int TODO
gun_curvature Int TODO
gun_speed Int TODO
gun_lifetime Int TODO
shotgun_curvature Int TODO
shotgun_speed Int TODO
shotgun_speeddiff Int TODO
shotgun_lifetime Int TODO
grenade_curvature Int TODO
grenade_speed Int TODO
grenade_lifetime Int TODO
laser_reach Int TODO
laser_bounce_delay Int TODO
laser_bounce_num Int TODO
laser_bounce_cost Int TODO
laser_damage Int This field is 0.6 only and was removed in 0.7
All other fields are the same in 0.6 and 0.7
player_collision Int TODO
player_hooking Int TODO
Unpacked by the client in CGameClient::OnMessage()
                
    void CGameClient::OnMessage(int MsgId, CUnpacker *pUnpacker)
    {
        // special messages
        if(MsgId == NETMSGTYPE_SV_TUNEPARAMS)
        {
            // unpack the new tuning
            CTuningParams NewTuning;
            int *pParams = (int *)&NewTuning;
            for(unsigned i = 0; i < sizeof(CTuningParams)/sizeof(int); i++)
                pParams[i] = pUnpacker->GetInt();

            // check for unpacking errors
            if(pUnpacker->Error())
                return;

            m_ServerMode = SERVERMODE_PURE;

            // apply new tuning
            m_Tuning = NewTuning;
            return;
	}
                
            
Sent by the server in CGameContext::SendTuningParams()
                
    void CGameContext::SendTuningParams(int ClientID)
    {
        CheckPureTuning();

        CMsgPacker Msg(NETMSGTYPE_SV_TUNEPARAMS);
        int *pParams = (int *)&m_Tuning;
        for(unsigned i = 0; i < sizeof(m_Tuning)/sizeof(int); i++)
            Msg.AddInt(pParams[i]);
        Server()->SendMsg(&Msg, MSGFLAG_VITAL, ClientID);
    }
                
            


NETMSGTYPE_SV_EXTRAPROJECTILE

Sender:Server
Recipient:Client
Message ID:7
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
Num Int The amount of CNetObj_Projectile structs in this message
X Int m_X in the CNetObj_Projectile struct
Y Int m_Y in the CNetObj_Projectile struct
VelX Int m_VelX in the CNetObj_Projectile struct
VelY Int m_VelY in the CNetObj_Projectile struct
Type Int m_Type in the CNetObj_Projectile struct
StartTick Int m_StartTick in the CNetObj_Projectile struct
Latest 0.6 clients do not know this message. It was removed in 2015. It has two different fields. The first being the amount of projectiles. The rest being integer fields representing this struct.
                
    struct CNetObj_Projectile
    {
        int m_X;
        int m_Y;
        int m_VelX;
        int m_VelY;
        int m_Type;
        int m_StartTick;
    };
                
            


NETMSGTYPE_SV_READYTOENTER

Sender:Server
Recipient:Client
Message ID:8
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
None
Sent by the server in CGameContext::OnMessage
                
    CNetMsg_Sv_ReadyToEnter m;
    Server()->SendPackMsg(&m, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID);
                
            


NETMSGTYPE_SV_WEAPONPICKUP

Sender:Server
Recipient:Client
Message ID:9
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
TODO String Int TODO


NETMSGTYPE_SV_EMOTICON

Sender:Server
Recipient:Client
Message ID:10
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
Client ID Int Client ID of the tee who sent the emoticon.
Emoticon Int
  • 0 - oop!
  • 1 - alert
  • 2 - heart
  • 3 - tear
  • 4 - ...
  • 5 - music
  • 6 - sorry
  • 7 - ghost
  • 8 - annoyed
  • 9 - angry
  • 10 - devil
  • 11 - swearing
  • 12 - zzZ
  • 13 - WTF
  • 14 - happy
  • 15 - ??


NETMSGTYPE_SV_VOTECLEAROPTIONS

Sender:Server
Recipient:Client
Message ID:11
Response to: NETMSGTYPE_CL_STARTINFO |
NETMSG_RCON_CMD (remove_vote, clear_votes)
Expected response: None
Flags: MSGFLAG_VITAL
Argument name Type Note
None
Unpacked by the client in CVoting::OnMessage()
                
    else if(MsgType == NETMSGTYPE_SV_VOTECLEAROPTIONS)
    {
        ClearOptions();
    }
                
            
The server sends the message from multiple places. For example when the a rcon command clears it. Or when a new client joins. And the layout is always something like this:
                
    CNetMsg_Sv_VoteClearOptions ClearMsg;
    Server()->SendPackMsg(&ClearMsg, MSGFLAG_VITAL, ClientID);
                
            


NETMSGTYPE_SV_VOTEOPTIONLISTADD

Sender:Server
Recipient:Client
Message ID:12
Response to: NETMSGTYPE_CL_STARTINFO
Expected response: None
Flags: MSGFLAG_VITAL
Argument name Type Note
Num options Int Number of used description fields should be in the range from 1 to 15
Description 0 String TODO
Description 1 String TODO
Description 2 String TODO
Description 3 String TODO
Description 4 String TODO
Description 5 String TODO
Description 6 String TODO
Description 7 String TODO
Description 8 String TODO
Description 9 String TODO
Description 10 String TODO
Description 11 String TODO
Description 12 String TODO
Description 13 String TODO
Description 14 String TODO
The message always contains 15 description strings. If less are needed the Num options value is indicating the amount of used ones. The client is supposed to only look at the options from zero to Num options.

Sent by the server in CGameContext::OnMessage()
                
    if(MsgID == NETMSGTYPE_CL_STARTINFO)
    {
        // [..]

        // send vote options
        CNetMsg_Sv_VoteClearOptions ClearMsg;
        Server()->SendPackMsg(&ClearMsg, MSGFLAG_VITAL, ClientID);

        CNetMsg_Sv_VoteOptionListAdd OptionMsg;
        int NumOptions = 0;
        OptionMsg.m_pDescription0 = "";
        OptionMsg.m_pDescription1 = "";
        OptionMsg.m_pDescription2 = "";
        OptionMsg.m_pDescription3 = "";
        OptionMsg.m_pDescription4 = "";
        OptionMsg.m_pDescription5 = "";
        OptionMsg.m_pDescription6 = "";
        OptionMsg.m_pDescription7 = "";
        OptionMsg.m_pDescription8 = "";
        OptionMsg.m_pDescription9 = "";
        OptionMsg.m_pDescription10 = "";
        OptionMsg.m_pDescription11 = "";
        OptionMsg.m_pDescription12 = "";
        OptionMsg.m_pDescription13 = "";
        OptionMsg.m_pDescription14 = "";
        CVoteOptionServer *pCurrent = m_pVoteOptionFirst;
        while(pCurrent)
        {
            switch(NumOptions++)
            {
            case 0: OptionMsg.m_pDescription0 = pCurrent->m_aDescription; break;
            case 1: OptionMsg.m_pDescription1 = pCurrent->m_aDescription; break;
            case 2: OptionMsg.m_pDescription2 = pCurrent->m_aDescription; break;
            case 3: OptionMsg.m_pDescription3 = pCurrent->m_aDescription; break;
            case 4: OptionMsg.m_pDescription4 = pCurrent->m_aDescription; break;
            case 5: OptionMsg.m_pDescription5 = pCurrent->m_aDescription; break;
            case 6: OptionMsg.m_pDescription6 = pCurrent->m_aDescription; break;
            case 7: OptionMsg.m_pDescription7 = pCurrent->m_aDescription; break;
            case 8: OptionMsg.m_pDescription8 = pCurrent->m_aDescription; break;
            case 9: OptionMsg.m_pDescription9 = pCurrent->m_aDescription; break;
            case 10: OptionMsg.m_pDescription10 = pCurrent->m_aDescription; break;
            case 11: OptionMsg.m_pDescription11 = pCurrent->m_aDescription; break;
            case 12: OptionMsg.m_pDescription12 = pCurrent->m_aDescription; break;
            case 13: OptionMsg.m_pDescription13 = pCurrent->m_aDescription; break;
            case 14:
                {
                    OptionMsg.m_pDescription14 = pCurrent->m_aDescription;
                    OptionMsg.m_NumOptions = NumOptions;
                    Server()->SendPackMsg(&OptionMsg, MSGFLAG_VITAL, ClientID);
                    OptionMsg = CNetMsg_Sv_VoteOptionListAdd();
                    NumOptions = 0;
                    OptionMsg.m_pDescription1 = "";
                    OptionMsg.m_pDescription2 = "";
                    OptionMsg.m_pDescription3 = "";
                    OptionMsg.m_pDescription4 = "";
                    OptionMsg.m_pDescription5 = "";
                    OptionMsg.m_pDescription6 = "";
                    OptionMsg.m_pDescription7 = "";
                    OptionMsg.m_pDescription8 = "";
                    OptionMsg.m_pDescription9 = "";
                    OptionMsg.m_pDescription10 = "";
                    OptionMsg.m_pDescription11 = "";
                    OptionMsg.m_pDescription12 = "";
                    OptionMsg.m_pDescription13 = "";
                    OptionMsg.m_pDescription14 = "";
                }
            }
            pCurrent = pCurrent->m_pNext;
        }
        if(NumOptions > 0)
        {
            OptionMsg.m_NumOptions = NumOptions;
            Server()->SendPackMsg(&OptionMsg, MSGFLAG_VITAL, ClientID);
        }
                
            
Unpacked by the client in CVoting::OnMessage()
                
    else if(MsgType == NETMSGTYPE_SV_VOTEOPTIONLISTADD)
    {
        CNetMsg_Sv_VoteOptionListAdd *pMsg = (CNetMsg_Sv_VoteOptionListAdd *)pRawMsg;
        int NumOptions = pMsg->m_NumOptions;
        for(int i = 0; i < NumOptions; ++i)
        {
            switch(i)
            {
            case 0: AddOption(pMsg->m_pDescription0); break;
            case 1: AddOption(pMsg->m_pDescription1); break;
            case 2: AddOption(pMsg->m_pDescription2); break;
            case 3: AddOption(pMsg->m_pDescription3); break;
            case 4: AddOption(pMsg->m_pDescription4); break;
            case 5: AddOption(pMsg->m_pDescription5); break;
            case 6: AddOption(pMsg->m_pDescription6); break;
            case 7: AddOption(pMsg->m_pDescription7); break;
            case 8: AddOption(pMsg->m_pDescription8); break;
            case 9: AddOption(pMsg->m_pDescription9); break;
            case 10: AddOption(pMsg->m_pDescription10); break;
            case 11: AddOption(pMsg->m_pDescription11); break;
            case 12: AddOption(pMsg->m_pDescription12); break;
            case 13: AddOption(pMsg->m_pDescription13); break;
            case 14: AddOption(pMsg->m_pDescription14);
            }
        }
    }
                
            


NETMSGTYPE_SV_VOTEOPTIONADD

Sender:Server
Recipient:Client
Message ID:13
Response to: TODO
Expected response: None
Flags: TODO
Argument name Type Note
Vote description String Display name of the vote option
Unpacked by the client in CVoting::OnMessage()
                
    else if(MsgType == NETMSGTYPE_SV_VOTEOPTIONADD)
    {
        CNetMsg_Sv_VoteOptionAdd *pMsg = (CNetMsg_Sv_VoteOptionAdd *)pRawMsg;
        AddOption(pMsg->m_pDescription);
    }
                
            


NETMSGTYPE_SV_VOTEOPTIONREMOVE

Sender:Server
Recipient:Client
Message ID:14
Response to: TODO
Expected response: None
Flags: TODO
Argument name Type Note
Vote description String Display name of the vote option to be deleted
Unpacked by the client in CVoting::OnMessage()
                
    else if(MsgType == NETMSGTYPE_SV_VOTEOPTIONREMOVE)
    {
        CNetMsg_Sv_VoteOptionRemove *pMsg = (CNetMsg_Sv_VoteOptionRemove *)pRawMsg;

        for(CVoteOptionClient *pOption = m_pFirst; pOption; pOption = pOption->m_pNext)
        {
            if(str_comp(pOption->m_aDescription, pMsg->m_pDescription) == 0)
            {
                // remove it from the list
                if(m_pFirst == pOption)
                    m_pFirst = m_pFirst->m_pNext;
                if(m_pLast == pOption)
                    m_pLast = m_pLast->m_pPrev;
                if(pOption->m_pPrev)
                    pOption->m_pPrev->m_pNext = pOption->m_pNext;
                if(pOption->m_pNext)
                    pOption->m_pNext->m_pPrev = pOption->m_pPrev;
                --m_NumVoteOptions;

                // add it to recycle list
                pOption->m_pNext = 0;
                pOption->m_pPrev = m_pRecycleLast;
                if(pOption->m_pPrev)
                    pOption->m_pPrev->m_pNext = pOption;
                m_pRecycleLast = pOption;
                if(!m_pRecycleFirst)
                    m_pRecycleLast = pOption;

                break;
            }
        }
    }
                
            


NETMSGTYPE_SV_VOTESET

Sender:Server
Recipient:Client
Message ID:15
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
Timeout Int TODO
Description String TODO
Reason String TODO
Unpacked by the client in voting.cpp OnMessage()
                
    void CVoting::OnMessage(int MsgType, void *pRawMsg)
    {
	if(MsgType == NETMSGTYPE_SV_VOTESET)
	{
		CNetMsg_Sv_VoteSet *pMsg = (CNetMsg_Sv_VoteSet *)pRawMsg;
		if(pMsg->m_Timeout)
		{
			OnReset();
			str_copy(m_aDescription, pMsg->m_pDescription, sizeof(m_aDescription));
			str_copy(m_aReason, pMsg->m_pReason, sizeof(m_aReason));
			m_Closetime = time_get() + time_freq() * pMsg->m_Timeout;
		}
		else
			OnReset();
	}
                
            


NETMSGTYPE_SV_VOTESTATUS

Sender:Server
Recipient:Client
Message ID:16
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
Yes Int TODO
No Int TODO
Pass Int TODO
Total Int TODO
Unpacked by the client in voting.cpp OnMessage()
                
    else if(MsgType == NETMSGTYPE_SV_VOTESTATUS)
    {
        CNetMsg_Sv_VoteStatus *pMsg = (CNetMsg_Sv_VoteStatus *)pRawMsg;
        m_Yes = pMsg->m_Yes;
        m_No = pMsg->m_No;
        m_Pass = pMsg->m_Pass;
        m_Total = pMsg->m_Total;
    }
                
            
Sent by the server in SendVoteStatus()
                
    void CGameContext::SendVoteStatus(int ClientID, int Total, int Yes, int No)
    {
        CNetMsg_Sv_VoteStatus Msg = {0};
        Msg.m_Total = Total;
        Msg.m_Yes = Yes;
        Msg.m_No = No;
        Msg.m_Pass = Total - (Yes+No);

        Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID);
    }
                
            
Which is called in CGameContext::OnTick()


NETMSGTYPE_CL_SAY

Sender:Client
Recipient:Server
Message ID:17
Response to: This is initiaited by user input.
Expected response: NETMSGTYPE_SV_CHAT
Flags: MSGFLAG_VITAL
Argument name Type Note
Team Int Indicating wether it is team chat or not.
  • 0 - public chat
  • 1 - team chat
The client only tells the server that it wants team chat. And the server then figures out the team.
                            
    int Team = pMsg->m_Team ? pPlayer->GetTeam() : CGameContext::CHAT_ALL;
                            
                        
Message String TODO
Unpacked by the server in CGameContext::OnMessage()
                
    if(MsgID == NETMSGTYPE_CL_SAY)
    {
        if(g_Config.m_SvSpamprotection && pPlayer->m_LastChat && pPlayer->m_LastChat+Server()->TickSpeed() > Server()->Tick())
            return;

        CNetMsg_Cl_Say *pMsg = (CNetMsg_Cl_Say *)pRawMsg;
        int Team = pMsg->m_Team ? pPlayer->GetTeam() : CGameContext::CHAT_ALL;

        // trim right and set maximum length to 128 utf8-characters
        // [...]

        // drop empty and autocreated spam messages (more than 16 characters per second)
        if(Length == 0 || (g_Config.m_SvSpamprotection && pPlayer->m_LastChat && pPlayer->m_LastChat+Server()->TickSpeed()*((15+Length)/16) > Server()->Tick()))
            return;

        pPlayer->m_LastChat = Server()->Tick();

        SendChat(ClientID, Team, pMsg->m_pMessage);
    }
                
            


NETMSGTYPE_CL_SETTEAM

Sender:Client
Recipient:Server
Message ID:18
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
TODO String Int TODO


NETMSGTYPE_CL_SETSPECTATORMODE

Sender:Client
Recipient:Server
Message ID:19
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
TODO String Int TODO


NETMSGTYPE_CL_STARTINFO

Sender:Client
Recipient:Server
Message ID:20
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
Name String TODO
Clan String TODO
Country Int TODO
Skin String TODO
Use custom color Int TODO
Color body Int TODO
Color feet Int TODO


NETMSGTYPE_CL_CHANGEINFO

Sender:Client
Recipient:Server
Message ID:21
Response to: TODO
Expected response: NETMSG_SNAP
Flags: MSGFLAG_VITAL
Argument name Type Note
Name String Player name displayed in scoreboard and above every tee. If an empty string is sent the server sets the name (1). If there are two players with no name the second gets the name (2). The official implemenation supports some unicode characters.
Clan String Displayed in the scoreabord. Can be an empty string. The official implemenation supports some unicode characters.
Country Int This is used for the country flag that is displayed in the scoreboard. Here a few examples:
  • -1 - default
  • 4 - AF
  • 904 - XWA
Skin name String If a matching filename without .png extension in the skins folder is found that texture is used as skin for the tee.
Use custom color Int If set to 0 the next two fields (color body, color feet) are supposed to be ignored. And the default colors of the skin image file are used.
Color body Int TODO
Color feet Int TODO
The new info will be put into the snap item obj_client_info by the server. The official client implementation does not apply the new info locally on send but on receive of the snap item from the server. So custom servers could enforce or ignore any kind of info and clients are supposed to pick it up.


NETMSGTYPE_CL_KILL

Sender:Client
Recipient:Server
Message ID:22
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
TODO String Int TODO


NETMSGTYPE_CL_EMOTICON

Sender:Client
Recipient:Server
Message ID:23
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
Emoticon Int
  • 0 - oop!
  • 1 - alert
  • 2 - heart
  • 3 - tear
  • 4 - ...
  • 5 - music
  • 6 - sorry
  • 7 - ghost
  • 8 - annoyed
  • 9 - angry
  • 10 - devil
  • 11 - swearing
  • 12 - zzZ
  • 13 - WTF
  • 14 - happy
  • 15 - ??


NETMSGTYPE_CL_VOTE

Sender:Client
Recipient:Server
Message ID:24
Response to: TODO
Expected response: TODO
Flags: TODO
Argument name Type Note
TODO String Int TODO


NETMSGTYPE_CL_CALLVOTE

Sender:Client
Recipient:Server
Message ID:25
Response to: The user clicking "Call vote" button in the menu or using the callvote console command.
Expected response: TODO
Flags: TODO
Argument name Type Note
Type String Possible values are
  • kick
  • spectate
  • option
Value String TODO
Reason String TODO
It is sent by the client from the voting.cpp component in the Callvote() method.
                
    void CVoting::Callvote(const char *pType, const char *pValue, const char *pReason)
    {
        CNetMsg_Cl_CallVote Msg = {0};
        Msg.m_Type = pType;
        Msg.m_Value = pValue;
        Msg.m_Reason = pReason;
        Client()->SendPackMsg(&Msg, MSGFLAG_VITAL);
    }