Common Messages

Useful CS2 user and net messages — their ids, protobuf class names and fields, checked against the game's .proto files.

A reference for the messages plugins use most. Every id and class name here is taken from the CS2 .proto files (usermessages.proto, cstrike15_usermessages.proto, netmessages.proto, networkbasetypes.proto, cs_gameevents.proto); the fields are listed with their .proto types so you can pick the right accessor (Setting fields).

Valve changes these between updates. When a message does not do what this page says, compare with the current .proto in SteamTracking/Protobufs.

Text

Before sending text yourself, look at the helpers: CBasePlayerController has PrintToChat, PrintToCenter, PrintToCenterAlert and PrintToConsole, all built on UM_TextMsg, and CCSPlayerController::PrintToCenterHtml shows HTML in the centre of the screen.

idvalueclassfields
UM_TextMsg124CUserMessageTextMsguint32 dest, repeated string param
UM_SayText2118CUserMessageSayText2int32 entityindex, bool chat, string messagename, string param1 … param4, bool textallchat
UM_SayText117CUserMessageSayTextint32 playerindex, string text, bool chat, bool textallchat
CS_UM_HintText323CCSUsrMsg_HintTextstring message
CS_UM_KeyHintText324CCSUsrMsg_KeyHintTextrepeated string messages
CS_UM_RadioText322CCSUsrMsg_RadioTextint32 msg_dst, int32 client, string msg_name, repeated string params
svc_Print48CSVCMsg_Printstring text — prints to the client's console

UM_TextMsg's dest is where the text appears. The values the SDK's print helpers use:

destwherehelper
1notify area
2consolePrintToConsole
3chatPrintToChat
4centre of the screenPrintToCenter
6centre alertPrintToCenterAlert

The text goes in param — the first element is the message (or a localisation token), the rest are its arguments.

void* pMsg = NET_MSG_ALLOC_BY_ID(UM_TextMsg);
g_pSource2ModNetworkMessages->SetUInt32(pMsg, "dest", 3);
g_pSource2ModNetworkMessages->AddString(pMsg, "param", "Round starts in 10 seconds");
NET_MSG_SEND_PLAYERS(pMsg, UM_TextMsg, ~0ull);
NET_MSG_FREE(pMsg);

Screen effects

idvalueclassfields
UM_Shake120CUserMessageShakeuint32 command, float amplitude, float frequency, float duration
UM_ShakeDir121CUserMessageShakeDirCUserMessageShake shake (nested), CMsgVector direction
UM_Fade106CUserMessageFadeuint32 duration, uint32 hold_time, uint32 flags, fixed32 color
UM_ScreenTilt125CUserMessageScreenTiltuint32 command, bool ease_in_out, CMsgVector angle, float duration, float time
CS_UM_Shake312CCSUsrMsg_Shakeint32 command, float local_amplitude, float frequency, float duration
CS_UM_Fade313CCSUsrMsg_Fadeint32 duration, int32 hold_time, int32 flags, CMsgRGBA clr

Note the differences between the two families: UM_Fade's colour is a packed fixed32 (SetUInt32), CS_UM_Fade's is a CMsgRGBA (SetColor); UM_Shake has amplitude, CS_UM_Shake has local_amplitude. For shakes, command 0 starts one — the sample plugin's sample_shake uses UM_Shake, FUNPLAY's slap uses CS_UM_Shake.

// A red flash, CS_UM_Fade.
void* pMsg = NET_MSG_ALLOC_BY_ID(CS_UM_Fade);
g_pSource2ModNetworkMessages->SetInt32(pMsg, "duration", 200);
g_pSource2ModNetworkMessages->SetInt32(pMsg, "hold_time", 100);
g_pSource2ModNetworkMessages->SetInt32(pMsg, "flags", 0x0001);
g_pSource2ModNetworkMessages->SetColor(pMsg, "clr", Color(255, 0, 0, 128));
NET_MSG_SEND(pMsg, CS_UM_Fade, slot);
NET_MSG_FREE(pMsg);

The flags, duration and hold_time of the fade messages follow the Source engine's screen-fade conventions; test the values on a client before relying on them.

Sounds

idvalueclassfields
UM_SendAudio130CUserMessageSendAudiostring soundname, bool stop
CS_UM_SendAudio317CCSUsrMsg_SendAudiostring radio_sound
CS_UM_WeaponSound369CCSUsrMsg_WeaponSoundint32 entidx, float origin_x / origin_y / origin_z, string sound, float game_timestamp, fixed32 source_soundscapeid, bool stealth
GE_SosStartSoundEvent208CMsgSosStartSoundEventthe game's own sound starts

For playing and filtering sounds, use ISource2ModSounds — SOUND_EMIT_FROM_ENTITY and HOOK_SOUND handle GE_SosStartSoundEvent decoded, which is far easier than building or picking apart the message yourself. See ISource2ModSounds.

HUD and player state (CS2)

idvalueclassfields
CS_UM_ServerRankRevealAll350CCSUsrMsg_ServerRankRevealAllint32 seconds_till_shutdown, reservation — send it empty to reveal every player's rank on the scoreboard
CS_UM_EntityOutlineHighlight371CCSUsrMsg_EntityOutlineHighlightint32 entidx, bool removehighlight
CS_UM_UpdateScreenHealthBar370CCSUsrMsg_UpdateScreenHealthBarint32 entidx, float healthratio_old, float healthratio_new, int32 style
CS_UM_Damage321CCSUsrMsg_Damageint32 amount, CMsgVector inflictor_world_pos, int32 victim_entindex
CS_UM_AdjustMoney327CCSUsrMsg_AdjustMoneyint32 amount
CS_UM_BarTime355CCSUsrMsg_BarTimestring time
CS_UM_KillCam330CCSUsrMsg_KillCamint32 obs_mode, int32 first_target, int32 second_target

FUNPLAY's Core re-sends CS_UM_ServerRankRevealAll on player_connect_full, round_start and from a timer: the client-side reveal is time-limited and cleared on map change. Do not send it every tick — spamming it makes the client scoreboard glitch.

Engine messages

idvalueclassfieldsuse
svc_GetCvarValue58CSVCMsg_GetCvarValueint32 cookie, string cvar_nameask a client for a cvar's value
clc_RespondCvarValue25CCLCMsg_RespondCvarValueint32 cookie, int32 status_code, string name, string valuethe client's answer — catch it with HOOK_CLIENT_MESSAGE
net_StringCmd5CNETMsg_StringCmdstring command, uint32 prediction_syncsent to a client, runs a command on it (only what the client allows from the server)
clc_VoiceData22CCLCMsg_VoiceDataCMsgVoiceAudio audio, fixed64 xuid, uint32 ticka client's voice — drop it to mute
svc_VoiceData47CSVCMsg_VoiceDataCMsgVoiceAudio audio, int32 client_deprecated, bool proximity, fixed64 xuid, int32 audible_mask, uint32 tickvoice relayed to listeners
GE_FireBulletsId452CMsgTEFireBulletssee cs_gameevents.protothe server's bullet broadcast; AntiCheat reads it for exact spread
// Ask a client for a cvar; the answer arrives as clc_RespondCvarValue with the same cookie.
void* pMsg = NET_MSG_ALLOC_BY_ID(svc_GetCvarValue);
g_pSource2ModNetworkMessages->SetInt32(pMsg, "cookie", ++g_iCookie);
g_pSource2ModNetworkMessages->SetString(pMsg, "cvar_name", "cl_interp_ratio");
NET_MSG_SEND(pMsg, svc_GetCvarValue, slot);
NET_MSG_FREE(pMsg);

HOOK_CLIENT_MESSAGE([](CPlayerSlot slot, int messageid, void* msg) -> Action
{
    if (messageid == clc_RespondCvarValue)
    {
        int cookie = g_pSource2ModNetworkMessages->GetInt32(msg, "cookie");
        std::string value = g_pSource2ModNetworkMessages->GetString(msg, "value");
        // ... match the cookie to the request ...
    }
    return Action::Ignore;
});

Where the ids come from

enumheader to includeSDK enum class
UM_*usermessages.pb.hEBaseUserMessages
CS_UM_*cstrike15_usermessages.pb.hECstrike15UserMessages
svc_*, clc_*netmessages.pb.hSVC_Messages, CLC_Messages
net_*networkbasetypes.pb.hNET_Messages
GE_* (base)gameevents.pb.hEBaseGameEvents
GE_*Id (CS2)cs_gameevents.pb.hECsgoGameEvents
TE_*Idte.pb.hETEProtobufIds

The .pb.h headers declare plain enums, usable directly as the int id; the SDK's enum class versions live in source2mod/schema/entity/enums/ and need a static_cast<int>. Scripts get all of these ids as plain constants from source2mod/netmessage_ids.inc, which source2mod/api includes.

On this page