Move OnQueryCvarValueFinished into the global hook manager.

This commit is contained in:
David Anderson 2015-08-30 17:44:07 -07:00
parent 2ed044804d
commit 5d55ff23bd
12 changed files with 178 additions and 154 deletions

View File

@ -34,17 +34,10 @@
#include <sm_namehashset.h>
#include "logic_bridge.h"
#include "sourcemod.h"
#include "provider.h"
ConVarManager g_ConVarManager;
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
#elif SOURCE_ENGINE != SE_DARKMESSIAH
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
#endif
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
typedef List<const ConVar *> ConVarList;
NameHashSet<ConVarInfo *> convar_cache;
@ -83,7 +76,7 @@ public:
ConVarReentrancyGuard *ConVarReentrancyGuard::chain = NULL;
ConVarManager::ConVarManager() : m_ConVarType(0), m_bIsDLLQueryHooked(false), m_bIsVSPQueryHooked(false)
ConVarManager::ConVarManager() : m_ConVarType(0)
{
}
@ -106,17 +99,6 @@ void ConVarManager::OnSourceModStartup(bool late)
void ConVarManager::OnSourceModAllInitialized()
{
/**
* Episode 2 has this function by default, but the older versions do not.
*/
#if SOURCE_ENGINE == SE_EPISODEONE
if (g_SMAPI->GetGameDLLVersion() >= 6)
{
SH_ADD_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
m_bIsDLLQueryHooked = true;
}
#endif
g_Players.AddClientListener(this);
scripts->AddPluginsListener(this);
@ -168,22 +150,6 @@ void ConVarManager::OnSourceModShutdown()
}
convar_cache.clear();
#if SOURCE_ENGINE != SE_DARKMESSIAH
/* Unhook things */
if (m_bIsDLLQueryHooked)
{
SH_REMOVE_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
m_bIsDLLQueryHooked = false;
}
else if (m_bIsVSPQueryHooked)
{
#if SOURCE_ENGINE != SE_DOTA
SH_REMOVE_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
#endif
m_bIsVSPQueryHooked = false;
}
#endif
g_Players.RemoveClientListener(this);
/* Remove the 'convars' option from the 'sm' console command */
@ -195,39 +161,6 @@ void ConVarManager::OnSourceModShutdown()
handlesys->RemoveType(m_ConVarType, g_pCoreIdent);
}
/**
* Orange Box will never use this.
*/
void ConVarManager::OnSourceModVSPReceived()
{
/**
* Don't bother if the DLL is already hooked.
*/
if (m_bIsDLLQueryHooked)
{
return;
}
/* For later MM:S versions, use the updated API, since it's cleaner. */
#if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11
int engine = g_SMAPI->GetSourceEngineBuild();
if (engine == SOURCE_ENGINE_ORIGINAL || vsp_version < 2)
{
return;
}
#else
if (g_HL2.IsOriginalEngine() || vsp_version < 2)
{
return;
}
#endif
#if SOURCE_ENGINE != SE_DARKMESSIAH && SOURCE_ENGINE != SE_DOTA
SH_ADD_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
m_bIsVSPQueryHooked = true;
#endif
}
bool convar_cache_lookup(const char *name, ConVarInfo **pVar)
{
return convar_cache.retrieve(name, pVar);
@ -607,35 +540,13 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback, Handle_t hndl)
{
QueryCvarCookie_t cookie = 0;
#if SOURCE_ENGINE != SE_DARKMESSIAH
/* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */
if (m_bIsDLLQueryHooked)
{
#if SOURCE_ENGINE == SE_DOTA
cookie = engine->StartQueryCvarValue(CEntityIndex(IndexOfEdict(pPlayer)), name);
#else
cookie = engine->StartQueryCvarValue(pPlayer, name);
#endif
}
#if SOURCE_ENGINE != SE_DOTA
else if (m_bIsVSPQueryHooked)
{
cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name);
}
#endif
else
{
return InvalidQueryCvarCookie;
}
QueryCvarCookie_t cookie = sCoreProviderImpl.QueryClientConVar(IndexOfEdict(pPlayer), name);
if (pCallback != NULL)
{
ConVarQuery query = { cookie, pCallback, (cell_t) hndl, IndexOfEdict(pPlayer) };
m_ConVarQueries.push_back(query);
}
#endif
return cookie;
}
@ -716,23 +627,16 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue, float
bool ConVarManager::IsQueryingSupported()
{
return (m_bIsDLLQueryHooked || m_bIsVSPQueryHooked);
return sCoreProviderImpl.IsClientConVarQueryingSupported();
}
#if SOURCE_ENGINE != SE_DARKMESSIAH
#if SOURCE_ENGINE == SE_DOTA
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
#else
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
#endif // SE_DOTA
void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
int client,
EQueryCvarValueStatus result,
const char *cvarName,
const char *cvarValue)
{
#if SOURCE_ENGINE == SE_CSGO
if (g_Players.HandleConVarQuery(cookie, pPlayer, result, cvarName, cvarValue))
{
return;
}
#endif
IPluginFunction *pCallback = NULL;
cell_t value = 0;
List<ConVarQuery>::iterator iter;
@ -753,11 +657,7 @@ void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *
cell_t ret;
pCallback->PushCell(cookie);
#if SOURCE_ENGINE == SE_DOTA
pCallback->PushCell(player.Get());
#else
pCallback->PushCell(IndexOfEdict(pPlayer));
#endif
pCallback->PushCell(client);
pCallback->PushCell(result);
pCallback->PushString(cvarName);

View File

@ -44,11 +44,6 @@
#include "concmd_cleaner.h"
#include "PlayerManager.h"
#if SOURCE_ENGINE == SE_DARKMESSIAH
class EQueryCvarValueStatus;
typedef int QueryCvarCookie_t;
#endif
using namespace SourceHook;
class IConVarChangeListener
@ -100,7 +95,6 @@ public: // SMGlobalClass
void OnSourceModStartup(bool late);
void OnSourceModAllInitialized();
void OnSourceModShutdown();
void OnSourceModVSPReceived();
public: // IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object);
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
@ -149,29 +143,24 @@ public:
// Called via game hooks.
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
#if SOURCE_ENGINE != SE_DARKMESSIAH
void OnClientQueryFinished(
QueryCvarCookie_t cookie,
int client,
EQueryCvarValueStatus result,
const char *cvarName,
const char *cvarValue);
#endif
private:
/**
* Adds a convar to a plugin's list.
*/
static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar);
/**
* Callback for when StartQueryCvarValue() has finished.
*/
#if SOURCE_ENGINE == SE_DOTA
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
#elif SOURCE_ENGINE != SE_DARKMESSIAH
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
#endif
private:
HandleType_t m_ConVarType;
List<ConVarInfo *> m_ConVars;
List<ConVarQuery> m_ConVarQueries;
bool m_bIsDLLQueryHooked;
bool m_bIsVSPQueryHooked;
};
extern ConVarManager g_ConVarManager;

View File

@ -34,35 +34,97 @@ SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallback, SH_NOATTRIB, false, ConVar *, const char *);
#endif
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
#elif SOURCE_ENGINE != SE_DARKMESSIAH
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
#endif
GameHooks::GameHooks()
: query_hook_mode_(QueryHookMode::Unavailable)
{
}
void GameHooks::Start()
{
// Hook ICvar::CallGlobalChangeCallbacks.
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_ADD_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
hooks_ += SH_ADD_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
#else
SH_ADD_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
hooks_ += SH_ADD_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
#endif
// Episode 2 has this function by default, but the older versions do not.
#if SOURCE_ENGINE == SE_EPISODEONE
if (g_SMAPI->GetGameDLLVersion() >= 6) {
hooks_ += SH_ADD_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &GameHooks::OnQueryCvarValueFinished), false);
query_hook_mode_ = QueryHookMode::DLL;
}
#endif
}
void GameHooks::OnVSPReceived()
{
if (query_hook_mode_ != QueryHookMode::Unavailable)
return;
// For later MM:S versions, use the updated API, since it's cleaner.
#if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL || vsp_version < 2)
return;
#else
if (g_HL2.IsOriginalEngine() || vsp_version < 2)
return;
#endif
#if SOURCE_ENGINE != SE_DARKMESSIAH && SOURCE_ENGINE != SE_DOTA
hooks_ += SH_ADD_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &GameHooks::OnQueryCvarValueFinished), false);
query_hook_mode_ = QueryHookMode::VSP;
#endif
}
void GameHooks::Shutdown()
{
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_REMOVE_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
#else
SH_REMOVE_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
#endif
for (size_t i = 0; i < hooks_.length(); i++)
SH_REMOVE_HOOK_ID(hooks_[i]);
hooks_.clear();
query_hook_mode_ = QueryHookMode::Unavailable;
}
#if SOURCE_ENGINE >= SE_ORANGEBOX
void GameHooks::OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue)
{
#else
void GameHooks::OnConVarChanged(ConVar *pConVar, const char *oldValue)
#endif
{
#if SOURCE_ENGINE < SE_ORANGEBOX
float flOldValue = atof(oldValue);
#endif
g_ConVarManager.OnConVarChanged(pConVar, oldValue, flOldValue);
}
#if SOURCE_ENGINE != SE_DARKMESSIAH
# if SOURCE_ENGINE == SE_DOTA
void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue)
# else
void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue)
# endif
{
# if SOURCE_ENGINE == SE_DOTA
int client = player.Get();
# else
int client = IndexOfEdict(pPlayer);
# endif
# if SOURCE_ENGINE == SE_CSGO
if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue))
return;
# endif
g_ConVarManager.OnClientQueryFinished(cookie, client, result, cvarName, cvarValue);
}
#endif

View File

@ -27,10 +27,23 @@
#ifndef _INCLUDE_SOURCEMOD_PROVIDER_GAME_HOOKS_H_
#define _INCLUDE_SOURCEMOD_PROVIDER_GAME_HOOKS_H_
// Needed for CEntityIndex, edict_t, etc.
#include <stdint.h>
#include <stddef.h>
#include <eiface.h>
#include <iserverplugin.h>
#include <amtl/am-vector.h>
class ConVar;
namespace SourceMod {
enum class QueryHookMode {
Unavailable,
DLL,
VSP
};
class GameHooks
{
public:
@ -38,13 +51,41 @@ public:
void Start();
void Shutdown();
void OnVSPReceived();
QueryHookMode GetQueryHookMode() const {
return query_hook_mode_;
}
private:
// Static callback that Valve's ConVar object executes when the convar's value changes.
#if SOURCE_ENGINE >= SE_ORANGEBOX
static void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
#else
static void OnConVarChanged(ConVar *pConVar, const char *oldValue);
#endif
// Callback for when StartQueryCvarValue() has finished.
#if SOURCE_ENGINE == SE_DOTA
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
#elif SOURCE_ENGINE != SE_DARKMESSIAH
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
#endif
private:
class HookList : public ke::Vector<int>
{
public:
HookList &operator += (int hook_id) {
this->append(hook_id);
return *this;
}
};
HookList hooks_;
QueryHookMode query_hook_mode_;
};
} // namespace SourceMod

View File

@ -2010,7 +2010,7 @@ void CmdMaxplayersCallback()
}
#if SOURCE_ENGINE == SE_CSGO
bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
{
for (int i = 1; i <= m_maxClients; i++)
{

View File

@ -233,7 +233,7 @@ public:
return m_bInCCKVHook;
}
#if SOURCE_ENGINE == SE_CSGO
bool HandleConVarQuery(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
#endif
private:
#if SOURCE_ENGINE == SE_DOTA

View File

@ -52,7 +52,7 @@ using namespace SourceHook;
* Add 1 to the RHS of this expression to bump the intercom file
* This is to prevent mismatching core/logic binaries
*/
#define SM_LOGIC_MAGIC (0x0F47C0DE - 47)
#define SM_LOGIC_MAGIC (0x0F47C0DE - 48)
#if defined SM_LOGIC
# define IVEngineClass IVEngineServer
@ -315,6 +315,10 @@ public:
virtual void ConPrint(const char *message) = 0;
virtual void ConsolePrintVa(const char *fmt, va_list ap) = 0;
// Game engine helper functions.
virtual bool IsClientConVarQueryingSupported() = 0;
virtual int QueryClientConVar(int client, const char *cvar) = 0;
// Metamod:Source functions.
virtual int LoadMMSPlugin(const char *file, bool *ok, char *error, size_t maxlength) = 0;
virtual void UnloadMMSPlugin(int id) = 0;

View File

@ -637,6 +637,32 @@ void CoreProviderImpl::UnloadMMSPlugin(int id)
g_pMMPlugins->Unload(id, true, ignore, sizeof(ignore));
}
bool CoreProviderImpl::IsClientConVarQueryingSupported()
{
return hooks_.GetQueryHookMode() != QueryHookMode::Unavailable;
}
int CoreProviderImpl::QueryClientConVar(int client, const char *cvar)
{
#if SOURCE_ENGINE != SE_DARKMESSIAH
switch (hooks_.GetQueryHookMode()) {
case QueryHookMode::DLL:
# if SOURCE_ENGINE == SE_DOTA
return ::engine->StartQueryCvarValue(CEntityIndex(client), cvar);
# else
return ::engine->StartQueryCvarValue(PEntityOfEntIndex(client), cvar);
# endif
case QueryHookMode::VSP:
# if SOURCE_ENGINE != SE_DOTA
return serverpluginhelpers->StartQueryCvarValue(PEntityOfEntIndex(client), cvar);
# endif
default:
return InvalidQueryCvarCookie;
}
#endif
return -1;
}
void CoreProviderImpl::InitializeBridge()
{
::serverGlobals.universalTime = g_pUniversalTime;
@ -721,6 +747,11 @@ void CoreProviderImpl::InitializeHooks()
hooks_.Start();
}
void CoreProviderImpl::OnVSPReceived()
{
hooks_.OnVSPReceived();
}
void CoreProviderImpl::ShutdownHooks()
{
hooks_.Shutdown();

View File

@ -43,6 +43,7 @@ public:
void InitializeHooks();
void ShutdownHooks();
void OnVSPReceived();
// Provider implementation.
ConVar *FindConVar(const char *name) override;
@ -61,6 +62,8 @@ public:
void ConsolePrintVa(const char *fmt, va_list ap) override;
int LoadMMSPlugin(const char *file, bool *ok, char *error, size_t maxlength) override;
void UnloadMMSPlugin(int id) override;
int QueryClientConVar(int client, const char *cvar) override;
bool IsClientConVarQueryingSupported() override;
private:
ke::Ref<ke::SharedLib> logic_;

View File

@ -159,13 +159,6 @@ public:
{
}
/**
* @brief Called when SourceMod receives a pointer to IServerPluginCallbacks from SourceMM
*/
virtual void OnSourceModVSPReceived()
{
}
/**
* @brief Called once all MM:S plugins are loaded.
*/

View File

@ -36,6 +36,7 @@
#include "compat_wrappers.h"
#include "logic_bridge.h"
#include <sourcemod_version.h>
#include "provider.h"
SourceMod_Core g_SourceMod_Core;
IVEngineServer *engine = NULL;
@ -207,12 +208,7 @@ void SourceMod_Core::OnVSPListening(IServerPluginCallbacks *iface)
#endif
/* Notify! */
SMGlobalClass *pBase = SMGlobalClass::head;
while (pBase)
{
pBase->OnSourceModVSPReceived();
pBase = pBase->m_pGlobalClassNext;
}
sCoreProviderImpl.OnVSPReceived();
}
#if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11

View File

@ -1,5 +1,5 @@
/**
* vim: set ts=4 :
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
@ -34,6 +34,11 @@
#include <datamap.h>
#if SOURCE_ENGINE == SE_DARKMESSIAH
class EQueryCvarValueStatus;
typedef int QueryCvarCookie_t;
#endif
#if SOURCE_ENGINE >= SE_ORANGEBOX
#define CONVAR_REGISTER(object) ConVar_Register(0, object)