Add IsClientTalking
This commit is contained in:
parent
d2905c03eb
commit
cfbaf18f66
@ -10,7 +10,9 @@ project = SM.HL2Project(builder, projectName + '.ext')
|
|||||||
project.sources += [
|
project.sources += [
|
||||||
'extension.cpp',
|
'extension.cpp',
|
||||||
'ringbuffer.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:
|
for sdk_name in SM.sdks:
|
||||||
|
144
extension.cpp
144
extension.cpp
@ -43,6 +43,7 @@
|
|||||||
#include <iserver.h>
|
#include <iserver.h>
|
||||||
#include <ISDKTools.h>
|
#include <ISDKTools.h>
|
||||||
|
|
||||||
|
#include "CDetour/detours.h"
|
||||||
#include "extension.h"
|
#include "extension.h"
|
||||||
|
|
||||||
ConVar g_SmVoiceAddr("sm_voice_addr", "127.0.0.1", FCVAR_PROTECTED, "Voice server listen ip address.");
|
ConVar g_SmVoiceAddr("sm_voice_addr", "127.0.0.1", FCVAR_PROTECTED, "Voice server listen ip address.");
|
||||||
@ -58,9 +59,36 @@ template <typename T> inline T min(T a, T b) { return a<b?a:b; }
|
|||||||
CVoice g_Interface;
|
CVoice g_Interface;
|
||||||
SMEXT_LINK(&g_Interface);
|
SMEXT_LINK(&g_Interface);
|
||||||
|
|
||||||
|
CGlobalVars *gpGlobals = NULL;
|
||||||
ISDKTools *g_pSDKTools = NULL;
|
ISDKTools *g_pSDKTools = NULL;
|
||||||
IServer *iserver = NULL;
|
IServer *iserver = NULL;
|
||||||
SH_DECL_MANUALHOOK0(GetPlayerSlot, 0, 0, 0, int); // IClient::GetPlayerSlot
|
|
||||||
|
double g_fLastVoiceData[SM_MAXPLAYERS + 1];
|
||||||
|
|
||||||
|
DETOUR_DECL_STATIC4(SV_BroadcastVoiceData, void, IClient *, pClient, int, nBytes, char *, data, int64, xuid)
|
||||||
|
{
|
||||||
|
g_Interface.OnBroadcastVoiceData(pClient, nBytes, data);
|
||||||
|
|
||||||
|
DETOUR_STATIC_CALL(SV_BroadcastVoiceData)(pClient, nBytes, data, xuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
DETOUR_DECL_STATIC2(SV_BroadcastVoiceData_LTCG, void, char *, data, int64, xuid)
|
||||||
|
{
|
||||||
|
IClient *pClient = NULL;
|
||||||
|
int nBytes = 0;
|
||||||
|
|
||||||
|
__asm mov pClient, ecx;
|
||||||
|
__asm mov nBytes, edx;
|
||||||
|
|
||||||
|
g_Interface.OnBroadcastVoiceData(pClient, nBytes, data);
|
||||||
|
|
||||||
|
__asm mov ecx, pClient;
|
||||||
|
__asm mov edx, nBytes;
|
||||||
|
|
||||||
|
DETOUR_STATIC_CALL(SV_BroadcastVoiceData_LTCG)(data, xuid);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
double getTime()
|
double getTime()
|
||||||
{
|
{
|
||||||
@ -92,6 +120,7 @@ CVoice::CVoice()
|
|||||||
m_pMode = NULL;
|
m_pMode = NULL;
|
||||||
m_pCodec = NULL;
|
m_pCodec = NULL;
|
||||||
|
|
||||||
|
m_VoiceDetour = NULL;
|
||||||
m_SV_BroadcastVoiceData = NULL;
|
m_SV_BroadcastVoiceData = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,47 +143,39 @@ bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int engineVersion = g_SMAPI->GetSourceEngineBuild();
|
int engineVersion = g_SMAPI->GetSourceEngineBuild();
|
||||||
int offsPlayerSlot = 0;
|
void *adrVoiceData = NULL;
|
||||||
|
|
||||||
switch (engineVersion)
|
switch (engineVersion)
|
||||||
{
|
{
|
||||||
case SOURCE_ENGINE_CSGO:
|
case SOURCE_ENGINE_CSGO:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x81\xEC\xD0\x00\x00\x00\x53\x56\x57", 12);
|
adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x81\xEC\xD0\x00\x00\x00\x53\x56\x57", 12);
|
||||||
offsPlayerSlot = 15;
|
|
||||||
#else
|
#else
|
||||||
m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
|
adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
|
||||||
offsPlayerSlot = 16;
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOURCE_ENGINE_LEFT4DEAD2:
|
case SOURCE_ENGINE_LEFT4DEAD2:
|
||||||
#ifdef _WIN32
|
#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);
|
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);
|
||||||
offsPlayerSlot = 14;
|
|
||||||
#else
|
#else
|
||||||
m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
|
adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
|
||||||
offsPlayerSlot = 15;
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOURCE_ENGINE_NUCLEARDAWN:
|
case SOURCE_ENGINE_NUCLEARDAWN:
|
||||||
#ifdef _WIN32
|
#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);
|
adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x58\x57\x33\xFF", 14);
|
||||||
offsPlayerSlot = 14;
|
|
||||||
#else
|
#else
|
||||||
m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
|
adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
|
||||||
offsPlayerSlot = 15;
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOURCE_ENGINE_INSURGENCY:
|
case SOURCE_ENGINE_INSURGENCY:
|
||||||
#ifdef _WIN32
|
#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);
|
adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x83\xEC\x74\x68\x2A\x2A\x2A\x2A\x8D\x4D\xE4\xE8", 15);
|
||||||
offsPlayerSlot = 14;
|
|
||||||
#else
|
#else
|
||||||
m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
|
adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
|
||||||
offsPlayerSlot = 15;
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -164,11 +185,9 @@ bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
|||||||
case SOURCE_ENGINE_DODS:
|
case SOURCE_ENGINE_DODS:
|
||||||
case SOURCE_ENGINE_SDK2013:
|
case SOURCE_ENGINE_SDK2013:
|
||||||
#ifdef _WIN32
|
#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);
|
adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x50\x83\x78\x30", 14);
|
||||||
offsPlayerSlot = 14;
|
|
||||||
#else
|
#else
|
||||||
m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
|
adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
|
||||||
offsPlayerSlot = 15;
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -179,13 +198,36 @@ bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
|||||||
}
|
}
|
||||||
dlclose(pEngineSo);
|
dlclose(pEngineSo);
|
||||||
|
|
||||||
|
m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)adrVoiceData;
|
||||||
if(!m_SV_BroadcastVoiceData)
|
if(!m_SV_BroadcastVoiceData)
|
||||||
{
|
{
|
||||||
g_SMAPI->Format(error, maxlength, "SV_BroadcastVoiceData sigscan failed.");
|
g_SMAPI->Format(error, maxlength, "SV_BroadcastVoiceData sigscan failed.");
|
||||||
return false;
|
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
|
// Init tcp server
|
||||||
m_ListenSocket = socket(AF_INET, SOCK_STREAM, 0);
|
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)
|
bool CVoice::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
|
||||||
{
|
{
|
||||||
GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION);
|
GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION);
|
||||||
|
gpGlobals = ismm->GetCGlobals();
|
||||||
ConVar_Register(0, this);
|
ConVar_Register(0, this);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -282,8 +325,37 @@ bool CVoice::RegisterConCommandBase(ConCommandBase *pVar)
|
|||||||
return META_REGCVAR(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()
|
void CVoice::SDK_OnAllLoaded()
|
||||||
{
|
{
|
||||||
|
sharesys->AddNatives(myself, MyNatives);
|
||||||
|
sharesys->RegisterLibrary(myself, "Voice");
|
||||||
|
|
||||||
SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools);
|
SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools);
|
||||||
if(g_pSDKTools == NULL)
|
if(g_pSDKTools == NULL)
|
||||||
smutils->LogError(myself, "SDKTools interface not found");
|
smutils->LogError(myself, "SDKTools interface not found");
|
||||||
@ -297,6 +369,12 @@ void CVoice::SDK_OnUnload()
|
|||||||
{
|
{
|
||||||
smutils->RemoveGameFrameHook(::OnGameFrame);
|
smutils->RemoveGameFrameHook(::OnGameFrame);
|
||||||
|
|
||||||
|
if(m_VoiceDetour)
|
||||||
|
{
|
||||||
|
m_VoiceDetour->Destroy();
|
||||||
|
m_VoiceDetour = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if(m_ListenSocket != -1)
|
if(m_ListenSocket != -1)
|
||||||
{
|
{
|
||||||
close(m_ListenSocket);
|
close(m_ListenSocket);
|
||||||
@ -325,6 +403,13 @@ void CVoice::OnGameFrame(bool simulating)
|
|||||||
HandleVoiceData();
|
HandleVoiceData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CVoice::OnBroadcastVoiceData(IClient *pClient, int nBytes, char *data)
|
||||||
|
{
|
||||||
|
int client = pClient->GetPlayerSlot() + 1;
|
||||||
|
|
||||||
|
g_fLastVoiceData[client] = gpGlobals->curtime;
|
||||||
|
}
|
||||||
|
|
||||||
void CVoice::HandleNetwork()
|
void CVoice::HandleNetwork()
|
||||||
{
|
{
|
||||||
if(m_ListenSocket == -1)
|
if(m_ListenSocket == -1)
|
||||||
@ -553,7 +638,7 @@ void CVoice::HandleVoiceData()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SV_BroadcastVoiceData(pClient, FinalSize, aFinal);
|
BroadcastVoiceData(pClient, FinalSize, aFinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_AvailableTime < getTime())
|
if(m_AvailableTime < getTime())
|
||||||
@ -562,7 +647,14 @@ void CVoice::HandleVoiceData()
|
|||||||
m_AvailableTime += (double)FramesAvailable * m_EncoderSettings.FrameTime;
|
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
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||||
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
#include "smsdk_ext.h"
|
#include "smsdk_ext.h"
|
||||||
#include "celt_header.h"
|
#include "celt_header.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
@ -49,6 +50,7 @@ typedef __int64 int64;
|
|||||||
typedef long long int64;
|
typedef long long int64;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class CDetour;
|
||||||
class IClient;
|
class IClient;
|
||||||
typedef void (*t_SV_BroadcastVoiceData)(IClient *, int, unsigned char *, int64);
|
typedef void (*t_SV_BroadcastVoiceData)(IClient *, int, unsigned char *, int64);
|
||||||
|
|
||||||
@ -135,6 +137,7 @@ public: // IConCommandBaseAccessor
|
|||||||
public:
|
public:
|
||||||
CVoice();
|
CVoice();
|
||||||
void OnGameFrame(bool simulating);
|
void OnGameFrame(bool simulating);
|
||||||
|
void OnBroadcastVoiceData(IClient *pClient, int nBytes, char *data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_ListenSocket;
|
int m_ListenSocket;
|
||||||
@ -169,11 +172,12 @@ private:
|
|||||||
CELTEncoder *m_pCodec;
|
CELTEncoder *m_pCodec;
|
||||||
|
|
||||||
t_SV_BroadcastVoiceData m_SV_BroadcastVoiceData;
|
t_SV_BroadcastVoiceData m_SV_BroadcastVoiceData;
|
||||||
|
CDetour *m_VoiceDetour;
|
||||||
|
|
||||||
void HandleNetwork();
|
void HandleNetwork();
|
||||||
void OnDataReceived(CClient *pClient, int16_t *pData, size_t Samples);
|
void OnDataReceived(CClient *pClient, int16_t *pData, size_t Samples);
|
||||||
void HandleVoiceData();
|
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_
|
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
/* Basic information exposed publicly */
|
/* Basic information exposed publicly */
|
||||||
#define SMEXT_CONF_NAME "Voice"
|
#define SMEXT_CONF_NAME "Voice"
|
||||||
#define SMEXT_CONF_DESCRIPTION "Inject voice data over existing clients"
|
#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_AUTHOR "BotoX"
|
||||||
#define SMEXT_CONF_URL ""
|
#define SMEXT_CONF_URL ""
|
||||||
#define SMEXT_CONF_LOGTAG "VOICE"
|
#define SMEXT_CONF_LOGTAG "VOICE"
|
||||||
@ -61,7 +61,7 @@
|
|||||||
/** Enable interfaces you want to use here by uncommenting lines */
|
/** Enable interfaces you want to use here by uncommenting lines */
|
||||||
//#define SMEXT_ENABLE_FORWARDSYS
|
//#define SMEXT_ENABLE_FORWARDSYS
|
||||||
//#define SMEXT_ENABLE_HANDLESYS
|
//#define SMEXT_ENABLE_HANDLESYS
|
||||||
//#define SMEXT_ENABLE_PLAYERHELPERS
|
#define SMEXT_ENABLE_PLAYERHELPERS
|
||||||
//#define SMEXT_ENABLE_DBMANAGER
|
//#define SMEXT_ENABLE_DBMANAGER
|
||||||
#define SMEXT_ENABLE_GAMECONF
|
#define SMEXT_ENABLE_GAMECONF
|
||||||
#define SMEXT_ENABLE_MEMUTILS
|
#define SMEXT_ENABLE_MEMUTILS
|
||||||
|
Loading…
Reference in New Issue
Block a user