diff --git a/src/Components/Modules/Voice.cpp b/src/Components/Modules/Voice.cpp index adf233b4..7b6d5848 100644 --- a/src/Components/Modules/Voice.cpp +++ b/src/Components/Modules/Voice.cpp @@ -5,6 +5,8 @@ namespace Components Game::VoicePacket_t Voice::voicePackets[Game::MAX_CLIENTS][MAX_SERVER_QUEUED_VOICE_PACKETS]; int Voice::voicePacketCount[Game::MAX_CLIENTS]; + bool Voice::s_playerMute[Game::MAX_CLIENTS]; + const Game::dvar_t* Voice::sv_voice; bool Voice::SV_VoiceEnabled() @@ -82,7 +84,7 @@ namespace Components return false; } - void Voice::SV_QueueVoicePacket(int talkerNum, int clientNum, Game::VoicePacket_t* voicePacket) + void Voice::SV_QueueVoicePacket(const int talkerNum, const int clientNum, Game::VoicePacket_t* voicePacket) { assert(talkerNum >= 0); assert(clientNum >= 0); @@ -163,7 +165,7 @@ namespace Components } } - void Voice::CL_WriteVoicePacket_Hk(int localClientNum) + void Voice::CL_WriteVoicePacket_Hk(const int localClientNum) { const auto connstate = Game::CL_GetLocalClientConnectionState(localClientNum); const auto clc = Game::CL_GetLocalClientConnection(localClientNum); @@ -197,6 +199,38 @@ namespace Components } } + bool Voice::CL_IsPlayerMuted_Hk([[maybe_unused]] Game::SessionData* session, [[maybe_unused]] const int localClientNum, const int muteClientIndex) + { + AssertIn(muteClientIndex, Game::MAX_CLIENTS); + return s_playerMute[muteClientIndex]; + } + + void Voice::CL_MutePlayer_Hk([[maybe_unused]] Game::SessionData* session, const int muteClientIndex) + { + AssertIn(muteClientIndex, Game::MAX_CLIENTS); + s_playerMute[muteClientIndex] = true; + } + + void Voice::Voice_UnmuteMember_Hk([[maybe_unused]] Game::SessionData* session, const int clientNum) + { + AssertIn(clientNum, Game::MAX_CLIENTS); + s_playerMute[clientNum] = false; + } + + void Voice::CL_TogglePlayerMute(const int localClientNum, const int muteClientIndex) + { + AssertIn(muteClientIndex, Game::MAX_CLIENTS); + + if (CL_IsPlayerMuted_Hk(nullptr, localClientNum, muteClientIndex)) + { + Voice_UnmuteMember_Hk(nullptr, muteClientIndex); + } + else + { + CL_MutePlayer_Hk(nullptr, muteClientIndex); + } + } + void Voice::CL_VoicePacket_Hk(const int localClientNum, Game::msg_t* msg) { const auto numPackets = Game::MSG_ReadByte(msg); @@ -224,45 +258,65 @@ namespace Components return; } - Game::SessionData* session{}; - if (Game::Party_InParty(Game::g_lobbyData)) - { - session = Game::g_lobbyData->session; - } - else if (Game::Party_InParty(Game::g_partyData)) - { - session = Game::g_partyData->session; - } - else - { - session = Game::g_serverSession; - } - - if (!Game::CL_IsPlayerMuted(session, localClientNum, voicePacket.talker)) + if (!CL_IsPlayerMuted_Hk(nullptr, localClientNum, voicePacket.talker)) { if ((*Game::cl_voice)->current.enabled) { - Game::Voice_IncomingVoiceData(session, voicePacket.talker, reinterpret_cast(voicePacket.data), voicePacket.dataSize); + Game::Voice_IncomingVoiceData(nullptr, voicePacket.talker, reinterpret_cast(voicePacket.data), voicePacket.dataSize); } } } } + void Voice::UI_Mute_player(int clientNum, const int localClientNum) + { + if (Game::cgArray->clientNum != Game::sharedUiInfo->playerClientNums[clientNum]) + { + CL_TogglePlayerMute(localClientNum, Game::sharedUiInfo->playerClientNums[clientNum]); + } + } + + __declspec(naked) void Voice::UI_Mute_Player_Stub() + { + __asm + { + push eax + call UI_Mute_player + add esp, 8 // Game already pushed localClientNum + + pop edi + pop esi + add esp, 0xC00 + ret + } + } + Voice::Voice() { AssertOffset(Game::clientUIActive_t, connectionState, 0x9B8); + std::memset(voicePackets, 0, sizeof(voicePackets)); + std::memset(voicePacketCount, 0, sizeof(voicePacketCount)); + std::memset(s_playerMute, 0, sizeof(s_playerMute)); + // Write voice packets to the server instead of other clients Utils::Hook(0x487935, CL_WriteVoicePacket_Hk, HOOK_CALL).install()->quick(); Utils::Hook(0x5AD945, CL_WriteVoicePacket_Hk, HOOK_CALL).install()->quick(); Utils::Hook(0x5A9E06, CL_VoicePacket_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x4B6250, CL_IsPlayerMuted_Hk, HOOK_JUMP).install()->quick(); + Utils::Hook(0x4519F5, SV_SendClientMessages_Stub, HOOK_CALL).install()->quick(); // Recycle packet handler for 'icanthear' Utils::Hook::Set(0x62673F, "v"); Utils::Hook(0x626787, SV_VoicePacket, HOOK_CALL).install()->quick(); + Utils::Hook(0x45F041, UI_Mute_Player_Stub, HOOK_JUMP).install()->quick(); + + Utils::Hook(0x4C6B50, Voice_UnmuteMember_Hk, HOOK_JUMP).install()->quick(); + Utils::Hook(0x43F460, CL_MutePlayer_Hk, HOOK_JUMP).install()->quick(); + sv_voice = Game::Dvar_RegisterBool("sv_voice", false, Game::DVAR_NONE, "Use server side voice communications"); } } diff --git a/src/Components/Modules/Voice.hpp b/src/Components/Modules/Voice.hpp index 211204d4..747ee870 100644 --- a/src/Components/Modules/Voice.hpp +++ b/src/Components/Modules/Voice.hpp @@ -16,6 +16,8 @@ namespace Components static Game::VoicePacket_t voicePackets[Game::MAX_CLIENTS][MAX_SERVER_QUEUED_VOICE_PACKETS]; static int voicePacketCount[Game::MAX_CLIENTS]; + static bool s_playerMute[Game::MAX_CLIENTS]; + static const Game::dvar_t* sv_voice; static void SV_WriteVoiceDataToClient(int clientNum, Game::msg_t* msg); @@ -28,7 +30,15 @@ namespace Components static void SV_UserVoice(Game::client_t* cl, Game::msg_t* msg); static void SV_VoicePacket(Game::netadr_t from, Game::msg_t* msg); + static bool CL_IsPlayerMuted_Hk(Game::SessionData* session, int localClientNum, int muteClientIndex); + static void CL_MutePlayer_Hk(Game::SessionData* session, const int muteClientIndex); + static void Voice_UnmuteMember_Hk(Game::SessionData* session, int clientNum); + static void CL_TogglePlayerMute(int localClientNum, int muteClientIndex); + static void CL_WriteVoicePacket_Hk(int localClientNum); static void CL_VoicePacket_Hk(int localClientNum, Game::msg_t* msg); + + static void UI_Mute_player(int clientNum, int localClientNum); + static void UI_Mute_Player_Stub(); }; } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 8c854d9e..bf513541 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -69,7 +69,6 @@ namespace Game CL_GetLocalClientActiveCount_t CL_GetLocalClientActiveCount = CL_GetLocalClientActiveCount_t(0x5BAD90); CL_ControllerIndexFromClientNum_t CL_ControllerIndexFromClientNum = CL_ControllerIndexFromClientNum_t(0x449E30); CL_MouseEvent_t CL_MouseEvent = CL_MouseEvent_t(0x4D7C50); - CL_IsPlayerMuted_t CL_IsPlayerMuted = CL_IsPlayerMuted_t(0x4B6250); Cmd_AddCommand_t Cmd_AddCommand = Cmd_AddCommand_t(0x470090); Cmd_AddServerCommand_t Cmd_AddServerCommand = Cmd_AddServerCommand_t(0x4DCE00); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index f736de1a..7d4f09fa 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -148,9 +148,6 @@ namespace Game typedef int(__cdecl * CL_MouseEvent_t)(int x, int y, int dx, int dy); extern CL_MouseEvent_t CL_MouseEvent; - typedef bool(__cdecl * CL_IsPlayerMuted_t)(SessionData* session, int localClientNum, int muteClientIndex); - extern CL_IsPlayerMuted_t CL_IsPlayerMuted; - typedef void(__cdecl * Cmd_AddCommand_t)(const char* cmdName, void(*function), cmd_function_t* allocedCmd, bool isKey); extern Cmd_AddCommand_t Cmd_AddCommand;