diff --git a/publish.gradle b/publish.gradle index 1b4eaba..a0fe262 100644 --- a/publish.gradle +++ b/publish.gradle @@ -10,22 +10,25 @@ void _copyFile(String from, String to) { GradleCppUtils.copyFile(project.file(from), project.file(to), false) } -task publishPrepareFiles { - doLast { - def pubRootDir = project.file('publish/publishRoot') - if (pubRootDir.exists()) { - if (!pubRootDir.deleteDir()) { - throw new RuntimeException("Failed to delete ${pubRootDir}") - } +task publishPrepareFiles << { + def pubRootDir = project.file('publish/publishRoot') + if (pubRootDir.exists()) { + if (!pubRootDir.deleteDir()) { + throw new RuntimeException("Failed to delete ${pubRootDir}") } + } - pubRootDir.mkdirs() + pubRootDir.mkdirs() - project.file('publish/publishRoot/revoice/bin/win32').mkdirs() - project.file('publish/publishRoot/revoice/bin/linux32').mkdirs() + project.file('publish/publishRoot/revoice/bin/win32').mkdirs() + project.file('publish/publishRoot/revoice/bin/linux32').mkdirs() - _copyFileToDir('publish/revoice_mm.dll', 'publish/publishRoot/revoice/bin/win32/') - _copyFile('publish/librevoice_mm_i386.so', 'publish/publishRoot/revoice/bin/linux32/revoice_mm_i386.so') + _copyFileToDir('publish/revoice_mm.dll', 'publish/publishRoot/revoice/bin/win32/') + _copyFile('publish/librevoice_mm_i386.so', 'publish/publishRoot/revoice/bin/linux32/revoice_mm_i386.so') + + copy { + from 'revoice/dist' + into 'publish/publishRoot/revoice' } } diff --git a/revoice/dist/revoice.cfg b/revoice/dist/revoice.cfg new file mode 100644 index 0000000..d88184b --- /dev/null +++ b/revoice/dist/revoice.cfg @@ -0,0 +1,2 @@ +REV_HltvCodec opus // speex, opus +REV_DefaultCodec speex // speex, opus diff --git a/revoice/msvc/revoice.vcxproj b/revoice/msvc/revoice.vcxproj index a11d68a..01ec10a 100644 --- a/revoice/msvc/revoice.vcxproj +++ b/revoice/msvc/revoice.vcxproj @@ -144,7 +144,7 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;REVOICE_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) $(ProjectDir)../src/;$(ProjectDir)../public/;$(ProjectDir)../version/;$(ProjectDir)../include/;$(SolutionDir)../dep/rehlsdk/common/;$(SolutionDir)../dep/rehlsdk/dlls/;$(SolutionDir)../dep/rehlsdk/engine/;$(SolutionDir)../dep/rehlsdk/public/;$(SolutionDir)../dep/silk/include/;$(SolutionDir)../dep/opus/include/;$(SolutionDir)../dep/speex/include/;$(SolutionDir)../dep/metamod/;%(AdditionalIncludeDirectories) precompiled.h @@ -187,7 +187,7 @@ IF EXIST "$(ProjectDir)start_6153.bat" (CALL "$(ProjectDir)start_6153.bat")MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;REVOICE_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) $(ProjectDir)../src/;$(ProjectDir)../public/;$(ProjectDir)../version/;$(ProjectDir)../include/;$(SolutionDir)../dep/rehlsdk/common/;$(SolutionDir)../dep/rehlsdk/dlls/;$(SolutionDir)../dep/rehlsdk/engine/;$(SolutionDir)../dep/rehlsdk/public/;$(SolutionDir)../dep/silk/include/;$(SolutionDir)../dep/opus/include/;$(SolutionDir)../dep/speex/include/;$(SolutionDir)../dep/metamod/;%(AdditionalIncludeDirectories) precompiled.h diff --git a/revoice/public/IVoiceCodec.h b/revoice/public/IVoiceCodec.h index 4d8ac2b..632c45b 100644 --- a/revoice/public/IVoiceCodec.h +++ b/revoice/public/IVoiceCodec.h @@ -2,19 +2,15 @@ #include "interface.h" -class IVoiceCodec : public IBaseInterface { +class IGameClient; +class IVoiceCodec: public IBaseInterface { protected: - virtual ~IVoiceCodec() { - } - + virtual ~IVoiceCodec() {} static const int BYTES_PER_SAMPLE = 2; public: - - // Initialize the object. The uncompressed format is always 8-bit signed mono. virtual bool Init(int quality) = 0; - virtual void Release() = 0; // Compress the voice data. diff --git a/revoice/src/SteamP2PCodec.cpp b/revoice/src/SteamP2PCodec.cpp index a9fd5f8..de5fd81 100644 --- a/revoice/src/SteamP2PCodec.cpp +++ b/revoice/src/SteamP2PCodec.cpp @@ -10,6 +10,11 @@ bool CSteamP2PCodec::Init(int quality) return m_BackendCodec->Init(quality); } +void CSteamP2PCodec::SetClient(IGameClient *client) +{ + m_Client = client; +} + void CSteamP2PCodec::Release() { m_BackendCodec->Release(); @@ -28,13 +33,13 @@ int CSteamP2PCodec::StreamDecode(const char *pCompressed, int compressedBytes, c while (readPos < maxReadPos) { - uint8 opcode = *(uint8*)readPos; + PayLoadType opcode = *(PayLoadType *)readPos; readPos++; switch (opcode) { // Set sampling rate - case 0xB: + case PLT_SamplingRate: { if (readPos + 2 > maxReadPos) { return 0; @@ -43,12 +48,12 @@ int CSteamP2PCodec::StreamDecode(const char *pCompressed, int compressedBytes, c break; } // Voice payload - case 0x04: // silk deprecated - case 0x05: // opus deprecated + case PLT_Silk: // silk deprecated + case PLT_OPUS: // opus deprecated { break; } - case 0x06: // opus plc + case PLT_OPUS_PLC: // opus plc { if (readPos + 2 > maxReadPos) { return 0; @@ -67,11 +72,13 @@ int CSteamP2PCodec::StreamDecode(const char *pCompressed, int compressedBytes, c // Invalid or unknown opcode default: + LCPrintf(true, "CSteamP2PCodec::StreamDecode() called on client(%d) with unknown voice codec opcode (%d)\n", m_Client->GetId(), opcode); return 0; } } - return 0; // no voice payload in the stream + // no voice payload in the stream + return 0; } int CSteamP2PCodec::StreamEncode(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal) const @@ -82,11 +89,11 @@ int CSteamP2PCodec::StreamEncode(const char *pUncompressedBytes, int nSamples, c return 0; } - *(writePos++) = 0x0B; // Set sampling rate + *(writePos++) = PLT_SamplingRate; // Set sampling rate *(uint16 *)writePos = 16000; writePos += 2; - *(writePos++) = 0x04; // Voice payload + *(writePos++) = PLT_Silk; // Voice payload int compressRes = m_BackendCodec->Compress(pUncompressedBytes, nSamples, writePos + 2, maxCompressedBytes - (1 + 2 + 1 + 2), bFinal); if (compressRes == 0) { diff --git a/revoice/src/SteamP2PCodec.h b/revoice/src/SteamP2PCodec.h index 61795f4..f8a99c3 100644 --- a/revoice/src/SteamP2PCodec.h +++ b/revoice/src/SteamP2PCodec.h @@ -3,15 +3,30 @@ #include "revoice_shared.h" #include "IVoiceCodec.h" -class CSteamP2PCodec : public IVoiceCodec { +class CSteamP2PCodec: public IVoiceCodec { public: CSteamP2PCodec(IVoiceCodec *backend); + + enum PayLoadType : uint8 + { + PLT_Silence = 0, // Number of empty samples, which should be set to NULL. + PLT_UnknownCodec = 1, + PLT_Speex = 2, + PLT_Raw = 3, + PLT_Silk = 4, + PLT_OPUS = 5, + PLT_OPUS_PLC = 6, + PLT_Unknown = 10, + PLT_SamplingRate = 11 + }; + virtual bool Init(int quality); virtual void Release(); virtual int Compress(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal); virtual int Decompress(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes); virtual bool ResetState(); + void SetClient(IGameClient *client); IVoiceCodec *GetCodec() const { return m_BackendCodec; } private: @@ -19,5 +34,6 @@ private: int StreamEncode(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal) const; private: + IGameClient *m_Client; IVoiceCodec *m_BackendCodec; }; diff --git a/revoice/src/VoiceEncoder_Silk.cpp b/revoice/src/VoiceEncoder_Silk.cpp index 1681d16..6a61820 100644 --- a/revoice/src/VoiceEncoder_Silk.cpp +++ b/revoice/src/VoiceEncoder_Silk.cpp @@ -2,8 +2,8 @@ VoiceEncoder_Silk::VoiceEncoder_Silk() { - m_pEncoder = NULL; - m_pDecoder = NULL; + m_pEncoder = nullptr; + m_pDecoder = nullptr; m_targetRate_bps = 25000; m_packetLoss_perc = 0; } @@ -12,12 +12,12 @@ VoiceEncoder_Silk::~VoiceEncoder_Silk() { if (m_pEncoder) { free(m_pEncoder); - m_pEncoder = NULL; + m_pEncoder = nullptr; } if (m_pDecoder) { free(m_pDecoder); - m_pDecoder = NULL; + m_pDecoder = nullptr; } } @@ -97,7 +97,7 @@ int VoiceEncoder_Silk::Compress(const char *pUncompressedIn, int nSamplesIn, cha while (nSamples > 0) { - int16* pWritePayloadSize = (int16*)pWritePos; + int16 *pWritePayloadSize = (int16 *)pWritePos; pWritePos += sizeof(int16); //leave 2 bytes for the frame size (will be written after encoding) int originalNBytes = (pWritePosMax - pWritePos > 0xFFFF) ? -1 : (pWritePosMax - pWritePos); @@ -111,11 +111,11 @@ int VoiceEncoder_Silk::Compress(const char *pUncompressedIn, int nSamplesIn, cha this->m_encControl.packetSize = 20 * (inSampleRate / 1000); this->m_encControl.packetLossPercentage = this->m_packetLoss_perc; this->m_encControl.bitRate = (m_targetRate_bps >= 0) ? m_targetRate_bps : 0; - + nSamples -= nSamplesToEncode; - + int16 nBytes = originalNBytes; - int res = SKP_Silk_SDK_Encode(this->m_pEncoder, &this->m_encControl, psRead, nSamplesToEncode, (unsigned char*)pWritePos, &nBytes); + int res = SKP_Silk_SDK_Encode(this->m_pEncoder, &this->m_encControl, psRead, nSamplesToEncode, (unsigned char *)pWritePos, &nBytes); *pWritePayloadSize = nBytes; //write frame size pWritePos += nBytes; @@ -133,7 +133,7 @@ int VoiceEncoder_Silk::Compress(const char *pUncompressedIn, int nSamplesIn, cha ResetState(); if (pWritePosMax > pWritePos + 2) { - uint16 * pWriteEndFlag = (uint16*)pWritePos; + uint16 *pWriteEndFlag = (uint16*)pWritePos; pWritePos += sizeof(uint16); *pWriteEndFlag = 0xFFFF; } diff --git a/revoice/src/VoiceEncoder_Speex.cpp b/revoice/src/VoiceEncoder_Speex.cpp index f792e77..3f6f22c 100644 --- a/revoice/src/VoiceEncoder_Speex.cpp +++ b/revoice/src/VoiceEncoder_Speex.cpp @@ -2,28 +2,18 @@ size_t ENCODED_FRAME_SIZE[] = { 0x6u, 0x6u, 0xFu, 0xFu, 0x14u, 0x14u, 0x1Cu, 0x1Cu, 0x26u, 0x26u, 0x26u }; -/* ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:70 */ -/*IBaseInterface *CreateSpeexVoiceCodec(void) -{ - IFrameEncoder *pEncoder = (IFrameEncoder *)new VoiceEncoder_Speex; - return (IBaseInterface *)CreateVoiceCodec_Frame(pEncoder); -}*/ - -/* ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:82 */ VoiceEncoder_Speex::VoiceEncoder_Speex() { - m_EncoderState = NULL; - m_DecoderState = NULL; + m_EncoderState = nullptr; + m_DecoderState = nullptr; m_Quality = 0; } -/* ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:89 */ VoiceEncoder_Speex::~VoiceEncoder_Speex() { TermStates(); } -/* ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:94 */ bool VoiceEncoder_Speex::Init(int quality, int &rawFrameSize, int &encodedFrameSize) { int postfilter; @@ -67,13 +57,11 @@ bool VoiceEncoder_Speex::Init(int quality, int &rawFrameSize, int &encodedFrameS return true; } -/* ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:127 */ void VoiceEncoder_Speex::Release() { delete this; } -/* ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:132 */ void VoiceEncoder_Speex::EncodeFrame(const char *pUncompressedBytes, char *pCompressed) { float input[160]; @@ -88,7 +76,6 @@ void VoiceEncoder_Speex::EncodeFrame(const char *pUncompressedBytes, char *pComp speex_bits_write(&m_Bits, pCompressed, ENCODED_FRAME_SIZE[m_Quality]); } -/* ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:156 */ void VoiceEncoder_Speex::DecodeFrame(const char *pCompressed, char *pDecompressedBytes) { float output[160]; @@ -102,7 +89,6 @@ void VoiceEncoder_Speex::DecodeFrame(const char *pCompressed, char *pDecompresse } } -/* ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:175 */ bool VoiceEncoder_Speex::ResetState() { speex_encoder_ctl(m_EncoderState, SPEEX_RESET_STATE, 0); @@ -111,29 +97,25 @@ bool VoiceEncoder_Speex::ResetState() return true; } -/* ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:182 */ bool VoiceEncoder_Speex::InitStates() { speex_bits_init(&m_Bits); m_EncoderState = speex_encoder_init(&speex_nb_mode); m_DecoderState = speex_decoder_init(&speex_nb_mode); - return (m_EncoderState != NULL && m_DecoderState != NULL); + return (m_EncoderState != nullptr && m_DecoderState != nullptr); } -/* ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:193 */ void VoiceEncoder_Speex::TermStates() { - if (m_EncoderState != NULL) { + if (m_EncoderState) { speex_encoder_destroy(m_EncoderState); - m_EncoderState = NULL; + m_EncoderState = nullptr; } - if (m_DecoderState != NULL) { + if (m_DecoderState) { speex_encoder_destroy(m_DecoderState); - m_DecoderState = NULL; + m_DecoderState = nullptr; } speex_bits_destroy(&m_Bits); } - -//EXPOSE_INTERFACE_FN(CreateSpeexVoiceCodec, VoiceEncoder_Speex, "voice_speex"); diff --git a/revoice/src/VoiceEncoder_Speex.h b/revoice/src/VoiceEncoder_Speex.h index b5e2f66..3b522e1 100644 --- a/revoice/src/VoiceEncoder_Speex.h +++ b/revoice/src/VoiceEncoder_Speex.h @@ -4,7 +4,6 @@ #include "iframeencoder.h" #include "speex.h" -/* <61c> ../engine/voice_codecs/speex/VoiceEncoder_Speex.h:57 */ class VoiceEncoder_Speex: public IFrameEncoder { protected: virtual ~VoiceEncoder_Speex(); @@ -12,26 +11,14 @@ protected: public: VoiceEncoder_Speex(); - /* <6c8> ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:94 */ - bool Init(int quality, int &rawFrameSize, int &encodedFrameSize); - - /* <6ff> ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:127 */ - void Release(); - - /* <751> ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:132 */ - void EncodeFrame(const char *pUncompressedBytes, char *pCompressed); - - /* <723> ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:156 */ - void DecodeFrame(const char *pCompressed, char *pDecompressedBytes); - - /* <77f> ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:175 */ - bool ResetState(); + virtual bool Init(int quality, int &rawFrameSize, int &encodedFrameSize); + virtual void Release(); + virtual void EncodeFrame(const char *pUncompressedBytes, char *pCompressed); + virtual void DecodeFrame(const char *pCompressed, char *pDecompressedBytes); + virtual bool ResetState(); protected: - /* <7a7> ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:182 */ bool InitStates(); - - /* <7c8> ../engine/voice_codecs/speex/VoiceEncoder_Speex.cpp:193 */ void TermStates(); private: @@ -39,7 +26,4 @@ private: void *m_EncoderState; void *m_DecoderState; SpeexBits m_Bits; - }; - -extern IVoiceCodec *CreateVoiceCodec_Frame(IFrameEncoder *pEncoder); diff --git a/revoice/src/dllapi.cpp b/revoice/src/dllapi.cpp index caf3e44..8b5e149 100644 --- a/revoice/src/dllapi.cpp +++ b/revoice/src/dllapi.cpp @@ -31,7 +31,8 @@ #include "precompiled.h" -static DLL_FUNCTIONS gFunctionTable = { +DLL_FUNCTIONS g_DLLFuncTable = +{ NULL, // pfnGameInit NULL, // pfnSpawn NULL, // pfnThink @@ -42,15 +43,12 @@ static DLL_FUNCTIONS gFunctionTable = { NULL, // pfnSave NULL, // pfnRestore NULL, // pfnSetAbsBox - NULL, // pfnSaveWriteFields NULL, // pfnSaveReadFields - NULL, // pfnSaveGlobalState NULL, // pfnRestoreGlobalState NULL, // pfnResetGlobalState - - &mm_ClientConnect, + &ClientConnect_PreHook, // pfnClientDisconnect NULL, // pfnClientDisconnect NULL, // pfnClientKill NULL, // pfnClientPutInServer @@ -58,27 +56,20 @@ static DLL_FUNCTIONS gFunctionTable = { NULL, // pfnClientUserInfoChanged NULL, // pfnServerActivate NULL, // pfnServerDeactivate - NULL, // pfnPlayerPreThink NULL, // pfnPlayerPostThink - NULL, // pfnStartFrame NULL, // pfnParmsNewLevel NULL, // pfnParmsChangeLevel - NULL, // pfnGetGameDescription NULL, // pfnPlayerCustomization - NULL, // pfnSpectatorConnect NULL, // pfnSpectatorDisconnect NULL, // pfnSpectatorThink - NULL, // pfnSys_Error - NULL, // pfnPM_Move NULL, // pfnPM_Init NULL, // pfnPM_FindTextureType - NULL, // pfnSetupVisibility NULL, // pfnUpdateClientData NULL, // pfnAddToFullPack @@ -94,43 +85,124 @@ static DLL_FUNCTIONS gFunctionTable = { NULL, // pfnAllowLagCompensation }; -static NEW_DLL_FUNCTIONS gNewFunctionTable = { - NULL, //pfnOnFreeEntPrivateData - NULL, //pfnGameShutdown - NULL, //pfnShouldCollide - NULL, //pfnCvarValue - &mm_CvarValue2, //pfnCvarValue2 +DLL_FUNCTIONS g_DLLFuncTable_Post = +{ + NULL, // pfnGameInit + NULL, // pfnSpawn + NULL, // pfnThink + NULL, // pfnUse + NULL, // pfnTouch + NULL, // pfnBlocked + NULL, // pfnKeyValue + NULL, // pfnSave + NULL, // pfnRestore + NULL, // pfnSetAbsBox + NULL, // pfnSaveWriteFields + NULL, // pfnSaveReadFields + NULL, // pfnSaveGlobalState + NULL, // pfnRestoreGlobalState + NULL, // pfnResetGlobalState + NULL, // pfnClientConnect + NULL, // pfnClientDisconnect + NULL, // pfnClientKill + NULL, // pfnClientPutInServer + NULL, // pfnClientCommand + NULL, // pfnClientUserInfoChanged + &ServerActivate_PostHook, // pfnServerActivate + NULL, // pfnServerDeactivate + NULL, // pfnPlayerPreThink + NULL, // pfnPlayerPostThink + NULL, // pfnStartFrame + NULL, // pfnParmsNewLevel + NULL, // pfnParmsChangeLevel + NULL, // pfnGetGameDescription + NULL, // pfnPlayerCustomization + NULL, // pfnSpectatorConnect + NULL, // pfnSpectatorDisconnect + NULL, // pfnSpectatorThink + NULL, // pfnSys_Error + NULL, // pfnPM_Move + NULL, // pfnPM_Init + NULL, // pfnPM_FindTextureType + NULL, // pfnSetupVisibility + NULL, // pfnUpdateClientData + NULL, // pfnAddToFullPack + NULL, // pfnCreateBaseline + NULL, // pfnRegisterEncoders + NULL, // pfnGetWeaponData + NULL, // pfnCmdStart + NULL, // pfnCmdEnd + NULL, // pfnConnectionlessPacket + NULL, // pfnGetHullBounds + NULL, // pfnCreateInstancedBaselines + NULL, // pfnInconsistentFile + NULL, // pfnAllowLagCompensation }; +NEW_DLL_FUNCTIONS g_NewDLLFuncTable = +{ + NULL, //! pfnOnFreeEntPrivateData() Called right before the object's memory is freed. Calls its destructor. + NULL, //! pfnGameShutdown() + NULL, //! pfnShouldCollide() + NULL, //! pfnCvarValue() + &CvarValue2_PreHook, //! pfnCvarValue2() +}; C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion) { - if(!pFunctionTable) { + if (!pFunctionTable) + { UTIL_LogPrintf("GetEntityAPI2 called with null pFunctionTable"); - return(FALSE); + return FALSE; } - else if(*interfaceVersion != INTERFACE_VERSION) { + + if (*interfaceVersion != INTERFACE_VERSION) + { UTIL_LogPrintf("GetEntityAPI2 version mismatch; requested=%d ours=%d", *interfaceVersion, INTERFACE_VERSION); //! Tell metamod what version we had, so it can figure out who is out of date. *interfaceVersion = INTERFACE_VERSION; - return(FALSE); + return FALSE; } - memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS)); - return(TRUE); + + memcpy(pFunctionTable, &g_DLLFuncTable, sizeof(DLL_FUNCTIONS)); + return TRUE; +} + +C_DLLEXPORT int GetEntityAPI2_Post(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion) +{ + if (!pFunctionTable) + { + ALERT(at_logged, "%s called with null pFunctionTable", __FUNCTION__); + return FALSE; + } + + if (*interfaceVersion != INTERFACE_VERSION) + { + ALERT(at_logged, "%s version mismatch; requested=%d ours=%d", __FUNCTION__, *interfaceVersion, INTERFACE_VERSION); + *interfaceVersion = INTERFACE_VERSION; + return FALSE; + } + + memcpy(pFunctionTable, &g_DLLFuncTable_Post, sizeof(DLL_FUNCTIONS)); + return TRUE; } C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion) { - if (!pNewFunctionTable) { + if (!pNewFunctionTable) + { UTIL_LogPrintf("GetNewDLLFunctions called with null pNewFunctionTable"); return(FALSE); } - else if (*interfaceVersion != NEW_DLL_FUNCTIONS_VERSION) { + + if (*interfaceVersion != NEW_DLL_FUNCTIONS_VERSION) + { UTIL_LogPrintf("GetNewDLLFunctions version mismatch; requested=%d ours=%d", *interfaceVersion, NEW_DLL_FUNCTIONS_VERSION); //! Tell metamod what version we had, so it can figure out who is out of date. *interfaceVersion = NEW_DLL_FUNCTIONS_VERSION; - return(FALSE); + return FALSE; } - memcpy(pNewFunctionTable, &gNewFunctionTable, sizeof(NEW_DLL_FUNCTIONS)); - return(TRUE); + + memcpy(pNewFunctionTable, &g_NewDLLFuncTable, sizeof(NEW_DLL_FUNCTIONS)); + return TRUE; } diff --git a/revoice/src/iframeencoder.h b/revoice/src/iframeencoder.h index ba9bec8..6e20ee4 100644 --- a/revoice/src/iframeencoder.h +++ b/revoice/src/iframeencoder.h @@ -1,24 +1,14 @@ #pragma once -/* <7e2> ../engine/voice_codecs/speex/../frame_encoder/iframeencoder.h:15 */ class IFrameEncoder { protected: virtual ~IFrameEncoder() {}; public: // quality is in [0..10] - /* <855> ../engine/voice_codecs/speex/../frame_encoder/iframeencoder.h:23 */ virtual bool Init(int quality, int &rawFrameSize, int &encodedFrameSize) = 0; - - /* <88c> ../engine/voice_codecs/speex/../frame_encoder/iframeencoder.h:25 */ virtual void Release() = 0; - - /* <8b0> ../engine/voice_codecs/speex/../frame_encoder/iframeencoder.h:29 */ virtual void EncodeFrame(const char *pUncompressedBytes, char *pCompressed) = 0; - - /* <8de> ../engine/voice_codecs/speex/../frame_encoder/iframeencoder.h:33 */ virtual void DecodeFrame(const char *pCompressed, char *pDecompressedBytes) = 0; - - /* <90c> ../engine/voice_codecs/speex/../frame_encoder/iframeencoder.h:36 */ virtual bool ResetState() = 0; }; diff --git a/revoice/src/meta_api.cpp b/revoice/src/meta_api.cpp index 12bc7d0..f4f5787 100644 --- a/revoice/src/meta_api.cpp +++ b/revoice/src/meta_api.cpp @@ -42,7 +42,7 @@ static META_FUNCTIONS gMetaFunctionTable = { NULL, // pfnGetEntityAPI HL SDK; called before game DLL NULL, // pfnGetEntityAPI_Post META; called after game DLL &GetEntityAPI2, // pfnGetEntityAPI2 HL SDK2; called before game DLL - NULL, // pfnGetEntityAPI2_Post META; called after game DLL + &GetEntityAPI2_Post, // pfnGetEntityAPI2_Post META; called after game DLL &GetNewDLLFunctions, // pfnGetNewDLLFunctions HL SDK2; called before game DLL NULL, // pfnGetNewDLLFunctions_Post META; called after game DLL NULL, // pfnGetEngineFunctions META; called before HL engine @@ -79,7 +79,7 @@ C_DLLEXPORT int Meta_Query(char * /*ifvers */, plugin_info_t **pPlugInfo, mutil_ // Get metamod utility function table. gpMetaUtilFuncs = pMetaUtilFuncs; - return(TRUE); + return TRUE; } // Metamod attaching plugin to the server. @@ -91,20 +91,20 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME /* now */, META_FUNCTIONS *pFunctionTa { if(!pMGlobals) { LOG_ERROR(PLID, "Meta_Attach called with null pMGlobals"); - return(FALSE); + return FALSE; } gpMetaGlobals = pMGlobals; if(!pFunctionTable) { LOG_ERROR(PLID, "Meta_Attach called with null pFunctionTable"); - return(FALSE); + return FALSE; } memcpy(pFunctionTable, &gMetaFunctionTable, sizeof(META_FUNCTIONS)); gpGamedllFuncs = pGamedllFuncs; - return Revoice_Load() ? (TRUE) : (FALSE); + return Revoice_Load() ? TRUE : FALSE; } // Metamod detaching plugin from the server. @@ -112,31 +112,6 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME /* now */, META_FUNCTIONS *pFunctionTa // reason (given) why detaching (refresh, console unload, forced unload, etc) C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME /* now */, PL_UNLOAD_REASON /* reason */) { - return(TRUE); -} - -bool Revoice_Load() -{ - if (!Revoice_Utils_Init()) - return false; - - /*if (!Revoice_Cfg_LoadDefault()) - return false;*/ - - if (!Revoice_RehldsApi_Init()) { - LCPrintf(true, "Failed to locate REHLDS API\n"); - return false; - } - - if (!Revoice_ReunionApi_Init()) - return false; - - Revoice_Init_Players(); - - if (!Revoice_Main_Init()) { - LCPrintf(true, "Initialization failed\n"); - return false; - } - - return true; + Revoice_Main_DeInit(); + return TRUE; } diff --git a/revoice/src/revoice_cfg.cpp b/revoice/src/revoice_cfg.cpp index 67760a3..42cc151 100644 --- a/revoice/src/revoice_cfg.cpp +++ b/revoice/src/revoice_cfg.cpp @@ -1,129 +1,77 @@ #include "precompiled.h" -CRevoiceConfig* g_RevoiceConfig; +char g_ExecConfigCmd[MAX_PATH]; +const char REVOICE_CFG_FILE[] = "revoice.cfg"; -bool Revoice_Cfg_LoadDefault() +void Revoice_Exec_Config() { - CRevoiceConfig* cfg = CRevoiceConfig::load(REVOICE_CFG_FILE); + if (!g_ExecConfigCmd[0]) { + return; + } - if (!cfg) - return false; + g_engfuncs.pfnServerCommand(g_ExecConfigCmd); + g_engfuncs.pfnServerExecute(); +} - if (g_RevoiceConfig) - delete g_RevoiceConfig; +bool Revoice_Init_Config() +{ + const char *pszGameDir = GET_GAME_INFO(PLID, GINFO_GAMEDIR); + const char *pszPluginDir = GET_PLUGIN_PATH(PLID); - g_RevoiceConfig = cfg; + char szRelativePath[MAX_PATH]; + strncpy(szRelativePath, &pszPluginDir[strlen(pszGameDir) + 1], sizeof(szRelativePath) - 1); + szRelativePath[sizeof(szRelativePath) - 1] = '\0'; + NormalizePath(szRelativePath); + char *pos = strrchr(szRelativePath, '/'); + if (pos) { + *(pos + 1) = '\0'; + } + + snprintf(g_ExecConfigCmd, sizeof(g_ExecConfigCmd), "exec \"%s%s\"\n", szRelativePath, REVOICE_CFG_FILE); return true; } -CRevoiceConfig* CRevoiceConfig::load(const char* fname) +cvar_t g_cv_rev_hltv_codec = { "REV_HltvCodec", "opus", 0, 0.0f, nullptr }; +cvar_t g_cv_rev_default_codec = { "REV_DefaultCodec", "speex", 0, 0.0f, nullptr }; +cvar_t g_cv_rev_version = { "revoice_version", APP_VERSION, FCVAR_SERVER, 0.0f, nullptr }; + +cvar_t *g_pcv_rev_hltv_codec = nullptr; +cvar_t *g_pcv_rev_default_codec = nullptr; +cvar_t *g_pcv_sv_voiceenable = nullptr; + +void Revoice_Init_Cvars() { - char namebuf[MAX_PATH]; - char gamedir[MAX_PATH]; + g_engfuncs.pfnAddServerCommand("rev", Revoice_Cmds_Handler); - sprintf(namebuf, "./%s", fname); + g_engfuncs.pfnCvar_RegisterVariable(&g_cv_rev_version); + g_engfuncs.pfnCvar_RegisterVariable(&g_cv_rev_hltv_codec); + g_engfuncs.pfnCvar_RegisterVariable(&g_cv_rev_default_codec); - FILE *fl = fopen(namebuf, "r"); + g_pcv_sv_voiceenable = g_engfuncs.pfnCVarGetPointer("sv_voiceenable"); + g_pcv_rev_hltv_codec = g_engfuncs.pfnCVarGetPointer(g_cv_rev_hltv_codec.name); + g_pcv_rev_default_codec = g_engfuncs.pfnCVarGetPointer(g_cv_rev_default_codec.name); +} - if (fl == NULL) +REVCmds g_revoice_cmds[] = { + { "version", Cmd_REV_Version } +}; + +void Revoice_Cmds_Handler() +{ + const char *pcmd = CMD_ARGV(1); + for (auto& cmds : g_revoice_cmds) { - g_engfuncs.pfnGetGameDir(gamedir); - sprintf(namebuf, "./%s/%s", gamedir, fname); - - fl = fopen(namebuf, "r"); - - if (fl == NULL) { - LCPrintf(true, "Failed to load config: can't find %s in server root or gamedir\n", fname); - return NULL; + if (_stricmp(cmds.name, pcmd) == 0 && cmds.func) { + cmds.func(); } } - - char linebuf[2048]; - int cline = 0; - CRevoiceConfig* cfg = createDefault(); - - while (fgets(linebuf, sizeof(linebuf), fl)) - { - cline++; - - char* l = trimbuf(linebuf); - - if (l[0] == '\0' || l[0] == '#') - continue; - - char* valSeparator = strchr(l, '='); - - if (valSeparator == NULL) { - LCPrintf(true, "Config line parsing failed: missed '=' on line %d\n", cline); - } - - *(valSeparator++) = 0; - - char* param = trimbuf(l); - char* value = trimbuf(valSeparator); - - if (!cfg->parseCfgParam(param, value)) { - LCPrintf(true, "Config line parsing failed: unknown parameter '%s' at line %d\n", param, cline); - } - } - - if (fl) - fclose(fl); - - return cfg; } -CRevoiceConfig* CRevoiceConfig::createDefault() +void Cmd_REV_Version() { - CRevoiceConfig* cfg = new CRevoiceConfig(); - - cfg->m_LogMode = rl_console | rl_logfile; - - return cfg; -} - -bool CRevoiceConfig::parseCfgParam(const char* param, const char* value) -{ - -#define REV_CFG_PARSE_INT(paramName, field, _type, minVal, maxVal) \ - if (!strcasecmp(paramName, param)) { \ - int i = atoi(value); \ - if (i < minVal || i > maxVal) { \ - LCPrintf(true, "Invalid %s value '%s'\n", param, value); \ - return false; \ - } \ - field = (_type) i; \ - return true; \ - } - -#define REV_CFG_PARSE_IP(paramName, field) \ - if (!strcasecmp(paramName, param)) { \ - field = inet_addr(value); \ - return true; \ - } - -#define REV_CFG_PARSE_BOOL(paramName, field) \ - if (!strcasecmp(paramName, param)) { \ - int i = atoi(value); \ - if (i < 0 || i > 1) { \ - LCPrintf(true, "Invalid %s value '%s'\n", param, value); \ - return false; \ - } \ - field = i ? true : false; \ - return true; \ - } - -#define REV_CFG_PARSE_STR(paramName, field) \ - if (!strcasecmp(paramName, param)) { \ - strncpy(field, value, ARRAYSIZE(field) - 1); \ - field[ARRAYSIZE(field) - 1] = 0; \ - return true; \ - } - - REV_CFG_PARSE_INT("LoggingMode", m_LogMode, int, rl_none, (rl_console | rl_logfile)); - - LCPrintf(true, " Config line parsing failed: unknown parameter '%s'\n", param); - - return false; + // print version + g_engfuncs.pfnServerPrint("Revoice version: " APP_VERSION "\n"); + g_engfuncs.pfnServerPrint("Build date: " APP_COMMIT_TIME " " APP_COMMIT_DATE "\n"); + g_engfuncs.pfnServerPrint("Build from: " APP_COMMIT_URL APP_COMMIT_SHA "\n"); } diff --git a/revoice/src/revoice_cfg.h b/revoice/src/revoice_cfg.h index 1fcdcac..5ce4893 100644 --- a/revoice/src/revoice_cfg.h +++ b/revoice/src/revoice_cfg.h @@ -2,23 +2,18 @@ #include "revoice_shared.h" -#define REVOICE_CFG_FILE "revoice.cfg" - -class CRevoiceConfig { -private: - int m_LogMode; - - bool parseCfgParam(const char* param, const char* value); - -public: - static CRevoiceConfig* createDefault(); - static CRevoiceConfig* load(const char* fname); - - bool hasLogMode(revoice_log_mode m) { - return (m_LogMode & m) == m; - } - +struct REVCmds { + const char *name; + void (*func)(); }; -extern CRevoiceConfig* g_RevoiceConfig; -extern bool Revoice_Cfg_LoadDefault(); +void Revoice_Exec_Config(); +bool Revoice_Init_Config(); +void Revoice_Init_Cvars(); + +void Revoice_Cmds_Handler(); +void Cmd_REV_Version(); + +extern cvar_t *g_pcv_sv_voiceenable; +extern cvar_t *g_pcv_rev_hltv_codec; +extern cvar_t *g_pcv_rev_default_codec; diff --git a/revoice/src/revoice_main.cpp b/revoice/src/revoice_main.cpp index 527785d..22f30cd 100644 --- a/revoice/src/revoice_main.cpp +++ b/revoice/src/revoice_main.cpp @@ -1,7 +1,5 @@ #include "precompiled.h" -cvar_t *pcv_sv_voiceenable = NULL; - void SV_DropClient_hook(IRehldsHook_SV_DropClient *chain, IGameClient *cl, bool crash, const char *msg) { CRevoicePlayer *plr = GetPlayerByClientPtr(cl); @@ -11,16 +9,14 @@ void SV_DropClient_hook(IRehldsHook_SV_DropClient *chain, IGameClient *cl, bool chain->callNext(cl, crash, msg); } -void mm_CvarValue2(const edict_t *pEnt, int requestID, const char *cvarName, const char *cvarValue) +void CvarValue2_PreHook(const edict_t *pEnt, int requestID, const char *cvarName, const char *cvarValue) { CRevoicePlayer *plr = GetPlayerByEdict(pEnt); - if (plr->GetRequestId() != requestID) { RETURN_META(MRES_IGNORED); } const char *lastSeparator = strrchr(cvarValue, ','); - if (lastSeparator) { int buildNumber = atoi(lastSeparator + 1); @@ -32,7 +28,7 @@ void mm_CvarValue2(const edict_t *pEnt, int requestID, const char *cvarName, con RETURN_META(MRES_IGNORED); } -int TranscodeVoice(const char *srcBuf, int srcBufLen, IVoiceCodec *srcCodec, IVoiceCodec *dstCodec, char *dstBuf, int dstBufSize) +int TranscodeVoice(CRevoicePlayer *srcPlayer, const char *srcBuf, int srcBufLen, IVoiceCodec *srcCodec, IVoiceCodec *dstCodec, char *dstBuf, int dstBufSize) { char decodedBuf[32768]; @@ -74,7 +70,7 @@ void SV_ParseVoiceData_emu(IGameClient *cl) g_RehldsFuncs->MSG_ReadBuf(nDataLength, chReceived); - if (pcv_sv_voiceenable->value == 0.0f) { + if (g_pcv_sv_voiceenable->value == 0.0f) { return; } @@ -94,38 +90,38 @@ void SV_ParseVoiceData_emu(IGameClient *cl) switch (srcPlayer->GetCodecType()) { - case vct_silk: - { - if (nDataLength > MAX_SILK_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_SILK_VOICE_RATE) - return; - - silkData = chReceived; silkDataLen = nDataLength; - speexData = transcodedBuf; - speexDataLen = TranscodeVoice(silkData, silkDataLen, srcPlayer->GetSilkCodec(), srcPlayer->GetSpeexCodec(), transcodedBuf, sizeof(transcodedBuf)); - break; - } - case vct_opus: - { - if (nDataLength > MAX_OPUS_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_OPUS_VOICE_RATE) - return; - - opusData = chReceived; opusDataLen = nDataLength; - speexData = transcodedBuf; - speexDataLen = TranscodeVoice(opusData, opusDataLen, srcPlayer->GetOpusCodec(), srcPlayer->GetSpeexCodec(), transcodedBuf, sizeof(transcodedBuf)); - break; - } - case vct_speex: - { - if (nDataLength > MAX_SPEEX_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_SPEEX_VOICE_RATE) - return; - - speexData = chReceived; speexDataLen = nDataLength; - silkData = transcodedBuf; - silkDataLen = TranscodeVoice(speexData, speexDataLen, srcPlayer->GetSpeexCodec(), srcPlayer->GetSilkCodec(), transcodedBuf, sizeof(transcodedBuf)); - break; - } - default: + case vct_silk: + { + if (nDataLength > MAX_SILK_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_SILK_VOICE_RATE) return; + + silkData = chReceived; silkDataLen = nDataLength; + speexData = transcodedBuf; + speexDataLen = TranscodeVoice(srcPlayer, silkData, silkDataLen, srcPlayer->GetSilkCodec(), srcPlayer->GetSpeexCodec(), transcodedBuf, sizeof(transcodedBuf)); + break; + } + case vct_opus: + { + if (nDataLength > MAX_OPUS_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_OPUS_VOICE_RATE) + return; + + opusData = chReceived; opusDataLen = nDataLength; + speexData = transcodedBuf; + speexDataLen = TranscodeVoice(srcPlayer, opusData, opusDataLen, srcPlayer->GetOpusCodec(), srcPlayer->GetSpeexCodec(), transcodedBuf, sizeof(transcodedBuf)); + break; + } + case vct_speex: + { + if (nDataLength > MAX_SPEEX_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_SPEEX_VOICE_RATE) + return; + + speexData = chReceived; speexDataLen = nDataLength; + silkData = transcodedBuf; + silkDataLen = TranscodeVoice(srcPlayer, speexData, speexDataLen, srcPlayer->GetSpeexCodec(), srcPlayer->GetSilkCodec(), transcodedBuf, sizeof(transcodedBuf)); + break; + } + default: + return; } int maxclients = g_RehldsSvs->GetMaxClients(); @@ -140,7 +136,8 @@ void SV_ParseVoiceData_emu(IGameClient *cl) if (!dstClient->IsActive() && !dstClient->IsConnected() && dstPlayer != srcPlayer) continue; - char *sendBuf; int nSendLen; + char *sendBuf; + int nSendLen; switch (dstPlayer->GetCodecType()) { case vct_silk: @@ -153,12 +150,12 @@ void SV_ParseVoiceData_emu(IGameClient *cl) nSendLen = speexDataLen; break; default: - sendBuf = NULL; + sendBuf = nullptr; nSendLen = 0; break; } - if (sendBuf == NULL || nSendLen == 0) + if (sendBuf == nullptr || nSendLen == 0) continue; if (dstPlayer == srcPlayer && !dstClient->GetLoopback()) @@ -185,15 +182,20 @@ void Rehlds_HandleNetCommand(IRehldsHook_HandleNetCommand *chain, IGameClient *c chain->callNext(cl, opcode); } -qboolean mm_ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]) { - +qboolean ClientConnect_PreHook(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]) +{ CRevoicePlayer *plr = GetPlayerByEdict(pEntity); - plr->OnConnected(); RETURN_META_VALUE(MRES_IGNORED, TRUE); } +void ServerActivate_PostHook(edict_t *pEdictList, int edictCount, int clientMax) +{ + Revoice_Exec_Config(); + SET_META_RESULT(MRES_IGNORED); +} + void SV_WriteVoiceCodec_hooked(IRehldsHook_SV_WriteVoiceCodec *chain, sizebuf_t *sb) { IGameClient *cl = g_RehldsFuncs->GetHostClient(); @@ -203,17 +205,11 @@ void SV_WriteVoiceCodec_hooked(IRehldsHook_SV_WriteVoiceCodec *chain, sizebuf_t { case vct_silk: case vct_opus: - { - g_RehldsFuncs->MSG_WriteByte(sb, svc_voiceinit); // svc_voiceinit - g_RehldsFuncs->MSG_WriteString(sb, ""); // codec id - g_RehldsFuncs->MSG_WriteByte(sb, 0); // quality - break; - } case vct_speex: { - g_RehldsFuncs->MSG_WriteByte(sb, svc_voiceinit); // svc_voiceinit - g_RehldsFuncs->MSG_WriteString(sb, "voice_speex"); // codec id - g_RehldsFuncs->MSG_WriteByte(sb, 5); // quality + g_RehldsFuncs->MSG_WriteByte(sb, svc_voiceinit); + g_RehldsFuncs->MSG_WriteString(sb, "voice_speex"); // codec id + g_RehldsFuncs->MSG_WriteByte(sb, 5); // quality break; } default: @@ -222,13 +218,55 @@ void SV_WriteVoiceCodec_hooked(IRehldsHook_SV_WriteVoiceCodec *chain, sizebuf_t } } -bool Revoice_Main_Init() +void Cvar_DirectSet_hooked(IRehldsHook_Cvar_DirectSet *chain, cvar_t *var, const char *value) { - g_RehldsHookchains->SV_DropClient()->registerHook(SV_DropClient_hook, HC_PRIORITY_DEFAULT + 1); - g_RehldsHookchains->HandleNetCommand()->registerHook(Rehlds_HandleNetCommand, HC_PRIORITY_DEFAULT + 1); - g_RehldsHookchains->SV_WriteVoiceCodec()->registerHook(SV_WriteVoiceCodec_hooked, HC_PRIORITY_DEFAULT + 1); + chain->callNext(var, value); - pcv_sv_voiceenable = g_engfuncs.pfnCVarGetPointer("sv_voiceenable"); + if (g_pcv_rev_hltv_codec == var + || g_pcv_rev_default_codec == var) { + Revoice_Update_Players(); + } +} + +bool Revoice_Load() +{ + if (!Revoice_Utils_Init()) + return false; + + if (!Revoice_RehldsApi_Init()) { + LCPrintf(true, "Failed to locate REHLDS API\n"); + return false; + } + + if (!Revoice_ReunionApi_Init()) + return false; + + Revoice_Init_Cvars(); + Revoice_Init_Config(); + Revoice_Init_Players(); + + if (!Revoice_Main_Init()) { + LCPrintf(true, "Initialization failed\n"); + return false; + } return true; } + +bool Revoice_Main_Init() +{ + g_RehldsHookchains->SV_DropClient()->registerHook(&SV_DropClient_hook, HC_PRIORITY_DEFAULT + 1); + g_RehldsHookchains->HandleNetCommand()->registerHook(&Rehlds_HandleNetCommand, HC_PRIORITY_DEFAULT + 1); + g_RehldsHookchains->SV_WriteVoiceCodec()->registerHook(&SV_WriteVoiceCodec_hooked, HC_PRIORITY_DEFAULT + 1); + g_RehldsHookchains->Cvar_DirectSet()->registerHook(&Cvar_DirectSet_hooked, HC_PRIORITY_DEFAULT + 1); + + return true; +} + +void Revoice_Main_DeInit() +{ + g_RehldsHookchains->SV_DropClient()->unregisterHook(&SV_DropClient_hook); + g_RehldsHookchains->HandleNetCommand()->unregisterHook(&Rehlds_HandleNetCommand); + g_RehldsHookchains->SV_WriteVoiceCodec()->unregisterHook(&SV_WriteVoiceCodec_hooked); + g_RehldsHookchains->Cvar_DirectSet()->unregisterHook(&Cvar_DirectSet_hooked); +} diff --git a/revoice/src/revoice_main.h b/revoice/src/revoice_main.h index b0c2daf..b920130 100644 --- a/revoice/src/revoice_main.h +++ b/revoice/src/revoice_main.h @@ -3,7 +3,11 @@ #include "revoice_shared.h" #include "revoice_player.h" -extern qboolean mm_ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]); -extern void mm_CvarValue2(const edict_t *pEnt, int requestID, const char *cvarName, const char *value); +bool Revoice_Load(); +void Revoice_Main_DeInit(); +bool Revoice_Main_Init(); + +void CvarValue2_PreHook(const edict_t *pEnt, int requestID, const char *cvarName, const char *cvarValue); +qboolean ClientConnect_PreHook(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]); +void ServerActivate_PostHook(edict_t *pEdictList, int edictCount, int clientMax); -extern bool Revoice_Main_Init(); diff --git a/revoice/src/revoice_player.cpp b/revoice/src/revoice_player.cpp index 4a7b365..d625445 100644 --- a/revoice/src/revoice_player.cpp +++ b/revoice/src/revoice_player.cpp @@ -1,26 +1,38 @@ #include "precompiled.h" +const char *CRevoicePlayer::m_szCodecType[] = { + "none", + "silk", + "opus", + "speex" +}; + CRevoicePlayer g_Players[MAX_PLAYERS]; CRevoicePlayer::CRevoicePlayer() { m_CodecType = vct_none; m_SpeexCodec = new VoiceCodec_Frame(new VoiceEncoder_Speex()); - m_SilkCodec = new CSteamP2PCodec(new VoiceEncoder_Silk()); - m_OpusCodec = new CSteamP2PCodec(new VoiceEncoder_Opus()); + m_SilkCodec = new CSteamP2PCodec(new VoiceEncoder_Silk()); + m_OpusCodec = new CSteamP2PCodec(new VoiceEncoder_Opus()); m_SpeexCodec->Init(SPEEX_VOICE_QUALITY); - m_SilkCodec->Init(SILK_VOICE_QUALITY); - m_OpusCodec->Init(OPUS_VOICE_QUALITY); + m_SilkCodec ->Init(SILK_VOICE_QUALITY); + m_OpusCodec ->Init(OPUS_VOICE_QUALITY); - m_RehldsClient = NULL; m_Protocol = 0; + m_HLTV = false; m_Connected = false; + m_Client = nullptr; } -void CRevoicePlayer::Initialize(IGameClient* cl) +void CRevoicePlayer::Initialize(IGameClient *cl) { - m_RehldsClient = cl; + m_Client = cl; + + m_SpeexCodec->SetClient(cl); + m_SilkCodec ->SetClient(cl); + m_OpusCodec ->SetClient(cl); } void CRevoicePlayer::OnConnected() @@ -31,8 +43,7 @@ void CRevoicePlayer::OnConnected() return; } - int protocol = g_ReunionApi->GetClientProtocol(m_RehldsClient->GetId()); - + int protocol = g_ReunionApi->GetClientProtocol(m_Client->GetId()); if (protocol != 47 && protocol != 48) { return; } @@ -43,19 +54,24 @@ void CRevoicePlayer::OnConnected() m_SpeexCodec->ResetState(); // default codec - m_CodecType = vct_speex; + m_CodecType = GetCodecTypeByString(g_pcv_rev_default_codec->string); m_VoiceRate = 0; m_Connected = true; m_RequestId = MAKE_REQUESTID(PLID); m_Protocol = protocol; - if (m_Protocol == 48) { - g_engfuncs.pfnQueryClientCvarValue2(m_RehldsClient->GetEdict(), "sv_version", m_RequestId); + if (g_ReunionApi->GetClientAuthtype(m_Client->GetId()) == DP_AUTH_HLTV) { + m_CodecType = GetCodecTypeByString(g_pcv_rev_hltv_codec->string); + m_HLTV = true; + } + else if (m_Protocol == 48) { + g_engfuncs.pfnQueryClientCvarValue2(m_Client->GetEdict(), "sv_version", m_RequestId); } } void CRevoicePlayer::OnDisconnected() { + m_HLTV = false; m_Connected = false; m_Protocol = 0; m_CodecType = vct_none; @@ -63,10 +79,31 @@ void CRevoicePlayer::OnDisconnected() m_RequestId = 0; } +void CRevoicePlayer::Update() +{ + m_CodecType = GetCodecTypeByString(((m_HLTV) ? + g_pcv_rev_hltv_codec : g_pcv_rev_default_codec)->string); + + m_RequestId = MAKE_REQUESTID(PLID); + + if (m_Protocol == 48) { + g_engfuncs.pfnQueryClientCvarValue2(m_Client->GetEdict(), "sv_version", m_RequestId); + } +} + +void Revoice_Update_Players() +{ + int maxclients = g_RehldsSvs->GetMaxClients(); + for (int i = 0; i < maxclients; i++) { + if (g_Players[i].IsConnected()) { + g_Players[i].Update(); + } + } +} + void Revoice_Init_Players() { int maxclients = g_RehldsSvs->GetMaxClients(); - for (int i = 0; i < maxclients; i++) { g_Players[i].Initialize(g_RehldsSvs->GetClient(i)); } @@ -90,8 +127,8 @@ CRevoicePlayer *GetPlayerByEdict(const edict_t *ed) void CRevoicePlayer::SetLastVoiceTime(double time) { - UpdateVoiceRate(time - m_RehldsClient->GetLastVoiceTime()); - m_RehldsClient->SetLastVoiceTime(time); + UpdateVoiceRate(time - m_Client->GetLastVoiceTime()); + m_Client->SetLastVoiceTime(time); } void CRevoicePlayer::UpdateVoiceRate(double delta) @@ -100,20 +137,17 @@ void CRevoicePlayer::UpdateVoiceRate(double delta) { switch (m_CodecType) { - case vct_silk: - m_VoiceRate -= int(delta * MAX_SILK_VOICE_RATE) + MAX_SILK_DATA_LEN; - break; - - case vct_opus: - m_VoiceRate -= int(delta * MAX_OPUS_VOICE_RATE) + MAX_OPUS_DATA_LEN; - break; - - case vct_speex: - m_VoiceRate -= int(delta * MAX_SPEEX_VOICE_RATE) + MAX_SPEEX_DATA_LEN; - break; - - default: - break; + case vct_silk: + m_VoiceRate -= int(delta * MAX_SILK_VOICE_RATE) + MAX_SILK_DATA_LEN; + break; + case vct_opus: + m_VoiceRate -= int(delta * MAX_OPUS_VOICE_RATE) + MAX_OPUS_DATA_LEN; + break; + case vct_speex: + m_VoiceRate -= int(delta * MAX_SPEEX_VOICE_RATE) + MAX_SPEEX_DATA_LEN; + break; + default: + break; } if (m_VoiceRate < 0) @@ -121,7 +155,27 @@ void CRevoicePlayer::UpdateVoiceRate(double delta) } } +const char *CRevoicePlayer::GetCodecTypeToString() +{ + return m_szCodecType[ m_CodecType ]; +} + void CRevoicePlayer::IncreaseVoiceRate(int dataLength) { m_VoiceRate += dataLength; } + +CodecType CRevoicePlayer::GetCodecTypeByString(const char *codec) +{ +#define REV_CODEC(know_codec)\ + if (_stricmp(codec, #know_codec) == 0) {\ + return vct_##know_codec;\ + }\ + + REV_CODEC(opus); + REV_CODEC(silk); + REV_CODEC(speex); +#undef REV_CODEC + + return vct_none; +} diff --git a/revoice/src/revoice_player.h b/revoice/src/revoice_player.h index bb1c9eb..51d7181 100644 --- a/revoice/src/revoice_player.h +++ b/revoice/src/revoice_player.h @@ -8,40 +8,49 @@ class CRevoicePlayer { private: - IGameClient* m_RehldsClient; - revoice_codec_type m_CodecType; - CSteamP2PCodec* m_SilkCodec; - CSteamP2PCodec* m_OpusCodec; - VoiceCodec_Frame* m_SpeexCodec; + IGameClient *m_Client; + CodecType m_CodecType; + CSteamP2PCodec *m_SilkCodec; + CSteamP2PCodec *m_OpusCodec; + VoiceCodec_Frame *m_SpeexCodec; int m_Protocol; int m_VoiceRate; int m_RequestId; bool m_Connected; + bool m_HLTV; public: CRevoicePlayer(); - void Initialize(IGameClient* cl); + void Update(); + void Initialize(IGameClient *cl); void OnConnected(); void OnDisconnected(); void SetLastVoiceTime(double time); void UpdateVoiceRate(double delta); void IncreaseVoiceRate(int dataLength); + CodecType GetCodecTypeByString(const char *codec); + const char *GetCodecTypeToString(); int GetVoiceRate() const { return m_VoiceRate; } int GetRequestId() const { return m_RequestId; } bool IsConnected() const { return m_Connected; } + bool IsHLTV() const { return m_HLTV; } - void SetCodecType(revoice_codec_type codecType) { m_CodecType = codecType; }; - revoice_codec_type GetCodecType() const { return m_CodecType; } - CSteamP2PCodec* GetSilkCodec() const { return m_SilkCodec; } - CSteamP2PCodec* GetOpusCodec() const { return m_OpusCodec; } - VoiceCodec_Frame* GetSpeexCodec() const { return m_SpeexCodec; } - IGameClient* GetClient() const { return m_RehldsClient; } + static const char *m_szCodecType[]; + void SetCodecType(CodecType codecType) { m_CodecType = codecType; } + + CodecType GetCodecType() const { return m_CodecType; } + CSteamP2PCodec *GetSilkCodec() const { return m_SilkCodec; } + CSteamP2PCodec *GetOpusCodec() const { return m_OpusCodec; } + VoiceCodec_Frame *GetSpeexCodec() const { return m_SpeexCodec; } + IGameClient *GetClient() const { return m_Client; } }; extern CRevoicePlayer g_Players[MAX_PLAYERS]; -extern void Revoice_Init_Players(); -extern CRevoicePlayer* GetPlayerByClientPtr(IGameClient* cl); -extern CRevoicePlayer* GetPlayerByEdict(const edict_t* ed); +CRevoicePlayer *GetPlayerByClientPtr(IGameClient *cl); +CRevoicePlayer *GetPlayerByEdict(const edict_t *ed); + +void Revoice_Init_Players(); +void Revoice_Update_Players(); diff --git a/revoice/src/revoice_rehlds_api.cpp b/revoice/src/revoice_rehlds_api.cpp index 0e1b2e2..313ea75 100644 --- a/revoice/src/revoice_rehlds_api.cpp +++ b/revoice/src/revoice_rehlds_api.cpp @@ -1,12 +1,12 @@ #include "precompiled.h" -IRehldsApi* g_RehldsApi; -const RehldsFuncs_t* g_RehldsFuncs; -IRehldsHookchains* g_RehldsHookchains; -IRehldsServerStatic* g_RehldsSvs; -IRehldsServerData* g_RehldsSv; +IRehldsApi *g_RehldsApi; +const RehldsFuncs_t *g_RehldsFuncs; +IRehldsHookchains *g_RehldsHookchains; +IRehldsServerStatic *g_RehldsSvs; +IRehldsServerData *g_RehldsSv; -bool Revoice_RehldsApi_TryInit(CSysModule* engineModule, char* failureReason) +bool Revoice_RehldsApi_TryInit(CSysModule *engineModule, char *failureReason) { if (!engineModule) { LCPrintf(true, "Failed to locate engine module\n"); @@ -53,16 +53,13 @@ bool Revoice_RehldsApi_Init() { char failReason[2048]; #ifdef WIN32 - CSysModule* engineModule = Sys_LoadModule("swds.dll"); + CSysModule *engineModule = Sys_LoadModule("swds.dll"); if (!Revoice_RehldsApi_TryInit(engineModule, failReason)) { - engineModule = Sys_LoadModule("filesystem_stdio.dll"); - if (!Revoice_RehldsApi_TryInit(engineModule, failReason)) { - LCPrintf(true, "%s", failReason); - return false; - } + LCPrintf(true, "%s", failReason); + return false; } #else - CSysModule* engineModule = Sys_LoadModule("engine_i486.so"); + CSysModule *engineModule = Sys_LoadModule("engine_i486.so"); if (!Revoice_RehldsApi_TryInit(engineModule, failReason)) { LCPrintf(true, "%s", failReason); return false; diff --git a/revoice/src/revoice_shared.h b/revoice/src/revoice_shared.h index 72bc315..351dc78 100644 --- a/revoice/src/revoice_shared.h +++ b/revoice/src/revoice_shared.h @@ -24,7 +24,7 @@ enum revoice_log_mode { rl_logfile = 2, }; -enum revoice_codec_type { +enum CodecType { vct_none, vct_silk, vct_opus, @@ -52,9 +52,11 @@ T clamp(T a, T min, T max) { } extern char* trimbuf(char *str); +extern void NormalizePath(char *path); +extern bool IsFileExists(const char *path); extern void LCPrintf(bool critical, const char *fmt, ...); -extern uint32 crc32(const void* buf, unsigned int bufLen); +extern uint32 crc32(const void *buf, unsigned int bufLen); extern bool Revoice_Load(); extern bool Revoice_Utils_Init(); -extern void util_syserror(const char* fmt, ...); +extern void util_syserror(const char *fmt, ...); diff --git a/revoice/src/revoice_utils.cpp b/revoice/src/revoice_utils.cpp index 503f123..7439a68 100644 --- a/revoice/src/revoice_utils.cpp +++ b/revoice/src/revoice_utils.cpp @@ -1,10 +1,7 @@ #include "precompiled.h" -cvar_t cv_revoice_version = {"revoice_version", APP_VERSION_STRD, FCVAR_SERVER|FCVAR_EXTDLL, 0, NULL}; - -cvar_t* pcv_revoice_version; -cvar_t* pcv_mp_logecho; -char logstring[2048]; +cvar_t *pcv_mp_logecho; +char g_szLogstring[2048]; void LCPrintf(bool critical, const char *fmt, ...) { @@ -12,11 +9,11 @@ void LCPrintf(bool critical, const char *fmt, ...) const int prefixlen = 11; //sizeof(LOG_PREFIX) - 1; va_start(argptr, fmt); - vsnprintf(logstring + prefixlen, sizeof(logstring) - prefixlen, fmt, argptr); + vsnprintf(g_szLogstring + prefixlen, sizeof(g_szLogstring) - prefixlen, fmt, argptr); va_end(argptr); - bool bNeedWriteInConsole = critical || (g_RevoiceConfig && g_RevoiceConfig->hasLogMode(rl_console)); - bool bNeedWriteInLog = critical || (g_RevoiceConfig && g_RevoiceConfig->hasLogMode(rl_logfile)); + bool bNeedWriteInConsole = critical; + bool bNeedWriteInLog = critical; if (bNeedWriteInConsole && bNeedWriteInLog && g_RehldsSvs && g_RehldsSvs->IsLogActive()) { @@ -25,30 +22,27 @@ void LCPrintf(bool critical, const char *fmt, ...) } if (bNeedWriteInConsole) - SERVER_PRINT(logstring); + SERVER_PRINT(g_szLogstring); if (bNeedWriteInLog) - ALERT(at_logged, logstring); + ALERT(at_logged, g_szLogstring); } bool Revoice_Utils_Init() { - g_engfuncs.pfnCvar_RegisterVariable(&cv_revoice_version); - - pcv_revoice_version = g_engfuncs.pfnCVarGetPointer(cv_revoice_version.name); pcv_mp_logecho = g_engfuncs.pfnCVarGetPointer("mp_logecho"); - - strcpy(logstring, LOG_PREFIX); + strcpy(g_szLogstring, LOG_PREFIX); return true; } -char* trimbuf(char *str) +char *trimbuf(char *str) { char *ibuf = str; int i = 0; - if (str == NULL) return NULL; + if (str == NULL) + return NULL; for (ibuf = str; *ibuf && (byte)(*ibuf) < (byte)0x80 && isspace(*ibuf); ++ibuf) ; @@ -70,7 +64,7 @@ char* trimbuf(char *str) return str; } -uint32 crc32(const void* buf, unsigned int bufLen) +uint32 crc32(const void *buf, unsigned int bufLen) { CRC32_t hCrc; g_engfuncs.pfnCRC32_Init(&hCrc); @@ -79,7 +73,18 @@ uint32 crc32(const void* buf, unsigned int bufLen) return hCrc; } -void util_syserror(const char* fmt, ...) +void NormalizePath(char *path) +{ + for (char *cp = path; *cp; cp++) { + if (isupper(*cp)) + *cp = tolower(*cp); + + if (*cp == '\\') + *cp = '/'; + } +} + +void util_syserror(const char *fmt, ...) { va_list argptr; char buf[4096]; @@ -91,5 +96,7 @@ void util_syserror(const char* fmt, ...) LCPrintf(true, "ERROR: %s", buf); - *(int *)0 = 0; + int *null = 0; + *null = 0; + exit(-1); } diff --git a/revoice/src/voice_codec_frame.cpp b/revoice/src/voice_codec_frame.cpp index b2c1b8c..b77000e 100644 --- a/revoice/src/voice_codec_frame.cpp +++ b/revoice/src/voice_codec_frame.cpp @@ -1,6 +1,5 @@ #include "precompiled.h" -/* <1f68> ../engine/voice_codecs/speex/../frame_encoder/voice_codec_frame.cpp:23 */ VoiceCodec_Frame::VoiceCodec_Frame(IFrameEncoder *pEncoder) { m_nEncodeBufferSamples = 0; @@ -8,72 +7,68 @@ VoiceCodec_Frame::VoiceCodec_Frame(IFrameEncoder *pEncoder) m_pFrameEncoder = pEncoder; } -/* <2107> ../engine/voice_codecs/speex/../frame_encoder/voice_codec_frame.cpp:30 */ VoiceCodec_Frame::~VoiceCodec_Frame() { - if (m_pFrameEncoder != NULL) { + if (m_pFrameEncoder) { m_pFrameEncoder->Release(); - m_pFrameEncoder = NULL; + m_pFrameEncoder = nullptr; } } -/* <22bc> ../engine/voice_codecs/speex/../frame_encoder/voice_codec_frame.cpp:36 */ bool VoiceCodec_Frame::Init(int quality) { - if (m_pFrameEncoder == NULL) + if (!m_pFrameEncoder) return false; if (m_pFrameEncoder->Init(quality, m_nRawBytes, m_nEncodedBytes)) { m_nRawSamples = m_nRawBytes >> 1; return true; - } else { - m_pFrameEncoder->Release(); - m_pFrameEncoder = NULL; - return false; } + + m_pFrameEncoder->Release(); + m_pFrameEncoder = nullptr; + return false; } -/* <2038> ../engine/voice_codecs/speex/../frame_encoder/voice_codec_frame.cpp:54 */ void VoiceCodec_Frame::Release() { delete this; } -/* <21fb> ../engine/voice_codecs/speex/../frame_encoder/voice_codec_frame.cpp:59 */ int VoiceCodec_Frame::Compress(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal) { - if (m_pFrameEncoder == NULL) + if (m_pFrameEncoder == nullptr) return 0; - const int16 *pUncompressed = (const int16*) pUncompressedBytes; + const int16 *pUncompressed = (const int16 *) pUncompressedBytes; int nCompressedBytes = 0; while ((nSamples + m_nEncodeBufferSamples) >= m_nRawSamples && (maxCompressedBytes - nCompressedBytes) >= m_nEncodedBytes) { // Get the data block out. int16 samples[MAX_FRAMEBUFFER_SAMPLES]; - memcpy(samples, m_EncodeBuffer, m_nEncodeBufferSamples*BYTES_PER_SAMPLE); + memcpy(samples, m_EncodeBuffer, m_nEncodeBufferSamples * BYTES_PER_SAMPLE); memcpy(&samples[m_nEncodeBufferSamples], pUncompressed, (m_nRawSamples - m_nEncodeBufferSamples) * BYTES_PER_SAMPLE); nSamples -= m_nRawSamples - m_nEncodeBufferSamples; pUncompressed += m_nRawSamples - m_nEncodeBufferSamples; m_nEncodeBufferSamples = 0; - + // Compress it. - m_pFrameEncoder->EncodeFrame((const char*)samples, &pCompressed[nCompressedBytes]); + m_pFrameEncoder->EncodeFrame((const char *)samples, &pCompressed[nCompressedBytes]); nCompressedBytes += m_nEncodedBytes; } // Store the remaining samples. - int nNewSamples = _min(nSamples, _min(m_nRawSamples-m_nEncodeBufferSamples, m_nRawSamples)); + int nNewSamples = _min(nSamples, _min(m_nRawSamples - m_nEncodeBufferSamples, m_nRawSamples)); if (nNewSamples) { - memcpy(&m_EncodeBuffer[m_nEncodeBufferSamples], &pUncompressed[nSamples - nNewSamples], nNewSamples*BYTES_PER_SAMPLE); + memcpy(&m_EncodeBuffer[m_nEncodeBufferSamples], &pUncompressed[nSamples - nNewSamples], nNewSamples * BYTES_PER_SAMPLE); m_nEncodeBufferSamples += nNewSamples; } // If it must get the last data, just pad with zeros.. if (bFinal && m_nEncodeBufferSamples && (maxCompressedBytes - nCompressedBytes) >= m_nEncodedBytes) { memset(&m_EncodeBuffer[m_nEncodeBufferSamples], 0, (m_nRawSamples - m_nEncodeBufferSamples) * BYTES_PER_SAMPLE); - m_pFrameEncoder->EncodeFrame((const char*)m_EncodeBuffer, &pCompressed[nCompressedBytes]); + m_pFrameEncoder->EncodeFrame((const char *)m_EncodeBuffer, &pCompressed[nCompressedBytes]); nCompressedBytes += m_nEncodedBytes; m_nEncodeBufferSamples = 0; } @@ -81,10 +76,9 @@ int VoiceCodec_Frame::Compress(const char *pUncompressedBytes, int nSamples, cha return nCompressedBytes; } -/* <205e> ../engine/voice_codecs/speex/../frame_encoder/voice_codec_frame.cpp:102 */ int VoiceCodec_Frame::Decompress(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes) { - if (m_pFrameEncoder == NULL || compressedBytes < m_nEncodedBytes || maxUncompressedBytes < m_nRawBytes) + if (m_pFrameEncoder == nullptr || compressedBytes < m_nEncodedBytes || maxUncompressedBytes < m_nRawBytes) return 0; int nDecompressedBytes = 0; @@ -104,17 +98,11 @@ int VoiceCodec_Frame::Decompress(const char *pCompressed, int compressedBytes, c return nDecompressedBytes / BYTES_PER_SAMPLE; } -/* <20e1> ../engine/voice_codecs/speex/../frame_encoder/voice_codec_frame.cpp:120 */ bool VoiceCodec_Frame::ResetState() { - if (m_pFrameEncoder) + if (m_pFrameEncoder) { return m_pFrameEncoder->ResetState(); - else - return false; -} + } -/* <230a> ../engine/voice_codecs/speex/../frame_encoder/voice_codec_frame.cpp:141 */ -IVoiceCodec *CreateVoiceCodec_Frame(IFrameEncoder *pEncoder) -{ - return new VoiceCodec_Frame(pEncoder); + return false; } diff --git a/revoice/src/voice_codec_frame.h b/revoice/src/voice_codec_frame.h index c489bb8..c453a7a 100644 --- a/revoice/src/voice_codec_frame.h +++ b/revoice/src/voice_codec_frame.h @@ -3,17 +3,19 @@ #include "IVoiceCodec.h" #include "iframeencoder.h" -/* <19b1> ../engine/voice_codecs/speex/../frame_encoder/voice_codec_frame.cpp:18 */ +class IGameClient; class VoiceCodec_Frame: public IVoiceCodec { public: virtual ~VoiceCodec_Frame(); VoiceCodec_Frame(IFrameEncoder *pEncoder); - bool Init(int quality); - void Release(); - int Compress(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal); - int Decompress(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes); - bool ResetState(); + virtual bool Init(int quality); + virtual void Release(); + virtual int Compress(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal); + virtual int Decompress(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes); + virtual bool ResetState(); + + void SetClient(IGameClient *client) { m_Client = client; } protected: enum { MAX_FRAMEBUFFER_SAMPLES = 1024 }; @@ -26,4 +28,6 @@ protected: int m_nRawSamples; int m_nEncodedBytes; -}; /* size: 2072, cachelines: 33, members: 7 */ +public: + IGameClient *m_Client; +};