Added client convar querying :o

Also added ISourceMod::GetModFolderName() for returning the name of the mod directory by itself

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40702
This commit is contained in:
Scott Ehlert
2007-04-14 04:27:47 +00:00
parent c8f507561c
commit 77e49c855f
11 changed files with 297 additions and 62 deletions
+112 -11
View File
@@ -13,6 +13,7 @@
*/
#include "ConVarManager.h"
#include "HalfLife2.h"
#include "PluginSys.h"
#include "ForwardSys.h"
#include "HandleSys.h"
@@ -22,10 +23,13 @@
ConVarManager g_ConVarManager;
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 *);
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
typedef List<const ConVar *> ConVarList;
ConVarManager::ConVarManager() : m_ConVarType(0)
ConVarManager::ConVarManager() : m_ConVarType(0), m_VSPIface(NULL), m_CanQueryConVars(false)
{
/* Create a convar lookup trie */
m_ConVarCache = sm_trie_create();
@@ -49,6 +53,13 @@ ConVarManager::~ConVarManager()
void ConVarManager::OnSourceModAllInitialized()
{
/* Only valid with ServerGameDLL006 or greater */
if (g_SMAPI->GetGameDLLVersion() >= 6)
{
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
m_CanQueryConVars = true;
}
HandleAccess sec;
/* Set up access rights for the 'ConVar' handle type */
@@ -65,13 +76,19 @@ void ConVarManager::OnSourceModAllInitialized()
void ConVarManager::OnSourceModShutdown()
{
if (m_CanQueryConVars)
{
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
SH_REMOVE_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, m_VSPIface, this, &ConVarManager::OnQueryCvarValueFinished, false);
}
IChangeableForward *fwd;
List<ConVarInfo *>::iterator i;
/* Iterate list of ConVarInfo structures */
for (i = m_ConVars.begin(); i != m_ConVars.end(); i++)
{
fwd = (*i)->changeForward;
fwd = (*i)->pChangeForward;
/* Free any convar-change forwards that still exist */
if (fwd)
@@ -87,6 +104,29 @@ void ConVarManager::OnSourceModShutdown()
g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent);
}
void ConVarManager::OnSourceModVSPReceived(IServerPluginCallbacks *iface)
{
/* This will be called after OnSourceModAllInitialized(), so...
*
* If we haven't been able to hook the IServerGameDLL version at this point,
* then use hook IServerPluginCallbacks version from the engine.
*/
/* The Ship currently only supports ServerPluginCallbacks001, but we need 002 */
if (g_IsOriginalEngine)
{
return;
}
if (!m_CanQueryConVars)
{
m_VSPIface = iface;
SH_ADD_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, iface, this, &ConVarManager::OnQueryCvarValueFinished, false);
m_CanQueryConVars = true;
}
}
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
{
ConVarList *pConVarList;
@@ -190,7 +230,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
pInfo = new ConVarInfo();
pInfo->handle = hndl;
pInfo->sourceMod = false;
pInfo->changeForward = NULL;
pInfo->pChangeForward = NULL;
pInfo->origCallback = pConVar->GetCallback();
/* Insert struct into caches */
@@ -201,7 +241,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
}
}
// To prevent creating a convar that has the same name as a console command... ugh
/* To prevent creating a convar that has the same name as a console command... ugh */
ConCommandBase *pBase = icvar->GetCommands();
while (pBase)
@@ -227,7 +267,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
pInfo = new ConVarInfo();
pInfo->handle = hndl;
pInfo->sourceMod = true;
pInfo->changeForward = NULL;
pInfo->pChangeForward = NULL;
pInfo->origCallback = NULL;
/* Insert struct into caches */
@@ -265,7 +305,7 @@ Handle_t ConVarManager::FindConVar(const char *name)
pInfo = new ConVarInfo();
pInfo->handle = hndl;
pInfo->sourceMod = false;
pInfo->changeForward = NULL;
pInfo->pChangeForward = NULL;
pInfo->origCallback = pConVar->GetCallback();
/* Insert struct into our caches */
@@ -284,13 +324,13 @@ void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction
if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), (void **)&pInfo))
{
/* Get the forward */
pForward = pInfo->changeForward;
pForward = pInfo->pChangeForward;
/* If forward does not exist, create it */
if (!pForward)
{
pForward = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS);
pInfo->changeForward = pForward;
pInfo->pChangeForward = pForward;
/* Install our own callback */
pConVar->InstallChangeCallback(OnConVarChanged);
@@ -311,7 +351,7 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), (void **)&pInfo))
{
/* Get the forward */
pForward = pInfo->changeForward;
pForward = pInfo->pChangeForward;
/* If the forward doesn't exist, we can't unhook anything */
if (!pForward)
@@ -332,7 +372,7 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
{
/* Free this forward */
g_Forwards.ReleaseForward(pForward);
pInfo->changeForward = NULL;
pInfo->pChangeForward = NULL;
/* Put back the original convar callback */
pConVar->InstallChangeCallback(pInfo->origCallback);
@@ -340,6 +380,24 @@ 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;
/* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */
if (!m_VSPIface)
{
cookie = engine->StartQueryCvarValue(pPlayer, name);
} else {
cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name);
}
ConVarQuery query = {cookie, pCallback, hndl};
m_ConVarQueries.push_back(query);
return cookie;
}
void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar)
{
ConVarList *pConVarList;
@@ -388,7 +446,7 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue)
sm_trie_retrieve(pCache, pConVar->GetName(), (void **)&pInfo);
FnChangeCallback origCallback = pInfo->origCallback;
IChangeableForward *pForward = pInfo->changeForward;
IChangeableForward *pForward = pInfo->pChangeForward;
/* If there was a change callback installed previously, call it */
if (origCallback)
@@ -403,6 +461,49 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue)
pForward->Execute(NULL);
}
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
{
IPluginFunction *pCallback = NULL;
cell_t value = 0;
List<ConVarQuery>::iterator iter;
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end(); iter++)
{
ConVarQuery &query = (*iter);
if (query.cookie == cookie)
{
pCallback = query.pCallback;
value = query.value;
break;
}
}
if (pCallback)
{
cell_t ret;
pCallback->PushCell(cookie);
pCallback->PushCell(engine->IndexOfEdict(pPlayer));
pCallback->PushCell(result);
pCallback->PushString(cvarName);
if (result == eQueryCvarValueStatus_ValueIntact)
{
pCallback->PushString(cvarValue);
} else {
pCallback->PushString("\0");
}
pCallback->PushCell(value);
pCallback->Execute(&ret);
m_ConVarQueries.erase(iter);
}
}
static int s_YamagramState = 0;
void _YamagramPrinterTwoPointOhOh(int yamagram)
+28 -2
View File
@@ -33,10 +33,20 @@ struct ConVarInfo
{
Handle_t handle; /**< Handle to convar */
bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */
IChangeableForward *changeForward; /**< Forward associated with convar */
IChangeableForward *pChangeForward; /**< Forward associated with convar */
FnChangeCallback origCallback; /**< The original callback function */
};
/**
* Holds information about a client convar query
*/
struct ConVarQuery
{
QueryCvarCookie_t cookie; /**< Cookie that identifies query */
IPluginFunction *pCallback; /**< Function that will be called when query is finished */
cell_t value; /**< Optional value passed to query function */
};
class ConVarManager :
public SMGlobalClass,
public IHandleTypeDispatch,
@@ -49,6 +59,7 @@ public:
public: // SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
void OnSourceModVSPReceived(IServerPluginCallbacks *iface);
public: // IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object);
public: // IPluginsListener
@@ -92,6 +103,12 @@ public:
* Remove a function from the forward that will be called when the specified convar changes.
*/
void UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFunction);
/**
* Starts a query to find the value of a client convar.
*/
QueryCvarCookie_t QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback,
Handle_t hndl);
private:
/**
* Adds a convar to a plugin's list.
@@ -99,13 +116,22 @@ private:
static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar);
/**
* Static callback that Valve's ConVar class executes when the convar's value changes.
* Static callback that Valve's ConVar object executes when the convar's value changes.
*/
static void OnConVarChanged(ConVar *pConVar, const char *oldValue);
/**
* Callback for when StartQueryCvarValue() has finished.
*/
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
private:
HandleType_t m_ConVarType;
List<ConVarInfo *> m_ConVars;
List<ConVarQuery> m_ConVarQueries;
Trie *m_ConVarCache;
IServerPluginCallbacks *m_VSPIface;
bool m_CanQueryConVars;
};
extern ConVarManager g_ConVarManager;
+1 -22
View File
@@ -301,28 +301,7 @@ void GameConfigManager::OnSourceModStartup(bool late)
{
LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
char mod[255];
engine->GetGameDir(mod, sizeof(mod));
g_mod[0] = '\0';
size_t len = strlen(mod);
for (size_t i=len-1; i>=0 && i<len; i++)
{
if (mod[i] == '/')
{
if (i == len-1)
{
mod[i] = '\0';
continue;
}
strcpy(g_mod, &mod[i]);
break;
}
}
if (g_mod[0] != '\0')
{
strcpy(g_mod, mod);
}
strncopy(g_mod, g_SourceMod.GetModFolderName(), sizeof(g_mod));
}
void GameConfigManager::OnSourceModAllInitialized()
+6 -1
View File
@@ -13,6 +13,7 @@
*/
#include "HalfLife2.h"
#include "sourcemod.h"
#include "sourcemm_api.h"
CHalfLife2 g_HL2;
@@ -70,8 +71,12 @@ CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL;
void CHalfLife2::OnSourceModStartup(bool late)
{
if (!g_IsOriginalEngine && !g_pSharedChangeInfo)
/* The Ship currently is the only known game to use an older version of the engine */
if (strcasecmp(g_SourceMod.GetModFolderName(), "ship") == 0)
{
/* :TODO: Better engine versioning - perhaps something added to SourceMM? */
g_IsOriginalEngine = true;
} else if (!g_pSharedChangeInfo) {
g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo();
}
}
+44
View File
@@ -13,6 +13,7 @@
*/
#include "sm_globals.h"
#include "HalfLife2.h"
#include "sourcemm_api.h"
#include "HandleSys.h"
#include "ConVarManager.h"
@@ -342,6 +343,48 @@ static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
return 1;
}
static bool s_QueryAlreadyWarned = false;
static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
{
CPlayer *pPlayer;
char *name;
IPluginFunction *pCallback;
if (g_IsOriginalEngine)
{
if (!s_QueryAlreadyWarned)
{
s_QueryAlreadyWarned = true;
return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
}
return 0;
}
pPlayer = g_Players.GetPlayerByIndex(params[1]);
if (!pPlayer)
{
return pContext->ThrowNativeError("Player %d is not a valid player", params[1]);
}
if (!pPlayer->IsConnected() || pPlayer->IsFakeClient())
{
return pContext->ThrowNativeError("Player %d is either not connected or a bot", params[1]);
}
pContext->LocalToString(params[2], &name);
pCallback = pContext->GetFunctionById(params[3]);
if (!pCallback)
{
return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
}
return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
}
static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
{
char *name,*help;
@@ -584,6 +627,7 @@ REGISTER_NATIVES(consoleNatives)
{"GetConVarMin", sm_GetConVarMin},
{"GetConVarMax", sm_GetConVarMax},
{"ResetConVar", sm_ResetConVar},
{"QueryClientConVar", sm_QueryClientConVar},
{"RegServerCmd", sm_RegServerCmd},
{"RegConsoleCmd", sm_RegConsoleCmd},
{"GetCmdArgString", sm_GetCmdArgString},
+20 -1
View File
@@ -100,7 +100,21 @@ ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key,
bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late)
{
g_BaseDir.assign(g_SMAPI->GetBaseDir());
const char *gamepath = g_SMAPI->GetBaseDir();
/* Store full path to game */
g_BaseDir.assign(gamepath);
/* Store name of game directory by itself */
size_t len = strlen(gamepath);
for (size_t i = len - 1; i >= 0; i--)
{
if (gamepath[i] == PLATFORM_SEP_CHAR)
{
strncopy(m_ModDir, &gamepath[++i], sizeof(m_ModDir));
break;
}
}
/* Initialize CoreConfig so we can get SourceMod base path properly - this basically parses core.cfg */
g_CoreConfig.Initialize();
@@ -528,6 +542,11 @@ Handle_t SourceModBase::GetDataPackHandleType(bool readonly)
return 0;
}
const char *SourceModBase::GetModFolderName() const
{
return m_ModDir;
}
SMGlobalClass *SMGlobalClass::head = NULL;
SMGlobalClass::SMGlobalClass()
+2
View File
@@ -94,6 +94,7 @@ public: // ISourceMod
void FreeDataPack(IDataPack *pack);
HandleType_t GetDataPackHandleType(bool readonly=false);
KeyValues *ReadKeyValuesHandle(Handle_t hndl, HandleError *err=NULL, bool root=false);
const char *GetModFolderName() const;
private:
/**
* @brief Loading plugins
@@ -108,6 +109,7 @@ private:
CStack<CDataPack *> m_freepacks;
char m_SMBaseDir[PLATFORM_MAX_PATH];
char m_SMRelDir[PLATFORM_MAX_PATH];
char m_ModDir[32];
bool m_IsMapLoading;
bool m_ExecPluginReload;
unsigned int m_target;
+1 -1
View File
@@ -711,7 +711,7 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *sour
len = strlen(source);
dest = (char *)(ctx->memory + local_addr);
if ((size_t)len >= bytes)
if (len >= bytes)
{
len = bytes - 1;
}