Add source2 convar/concommand support (#203)

Co-authored-by: Nicholas Hastings <nshastings@gmail.com>
This commit is contained in:
GAMMACASE 2025-02-15 22:00:01 +03:00 committed by GitHub
parent 4fe356b724
commit a0ef30603f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 402 additions and 107 deletions

View File

@ -121,6 +121,7 @@ class MMSConfig(object):
'-Wall', '-Wall',
'-Werror', '-Werror',
'-Wno-uninitialized', '-Wno-uninitialized',
'-Wno-sign-compare',
'-Wno-unused', '-Wno-unused',
'-Wno-switch', '-Wno-switch',
'-msse', '-msse',

View File

@ -28,6 +28,9 @@ for sdk_target in MMS.sdk_targets:
binary.sources += [ binary.sources += [
'provider/source2/provider_source2.cpp', 'provider/source2/provider_source2.cpp',
] ]
binary.custom = [builder.tools.Protoc(protoc = sdk_target.protoc, sources = [
os.path.join(sdk['path'], 'common', 'network_connection.proto'),
])]
else: else:
binary.sources += [ binary.sources += [
'provider/source/provider_source.cpp', 'provider/source/provider_source.cpp',
@ -35,11 +38,6 @@ for sdk_target in MMS.sdk_targets:
'vsp_bridge.cpp' 'vsp_bridge.cpp'
] ]
if sdk['name'] == 'cs2':
binary.custom = [builder.tools.Protoc(protoc = sdk_target.protoc, sources = [
os.path.join(sdk['path'], 'common', 'network_connection.proto'),
])]
if cxx.target.arch == 'x86': if cxx.target.arch == 'x86':
binary.sources += ['sourcehook/sourcehook_hookmangen_x86.cpp'] binary.sources += ['sourcehook/sourcehook_hookmangen_x86.cpp']
elif binary.compiler.target.arch == 'x86_64' and binary.compiler.target.platform != 'linux': elif binary.compiler.target.arch == 'x86_64' and binary.compiler.target.platform != 'linux':

View File

@ -41,8 +41,19 @@
class CGlobalVars; class CGlobalVars;
struct edict_t; struct edict_t;
class ConCommandBase; class ConCommandBase;
typedef ConCommandBase ProviderConVar;
typedef ConCommandBase ProviderConCommand;
#else #else
#include <eiface.h> #include <eiface.h>
#if defined META_IS_SOURCE2
typedef ConVarRefAbstract ProviderConVar;
typedef ConCommandRef ProviderConCommand;
class ConCommandBase;
#else
typedef ConCommandBase ProviderConVar;
typedef ConCommandBase ProviderConCommand;
#endif
#endif #endif
#include <ISmmPlugin.h> #include <ISmmPlugin.h>
@ -131,6 +142,8 @@ namespace SourceMM
/** /**
* @brief Registers a ConCommandBase. * @brief Registers a ConCommandBase.
* *
* @deprecated since 2.1
*
* @param plugin Parent plugin API pointer. * @param plugin Parent plugin API pointer.
* @param pCommand ConCommandBase to register. * @param pCommand ConCommandBase to register.
* @return True if successful, false otherwise. * @return True if successful, false otherwise.
@ -140,6 +153,8 @@ namespace SourceMM
/** /**
* @brief Unregisters a ConCommandBase. * @brief Unregisters a ConCommandBase.
* *
* @deprecated since 2.1
*
* @param plugin Parent plugin API pointer. * @param plugin Parent plugin API pointer.
* @param pCommand ConCommandBase to unlink. * @param pCommand ConCommandBase to unlink.
*/ */
@ -400,6 +415,40 @@ namespace SourceMM
size_t maxlength, size_t maxlength,
const char *format, const char *format,
va_list ap) =0; va_list ap) =0;
/**
* @brief Registers a ConCommand.
*
* @param plugin Parent plugin API pointer.
* @param pCommand ConCommand to register.
* @return True if successful, false otherwise.
*/
virtual bool RegisterConCommand(ISmmPlugin *plugin, ProviderConCommand *pCommand) =0;
/**
* @brief Registers a ConVar.
*
* @param plugin Parent plugin API pointer.
* @param pCvar ConVar to register.
* @return True if successful, false otherwise.
*/
virtual bool RegisterConVar(ISmmPlugin *plugin, ProviderConVar *pCvar) =0;
/**
* @brief Unregisters a ConCommand.
*
* @param plugin Parent plugin API pointer.
* @param pCommand ConCommand to unlink.
*/
virtual void UnregisterConCommand(ISmmPlugin *plugin, ProviderConCommand *pCommand) =0;
/**
* @brief Unregisters a ConVar.
*
* @param plugin Parent plugin API pointer.
* @param pCvar ConVar to unlink.
*/
virtual void UnregisterConVar(ISmmPlugin *plugin, ProviderConVar *pCvar) =0;
}; };
} }

View File

@ -420,6 +420,8 @@ namespace SourceMM
* convar. This can also be called if ISmmAPI::UnregisterConCmdBase is * convar. This can also be called if ISmmAPI::UnregisterConCmdBase is
* used by a plugin. * used by a plugin.
* *
* @deprecated since PLAPI 17
*
* @param id Id of the plugin that created the concommand or * @param id Id of the plugin that created the concommand or
* convar. * convar.
* @param pCommand Pointer to concommand or convar that is being * @param pCommand Pointer to concommand or convar that is being
@ -428,6 +430,30 @@ namespace SourceMM
virtual void OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand) virtual void OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand)
{ {
} }
/**
* @brief Called when Metamod:Source is about to remove a concommand.
* This can also be called if ISmmAPI::UnregisterConCommand is
* used by a plugin.
*
* @param id Id of the plugin that created the concommand.
* @param pCommand Pointer to concommand that is being removed.
*/
virtual void OnUnlinkConCommand(PluginId id, ProviderConCommand *pCommand)
{
}
/**
* @brief Called when Metamod:Source is about to remove a convar.
* This can also be called if ISmmAPI::UnregisterConVar is
* used by a plugin.
*
* @param id Id of the plugin that created the convar.
* @param pVar Pointer to convar that is being removed.
*/
virtual void OnUnlinkConVar(PluginId id, ProviderConVar *pVar)
{
}
}; };
} }
@ -492,13 +518,31 @@ using namespace SourceMM;
g_PLID = id; g_PLID = id;
#define META_LOG g_SMAPI->LogMsg #define META_LOG g_SMAPI->LogMsg
#define META_REGCMD(name) g_SMAPI->RegisterConCommandBase(g_PLAPI, name##_command)
#define META_REGCVAR(var) g_SMAPI->RegisterConCommandBase(g_PLAPI, var)
#define META_UNREGCMD(name) g_SMAPI->UnregisterConCommandBase(g_PLAPI, name##_command)
#define META_UNREGCVAR(var) g_SMAPI->UnregisterConCommandBase(g_PLAPI, var)
#define META_CONPRINT g_SMAPI->ConPrint #define META_CONPRINT g_SMAPI->ConPrint
#define META_CONPRINTF g_SMAPI->ConPrintf #define META_CONPRINTF g_SMAPI->ConPrintf
#if defined META_IS_SOURCE2
#define META_UNREGCMD(name) g_SMAPI->UnregisterConCommand( g_PLAPI, name##_command )
#define META_UNREGCVAR(var) g_SMAPI->UnregisterConVar( g_PLAPI, var )
#define META_CONVAR_REGISTER(flags) ConVar_Register( flags, \
[]( ConVarRefAbstract *ref ) { g_SMAPI->RegisterConVar( g_PLAPI, ref ); }, \
[]( ConCommandRef *ref ) { g_SMAPI->RegisterConCommand( g_PLAPI, ref ); } \
)
#else
// @deprecated since 2.1
#define META_REGCMD(name) g_SMAPI->RegisterConCommandBase(g_PLAPI, name##_command)
// @deprecated since 2.1
#define META_REGCVAR(var) g_SMAPI->RegisterConCommandBase(g_PLAPI, var)
// @deprecated since 2.1
#define META_UNREGCMD(name) g_SMAPI->UnregisterConCommandBase(g_PLAPI, name##_command)
// @deprecated since 2.1
#define META_UNREGCVAR(var) g_SMAPI->UnregisterConCommandBase(g_PLAPI, var)
#define META_REGBASECMD(var) (var->IsCommand() ? g_SMAPI->RegisterConCommand(g_PLAPI, var) : g_SMAPI->RegisterConVar(g_PLAPI, var))
#define META_UNREGBASECMD(var) (var->IsCommand() ? g_SMAPI->UnregisterConCommand(g_PLAPI, var) : g_SMAPI->UnregisterConVar(g_PLAPI, var))
#endif
/* Probably should use this up above someday */ /* Probably should use this up above someday */
#define CONCMD_VARNAME(name) name##_command #define CONCMD_VARNAME(name) name##_command

View File

@ -65,7 +65,7 @@
#define SOURCE_ENGINE_MCV 27 /**< Military Conflict: Vietnam */ #define SOURCE_ENGINE_MCV 27 /**< Military Conflict: Vietnam */
#define SOURCE_ENGINE_CS2 28 /**< Counter-Strike 2 */ #define SOURCE_ENGINE_CS2 28 /**< Counter-Strike 2 */
#define METAMOD_PLAPI_VERSION 16 /**< Version of this header file */ #define METAMOD_PLAPI_VERSION 17 /**< Version of this header file */
#define METAMOD_PLAPI_NAME "ISmmPlugin" /**< Name of the plugin interface */ #define METAMOD_PLAPI_NAME "ISmmPlugin" /**< Name of the plugin interface */
namespace SourceMM namespace SourceMM

View File

@ -919,33 +919,48 @@ const char *MetamodSource::GetVDFDir()
bool MetamodSource::RegisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand) bool MetamodSource::RegisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand)
{ {
if (provider->IsConCommandBaseACommand(pCommand)) if (provider->IsConCommandBaseACommand(pCommand))
{ return RegisterConCommand(plugin, (ProviderConCommand *)pCommand);
g_PluginMngr.AddPluginCmd(plugin, pCommand);
}
else else
{ return RegisterConVar(plugin, (ProviderConVar *)pCommand);
g_PluginMngr.AddPluginCvar(plugin, pCommand);
}
return provider->RegisterConCommandBase(pCommand);
} }
void MetamodSource::UnregisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand) void MetamodSource::UnregisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand)
{ {
if (provider->IsConCommandBaseACommand(pCommand)) if (provider->IsConCommandBaseACommand(pCommand))
{ UnregisterConCommand(plugin, (ProviderConCommand *)pCommand);
g_PluginMngr.RemovePluginCmd(plugin, pCommand);
}
else else
{ UnregisterConVar(plugin, (ProviderConVar *)pCommand);
g_PluginMngr.RemovePluginCvar(plugin, pCommand);
}
CPluginManager::CPlugin *pOrig = g_PluginMngr.FindByAPI(plugin);
UnregisterConCommandBase(pOrig ? pOrig->m_Id : 0, pCommand);
} }
void MetamodSource::UnregisterConCommandBase(PluginId id, ConCommandBase *pCommand) bool MetamodSource::RegisterConCommand(ISmmPlugin *plugin, ProviderConCommand *pCommand)
{
g_PluginMngr.AddPluginCmd(plugin, pCommand);
return provider->RegisterConCommand(pCommand);
}
bool MetamodSource::RegisterConVar(ISmmPlugin *plugin, ProviderConVar *pVar)
{
g_PluginMngr.AddPluginCvar(plugin, pVar);
return provider->RegisterConVar(pVar);
}
void MetamodSource::UnregisterConCommand(ISmmPlugin *plugin, ProviderConCommand *pCommand)
{
CPluginManager::CPlugin *pOrig = g_PluginMngr.FindByAPI(plugin);
g_PluginMngr.RemovePluginCmd(plugin, pCommand);
UnregisterConCommand(pOrig ? pOrig->m_Id : 0, pCommand);
}
void MetamodSource::UnregisterConVar(ISmmPlugin *plugin, ProviderConVar *pVar)
{
CPluginManager::CPlugin *pOrig = g_PluginMngr.FindByAPI(plugin);
g_PluginMngr.RemovePluginCvar(plugin, pVar);
UnregisterConVar(pOrig ? pOrig->m_Id : 0, pVar);
}
void MetamodSource::UnregisterConCommand(PluginId id, ProviderConCommand *pCommand)
{ {
PluginIter iter; PluginIter iter;
CPluginManager::CPlugin *pPlugin; CPluginManager::CPlugin *pPlugin;
@ -963,16 +978,74 @@ void MetamodSource::UnregisterConCommandBase(PluginId id, ConCommandBase *pComma
{ {
continue; continue;
} }
for (event=pPlugin->m_Events.begin();
event!=pPlugin->m_Events.end(); if(pPlugin->m_API->GetApiVersion() < 17)
{
for(event=pPlugin->m_Events.begin();
event != pPlugin->m_Events.end();
event++) event++)
{ {
pML = (*event); pML = (*event);
pML->OnUnlinkConCommandBase(id, pCommand); pML->OnUnlinkConCommandBase(id, (ConCommandBase *)pCommand);
}
}
else
{
for(event=pPlugin->m_Events.begin();
event != pPlugin->m_Events.end();
event++)
{
pML = (*event);
pML->OnUnlinkConCommand(id, pCommand);
}
} }
} }
return provider->UnregisterConCommandBase(pCommand); return provider->UnregisterConCommand(pCommand);
}
void MetamodSource::UnregisterConVar(PluginId id, ProviderConVar *pVar)
{
PluginIter iter;
CPluginManager::CPlugin *pPlugin;
List<IMetamodListener *>::iterator event;
IMetamodListener *pML;
for(iter=g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++)
{
pPlugin = (*iter);
if(pPlugin->m_Status < Pl_Paused)
{
continue;
}
/* Only valid for plugins >= 12 (v1:6, SourceMM 1.5) */
if(pPlugin->m_API->GetApiVersion() < 12)
{
continue;
}
if(pPlugin->m_API->GetApiVersion() < 17)
{
for(event=pPlugin->m_Events.begin();
event != pPlugin->m_Events.end();
event++)
{
pML = (*event);
pML->OnUnlinkConCommandBase(id, (ConCommandBase *)pVar);
}
}
else
{
for(event=pPlugin->m_Events.begin();
event != pPlugin->m_Events.end();
event++)
{
pML = (*event);
pML->OnUnlinkConVar(id, pVar);
}
}
}
return provider->UnregisterConVar(pVar);
} }
int MetamodSource::GetUserMessageCount() int MetamodSource::GetUserMessageCount()

View File

@ -49,7 +49,7 @@ using namespace SourceMM;
#define SOURCEMM_VERSION SVN_FILE_VERSION_STRING #define SOURCEMM_VERSION SVN_FILE_VERSION_STRING
#define SOURCEMM_DATE __DATE__ #define SOURCEMM_DATE __DATE__
#define METAMOD_API_MAJOR 2 /* increase this on a breaking change */ #define METAMOD_API_MAJOR 2 /* increase this on a breaking change */
#define METAMOD_API_MINOR 0 /* increase this on a non-breaking API change */ #define METAMOD_API_MINOR 1 /* increase this on a non-breaking API change */
class MetamodSource : public ISmmAPI class MetamodSource : public ISmmAPI
{ {
@ -62,6 +62,10 @@ public: // ISmmAPI
CGlobalVars *GetCGlobals() override; CGlobalVars *GetCGlobals() override;
bool RegisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand) override; bool RegisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand) override;
void UnregisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand) override; void UnregisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand) override;
bool RegisterConCommand(ISmmPlugin *plugin, ProviderConCommand *pCommand) override;
bool RegisterConVar(ISmmPlugin *plugin, ProviderConVar *pCvar) override;
void UnregisterConCommand(ISmmPlugin *plugin, ProviderConCommand *pCommand) override;
void UnregisterConVar(ISmmPlugin *plugin, ProviderConVar *pCvar) override;
void ConPrint(const char *str) override; void ConPrint(const char *str) override;
void ConPrintf(const char *fmt, ...) override; void ConPrintf(const char *fmt, ...) override;
void GetApiVersions(int &major, int &minor, int &plvers, int &plmin) override; void GetApiVersions(int &major, int &minor, int &plvers, int &plmin) override;
@ -91,7 +95,8 @@ public:
const char *GetGameBinaryPath(); const char *GetGameBinaryPath();
const char *GetPluginsFile(); const char *GetPluginsFile();
const char *GetVDFDir(); const char *GetVDFDir();
void UnregisterConCommandBase(PluginId id, ConCommandBase *pCommand); void UnregisterConCommand(PluginId id, ProviderConCommand *pCommand);
void UnregisterConVar(PluginId id, ProviderConVar *pVar);
void NotifyVSPListening(IServerPluginCallbacks *callbacks, int version); void NotifyVSPListening(IServerPluginCallbacks *callbacks, int version);
const char* GetGameDLLInterfaceName() const; const char* GetGameDLLInterfaceName() const;
void SetGameDLLInfo(CreateInterfaceFn serverFactory, const char *pGameDllIfaceName, int version, bool loaded); void SetGameDLLInfo(CreateInterfaceFn serverFactory, const char *pGameDllIfaceName, int version, bool loaded);

View File

@ -240,7 +240,7 @@ bool Command_Meta(IMetamodSourceCommandInfo *info)
else else
{ {
CONMSG("Console commands for %s:\n", pl->m_API->GetName()); CONMSG("Console commands for %s:\n", pl->m_API->GetName());
List<ConCommandBase *>::iterator ci; List<ProviderConCommand *>::iterator ci;
size_t count = 0; size_t count = 0;
for (ci=pl->m_Cmds.begin(); ci!=pl->m_Cmds.end(); ci++) for (ci=pl->m_Cmds.begin(); ci!=pl->m_Cmds.end(); ci++)
@ -277,7 +277,7 @@ bool Command_Meta(IMetamodSourceCommandInfo *info)
else else
{ {
CONMSG("Registered cvars for %s:\n", pl->m_API->GetName()); CONMSG("Registered cvars for %s:\n", pl->m_API->GetName());
List<ConCommandBase *>::iterator ci; List<ProviderConVar *>::iterator ci;
size_t count = 0; size_t count = 0;
for (ci=pl->m_Cvars.begin(); ci!=pl->m_Cvars.end(); ci++) for (ci=pl->m_Cvars.begin(); ci!=pl->m_Cvars.end(); ci++)

View File

@ -802,7 +802,7 @@ PluginIter CPluginManager::_end()
return m_Plugins.end(); return m_Plugins.end();
} }
void CPluginManager::AddPluginCvar(ISmmPlugin *api, ConCommandBase *pCvar) void CPluginManager::AddPluginCvar(ISmmPlugin *api, ProviderConVar *pCvar)
{ {
CPlugin *pl = FindByAPI(api); CPlugin *pl = FindByAPI(api);
@ -814,7 +814,7 @@ void CPluginManager::AddPluginCvar(ISmmPlugin *api, ConCommandBase *pCvar)
pl->m_Cvars.push_back(pCvar); pl->m_Cvars.push_back(pCvar);
} }
void CPluginManager::AddPluginCmd(ISmmPlugin *api, ConCommandBase *pCmd) void CPluginManager::AddPluginCmd(ISmmPlugin *api, ProviderConCommand *pCmd)
{ {
CPlugin *pl = FindByAPI(api); CPlugin *pl = FindByAPI(api);
@ -826,7 +826,7 @@ void CPluginManager::AddPluginCmd(ISmmPlugin *api, ConCommandBase *pCmd)
pl->m_Cmds.push_back(pCmd); pl->m_Cmds.push_back(pCmd);
} }
void CPluginManager::RemovePluginCvar(ISmmPlugin *api, ConCommandBase *pCvar) void CPluginManager::RemovePluginCvar(ISmmPlugin *api, ProviderConVar *pCvar)
{ {
CPlugin *pl = FindByAPI(api); CPlugin *pl = FindByAPI(api);
@ -838,7 +838,7 @@ void CPluginManager::RemovePluginCvar(ISmmPlugin *api, ConCommandBase *pCvar)
pl->m_Cvars.remove(pCvar); pl->m_Cvars.remove(pCvar);
} }
void CPluginManager::RemovePluginCmd(ISmmPlugin *api, ConCommandBase *pCmd) void CPluginManager::RemovePluginCmd(ISmmPlugin *api, ProviderConCommand *pCmd)
{ {
CPlugin *pl = FindByAPI(api); CPlugin *pl = FindByAPI(api);
@ -852,18 +852,16 @@ void CPluginManager::RemovePluginCmd(ISmmPlugin *api, ConCommandBase *pCmd)
void CPluginManager::UnregAllConCmds(CPlugin *pl) void CPluginManager::UnregAllConCmds(CPlugin *pl)
{ {
SourceHook::List<ConCommandBase *>::iterator i;
/* :TODO: */ /* :TODO: */
for (i=pl->m_Cvars.begin(); i!=pl->m_Cvars.end(); i++) for (auto i=pl->m_Cvars.begin(); i!=pl->m_Cvars.end(); i++)
{ {
g_Metamod.UnregisterConCommandBase(pl->m_Id, (*i) ); g_Metamod.UnregisterConVar(pl->m_Id, (*i) );
} }
pl->m_Cvars.clear(); pl->m_Cvars.clear();
for (i=pl->m_Cmds.begin(); i!=pl->m_Cmds.end(); i++) for (auto i=pl->m_Cmds.begin(); i!=pl->m_Cmds.end(); i++)
{ {
g_Metamod.UnregisterConCommandBase(pl->m_Id, (*i) ); g_Metamod.UnregisterConCommand(pl->m_Id, (*i) );
} }
pl->m_Cmds.clear(); pl->m_Cmds.clear();
} }

View File

@ -90,8 +90,8 @@ public:
PluginId m_Source; PluginId m_Source;
ISmmPlugin *m_API; ISmmPlugin *m_API;
HINSTANCE m_Lib; HINSTANCE m_Lib;
SourceHook::List<ConCommandBase *> m_Cvars; SourceHook::List<ProviderConVar *> m_Cvars;
SourceHook::List<ConCommandBase *> m_Cmds; SourceHook::List<ProviderConCommand *> m_Cmds;
SourceHook::List<IMetamodListener *> m_Events; SourceHook::List<IMetamodListener *> m_Events;
METAMOD_FN_UNLOAD m_UnloadFn; METAMOD_FN_UNLOAD m_UnloadFn;
}; };
@ -111,10 +111,10 @@ public:
bool QueryRunning(PluginId id, char *error, size_t maxlength); bool QueryRunning(PluginId id, char *error, size_t maxlength);
bool QueryHandle(PluginId id, void **handle); bool QueryHandle(PluginId id, void **handle);
void AddPluginCvar(ISmmPlugin *api, ConCommandBase *pCvar); void AddPluginCvar(ISmmPlugin *api, ProviderConVar *pCvar);
void AddPluginCmd(ISmmPlugin *api, ConCommandBase *pCmd); void AddPluginCmd(ISmmPlugin *api, ProviderConCommand *pCmd);
void RemovePluginCvar(ISmmPlugin *api, ConCommandBase *pCvar); void RemovePluginCvar(ISmmPlugin *api, ProviderConVar *pCvar);
void RemovePluginCmd(ISmmPlugin *api, ConCommandBase *pCmd); void RemovePluginCmd(ISmmPlugin *api, ProviderConCommand *pCmd);
/** /**
* @brief Finds a plugin by Id * @brief Finds a plugin by Id

View File

@ -254,19 +254,34 @@ namespace SourceMM
virtual const char *GetGameDescription() =0; virtual const char *GetGameDescription() =0;
/** /**
* @brief Registers a ConCommandBase. * @brief Registers a ConCommand.
* *
* @param pCommand ConCommandBase to register. * @param pCommand ConCommand to register.
* @return True if successful, false otherwise. * @return True if successful, false otherwise.
*/ */
virtual bool RegisterConCommandBase(ConCommandBase *pCommand) =0; virtual bool RegisterConCommand(ProviderConCommand *pCommand) =0;
/** /**
* @brief Unregisters a ConCommandBase. * @brief Registers a ConVar.
* *
* @param pCommand ConCommandBase to unlink. * @param pVar ConVar to register.
* @return True if successful, false otherwise.
*/ */
virtual void UnregisterConCommandBase(ConCommandBase *pCommand) =0; virtual bool RegisterConVar(ProviderConVar *pVar) =0;
/**
* @brief Unregisters a ConCommand.
*
* @param pCommand ConCommand to unlink.
*/
virtual void UnregisterConCommand(ProviderConCommand *pCommand) =0;
/**
* @brief Unregisters a ConVar.
*
* @param pVar ConVar to unlink.
*/
virtual void UnregisterConVar(ProviderConVar *pVar) =0;
/** /**
* @brief Returns whether a ConCommandBase is a command or not. * @brief Returns whether a ConCommandBase is a command or not.

View File

@ -68,8 +68,10 @@ public: // Must implement
int flags) override = 0; int flags) override = 0;
virtual const char* GetConVarString(MetamodSourceConVar *convar) override = 0; virtual const char* GetConVarString(MetamodSourceConVar *convar) override = 0;
virtual void SetConVarString(MetamodSourceConVar *convar, const char* str) override = 0; virtual void SetConVarString(MetamodSourceConVar *convar, const char* str) override = 0;
virtual bool RegisterConCommandBase(ConCommandBase* pCommand) override = 0; virtual bool RegisterConCommand(ProviderConCommand *pCommand) override = 0;
virtual void UnregisterConCommandBase(ConCommandBase* pCommand) override = 0; virtual bool RegisterConVar(ProviderConVar *pVar) override = 0;
virtual void UnregisterConCommand(ProviderConCommand *pCommand) override = 0;
virtual void UnregisterConVar(ProviderConVar *pVar) override = 0;
virtual bool IsConCommandBaseACommand(ConCommandBase* pCommand) override = 0; virtual bool IsConCommandBaseACommand(ConCommandBase* pCommand) override = 0;
public: // May implement/override (stubbed) public: // May implement/override (stubbed)
virtual int GetUserMessageCount() override { return -1; } virtual int GetUserMessageCount() override { return -1; }

View File

@ -385,14 +385,24 @@ bool SourceProvider::IsConCommandBaseACommand(ConCommandBase* pCommand)
return pCommand->IsCommand(); return pCommand->IsCommand();
} }
bool SourceProvider::RegisterConCommandBase(ConCommandBase* pCommand) bool SourceProvider::RegisterConCommand(ProviderConCommand* pCommand)
{ {
return m_ConVarAccessor.Register(pCommand); return m_ConVarAccessor.Register(pCommand);
} }
void SourceProvider::UnregisterConCommandBase(ConCommandBase* pCommand) bool SourceProvider::RegisterConVar(ProviderConVar* pVar)
{ {
return m_ConVarAccessor.Unregister(pCommand); return m_ConVarAccessor.Register(pVar);
}
void SourceProvider::UnregisterConCommand(ProviderConCommand* pCommand)
{
m_ConVarAccessor.Unregister(pCommand);
}
void SourceProvider::UnregisterConVar(ProviderConVar* pVar)
{
m_ConVarAccessor.Unregister(pVar);
} }
MetamodSourceConVar* SourceProvider::CreateConVar(const char* name, MetamodSourceConVar* SourceProvider::CreateConVar(const char* name,

View File

@ -55,8 +55,10 @@ public: // BaseProvider
int flags) override; int flags) override;
virtual const char* GetConVarString(MetamodSourceConVar *convar) override; virtual const char* GetConVarString(MetamodSourceConVar *convar) override;
virtual void SetConVarString(MetamodSourceConVar *convar, const char* str) override; virtual void SetConVarString(MetamodSourceConVar *convar, const char* str) override;
virtual bool RegisterConCommandBase(ConCommandBase* pCommand) override; virtual bool RegisterConCommand(ProviderConCommand *pCommand) override;
virtual void UnregisterConCommandBase(ConCommandBase* pCommand) override; virtual bool RegisterConVar(ProviderConVar *pVar) override;
virtual void UnregisterConCommand(ProviderConCommand *pCommand) override;
virtual void UnregisterConVar(ProviderConVar *pVar) override;
virtual bool IsConCommandBaseACommand(ConCommandBase* pCommand) override; virtual bool IsConCommandBaseACommand(ConCommandBase* pCommand) override;
virtual int GetUserMessageCount() override; virtual int GetUserMessageCount() override;
virtual int FindUserMessage(const char* name, int* size = nullptr) override; virtual int FindUserMessage(const char* name, int* size = nullptr) override;

View File

@ -151,6 +151,9 @@ void Source2Provider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory,
void Source2Provider::Notify_DLLShutdown_Pre() void Source2Provider::Notify_DLLShutdown_Pre()
{ {
for(auto cvar : m_RegisteredConVars)
delete cvar;
ConVar_Unregister(); ConVar_Unregister();
SH_REMOVE_HOOK(IEngineServiceMgr, RegisterLoopMode, enginesvcmgr, SH_MEMBER(this, &Source2Provider::Hook_RegisterLoopMode), false); SH_REMOVE_HOOK(IEngineServiceMgr, RegisterLoopMode, enginesvcmgr, SH_MEMBER(this, &Source2Provider::Hook_RegisterLoopMode), false);
@ -267,48 +270,61 @@ void Source2Provider::ServerCommand(const char* cmd)
const char* Source2Provider::GetConVarString(MetamodSourceConVar *convar) const char* Source2Provider::GetConVarString(MetamodSourceConVar *convar)
{ {
#ifdef S2_CONVAR_UNFINISHED
if (convar == NULL) if (convar == NULL)
{ {
return NULL; return NULL;
} }
return convar->GetString(); auto &value = reinterpret_cast<CConVar<CUtlString> *>(convar)->Get();
#else return !value.IsEmpty() ? value.Get() : nullptr;
return nullptr;
#endif
} }
void Source2Provider::SetConVarString(MetamodSourceConVar *convar, const char* str) void Source2Provider::SetConVarString(MetamodSourceConVar *convar, const char* str)
{ {
#ifdef S2_CONVAR_UNFINISHED reinterpret_cast<CConVar<CUtlString> *>(convar)->Set( str );
convar->SetValue(str);
#endif
} }
bool Source2Provider::IsConCommandBaseACommand(ConCommandBase* pCommand) bool Source2Provider::IsConCommandBaseACommand(ConCommandBase* pCommand)
{ {
#ifdef S2_CONVAR_UNFINISHED // This method shouldn't ever be called on s2 titles
return pCommand->IsCommand();
#else
return false; return false;
#endif
} }
bool Source2Provider::RegisterConCommandBase(ConCommandBase* pCommand) bool Source2Provider::RegisterConCommand(ProviderConCommand* pCommand)
{ {
#ifdef S2_CONVAR_UNFINISHED // Registration is handled by the plugins
return g_SMConVarAccessor.Register(pCommand);
#else // If command has FCVAR_DEVELOPMENTONLY and is registered through our system
// assume that it's previously plugin registered command that was hidden (on plugin reloads for example),
// so remove that flag to make it available again
if(pCommand->IsFlagSet( FCVAR_DEVELOPMENTONLY ))
pCommand->RemoveFlags( FCVAR_DEVELOPMENTONLY );
return true; return true;
#endif
} }
void Source2Provider::UnregisterConCommandBase(ConCommandBase* pCommand) bool Source2Provider::RegisterConVar(ProviderConVar *pVar)
{ {
#ifdef S2_CONVAR_UNFINISHED // Registration is handled by the plugins
return g_SMConVarAccessor.Unregister(pCommand); return true;
#endif }
void Source2Provider::UnregisterConCommand(ProviderConCommand *pCommand)
{
icvar->UnregisterConCommandCallbacks(*pCommand);
// Hide command from the search, as it would still be available otherwise
pCommand->AddFlags( FCVAR_DEVELOPMENTONLY );
}
void Source2Provider::UnregisterConVar(ProviderConVar *pVar)
{
icvar->UnregisterConVarCallbacks(*pVar);
// Invalidate cvar for future use
// This makes it hidden from the search and lets future convar registrations of that
// name to take over its setup
pVar->GetConVarData()->Invalidate();
} }
MetamodSourceConVar* Source2Provider::CreateConVar(const char* name, MetamodSourceConVar* Source2Provider::CreateConVar(const char* name,
@ -316,8 +332,7 @@ MetamodSourceConVar* Source2Provider::CreateConVar(const char* name,
const char* help, const char* help,
int flags) int flags)
{ {
#ifdef S2_CONVAR_UNFINISHED uint64 newflags = 0ll;
int newflags = 0;
if (flags & ConVarFlag_Notify) if (flags & ConVarFlag_Notify)
{ {
newflags |= FCVAR_NOTIFY; newflags |= FCVAR_NOTIFY;
@ -327,14 +342,11 @@ MetamodSourceConVar* Source2Provider::CreateConVar(const char* name,
newflags |= FCVAR_SPONLY; newflags |= FCVAR_SPONLY;
} }
ConVar* pVar = new ConVar(name, defval, newflags, help); CConVar<CUtlString> *pVar = new CConVar<CUtlString>( name, newflags, help, defval );
g_SMConVarAccessor.RegisterConCommandBase(pVar); m_RegisteredConVars.push_back( pVar );
return pVar; return reinterpret_cast<MetamodSourceConVar *>(pVar);
#else
return nullptr;
#endif
} }
class GlobCommand : public IMetamodSourceCommandInfo class GlobCommand : public IMetamodSourceCommandInfo

View File

@ -32,6 +32,7 @@
#include <tier1/utlvector.h> #include <tier1/utlvector.h>
#include <IEngineService.h> #include <IEngineService.h>
#include <string> #include <string>
#include <vector>
// TODO: is this still needed for Dota or CS2 on any platform? // TODO: is this still needed for Dota or CS2 on any platform?
#if SOURCE_ENGINE == SE_DOTA && defined( _WIN32 ) #if SOURCE_ENGINE == SE_DOTA && defined( _WIN32 )
@ -61,8 +62,10 @@ public:
int flags) override; int flags) override;
virtual const char* GetConVarString(MetamodSourceConVar *convar) override; virtual const char* GetConVarString(MetamodSourceConVar *convar) override;
virtual void SetConVarString(MetamodSourceConVar *convar, const char* str) override; virtual void SetConVarString(MetamodSourceConVar *convar, const char* str) override;
virtual bool RegisterConCommandBase(ConCommandBase* pCommand) override; virtual bool RegisterConCommand(ProviderConCommand *pCommand) override;
virtual void UnregisterConCommandBase(ConCommandBase* pCommand) override; virtual bool RegisterConVar(ProviderConVar *pVar) override;
virtual void UnregisterConCommand(ProviderConCommand *pCommand) override;
virtual void UnregisterConVar(ProviderConVar *pVar) override;
virtual bool IsConCommandBaseACommand(ConCommandBase* pCommand) override; virtual bool IsConCommandBaseACommand(ConCommandBase* pCommand) override;
public: public:
#ifdef SHOULD_OVERRIDE_ALLOWDEDICATED_SERVER #ifdef SHOULD_OVERRIDE_ALLOWDEDICATED_SERVER
@ -77,6 +80,7 @@ public:
void Hook_ClientCommand(CPlayerSlot nSlot, const CCommand& args); void Hook_ClientCommand(CPlayerSlot nSlot, const CCommand& args);
private: private:
IFileSystem* baseFs = nullptr; IFileSystem* baseFs = nullptr;
std::vector<CConVar<CUtlString> *> m_RegisteredConVars;
friend void LocalCommand_Meta(const CCommandContext& context, const CCommand& args); friend void LocalCommand_Meta(const CCommandContext& context, const CCommand& args);
}; };

@ -1 +1 @@
Subproject commit 2ae4644db6459ae16da7e3900260bbd6aa7ba03d Subproject commit 37da720ae7ff42fbda3be88c7465860c9e2421fc

View File

@ -54,8 +54,8 @@ class BaseAccessor : public IConCommandBaseAccessor
public: public:
bool RegisterConCommandBase(ConCommandBase *pCommandBase) bool RegisterConCommandBase(ConCommandBase *pCommandBase)
{ {
/* Always call META_REGCVAR instead of going through the engine. */ /* Always call META_REGBASECMD instead of going through the engine. */
return META_REGCVAR(pCommandBase); return META_REGBASECMD(pCommandBase);
} }
} s_BaseAccessor; } s_BaseAccessor;

View File

@ -154,6 +154,7 @@ class MMSPluginConfig(object):
'-fno-strict-aliasing', '-fno-strict-aliasing',
'-Wall', '-Wall',
'-Werror', '-Werror',
'-Wno-sign-compare',
'-Wno-uninitialized', '-Wno-uninitialized',
'-Wno-unused', '-Wno-unused',
'-Wno-switch', '-Wno-switch',

View File

@ -46,10 +46,17 @@ CGlobalVars *GetGameGlobals()
return g_pNetworkServerService->GetIGameServer()->GetGlobals(); return g_pNetworkServerService->GetIGameServer()->GetGlobals();
} }
#if 0 void SampleCvarFChangeCB( CConVar<float> *cvar, CSplitScreenSlot slot, const float *new_val, const float *old_val )
// Currently unavailable, requires hl2sdk work! {
ConVar sample_cvar("sample_cvar", "42", 0); META_CONPRINTF( "Sample convar \"%s\" was changed from %f to %f [%s]\n",
#endif cvar->GetName(), *old_val, *new_val,
// When convar is first initialised with a default value, it would have FCVAR_INITIAL_SETVALUE
// flag set, so you can check for it if needed.
cvar->IsFlagSet( FCVAR_INITIAL_SETVALUE ) ? "initialised" : "change" );
}
CConVar<int> sample_cvari("sample_cvari", FCVAR_NONE, "help string", 42);
CConVar<float> sample_cvarf("sample_cvarf", FCVAR_NONE, "help string", 69.69f, true, 10.0f, true, 100.0f, SampleCvarFChangeCB );
CON_COMMAND_F(sample_command, "Sample command", FCVAR_NONE) CON_COMMAND_F(sample_command, "Sample command", FCVAR_NONE)
{ {
@ -87,7 +94,81 @@ bool SamplePlugin::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen,
META_CONPRINTF( "All hooks started!\n" ); META_CONPRINTF( "All hooks started!\n" );
g_pCVar = icvar; g_pCVar = icvar;
ConVar_Register( FCVAR_RELEASE | FCVAR_CLIENT_CAN_EXECUTE | FCVAR_GAMEDLL ); META_CONVAR_REGISTER( FCVAR_RELEASE | FCVAR_CLIENT_CAN_EXECUTE | FCVAR_GAMEDLL );
// You can get a convar reference to an already existing cvar via CConVarRef.
// This will pre-register it if it's not yet registered and would use default data until
// the actual cvar is registered. You can assert data existance via IsConVarDataAvailable().
// Make sure the type is correct here otherwise it might prevent actual convar being registered,
// since you pre-registered it with a different type or if convar already exists you'd be left with
// an invalid ref, so a check for IsValidRef() is also nice to have.
// Generally with these you should just know the type of a cvar you are referencing beforehand
// and if not, refer to ConVarRefAbstract usage
//
// Side Note: Always make sure you are working with a valid ref (IsValidRef()) before reading/writing to it
// as otherwise you'd be reading/writing off of default convar data which is shared across
// all the invalid convar refs.
CConVarRef<int> ccvar_ref_example( "mp_limitteams" );
if(ccvar_ref_example.IsValidRef() && ccvar_ref_example.IsConVarDataAvailable())
{
META_CONPRINTF( "CConVarRef \"%s\" got value pre = %d [float = %f, bool = %d, string = \"%s\"]\n",
ccvar_ref_example.GetName(), ccvar_ref_example.Get(),
ccvar_ref_example.GetFloat(), ccvar_ref_example.GetBool(),
ccvar_ref_example.GetString() );
// By default if you are using CConVar or CConVarRef you should be using Get()/Set()
// methods to read/write values, as these are templated for the particular type the cvar is of.
// It also is usually faster since it skips all the type conversion logic of non templated methods
ccvar_ref_example.Set( 5 );
// As noted above there are methods that support value conversion between certain types
// so stuff like this is possible on an int typed cvar for example,
// refer to ConVarRefAbstract declaration for more info on these methods
ccvar_ref_example.SetFloat( 8.5f );
META_CONPRINTF( "CConVarRef \"%s\" got value after = %d [float = %f, bool = %d, string = \"%s\"]\n",
ccvar_ref_example.GetName(), ccvar_ref_example.Get(),
ccvar_ref_example.GetFloat(), ccvar_ref_example.GetBool(),
ccvar_ref_example.GetString() );
}
// You can also use ConVarRefAbstract class if you don't want typisation support
// or don't know the actual type used, since you are responsible for picking the correct type there!
// And ConVarRefAbstract won't pre-register the convar in the system, as it acts as a plain ref,
// so make sure to check the ref for validity before usage via IsValidRef()
ConVarRefAbstract cvar_ref_example( "mp_limitteams" );
if(cvar_ref_example.IsValidRef())
{
META_CONPRINTF( "ConVarRefAbstract \"%s\" got value pre [float = %f, bool = %d, string = \"%s\"]\n",
cvar_ref_example.GetName(), cvar_ref_example.GetFloat(), cvar_ref_example.GetBool(), cvar_ref_example.GetString() );
// Since the ref is not typed, you can't use direct Get() and Set() methods,
// instead you need to use methods with type conversion support.
cvar_ref_example.SetFloat( 10.0f );
// If you work with convars of non primitive types, you can also use SetAs() methods
// to try to set the value as a specific type, if type mismatches it would try to do
// conversion if possible and if not it would do nothing.
// There's also an equvialent methods for reading the value, GetAs()
cvar_ref_example.SetAs<Vector>( Vector( 1.0f, 2.0f, 3.0f ) );
// Alternatively you can "promote" plain ref to a typed variant by passing plain ref to a constructor
// but be careful, as there's a type checker in place that would invalidate convar ref
// if cast to a wrong type was attempted, you can check for that either via IsValidRef()
// or IsConVarDataValid() (usually IsValidRef() is enough) afterwards, but generally you should
// just know the correct type of the cvar you are casting to beforehand.
CConVarRef<int> promoted_ref( cvar_ref_example );
if(promoted_ref.IsValidRef() && promoted_ref.IsConVarDataValid())
{
// If the promoted ref is valid, you can use its templated methods like with CConVarRef/CConVar
promoted_ref.Set( 5 );
}
META_CONPRINTF( "ConVarRefAbstract \"%s\" got value after [float = %f, bool = %d, string = \"%s\"]\n",
cvar_ref_example.GetName(), cvar_ref_example.GetFloat(), cvar_ref_example.GetBool(), cvar_ref_example.GetString() );
}
return true; return true;
} }