From ccef71f1b573024bc4577f029e0bd8a0afe1de04 Mon Sep 17 00:00:00 2001 From: Faramour <44729057+Faramour@users.noreply.github.com> Date: Wed, 24 Jun 2026 20:12:57 +0200 Subject: [PATCH 1/2] Add !voicechat command --- src/commands.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++ src/cs2fixes.cpp | 27 ++++++++++++++++++++++ src/cs2fixes.h | 2 ++ src/playermanager.h | 4 ++++ 4 files changed, 88 insertions(+) diff --git a/src/commands.cpp b/src/commands.cpp index 516429315..932695738 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -750,6 +750,61 @@ CON_COMMAND_F(cs2f_fullupdate, "- Force a full update for all clients.", FCVAR_L g_playerManager->FullUpdateAllClients(); } +void VoiceChatPrintCmd(const CCommand& args, CCSPlayerController* player) +{ + if (!GetGlobals()) return; + + std::vector vecActivePlayers; + for (int i = 0; i < GetGlobals()->maxClients; i++) + { + ZEPlayer* pPlayer = g_playerManager->GetPlayer(i); + + if (pPlayer && !pPlayer->GetVoiceTimer().expired()) + vecActivePlayers.push_back(i); + } + + if (vecActivePlayers.empty()) + { + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "There are no players currently using voice chat."); + return; + } + + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "List of players using voice chat:"); + if (player) + ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "List of players using voice chat:"); + + for (const auto& slot : vecActivePlayers) + { + CCSPlayerController* pController = CCSPlayerController::FromSlot(slot); + ZEPlayer* pPlayer = g_playerManager->GetPlayer(slot); + + bool bSteamIDAuthed = pPlayer->IsAuthenticated(); + uint64 uSteamID = bSteamIDAuthed ? pPlayer->GetSteamId64() : pPlayer->GetUnauthenticatedSteamId64(); + + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "\x04%s \x01[UID: #\x05%hu\x01] [SteamID: $\x06%llu%s\x01]", + pController->GetPlayerName().c_str(), + g_pEngineServer2->GetPlayerUserId(slot), + uSteamID, + bSteamIDAuthed ? "" : " \x02(No Auth)"); + if (!player) continue; + ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "%s [UID: #%hu] [SteamID: $%llu%s]", + pController->GetPlayerName().c_str(), + g_pEngineServer2->GetPlayerUserId(slot), + uSteamID, + bSteamIDAuthed ? "" : " (No Auth)"); + } +} + +CON_COMMAND_CHAT(voicechat, "- Display players that are using voice chat") +{ + VoiceChatPrintCmd(args, player); +} + +CON_COMMAND_CHAT(vc, "- Display players that are using voice chat") +{ + VoiceChatPrintCmd(args, player); +} + #if _DEBUG CON_COMMAND_CHAT(myuid, "- Test") { diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index cac649b1b..b25396ac1 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -95,6 +95,7 @@ SH_DECL_MANUALHOOK3_void(DropWeapon, 0, 0, 0, CBasePlayerWeapon*, Vector*, Vecto SH_DECL_HOOK1_void(IServer, SetGameSpawnGroupMgr, SH_NOATTRIB, 0, IGameSpawnGroupMgr*); SH_DECL_HOOK2_void(CEntitySystem, Spawn, SH_NOATTRIB, 0, int, const EntitySpawnInfo_t*); SH_DECL_MANUALHOOK3_void(Teleport, 0, 0, 0, const Vector*, const QAngle*, const Vector*); +SH_DECL_HOOK1(CServerSideClient, ProcessVoiceData, SH_NOATTRIB, 0, bool, const CCLCMsg_VoiceData_t&); CS2Fixes g_CS2Fixes; IGameEventSystem* g_gameEventSystem = nullptr; @@ -117,6 +118,7 @@ int g_iWeaponServiceDropWeaponId = -1; int g_iSetGameSpawnGroupMgrId = -1; int g_iSpawnId = -1; int g_iTeleportId = -1; +int g_iProcessVoiceDataId = -1; double g_flUniversalTime = 0.0; float g_flLastTickedTime = 0.0f; @@ -322,6 +324,9 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool auto pCEntitySystemVTable = (CEntitySystem*)modules::server->FindVirtualTable("CGameEntitySystem"); g_iSpawnId = SH_ADD_DVPHOOK(CEntitySystem, Spawn, pCEntitySystemVTable, SH_MEMBER(this, &CS2Fixes::Hook_SpawnPost), true); + auto pCServerSideClientVTable = (CServerSideClient*)modules::engine->FindVirtualTable("CServerSideClient"); + g_iProcessVoiceDataId = SH_ADD_DVPHOOK(CServerSideClient, ProcessVoiceData, pCServerSideClientVTable, SH_MEMBER(this, &CS2Fixes::Hook_ProcessVoiceData), false); + if (!bRequiredInitLoaded) { snprintf(error, maxlen, "One or more address lookups, patches or detours failed, please refer to startup logs for more information"); @@ -428,6 +433,7 @@ bool CS2Fixes::Unload(char* error, size_t maxlen) SH_REMOVE_HOOK_ID(g_iCTriggerGravityEndTouchId); SH_REMOVE_HOOK_ID(g_iSpawnId); SH_REMOVE_HOOK_ID(g_iTeleportId); + SH_REMOVE_HOOK_ID(g_iProcessVoiceDataId); if (g_iSetGameSpawnGroupMgrId != -1) SH_REMOVE_HOOK_ID(g_iSetGameSpawnGroupMgrId); @@ -1208,6 +1214,27 @@ void CS2Fixes::Hook_CCSPlayerPawn_Teleport(const Vector* pPosition, const QAngle RETURN_META(MRES_HANDLED); } +bool CS2Fixes::Hook_ProcessVoiceData(const CCLCMsg_VoiceData_t& msg) +{ + CServerSideClient* client = META_IFACEPTR(CServerSideClient); + + if (!client) + RETURN_META_VALUE(MRES_IGNORED, true); + + ZEPlayer* pPlayer = g_playerManager->GetPlayer(client->GetPlayerSlot()); + + if (!pPlayer) + RETURN_META_VALUE(MRES_IGNORED, true); + + // logic following sourcemod's implementation of OnClientSpeaking + if (auto timer = pPlayer->GetVoiceTimer().lock()) + timer->Cancel(); + + pPlayer->SetVoiceTimer(CTimer::Create(0.3f, TIMERFLAG_NONE, [](){ return -1.0f; })); + + RETURN_META_VALUE(MRES_IGNORED, true); +} + void* CS2Fixes::OnMetamodQuery(const char* iface, int* ret) { if (V_strcmp(iface, CS2FIXES_INTERFACE)) diff --git a/src/cs2fixes.h b/src/cs2fixes.h index 18b6eb2b3..bd1f02069 100644 --- a/src/cs2fixes.h +++ b/src/cs2fixes.h @@ -30,6 +30,7 @@ #include #include #include +#include "cs2_sdk/netmessages.h" #ifdef AMBUILD #include "version_gen.h" @@ -107,6 +108,7 @@ class CS2Fixes : public ISmmPlugin, public IMetamodListener, public ICS2Fixes int Hook_LoadEventsFromFile(const char* filename, bool bSearchAll); void Hook_SetGameSpawnGroupMgr(IGameSpawnGroupMgr* pSpawnGroupMgr); void Hook_SpawnPost(int nCount, const EntitySpawnInfo_t* pInfo); + bool Hook_ProcessVoiceData(const CCLCMsg_VoiceData_t& msg); public: // MetaMod API void* OnMetamodQuery(const char* iface, int* ret); diff --git a/src/playermanager.h b/src/playermanager.h index 458a21a0e..68f574a5c 100644 --- a/src/playermanager.h +++ b/src/playermanager.h @@ -30,6 +30,7 @@ #include "steam/steamclientpublic.h" #include "utlvector.h" #include +#include "ctimer.h" extern CConVar g_cvarFlashLightTransmitOthers; extern CConVar g_cvarFlashLightAttachment; @@ -269,6 +270,7 @@ class ZEPlayer void SetEntwatchHudPos(float x, float y); void SetEntwatchHudSize(float flSize); void SetTopDefenderStatus(bool bStatus) { m_bTopDefender = bStatus; } + void SetVoiceTimer(std::weak_ptr timer) { m_pVoiceTimer = timer; } uint64 GetAdminFlags() { return m_iAdminFlags; } int GetAdminImmunity() { return m_iAdminImmunity; } @@ -319,6 +321,7 @@ class ZEPlayer float GetEntwatchHudY() { return m_flEntwatchHudY; } float GetEntwatchHudSize() { return m_flEntwatchHudSize; } bool GetTopDefenderStatus() { return m_bTopDefender; } + std::weak_ptr GetVoiceTimer() { return m_pVoiceTimer; } void OnSpawn(); void OnAuthenticated(); @@ -393,6 +396,7 @@ class ZEPlayer float m_flEntwatchHudY; float m_flEntwatchHudSize; bool m_bTopDefender; + std::weak_ptr m_pVoiceTimer; }; class CPlayerManager From 80f278099123a1308b41ebe99d61b4cde38b2ca2 Mon Sep 17 00:00:00 2001 From: Vauff Date: Thu, 25 Jun 2026 20:46:59 -0400 Subject: [PATCH 2/2] simplify format --- src/commands.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands.cpp b/src/commands.cpp index 932695738..391973c6d 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -781,13 +781,13 @@ void VoiceChatPrintCmd(const CCommand& args, CCSPlayerController* player) bool bSteamIDAuthed = pPlayer->IsAuthenticated(); uint64 uSteamID = bSteamIDAuthed ? pPlayer->GetSteamId64() : pPlayer->GetUnauthenticatedSteamId64(); - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "\x04%s \x01[UID: #\x05%hu\x01] [SteamID: $\x06%llu%s\x01]", + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "\x04%s \x06[#%hu] \x05[%llu%s\x05]", pController->GetPlayerName().c_str(), g_pEngineServer2->GetPlayerUserId(slot), uSteamID, bSteamIDAuthed ? "" : " \x02(No Auth)"); if (!player) continue; - ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "%s [UID: #%hu] [SteamID: $%llu%s]", + ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "%s [#%hu] [%llu%s]", pController->GetPlayerName().c_str(), g_pEngineServer2->GetPlayerUserId(slot), uSteamID,