From a0ef30603f768a5f36040c09546681fd8bf42ac9 Mon Sep 17 00:00:00 2001 From: GAMMACASE <31375974+GAMMACASE@users.noreply.github.com> Date: Sat, 15 Feb 2025 22:00:01 +0300 Subject: [PATCH] Add source2 convar/concommand support (#203) Co-authored-by: Nicholas Hastings --- AMBuildScript | 1 + core/AMBuilder | 8 +- core/ISmmAPI.h | 49 +++++++++ core/ISmmPlugin.h | 52 ++++++++- core/ISmmPluginExt.h | 2 +- core/metamod.cpp | 121 +++++++++++++++++---- core/metamod.h | 9 +- core/metamod_console.cpp | 4 +- core/metamod_plugins.cpp | 18 ++- core/metamod_plugins.h | 12 +- core/metamod_provider.h | 27 ++++- core/provider/provider_base.h | 6 +- core/provider/source/provider_source.cpp | 16 ++- core/provider/source/provider_source.h | 6 +- core/provider/source2/provider_source2.cpp | 72 +++++++----- core/provider/source2/provider_source2.h | 8 +- hl2sdk-manifests | 2 +- samples/s1_sample_mm/sample_mm.cpp | 4 +- samples/s2_sample_mm/AMBuildScript | 1 + samples/s2_sample_mm/sample_mm.cpp | 91 +++++++++++++++- 20 files changed, 402 insertions(+), 107 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index 0c8441b..f052473 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -121,6 +121,7 @@ class MMSConfig(object): '-Wall', '-Werror', '-Wno-uninitialized', + '-Wno-sign-compare', '-Wno-unused', '-Wno-switch', '-msse', diff --git a/core/AMBuilder b/core/AMBuilder index 2079e47..97ee60f 100644 --- a/core/AMBuilder +++ b/core/AMBuilder @@ -28,17 +28,15 @@ for sdk_target in MMS.sdk_targets: binary.sources += [ '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: binary.sources += [ 'provider/source/provider_source.cpp', 'provider/source/provider_source_console.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': binary.sources += ['sourcehook/sourcehook_hookmangen_x86.cpp'] diff --git a/core/ISmmAPI.h b/core/ISmmAPI.h index 2c2237d..fdd2ec4 100644 --- a/core/ISmmAPI.h +++ b/core/ISmmAPI.h @@ -41,8 +41,19 @@ class CGlobalVars; struct edict_t; class ConCommandBase; +typedef ConCommandBase ProviderConVar; +typedef ConCommandBase ProviderConCommand; #else #include + +#if defined META_IS_SOURCE2 +typedef ConVarRefAbstract ProviderConVar; +typedef ConCommandRef ProviderConCommand; +class ConCommandBase; +#else +typedef ConCommandBase ProviderConVar; +typedef ConCommandBase ProviderConCommand; +#endif #endif #include @@ -130,6 +141,8 @@ namespace SourceMM /** * @brief Registers a ConCommandBase. + * + * @deprecated since 2.1 * * @param plugin Parent plugin API pointer. * @param pCommand ConCommandBase to register. @@ -139,6 +152,8 @@ namespace SourceMM /** * @brief Unregisters a ConCommandBase. + * + * @deprecated since 2.1 * * @param plugin Parent plugin API pointer. * @param pCommand ConCommandBase to unlink. @@ -400,6 +415,40 @@ namespace SourceMM size_t maxlength, const char *format, 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; }; } diff --git a/core/ISmmPlugin.h b/core/ISmmPlugin.h index f0d185d..b5a2d11 100644 --- a/core/ISmmPlugin.h +++ b/core/ISmmPlugin.h @@ -419,6 +419,8 @@ namespace SourceMM * @brief Called when Metamod:Source is about to remove a concommand or * convar. This can also be called if ISmmAPI::UnregisterConCmdBase is * used by a plugin. + * + * @deprecated since PLAPI 17 * * @param id Id of the plugin that created the concommand or * convar. @@ -428,6 +430,30 @@ namespace SourceMM 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; #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_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 */ #define CONCMD_VARNAME(name) name##_command diff --git a/core/ISmmPluginExt.h b/core/ISmmPluginExt.h index 968ed66..9d755d3 100644 --- a/core/ISmmPluginExt.h +++ b/core/ISmmPluginExt.h @@ -65,7 +65,7 @@ #define SOURCE_ENGINE_MCV 27 /**< Military Conflict: Vietnam */ #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 */ namespace SourceMM diff --git a/core/metamod.cpp b/core/metamod.cpp index 67f58ee..226be81 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -919,33 +919,48 @@ const char *MetamodSource::GetVDFDir() bool MetamodSource::RegisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand) { if (provider->IsConCommandBaseACommand(pCommand)) - { - g_PluginMngr.AddPluginCmd(plugin, pCommand); - } + return RegisterConCommand(plugin, (ProviderConCommand *)pCommand); else - { - g_PluginMngr.AddPluginCvar(plugin, pCommand); - } - - return provider->RegisterConCommandBase(pCommand); + return RegisterConVar(plugin, (ProviderConVar *)pCommand); } void MetamodSource::UnregisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand) { if (provider->IsConCommandBaseACommand(pCommand)) - { - g_PluginMngr.RemovePluginCmd(plugin, pCommand); - } + UnregisterConCommand(plugin, (ProviderConCommand *)pCommand); else - { - g_PluginMngr.RemovePluginCvar(plugin, pCommand); - } - - CPluginManager::CPlugin *pOrig = g_PluginMngr.FindByAPI(plugin); - UnregisterConCommandBase(pOrig ? pOrig->m_Id : 0, pCommand); + UnregisterConVar(plugin, (ProviderConVar *)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; CPluginManager::CPlugin *pPlugin; @@ -963,16 +978,74 @@ void MetamodSource::UnregisterConCommandBase(PluginId id, ConCommandBase *pComma { continue; } - for (event=pPlugin->m_Events.begin(); - event!=pPlugin->m_Events.end(); - event++) + + if(pPlugin->m_API->GetApiVersion() < 17) { - pML = (*event); - pML->OnUnlinkConCommandBase(id, pCommand); + for(event=pPlugin->m_Events.begin(); + event != pPlugin->m_Events.end(); + event++) + { + pML = (*event); + 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::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() diff --git a/core/metamod.h b/core/metamod.h index ad479ac..f25e0c7 100644 --- a/core/metamod.h +++ b/core/metamod.h @@ -49,7 +49,7 @@ using namespace SourceMM; #define SOURCEMM_VERSION SVN_FILE_VERSION_STRING #define SOURCEMM_DATE __DATE__ #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 { @@ -62,6 +62,10 @@ public: // ISmmAPI CGlobalVars *GetCGlobals() override; bool RegisterConCommandBase(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 ConPrintf(const char *fmt, ...) override; void GetApiVersions(int &major, int &minor, int &plvers, int &plmin) override; @@ -91,7 +95,8 @@ public: const char *GetGameBinaryPath(); const char *GetPluginsFile(); 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); const char* GetGameDLLInterfaceName() const; void SetGameDLLInfo(CreateInterfaceFn serverFactory, const char *pGameDllIfaceName, int version, bool loaded); diff --git a/core/metamod_console.cpp b/core/metamod_console.cpp index 0fd08ac..5f1f19c 100644 --- a/core/metamod_console.cpp +++ b/core/metamod_console.cpp @@ -240,7 +240,7 @@ bool Command_Meta(IMetamodSourceCommandInfo *info) else { CONMSG("Console commands for %s:\n", pl->m_API->GetName()); - List::iterator ci; + List::iterator ci; size_t count = 0; for (ci=pl->m_Cmds.begin(); ci!=pl->m_Cmds.end(); ci++) @@ -277,7 +277,7 @@ bool Command_Meta(IMetamodSourceCommandInfo *info) else { CONMSG("Registered cvars for %s:\n", pl->m_API->GetName()); - List::iterator ci; + List::iterator ci; size_t count = 0; for (ci=pl->m_Cvars.begin(); ci!=pl->m_Cvars.end(); ci++) diff --git a/core/metamod_plugins.cpp b/core/metamod_plugins.cpp index ffc1013..8b45798 100644 --- a/core/metamod_plugins.cpp +++ b/core/metamod_plugins.cpp @@ -802,7 +802,7 @@ PluginIter CPluginManager::_end() return m_Plugins.end(); } -void CPluginManager::AddPluginCvar(ISmmPlugin *api, ConCommandBase *pCvar) +void CPluginManager::AddPluginCvar(ISmmPlugin *api, ProviderConVar *pCvar) { CPlugin *pl = FindByAPI(api); @@ -814,7 +814,7 @@ void CPluginManager::AddPluginCvar(ISmmPlugin *api, ConCommandBase *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); @@ -826,7 +826,7 @@ void CPluginManager::AddPluginCmd(ISmmPlugin *api, ConCommandBase *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); @@ -838,7 +838,7 @@ void CPluginManager::RemovePluginCvar(ISmmPlugin *api, ConCommandBase *pCvar) pl->m_Cvars.remove(pCvar); } -void CPluginManager::RemovePluginCmd(ISmmPlugin *api, ConCommandBase *pCmd) +void CPluginManager::RemovePluginCmd(ISmmPlugin *api, ProviderConCommand *pCmd) { CPlugin *pl = FindByAPI(api); @@ -852,18 +852,16 @@ void CPluginManager::RemovePluginCmd(ISmmPlugin *api, ConCommandBase *pCmd) void CPluginManager::UnregAllConCmds(CPlugin *pl) { - SourceHook::List::iterator i; - /* :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(); - 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(); } diff --git a/core/metamod_plugins.h b/core/metamod_plugins.h index 5bf4f90..60c002c 100644 --- a/core/metamod_plugins.h +++ b/core/metamod_plugins.h @@ -90,8 +90,8 @@ public: PluginId m_Source; ISmmPlugin *m_API; HINSTANCE m_Lib; - SourceHook::List m_Cvars; - SourceHook::List m_Cmds; + SourceHook::List m_Cvars; + SourceHook::List m_Cmds; SourceHook::List m_Events; METAMOD_FN_UNLOAD m_UnloadFn; }; @@ -111,10 +111,10 @@ public: bool QueryRunning(PluginId id, char *error, size_t maxlength); bool QueryHandle(PluginId id, void **handle); - void AddPluginCvar(ISmmPlugin *api, ConCommandBase *pCvar); - void AddPluginCmd(ISmmPlugin *api, ConCommandBase *pCmd); - void RemovePluginCvar(ISmmPlugin *api, ConCommandBase *pCvar); - void RemovePluginCmd(ISmmPlugin *api, ConCommandBase *pCmd); + void AddPluginCvar(ISmmPlugin *api, ProviderConVar *pCvar); + void AddPluginCmd(ISmmPlugin *api, ProviderConCommand *pCmd); + void RemovePluginCvar(ISmmPlugin *api, ProviderConVar *pCvar); + void RemovePluginCmd(ISmmPlugin *api, ProviderConCommand *pCmd); /** * @brief Finds a plugin by Id diff --git a/core/metamod_provider.h b/core/metamod_provider.h index 2c12a2e..e29ccc0 100644 --- a/core/metamod_provider.h +++ b/core/metamod_provider.h @@ -254,19 +254,34 @@ namespace SourceMM 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. */ - 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. diff --git a/core/provider/provider_base.h b/core/provider/provider_base.h index 413a5cf..3c5d18e 100644 --- a/core/provider/provider_base.h +++ b/core/provider/provider_base.h @@ -68,8 +68,10 @@ public: // Must implement int flags) override = 0; virtual const char* GetConVarString(MetamodSourceConVar *convar) override = 0; virtual void SetConVarString(MetamodSourceConVar *convar, const char* str) override = 0; - virtual bool RegisterConCommandBase(ConCommandBase* pCommand) override = 0; - virtual void UnregisterConCommandBase(ConCommandBase* pCommand) override = 0; + virtual bool RegisterConCommand(ProviderConCommand *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; public: // May implement/override (stubbed) virtual int GetUserMessageCount() override { return -1; } diff --git a/core/provider/source/provider_source.cpp b/core/provider/source/provider_source.cpp index 181b085..96247e7 100644 --- a/core/provider/source/provider_source.cpp +++ b/core/provider/source/provider_source.cpp @@ -385,14 +385,24 @@ bool SourceProvider::IsConCommandBaseACommand(ConCommandBase* pCommand) return pCommand->IsCommand(); } -bool SourceProvider::RegisterConCommandBase(ConCommandBase* pCommand) +bool SourceProvider::RegisterConCommand(ProviderConCommand* 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, diff --git a/core/provider/source/provider_source.h b/core/provider/source/provider_source.h index a74522b..db302ac 100644 --- a/core/provider/source/provider_source.h +++ b/core/provider/source/provider_source.h @@ -55,8 +55,10 @@ public: // BaseProvider int flags) override; virtual const char* GetConVarString(MetamodSourceConVar *convar) override; virtual void SetConVarString(MetamodSourceConVar *convar, const char* str) override; - virtual bool RegisterConCommandBase(ConCommandBase* pCommand) override; - virtual void UnregisterConCommandBase(ConCommandBase* pCommand) override; + virtual bool RegisterConCommand(ProviderConCommand *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 int GetUserMessageCount() override; virtual int FindUserMessage(const char* name, int* size = nullptr) override; diff --git a/core/provider/source2/provider_source2.cpp b/core/provider/source2/provider_source2.cpp index 18c75e4..f5da640 100644 --- a/core/provider/source2/provider_source2.cpp +++ b/core/provider/source2/provider_source2.cpp @@ -151,6 +151,9 @@ void Source2Provider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, void Source2Provider::Notify_DLLShutdown_Pre() { + for(auto cvar : m_RegisteredConVars) + delete cvar; + ConVar_Unregister(); 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) { -#ifdef S2_CONVAR_UNFINISHED if (convar == NULL) { return NULL; } - return convar->GetString(); -#else - return nullptr; -#endif + auto &value = reinterpret_cast *>(convar)->Get(); + return !value.IsEmpty() ? value.Get() : nullptr; } void Source2Provider::SetConVarString(MetamodSourceConVar *convar, const char* str) { -#ifdef S2_CONVAR_UNFINISHED - convar->SetValue(str); -#endif + reinterpret_cast *>(convar)->Set( str ); } bool Source2Provider::IsConCommandBaseACommand(ConCommandBase* pCommand) { -#ifdef S2_CONVAR_UNFINISHED - return pCommand->IsCommand(); -#else + // This method shouldn't ever be called on s2 titles return false; -#endif } -bool Source2Provider::RegisterConCommandBase(ConCommandBase* pCommand) +bool Source2Provider::RegisterConCommand(ProviderConCommand* pCommand) { -#ifdef S2_CONVAR_UNFINISHED - return g_SMConVarAccessor.Register(pCommand); -#else + // Registration is handled by the plugins + + // 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; -#endif } -void Source2Provider::UnregisterConCommandBase(ConCommandBase* pCommand) +bool Source2Provider::RegisterConVar(ProviderConVar *pVar) { -#ifdef S2_CONVAR_UNFINISHED - return g_SMConVarAccessor.Unregister(pCommand); -#endif + // Registration is handled by the plugins + return true; +} + +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, @@ -316,8 +332,7 @@ MetamodSourceConVar* Source2Provider::CreateConVar(const char* name, const char* help, int flags) { -#ifdef S2_CONVAR_UNFINISHED - int newflags = 0; + uint64 newflags = 0ll; if (flags & ConVarFlag_Notify) { newflags |= FCVAR_NOTIFY; @@ -327,14 +342,11 @@ MetamodSourceConVar* Source2Provider::CreateConVar(const char* name, newflags |= FCVAR_SPONLY; } - ConVar* pVar = new ConVar(name, defval, newflags, help); + CConVar *pVar = new CConVar( name, newflags, help, defval ); + + m_RegisteredConVars.push_back( pVar ); - g_SMConVarAccessor.RegisterConCommandBase(pVar); - - return pVar; -#else - return nullptr; -#endif + return reinterpret_cast(pVar); } class GlobCommand : public IMetamodSourceCommandInfo diff --git a/core/provider/source2/provider_source2.h b/core/provider/source2/provider_source2.h index 6f83311..4363395 100644 --- a/core/provider/source2/provider_source2.h +++ b/core/provider/source2/provider_source2.h @@ -32,6 +32,7 @@ #include #include #include +#include // TODO: is this still needed for Dota or CS2 on any platform? #if SOURCE_ENGINE == SE_DOTA && defined( _WIN32 ) @@ -61,8 +62,10 @@ public: int flags) override; virtual const char* GetConVarString(MetamodSourceConVar *convar) override; virtual void SetConVarString(MetamodSourceConVar *convar, const char* str) override; - virtual bool RegisterConCommandBase(ConCommandBase* pCommand) override; - virtual void UnregisterConCommandBase(ConCommandBase* pCommand) override; + virtual bool RegisterConCommand(ProviderConCommand *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; public: #ifdef SHOULD_OVERRIDE_ALLOWDEDICATED_SERVER @@ -77,6 +80,7 @@ public: void Hook_ClientCommand(CPlayerSlot nSlot, const CCommand& args); private: IFileSystem* baseFs = nullptr; + std::vector *> m_RegisteredConVars; friend void LocalCommand_Meta(const CCommandContext& context, const CCommand& args); }; diff --git a/hl2sdk-manifests b/hl2sdk-manifests index 2ae4644..37da720 160000 --- a/hl2sdk-manifests +++ b/hl2sdk-manifests @@ -1 +1 @@ -Subproject commit 2ae4644db6459ae16da7e3900260bbd6aa7ba03d +Subproject commit 37da720ae7ff42fbda3be88c7465860c9e2421fc diff --git a/samples/s1_sample_mm/sample_mm.cpp b/samples/s1_sample_mm/sample_mm.cpp index 01951ac..deeb79b 100644 --- a/samples/s1_sample_mm/sample_mm.cpp +++ b/samples/s1_sample_mm/sample_mm.cpp @@ -54,8 +54,8 @@ class BaseAccessor : public IConCommandBaseAccessor public: bool RegisterConCommandBase(ConCommandBase *pCommandBase) { - /* Always call META_REGCVAR instead of going through the engine. */ - return META_REGCVAR(pCommandBase); + /* Always call META_REGBASECMD instead of going through the engine. */ + return META_REGBASECMD(pCommandBase); } } s_BaseAccessor; diff --git a/samples/s2_sample_mm/AMBuildScript b/samples/s2_sample_mm/AMBuildScript index 26b7a5c..87c19ac 100644 --- a/samples/s2_sample_mm/AMBuildScript +++ b/samples/s2_sample_mm/AMBuildScript @@ -154,6 +154,7 @@ class MMSPluginConfig(object): '-fno-strict-aliasing', '-Wall', '-Werror', + '-Wno-sign-compare', '-Wno-uninitialized', '-Wno-unused', '-Wno-switch', diff --git a/samples/s2_sample_mm/sample_mm.cpp b/samples/s2_sample_mm/sample_mm.cpp index 65ae338..a217afc 100644 --- a/samples/s2_sample_mm/sample_mm.cpp +++ b/samples/s2_sample_mm/sample_mm.cpp @@ -46,10 +46,17 @@ CGlobalVars *GetGameGlobals() return g_pNetworkServerService->GetIGameServer()->GetGlobals(); } -#if 0 -// Currently unavailable, requires hl2sdk work! -ConVar sample_cvar("sample_cvar", "42", 0); -#endif +void SampleCvarFChangeCB( CConVar *cvar, CSplitScreenSlot slot, const float *new_val, const float *old_val ) +{ + META_CONPRINTF( "Sample convar \"%s\" was changed from %f to %f [%s]\n", + 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 sample_cvari("sample_cvari", FCVAR_NONE, "help string", 42); +CConVar 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) { @@ -87,7 +94,81 @@ bool SamplePlugin::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, META_CONPRINTF( "All hooks started!\n" ); 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 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( 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 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; }