sdktools_voice: implement ClientSpeaking forwards (#1247)
* Update basevotes When a player leaves during a voteban, he will be banned anyway. Also added a cvar with a ban time setting. * Update basevotes.sp * Added VoiceHook functions * Update extension.h * Update extension.h * Code optimization * Added support for more engines * Invalidate timers * Fixes * Update extension.cpp * Update voice.cpp * correct Forward event type to ET_Ignore. * sdktools_voice: de-implement IsClientSpeaking * sdktools_voice: Add notice/unbind IsClientSpeaking Co-authored-by: Kyle Sanderson <kyle.leet@gmail.com>
This commit is contained in:
parent
031f80f6e1
commit
1b86c8564d
@ -57,6 +57,9 @@ SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *,
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_CSGO
|
||||
SH_DECL_HOOK1_void_vafmt(IVEngineServer, ClientCommand, SH_NOATTRIB, 0, edict_t *);
|
||||
#endif
|
||||
#if defined CLIENTVOICE_HOOK_SUPPORT
|
||||
SH_DECL_HOOK1_void(IServerGameClients, ClientVoice, SH_NOATTRIB, 0, edict_t *);
|
||||
#endif
|
||||
|
||||
SDKTools g_SdkTools; /**< Global singleton for extension's main interface */
|
||||
IServerGameEnts *gameents = NULL;
|
||||
@ -76,6 +79,9 @@ IServer *iserver = NULL;
|
||||
IBaseFileSystem *basefilesystem = NULL;
|
||||
CGlobalVars *gpGlobals;
|
||||
ISoundEmitterSystemBase *soundemitterbase = NULL;
|
||||
ITimer *g_hTimerSpeaking[SM_MAXPLAYERS+1];
|
||||
IForward *m_OnClientSpeaking;
|
||||
IForward *m_OnClientSpeakingEnd;
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
IServerTools *servertools = NULL;
|
||||
@ -256,6 +262,9 @@ void SDKTools::SDK_OnUnload()
|
||||
g_Hooks.Shutdown();
|
||||
g_OutputManager.Shutdown();
|
||||
|
||||
forwards->ReleaseForward(m_OnClientSpeaking);
|
||||
forwards->ReleaseForward(m_OnClientSpeakingEnd);
|
||||
|
||||
gameconfs->CloseGameConfigFile(g_pGameConf);
|
||||
playerhelpers->RemoveClientListener(&g_SdkTools);
|
||||
playerhelpers->UnregisterCommandTargetProcessor(this);
|
||||
@ -314,7 +323,9 @@ bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_CSGO
|
||||
SH_ADD_HOOK(IVEngineServer, ClientCommand, engine, SH_MEMBER(this, &SDKTools::OnSendClientCommand), false);
|
||||
#endif
|
||||
|
||||
#if defined CLIENTVOICE_HOOK_SUPPORT
|
||||
SH_ADD_HOOK(IServerGameClients, ClientVoice, serverClients, SH_MEMBER(this, &SDKTools::OnClientVoice), true);
|
||||
#endif
|
||||
gpGlobals = ismm->GetCGlobals();
|
||||
enginePatch = SH_GET_CALLCLASS(engine);
|
||||
enginesoundPatch = SH_GET_CALLCLASS(engsound);
|
||||
@ -326,6 +337,9 @@ bool SDKTools::SDK_OnMetamodUnload(char *error, size_t maxlen)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_CSGO
|
||||
SH_REMOVE_HOOK(IVEngineServer, ClientCommand, engine, SH_MEMBER(this, &SDKTools::OnSendClientCommand), false);
|
||||
#endif
|
||||
#if defined CLIENTVOICE_HOOK_SUPPORT
|
||||
SH_REMOVE_HOOK(IServerGameClients, ClientVoice, serverClients, SH_MEMBER(this, &SDKTools::OnClientVoice), true);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@ -344,6 +358,9 @@ void SDKTools::SDK_OnAllLoaded()
|
||||
s_SoundHooks.Initialize();
|
||||
g_Hooks.Initialize();
|
||||
InitializeValveGlobals();
|
||||
|
||||
m_OnClientSpeaking = forwards->CreateForward("OnClientSpeaking", ET_Ignore, 1, NULL, Param_Cell);
|
||||
m_OnClientSpeakingEnd = forwards->CreateForward("OnClientSpeakingEnd", ET_Ignore, 1, NULL, Param_Cell);
|
||||
}
|
||||
|
||||
void SDKTools::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
|
||||
@ -516,6 +533,13 @@ bool SDKTools::InterceptClientConnect(int client, char *error, size_t maxlength)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
void SDKTools::OnClientConnected(int client)
|
||||
{
|
||||
g_Hooks.OnClientConnected(client);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_CSGO
|
||||
void SDKTools::OnSendClientCommand(edict_t *pPlayer, const char *szFormat)
|
||||
{
|
||||
@ -532,6 +556,43 @@ void SDKTools::OnSendClientCommand(edict_t *pPlayer, const char *szFormat)
|
||||
}
|
||||
#endif
|
||||
|
||||
SourceMod::ResultType SDKTools::OnTimer(ITimer *pTimer, void *pData)
|
||||
{
|
||||
int client = (int)(intptr_t)pData;
|
||||
|
||||
m_OnClientSpeakingEnd->PushCell(client);
|
||||
m_OnClientSpeakingEnd->Execute();
|
||||
|
||||
return Pl_Stop;
|
||||
}
|
||||
|
||||
void SDKTools::OnTimerEnd(ITimer *pTimer, void *pData)
|
||||
{
|
||||
g_hTimerSpeaking[(int)(intptr_t)pData] = nullptr;
|
||||
}
|
||||
|
||||
#if defined CLIENTVOICE_HOOK_SUPPORT
|
||||
void SDKTools::OnClientVoice(edict_t *pPlayer)
|
||||
{
|
||||
if (!pPlayer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int client = IndexOfEdict(pPlayer);
|
||||
|
||||
if (g_hTimerSpeaking[client])
|
||||
{
|
||||
timersys->KillTimer(g_hTimerSpeaking[client]);
|
||||
}
|
||||
|
||||
g_hTimerSpeaking[client] = timersys->CreateTimer(this, 0.3f, (void *)(intptr_t)client, 0);
|
||||
|
||||
m_OnClientSpeaking->PushCell(client);
|
||||
m_OnClientSpeaking->Execute();
|
||||
}
|
||||
#endif
|
||||
|
||||
void SDKTools::OnClientPutInServer(int client)
|
||||
{
|
||||
g_Hooks.OnClientPutInServer(client);
|
||||
|
@ -61,6 +61,12 @@
|
||||
#include <itoolentity.h>
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_ALIENSWARM || SOURCE_ENGINE == SE_PORTAL2 || SOURCE_ENGINE == SE_INSURGENCY || SOURCE_ENGINE == SE_DOI || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_CSGO
|
||||
#define CLIENTVOICE_HOOK_SUPPORT
|
||||
#else
|
||||
#include <inetmsghandler.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Implementation of the SDK Tools extension.
|
||||
* Note: Uncomment one of the pre-defined virtual functions in order to use it.
|
||||
@ -70,6 +76,7 @@ class SDKTools :
|
||||
public IHandleTypeDispatch,
|
||||
public IConCommandBaseAccessor,
|
||||
public IClientListener,
|
||||
public ITimedEvent,
|
||||
public ICommandTargetProcessor
|
||||
{
|
||||
public: //public IHandleTypeDispatch
|
||||
@ -95,8 +102,15 @@ public: //IConCommandBaseAccessor
|
||||
bool RegisterConCommandBase(ConCommandBase *pVar);
|
||||
public: //IClientListner
|
||||
bool InterceptClientConnect(int client, char *error, size_t maxlength);
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
void OnClientConnected(int client);
|
||||
#endif
|
||||
void OnClientPutInServer(int client);
|
||||
void OnClientDisconnecting(int client);
|
||||
public:
|
||||
#if defined CLIENTVOICE_HOOK_SUPPORT
|
||||
void OnClientVoice(edict_t *pPlayer);
|
||||
#endif
|
||||
public: // IVoiceServer
|
||||
bool OnSetClientListening(int iReceiver, int iSender, bool bListen);
|
||||
void VoiceInit();
|
||||
@ -108,6 +122,9 @@ public: // IVoiceServer
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_CSGO
|
||||
void OnSendClientCommand(edict_t *pPlayer, const char *szFormat);
|
||||
#endif
|
||||
public: //ITimedEvent
|
||||
ResultType OnTimer(ITimer *pTimer, void *pData);
|
||||
void OnTimerEnd(ITimer *pTimer, void *pData);
|
||||
|
||||
public: //ICommandTargetProcessor
|
||||
bool ProcessCommandTarget(cmd_target_info_t *info);
|
||||
@ -156,6 +173,11 @@ extern HandleType_t g_CallHandle;
|
||||
extern HandleType_t g_TraceHandle;
|
||||
/* Call Wrappers */
|
||||
extern ICallWrapper *g_pAcceptInput;
|
||||
/* Timers */
|
||||
extern ITimer *g_hTimerSpeaking[SM_MAXPLAYERS+1];
|
||||
/* Forwards */
|
||||
extern IForward *m_OnClientSpeaking;
|
||||
extern IForward *m_OnClientSpeakingEnd;
|
||||
/* Call classes */
|
||||
extern SourceHook::CallClass<IVEngineServer> *enginePatch;
|
||||
extern SourceHook::CallClass<IEngineSound> *enginesoundPatch;
|
||||
|
@ -46,6 +46,9 @@ static bool PRCH_enabled = false;
|
||||
static bool PRCH_used = false;
|
||||
static bool PRCHPost_used = false;
|
||||
static bool FILE_used = false;
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
static bool PVD_used = false;
|
||||
#endif
|
||||
|
||||
SH_DECL_MANUALHOOK2_void(PlayerRunCmdHook, 0, 0, 0, CUserCmd *, IMoveHelper *);
|
||||
SH_DECL_HOOK2(IBaseFileSystem, FileExists, SH_NOATTRIB, 0, bool, const char*, const char *);
|
||||
@ -54,6 +57,9 @@ SH_DECL_HOOK3(INetChannel, SendFile, SH_NOATTRIB, 0, bool, const char *, unsigne
|
||||
#else
|
||||
SH_DECL_HOOK2(INetChannel, SendFile, SH_NOATTRIB, 0, bool, const char *, unsigned int);
|
||||
#endif
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
SH_DECL_HOOK1(IClientMessageHandler, ProcessVoiceData, SH_NOATTRIB, 0, bool, CLC_VoiceData *);
|
||||
#endif
|
||||
SH_DECL_HOOK2_void(INetChannel, ProcessPacket, SH_NOATTRIB, 0, struct netpacket_s *, bool);
|
||||
|
||||
SourceHook::CallClass<IBaseFileSystem> *basefilesystemPatch = NULL;
|
||||
@ -141,6 +147,36 @@ void CHookManager::OnClientConnect(int client)
|
||||
NetChannelHook(client);
|
||||
}
|
||||
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
void CHookManager::OnClientConnected(int client)
|
||||
{
|
||||
if (!PVD_used)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IClient *pClient = iserver->GetClient(client-1);
|
||||
if (!pClient)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<CVTableHook *> &netProcessVoiceData = m_netProcessVoiceData;
|
||||
CVTableHook hook(pClient);
|
||||
for (size_t i = 0; i < netProcessVoiceData.size(); ++i)
|
||||
{
|
||||
if (hook == netProcessVoiceData[i])
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int hookid = SH_ADD_VPHOOK(IClientMessageHandler, ProcessVoiceData, (IClientMessageHandler *)((intptr_t)(pClient) + 4), SH_MEMBER(this, &CHookManager::ProcessVoiceData), true);
|
||||
hook.SetHookID(hookid);
|
||||
netProcessVoiceData.push_back(new CVTableHook(hook));
|
||||
}
|
||||
#endif
|
||||
|
||||
void CHookManager::OnClientPutInServer(int client)
|
||||
{
|
||||
if (PRCH_used)
|
||||
@ -459,6 +495,31 @@ bool CHookManager::SendFile(const char *filename, unsigned int transferID)
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
bool CHookManager::ProcessVoiceData(CLC_VoiceData *msg)
|
||||
{
|
||||
IClient *pClient = (IClient *)((intptr_t)(META_IFACEPTR(IClient)) - 4);
|
||||
if (pClient == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int client = pClient->GetPlayerSlot() + 1;
|
||||
|
||||
if (g_hTimerSpeaking[client])
|
||||
{
|
||||
timersys->KillTimer(g_hTimerSpeaking[client]);
|
||||
}
|
||||
|
||||
g_hTimerSpeaking[client] = timersys->CreateTimer(&g_SdkTools, 0.3f, (void *)(intptr_t)client, 0);
|
||||
|
||||
m_OnClientSpeaking->PushCell(client);
|
||||
m_OnClientSpeaking->Execute();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CHookManager::OnPluginLoaded(IPlugin *plugin)
|
||||
{
|
||||
if (PRCH_enabled)
|
||||
@ -502,6 +563,22 @@ void CHookManager::OnPluginLoaded(IPlugin *plugin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
if (!PVD_used && (m_OnClientSpeaking->GetFunctionCount() || m_OnClientSpeakingEnd->GetFunctionCount()))
|
||||
{
|
||||
PVD_used = true;
|
||||
|
||||
int MaxClients = playerhelpers->GetMaxClients();
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (playerhelpers->GetGamePlayer(i)->IsConnected())
|
||||
{
|
||||
OnClientConnected(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CHookManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
@ -538,6 +615,19 @@ void CHookManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
m_netChannelHooks.clear();
|
||||
FILE_used = false;
|
||||
}
|
||||
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
if (PVD_used && !m_OnClientSpeaking->GetFunctionCount() && !m_OnClientSpeakingEnd->GetFunctionCount())
|
||||
{
|
||||
for (size_t i = 0; i < m_netProcessVoiceData.size(); ++i)
|
||||
{
|
||||
delete m_netProcessVoiceData[i];
|
||||
}
|
||||
|
||||
m_netProcessVoiceData.clear();
|
||||
PVD_used = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
FeatureStatus CHookManager::GetFeatureStatus(FeatureType type, const char *name)
|
||||
|
@ -47,6 +47,9 @@ public:
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
void OnClientConnect(int client);
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
void OnClientConnected(int client);
|
||||
#endif
|
||||
void OnClientPutInServer(int client);
|
||||
void PlayerRunCmd(CUserCmd *ucmd, IMoveHelper *moveHelper);
|
||||
void PlayerRunCmdPost(CUserCmd *ucmd, IMoveHelper *moveHelper);
|
||||
@ -57,6 +60,9 @@ public: /* NetChannel/Related Hooks */
|
||||
bool SendFile(const char *filename, unsigned int transferID, bool isReplayDemo);
|
||||
#else
|
||||
bool SendFile(const char *filename, unsigned int transferID);
|
||||
#endif
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
bool ProcessVoiceData(CLC_VoiceData *msg);
|
||||
#endif
|
||||
void ProcessPacket(struct netpacket_s *packet, bool bHasHeader);
|
||||
void ProcessPacket_Post(struct netpacket_s *packet, bool bHasHeader);
|
||||
@ -78,6 +84,9 @@ private:
|
||||
std::vector<CVTableHook *> m_runUserCmdHooks;
|
||||
std::vector<CVTableHook *> m_runUserCmdPostHooks;
|
||||
std::vector<CVTableHook *> m_netChannelHooks;
|
||||
#if !defined CLIENTVOICE_HOOK_SUPPORT
|
||||
std::vector<CVTableHook *> m_netProcessVoiceData;
|
||||
#endif
|
||||
INetChannel *m_pActiveNetChannel;
|
||||
bool m_bFSTranHookWarned = false;
|
||||
bool m_bReplayEnabled = false;
|
||||
|
@ -66,7 +66,7 @@
|
||||
#define SMEXT_ENABLE_GAMECONF
|
||||
#define SMEXT_ENABLE_MEMUTILS
|
||||
#define SMEXT_ENABLE_GAMEHELPERS
|
||||
//#define SMEXT_ENABLE_TIMERSYS
|
||||
#define SMEXT_ENABLE_TIMERSYS
|
||||
#define SMEXT_ENABLE_ADTFACTORY
|
||||
#define SMEXT_ENABLE_PLUGINSYS
|
||||
|
||||
|
@ -167,6 +167,11 @@ bool SDKTools::OnSetClientListening(int iReceiver, int iSender, bool bListen)
|
||||
|
||||
void SDKTools::OnClientDisconnecting(int client)
|
||||
{
|
||||
if (g_hTimerSpeaking[client])
|
||||
{
|
||||
timersys->KillTimer(g_hTimerSpeaking[client]);
|
||||
}
|
||||
|
||||
int max_clients = playerhelpers->GetMaxClients();
|
||||
|
||||
if (g_VoiceHookCount == 0)
|
||||
@ -355,6 +360,33 @@ static cell_t IsClientMuted(IPluginContext *pContext, const cell_t *params)
|
||||
return g_ClientMutes[params[1]][params[2]];
|
||||
}
|
||||
|
||||
/* FIXME: Presently if there's no hook present these natives will result in an invalid state.
|
||||
* One suggestion could be to look at if the native is bound, and then invoke the hooks in the background.
|
||||
* However, at that point really we should be enforcing the forward usage to catch new-consumers immediately.
|
||||
* If you're looking to work on this, you're welcome to ping asherkin or KyleS, or even submit a patch to add this.
|
||||
* Additional comments can be found here (if GitHub still exists): https://github.com/alliedmodders/sourcemod/pull/1247
|
||||
*/
|
||||
static cell_t IsClientSpeaking(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IGamePlayer *player;
|
||||
|
||||
player = playerhelpers->GetGamePlayer(params[1]);
|
||||
if (player == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
|
||||
}
|
||||
else if (!player->IsConnected())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not connected", params[1]);
|
||||
}
|
||||
else if (!player->IsInGame())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return g_hTimerSpeaking[params[1]] != nullptr;
|
||||
}
|
||||
|
||||
sp_nativeinfo_t g_VoiceNatives[] =
|
||||
{
|
||||
{"SetClientListeningFlags", SetClientListeningFlags},
|
||||
|
@ -56,6 +56,20 @@ enum ListenOverride
|
||||
Listen_Yes /**< Can hear */
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when a client is speaking.
|
||||
*
|
||||
* @param client The client index
|
||||
*/
|
||||
forward void OnClientSpeaking(int client);
|
||||
|
||||
/**
|
||||
* Called once a client speaking end.
|
||||
*
|
||||
* @param client The client index
|
||||
*/
|
||||
forward void OnClientSpeakingEnd(int client);
|
||||
|
||||
/**
|
||||
* Set the client listening flags.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user