diff --git a/AMBuilder b/AMBuilder index bd6a690..f995ff4 100644 --- a/AMBuilder +++ b/AMBuilder @@ -10,7 +10,9 @@ project = SM.HL2Project(builder, projectName + '.ext') project.sources += [ 'extension.cpp', 'ringbuffer.cpp', - '../../public/smsdk_ext.cpp' + '../../public/smsdk_ext.cpp', + '../../public/CDetour/detours.cpp', + '../../public/asm/asm.c', ] for sdk_name in SM.sdks: diff --git a/extension.cpp b/extension.cpp index dfa855c..c24868d 100644 --- a/extension.cpp +++ b/extension.cpp @@ -43,6 +43,7 @@ #include #include +#include "CDetour/detours.h" #include "extension.h" ConVar g_SmVoiceAddr("sm_voice_addr", "127.0.0.1", FCVAR_PROTECTED, "Voice server listen ip address."); @@ -58,9 +59,36 @@ template inline T min(T a, T b) { return aGetSourceEngineBuild(); - int offsPlayerSlot = 0; + void *adrVoiceData = NULL; switch (engineVersion) { case SOURCE_ENGINE_CSGO: #ifdef _WIN32 - m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x81\xEC\xD0\x00\x00\x00\x53\x56\x57", 12); - offsPlayerSlot = 15; + adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x81\xEC\xD0\x00\x00\x00\x53\x56\x57", 12); #else - m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx"); - offsPlayerSlot = 16; + adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx"); #endif break; case SOURCE_ENGINE_LEFT4DEAD2: #ifdef _WIN32 - m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x83\xEC\x70\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\xA1\x2A\x2A\x2A\x2A\x53\x56", 23); - offsPlayerSlot = 14; + adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x83\xEC\x70\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\xA1\x2A\x2A\x2A\x2A\x53\x56", 23); #else - m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx"); - offsPlayerSlot = 15; + adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx"); #endif break; case SOURCE_ENGINE_NUCLEARDAWN: #ifdef _WIN32 - m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x58\x57\x33\xFF", 14); - offsPlayerSlot = 14; + adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x58\x57\x33\xFF", 14); #else - m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx"); - offsPlayerSlot = 15; + adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx"); #endif break; case SOURCE_ENGINE_INSURGENCY: #ifdef _WIN32 - m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x83\xEC\x74\x68\x2A\x2A\x2A\x2A\x8D\x4D\xE4\xE8", 15); - offsPlayerSlot = 14; + adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x83\xEC\x74\x68\x2A\x2A\x2A\x2A\x8D\x4D\xE4\xE8", 15); #else - m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx"); - offsPlayerSlot = 15; + adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx"); #endif break; @@ -164,11 +185,9 @@ bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late) case SOURCE_ENGINE_DODS: case SOURCE_ENGINE_SDK2013: #ifdef _WIN32 - m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x50\x83\x78\x30", 14); - offsPlayerSlot = 14; + adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x50\x83\x78\x30", 14); #else - m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx"); - offsPlayerSlot = 15; + adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx"); #endif break; @@ -179,13 +198,36 @@ bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late) } dlclose(pEngineSo); + m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)adrVoiceData; if(!m_SV_BroadcastVoiceData) { g_SMAPI->Format(error, maxlength, "SV_BroadcastVoiceData sigscan failed."); return false; } - SH_MANUALHOOK_RECONFIGURE(GetPlayerSlot, offsPlayerSlot, 0, 0); + // Setup voice detour. + CDetourManager::Init(g_pSM->GetScriptingEngine(), NULL); + +#ifdef _WIN32 + if (engineVersion == SOURCE_ENGINE_CSGO || engineVersion == SOURCE_ENGINE_INSURGENCY) + { + m_VoiceDetour = DETOUR_CREATE_STATIC(SV_BroadcastVoiceData_LTCG, adrVoiceData); + } + else + { + m_VoiceDetour = DETOUR_CREATE_STATIC(SV_BroadcastVoiceData, adrVoiceData); + } +#else + m_VoiceDetour = DETOUR_CREATE_STATIC(SV_BroadcastVoiceData, adrVoiceData); +#endif + + if (!m_VoiceDetour) + { + g_SMAPI->Format(error, maxlength, "SV_BroadcastVoiceData detour failed."); + return false; + } + + m_VoiceDetour->EnableDetour(); // Init tcp server m_ListenSocket = socket(AF_INET, SOCK_STREAM, 0); @@ -271,6 +313,7 @@ bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late) bool CVoice::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) { GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION); + gpGlobals = ismm->GetCGlobals(); ConVar_Register(0, this); return true; @@ -282,8 +325,37 @@ bool CVoice::RegisterConCommandBase(ConCommandBase *pVar) return META_REGCVAR(pVar); } +cell_t IsClientTalking(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + + if(client < 1 || client > SM_MAXPLAYERS) + { + return pContext->ThrowNativeError("Client index %d is invalid", client); + } + + double d = gpGlobals->curtime - g_fLastVoiceData[client]; + + if(d < 0) // mapchange + return false; + + if(d > 0.33) + return false; + + return true; +} + +const sp_nativeinfo_t MyNatives[] = +{ + { "IsClientTalking", IsClientTalking }, + { NULL, NULL } +}; + void CVoice::SDK_OnAllLoaded() { + sharesys->AddNatives(myself, MyNatives); + sharesys->RegisterLibrary(myself, "Voice"); + SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools); if(g_pSDKTools == NULL) smutils->LogError(myself, "SDKTools interface not found"); @@ -297,6 +369,12 @@ void CVoice::SDK_OnUnload() { smutils->RemoveGameFrameHook(::OnGameFrame); + if(m_VoiceDetour) + { + m_VoiceDetour->Destroy(); + m_VoiceDetour = NULL; + } + if(m_ListenSocket != -1) { close(m_ListenSocket); @@ -325,6 +403,13 @@ void CVoice::OnGameFrame(bool simulating) HandleVoiceData(); } +void CVoice::OnBroadcastVoiceData(IClient *pClient, int nBytes, char *data) +{ + int client = pClient->GetPlayerSlot() + 1; + + g_fLastVoiceData[client] = gpGlobals->curtime; +} + void CVoice::HandleNetwork() { if(m_ListenSocket == -1) @@ -553,7 +638,7 @@ void CVoice::HandleVoiceData() } } - SV_BroadcastVoiceData(pClient, FinalSize, aFinal); + BroadcastVoiceData(pClient, FinalSize, aFinal); } if(m_AvailableTime < getTime()) @@ -562,7 +647,14 @@ void CVoice::HandleVoiceData() m_AvailableTime += (double)FramesAvailable * m_EncoderSettings.FrameTime; } -void CVoice::SV_BroadcastVoiceData(IClient *pClient, int nBytes, unsigned char *pData) +void CVoice::BroadcastVoiceData(IClient *pClient, int nBytes, unsigned char *pData) { - m_SV_BroadcastVoiceData(pClient, nBytes, pData, 0); + #ifdef _WIN32 + __asm mov ecx, pClient; + __asm mov edx, nBytes; + + DETOUR_STATIC_CALL(SV_BroadcastVoiceData_LTCG)((char *)pData, 0); + #else + DETOUR_STATIC_CALL(SV_BroadcastVoiceData)(pClient, nBytes, (char *)pData, 0); + #endif } diff --git a/extension.h b/extension.h index a864fdd..7dd7941 100644 --- a/extension.h +++ b/extension.h @@ -32,6 +32,7 @@ #ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ #define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#include #include "smsdk_ext.h" #include "celt_header.h" #include "ringbuffer.h" @@ -49,6 +50,7 @@ typedef __int64 int64; typedef long long int64; #endif +class CDetour; class IClient; typedef void (*t_SV_BroadcastVoiceData)(IClient *, int, unsigned char *, int64); @@ -135,6 +137,7 @@ public: // IConCommandBaseAccessor public: CVoice(); void OnGameFrame(bool simulating); + void OnBroadcastVoiceData(IClient *pClient, int nBytes, char *data); private: int m_ListenSocket; @@ -169,11 +172,12 @@ private: CELTEncoder *m_pCodec; t_SV_BroadcastVoiceData m_SV_BroadcastVoiceData; + CDetour *m_VoiceDetour; void HandleNetwork(); void OnDataReceived(CClient *pClient, int16_t *pData, size_t Samples); void HandleVoiceData(); - void SV_BroadcastVoiceData(IClient *pClient, int nBytes, unsigned char *pData); + void BroadcastVoiceData(IClient *pClient, int nBytes, unsigned char *pData); }; #endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/smsdk_config.h b/smsdk_config.h index a6866d1..20bf4da 100644 --- a/smsdk_config.h +++ b/smsdk_config.h @@ -40,7 +40,7 @@ /* Basic information exposed publicly */ #define SMEXT_CONF_NAME "Voice" #define SMEXT_CONF_DESCRIPTION "Inject voice data over existing clients" -#define SMEXT_CONF_VERSION "1.0" +#define SMEXT_CONF_VERSION "1.1" #define SMEXT_CONF_AUTHOR "BotoX" #define SMEXT_CONF_URL "" #define SMEXT_CONF_LOGTAG "VOICE" @@ -61,7 +61,7 @@ /** Enable interfaces you want to use here by uncommenting lines */ //#define SMEXT_ENABLE_FORWARDSYS //#define SMEXT_ENABLE_HANDLESYS -//#define SMEXT_ENABLE_PLAYERHELPERS +#define SMEXT_ENABLE_PLAYERHELPERS //#define SMEXT_ENABLE_DBMANAGER #define SMEXT_ENABLE_GAMECONF #define SMEXT_ENABLE_MEMUTILS