From ea5fab536fa223396ac4a2dd10409f7784acd5d4 Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Sat, 2 Oct 2021 20:37:58 +0900 Subject: [PATCH 1/9] Added the ability to add callbacks to ConVar that will be called when ConVar is changed. --- src/core/modules/cvars/cvars.h | 96 +++++++++++++++++++++++++++ src/core/modules/cvars/cvars_wrap.cpp | 20 +++++- 2 files changed, 115 insertions(+), 1 deletion(-) mode change 100644 => 100755 src/core/modules/cvars/cvars.h diff --git a/src/core/modules/cvars/cvars.h b/src/core/modules/cvars/cvars.h old mode 100644 new mode 100755 index bfa2079f2..1eb8c9f5a --- a/src/core/modules/cvars/cvars.h +++ b/src/core/modules/cvars/cvars.h @@ -30,8 +30,22 @@ //----------------------------------------------------------------------------- // Includes. //----------------------------------------------------------------------------- +// C++ +#include +#include + #include "convar.h" + #include "utilities/sp_util.h" +#include "modules/listeners/listeners_manager.h" + + +//----------------------------------------------------------------------------- +// Global ConVar changed callback mapping. +//----------------------------------------------------------------------------- +typedef std::vector ChangedCallbacks; +typedef std::unordered_map ConVarMap; +ConVarMap g_ConVarMap; //----------------------------------------------------------------------------- @@ -117,6 +131,88 @@ class ConVarExt pConVar->m_nFlags &= ~FCVAR_NOTIFY; g_pCVar->CallGlobalChangeCallbacks(pConVar, pConVar->GetString(), pConVar->GetFloat()); } + + static void ChangedCallback(IConVar* var, const char* pOldValue, float flOldValue) + { + ConVarMap::iterator map_it = g_ConVarMap.find(var->GetName()); + if (map_it == g_ConVarMap.end()) + return; + + ConVar* pConVar = static_cast(var); + + ChangedCallbacks& callables = map_it->second; + for (ChangedCallbacks::iterator it = callables.begin(); it != callables.end(); ++it) + { + BEGIN_BOOST_PY() + (*it)(ptr(pConVar), pOldValue, pConVar->GetString()); + END_BOOST_PY_NORET() + } + } + + static void AddChangedCallback(ConVar* pConVar, PyObject* pCallable) + { + // Get the object instance of the callable + object oCallable = object(handle<>(borrowed(pCallable))); + + ChangedCallbacks& callables = g_ConVarMap[pConVar->GetName()]; + if (!callables.size()) + { + if (!installed) + { + g_pCVar->InstallGlobalChangeCallback(ChangedCallback); + installed = true; + } + } + else + { + for (ChangedCallbacks::iterator it = callables.begin(); it != callables.end(); ++it) + { + if (is_same_func(oCallable, *it)) + BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback already registered.") + } + } + + callables.push_back(oCallable); + } + + static void RemoveChangedCallback(ConVar* pConVar, PyObject* pCallable) + { + ConVarMap::iterator map_it = g_ConVarMap.find(pConVar->GetName()); + if (map_it == g_ConVarMap.end()) + BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback not registered.") + + // Get the object instance of the callable + object oCallable = object(handle<>(borrowed(pCallable))); + + ChangedCallbacks& callables = map_it->second; + for (ChangedCallbacks::iterator it = callables.begin();;) + { + if(it == callables.end()) + BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback not registered.") + + if (is_same_func(oCallable, *it)) + { + callables.erase(it); + break; + } + else + { + ++it; + } + } + + if (!callables.size()) + { + g_ConVarMap.erase(map_it); + if (!g_ConVarMap.size()) + { + g_pCVar->RemoveGlobalChangeCallback(ChangedCallback); + installed = false; + } + } + } + + static bool installed; }; diff --git a/src/core/modules/cvars/cvars_wrap.cpp b/src/core/modules/cvars/cvars_wrap.cpp index 997d410f6..d96eb4104 100644 --- a/src/core/modules/cvars/cvars_wrap.cpp +++ b/src/core/modules/cvars/cvars_wrap.cpp @@ -45,6 +45,12 @@ extern ICvar* g_pCVar; +//----------------------------------------------------------------------------- +// ConVar extension definition. +//----------------------------------------------------------------------------- +bool ConVarExt::installed = false; + + //----------------------------------------------------------------------------- // Forward declarations. //----------------------------------------------------------------------------- @@ -299,7 +305,19 @@ void export_convar(scope _cvars) &ConVarExt::RemovePublic, "Remove the notify flag and make the console variable no longer public." ) - + + .def("add_changed_callback", + &ConVarExt::AddChangedCallback, + "Add a callable object that will be called when the ConVar is changed.", + args("callable") + ) + + .def("remove_changed_callback", + &ConVarExt::RemoveChangedCallback, + "Remove a callable object that will be called when the ConVar is changed.", + args("callable") + ) + // Special methods... .def("__float__", &ConVar::GetFloat, From 759953f727fac97261e0c9822b2c36fa14a81ea4 Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Sat, 2 Oct 2021 21:17:21 +0900 Subject: [PATCH 2/9] Added ConVarChanged decorator class to cvars. --- .../packages/source-python/cvars/__init__.py | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) mode change 100644 => 100755 addons/source-python/packages/source-python/cvars/__init__.py diff --git a/addons/source-python/packages/source-python/cvars/__init__.py b/addons/source-python/packages/source-python/cvars/__init__.py old mode 100644 new mode 100755 index 66177aede..fdf30f472 --- a/addons/source-python/packages/source-python/cvars/__init__.py +++ b/addons/source-python/packages/source-python/cvars/__init__.py @@ -6,6 +6,8 @@ # >> IMPORTS # ============================================================================= # Source.Python Imports +# Core +from core import AutoUnload # Cvars from _cvars import ConVar from _cvars import _Cvar @@ -24,5 +26,64 @@ # >> ALL DECLARATION # ============================================================================= __all__ = ('ConVar', + 'ConVarChanged', 'cvar', ) + + +# ============================================================================= +# >> CLASSES +# ============================================================================= +class ConVarChanged(AutoUnload): + """ConVarChanged decorator class.""" + + def __init__(self, *convars): + """Store the convars.""" + self._convars = () + self.callback = None + + # Validate convars + if not convars: + raise ValueError('At least one convar is required.') + + _convars = [] + for convar in convars: + if not isinstance(convar, (str, ConVar)): + raise ValueError('Given convar is not ConVar or ConVar name.') + + elif isinstance(convar, str): + convar_name = convar + convar = cvar.find_var(convar_name) + if convar is None: + raise ValueError( + f'"{convar_name}" is not a valid ConVar name.') + + _convars.append(convar) + + self._convars = tuple(_convars) + + def __call__(self, callback): + """Store the callback and add it to convars.""" + # Store the callback + self.callback = callback + + # Loop through all convars + for convar in self._convars: + + # Add the callback + convar.add_changed_callback(self.callback) + + # Return the callback + return self.callback + + def _unload_instance(self): + """Remove the callback from convars.""" + # Was no callback registered? + if self.callback is None: + return + + # Loop through all convars + for convar in self._convars: + + # Remove the callback + convar.remove_changed_callback(self.callback) From 3672a3b2444c5ab704470991e15489f1aec6175f Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Sun, 3 Oct 2021 23:36:55 +0900 Subject: [PATCH 3/9] Fixed incorrect type of ConVarExt::GetMax. --- src/core/modules/cvars/cvars.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/modules/cvars/cvars.h b/src/core/modules/cvars/cvars.h index 1eb8c9f5a..066153bb1 100755 --- a/src/core/modules/cvars/cvars.h +++ b/src/core/modules/cvars/cvars.h @@ -108,7 +108,7 @@ class ConVarExt return fMin; } - static bool GetMax(ConVar* pConVar) + static float GetMax(ConVar* pConVar) { float fMax; pConVar->GetMax(fMax); From 04de099f1a5cae81bf1bedb08ae3d76b527365ab Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Sun, 3 Oct 2021 23:50:45 +0900 Subject: [PATCH 4/9] Added callbacks clean-up. --- src/CMakeLists.txt | 1 + src/core/modules/cvars/cvars.cpp | 209 ++++++++++++++++++++++++++ src/core/modules/cvars/cvars.h | 174 ++------------------- src/core/modules/cvars/cvars_wrap.cpp | 6 - src/core/sp_main.cpp | 4 + 5 files changed, 229 insertions(+), 165 deletions(-) mode change 100644 => 100755 src/CMakeLists.txt create mode 100755 src/core/modules/cvars/cvars.cpp mode change 100644 => 100755 src/core/modules/cvars/cvars_wrap.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt old mode 100644 new mode 100755 index 9bb21297a..889a15441 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -171,6 +171,7 @@ Set(SOURCEPYTHON_CVARS_MODULE_HEADERS ) Set(SOURCEPYTHON_CVARS_MODULE_SOURCES + core/modules/cvars/cvars.cpp core/modules/cvars/cvars_wrap.cpp ) diff --git a/src/core/modules/cvars/cvars.cpp b/src/core/modules/cvars/cvars.cpp new file mode 100755 index 000000000..1d87c0de6 --- /dev/null +++ b/src/core/modules/cvars/cvars.cpp @@ -0,0 +1,209 @@ +/** +* ============================================================================= +* Source Python +* Copyright (C) 2012-2015 Source Python Development Team. All rights reserved. +* ============================================================================= +* +* This program is free software; you can redistribute it and/or modify it under +* the terms of the GNU General Public License, version 3.0, as published by the +* Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +* details. +* +* You should have received a copy of the GNU General Public License along with +* this program. If not, see . +* +* As a special exception, the Source Python Team gives you permission +* to link the code of this program (as well as its derivative works) to +* "Half-Life 2," the "Source Engine," and any Game MODs that run on software +* by the Valve Corporation. You must obey the GNU General Public License in +* all respects for all other code used. Additionally, the Source.Python +* Development Team grants this exception to all derivative works. +*/ + +//----------------------------------------------------------------------------- +// Includes. +//----------------------------------------------------------------------------- +#include "cvars.h" + + +//----------------------------------------------------------------------------- +// Global ConVar changed callback mapping. +//----------------------------------------------------------------------------- +typedef std::vector ChangedCallbacks; +typedef std::unordered_map ConVarMap; +ConVarMap g_ConVarMap; + + +//----------------------------------------------------------------------------- +// ConVar extension class. +//----------------------------------------------------------------------------- +boost::shared_ptr ConVarExt::__init__(const char* name, const char* value, + const char* description, int flags, object min_value, object max_value) +{ + if (!name || name[0] == '\0') + BOOST_RAISE_EXCEPTION(PyExc_ValueError, "An empty string is not a valid ConVar name.") + + float fMin = 0; + float fMax = 0; + + try { + fMin = extract(min_value); + } + catch (...) { + PyErr_Clear(); + } + + try { + fMax = extract(max_value); + } + catch (...) { + PyErr_Clear(); + } + + ConVar *pConVar = g_pCVar->FindVar(name); + if (!pConVar) + { + ConVar* pConVar = new ConVar(strdup(name), strdup(value), flags, + strdup(description), !min_value.is_none(), fMin, !max_value.is_none(), fMax); + + return boost::shared_ptr(pConVar, &NeverDeleteDeleter); + } + + return boost::shared_ptr(pConVar, &NeverDeleteDeleter); +} + +bool ConVarExt::HasMin(ConVar* pConVar) +{ + float fMin; + return pConVar->GetMin(fMin); +} + +bool ConVarExt::HasMax(ConVar* pConVar) +{ + float fMax; + return pConVar->GetMax(fMax); +} + +float ConVarExt::GetMin(ConVar* pConVar) +{ + float fMin; + pConVar->GetMin(fMin); + return fMin; +} + +float ConVarExt::GetMax(ConVar* pConVar) +{ + float fMax; + pConVar->GetMax(fMax); + return fMax; +} + +void ConVarExt::SetValue(ConVar* pConVar, bool bValue) +{ + pConVar->SetValue(bValue); +} + +void ConVarExt::MakePublic(ConVar* pConVar) +{ + pConVar->m_nFlags |= FCVAR_NOTIFY; + g_pCVar->CallGlobalChangeCallbacks(pConVar, pConVar->GetString(), pConVar->GetFloat()); +} + +void ConVarExt::RemovePublic(ConVar* pConVar) +{ + pConVar->m_nFlags &= ~FCVAR_NOTIFY; + g_pCVar->CallGlobalChangeCallbacks(pConVar, pConVar->GetString(), pConVar->GetFloat()); +} + +void ConVarExt::ChangedCallback(IConVar* var, const char* pOldValue, float flOldValue) +{ + ConVarMap::iterator map_it = g_ConVarMap.find(var->GetName()); + if (map_it == g_ConVarMap.end()) + return; + + ConVar* pConVar = static_cast(var); + + ChangedCallbacks& callables = map_it->second; + for (ChangedCallbacks::iterator it = callables.begin(); it != callables.end(); ++it) + { + BEGIN_BOOST_PY() + (*it)(ptr(pConVar), pOldValue, pConVar->GetString()); + END_BOOST_PY_NORET() + } +} + +void ConVarExt::AddChangedCallback(ConVar* pConVar, PyObject* pCallable) +{ + // Get the object instance of the callable + object oCallable = object(handle<>(borrowed(pCallable))); + + ChangedCallbacks& callables = g_ConVarMap[pConVar->GetName()]; + if (!callables.size()) + { + if (!installed) + { + g_pCVar->InstallGlobalChangeCallback(ChangedCallback); + installed = true; + } + } + else + { + for (ChangedCallbacks::iterator it = callables.begin(); it != callables.end(); ++it) + { + if (is_same_func(oCallable, *it)) + BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback already registered.") + } + } + + callables.push_back(oCallable); +} + +void ConVarExt::RemoveChangedCallback(ConVar* pConVar, PyObject* pCallable) +{ + ConVarMap::iterator map_it = g_ConVarMap.find(pConVar->GetName()); + if (map_it == g_ConVarMap.end()) + BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback not registered.") + + // Get the object instance of the callable + object oCallable = object(handle<>(borrowed(pCallable))); + + ChangedCallbacks& callables = map_it->second; + for (ChangedCallbacks::iterator it = callables.begin();;) + { + if(it == callables.end()) + BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback not registered.") + + if (is_same_func(oCallable, *it)) + { + callables.erase(it); + break; + } + else + { + ++it; + } + } + + if (!callables.size()) + { + g_ConVarMap.erase(map_it); + if (!g_ConVarMap.size()) + { + g_pCVar->RemoveGlobalChangeCallback(ChangedCallback); + installed = false; + } + } +} + +void ConVarExt::ClearCallback() +{ + g_ConVarMap.clear(); + if (installed) + g_pCVar->RemoveGlobalChangeCallback(ChangedCallback); +} + +bool ConVarExt::installed = false; diff --git a/src/core/modules/cvars/cvars.h b/src/core/modules/cvars/cvars.h index 066153bb1..8c9f1e4bb 100755 --- a/src/core/modules/cvars/cvars.h +++ b/src/core/modules/cvars/cvars.h @@ -34,20 +34,15 @@ #include #include +// This is required for accessing m_nFlags without patching convar.h +#define private public #include "convar.h" +#undef private #include "utilities/sp_util.h" #include "modules/listeners/listeners_manager.h" -//----------------------------------------------------------------------------- -// Global ConVar changed callback mapping. -//----------------------------------------------------------------------------- -typedef std::vector ChangedCallbacks; -typedef std::unordered_map ConVarMap; -ConVarMap g_ConVarMap; - - //----------------------------------------------------------------------------- // ConVar extension class. //----------------------------------------------------------------------------- @@ -55,162 +50,23 @@ class ConVarExt { public: static boost::shared_ptr __init__(const char* name, const char* value, - const char* description, int flags, object min_value, object max_value) - { - if (!name || name[0] == '\0') - BOOST_RAISE_EXCEPTION(PyExc_ValueError, "An empty string is not a valid ConVar name.") - - float fMin = 0; - float fMax = 0; - - try { - fMin = extract(min_value); - } - catch (...) { - PyErr_Clear(); - } - - try { - fMax = extract(max_value); - } - catch (...) { - PyErr_Clear(); - } - - ConVar *pConVar = g_pCVar->FindVar(name); - if (!pConVar) - { - ConVar* pConVar = new ConVar(strdup(name), strdup(value), flags, - strdup(description), !min_value.is_none(), fMin, !max_value.is_none(), fMax); - - return boost::shared_ptr(pConVar, &NeverDeleteDeleter); - } - - return boost::shared_ptr(pConVar, &NeverDeleteDeleter); - } - - static bool HasMin(ConVar* pConVar) - { - float fMin; - return pConVar->GetMin(fMin); - } - - static bool HasMax(ConVar* pConVar) - { - float fMax; - return pConVar->GetMax(fMax); - } - - static float GetMin(ConVar* pConVar) - { - float fMin; - pConVar->GetMin(fMin); - return fMin; - } - - static float GetMax(ConVar* pConVar) - { - float fMax; - pConVar->GetMax(fMax); - return fMax; - } - - static void SetValue(ConVar* pConVar, bool bValue) - { - pConVar->SetValue(bValue); - } - - static void MakePublic(ConVar* pConVar) - { - pConVar->m_nFlags |= FCVAR_NOTIFY; - g_pCVar->CallGlobalChangeCallbacks(pConVar, pConVar->GetString(), pConVar->GetFloat()); - } - - static void RemovePublic(ConVar* pConVar) - { - pConVar->m_nFlags &= ~FCVAR_NOTIFY; - g_pCVar->CallGlobalChangeCallbacks(pConVar, pConVar->GetString(), pConVar->GetFloat()); - } - - static void ChangedCallback(IConVar* var, const char* pOldValue, float flOldValue) - { - ConVarMap::iterator map_it = g_ConVarMap.find(var->GetName()); - if (map_it == g_ConVarMap.end()) - return; - - ConVar* pConVar = static_cast(var); - - ChangedCallbacks& callables = map_it->second; - for (ChangedCallbacks::iterator it = callables.begin(); it != callables.end(); ++it) - { - BEGIN_BOOST_PY() - (*it)(ptr(pConVar), pOldValue, pConVar->GetString()); - END_BOOST_PY_NORET() - } - } - - static void AddChangedCallback(ConVar* pConVar, PyObject* pCallable) - { - // Get the object instance of the callable - object oCallable = object(handle<>(borrowed(pCallable))); - - ChangedCallbacks& callables = g_ConVarMap[pConVar->GetName()]; - if (!callables.size()) - { - if (!installed) - { - g_pCVar->InstallGlobalChangeCallback(ChangedCallback); - installed = true; - } - } - else - { - for (ChangedCallbacks::iterator it = callables.begin(); it != callables.end(); ++it) - { - if (is_same_func(oCallable, *it)) - BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback already registered.") - } - } - - callables.push_back(oCallable); - } + const char* description, int flags, object min_value, object max_value); - static void RemoveChangedCallback(ConVar* pConVar, PyObject* pCallable) - { - ConVarMap::iterator map_it = g_ConVarMap.find(pConVar->GetName()); - if (map_it == g_ConVarMap.end()) - BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback not registered.") + static bool HasMin(ConVar* pConVar); + static bool HasMax(ConVar* pConVar); - // Get the object instance of the callable - object oCallable = object(handle<>(borrowed(pCallable))); + static float GetMin(ConVar* pConVar); + static float GetMax(ConVar* pConVar); - ChangedCallbacks& callables = map_it->second; - for (ChangedCallbacks::iterator it = callables.begin();;) - { - if(it == callables.end()) - BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback not registered.") + static void SetValue(ConVar* pConVar, bool bValue); - if (is_same_func(oCallable, *it)) - { - callables.erase(it); - break; - } - else - { - ++it; - } - } + static void MakePublic(ConVar* pConVar); + static void RemovePublic(ConVar* pConVar); - if (!callables.size()) - { - g_ConVarMap.erase(map_it); - if (!g_ConVarMap.size()) - { - g_pCVar->RemoveGlobalChangeCallback(ChangedCallback); - installed = false; - } - } - } + static void ChangedCallback(IConVar* var, const char* pOldValue, float flOldValue); + static void AddChangedCallback(ConVar* pConVar, PyObject* pCallable); + static void RemoveChangedCallback(ConVar* pConVar, PyObject* pCallable); + static void ClearCallback(); static bool installed; }; diff --git a/src/core/modules/cvars/cvars_wrap.cpp b/src/core/modules/cvars/cvars_wrap.cpp old mode 100644 new mode 100755 index d96eb4104..f4d66b954 --- a/src/core/modules/cvars/cvars_wrap.cpp +++ b/src/core/modules/cvars/cvars_wrap.cpp @@ -45,12 +45,6 @@ extern ICvar* g_pCVar; -//----------------------------------------------------------------------------- -// ConVar extension definition. -//----------------------------------------------------------------------------- -bool ConVarExt::installed = false; - - //----------------------------------------------------------------------------- // Forward declarations. //----------------------------------------------------------------------------- diff --git a/src/core/sp_main.cpp b/src/core/sp_main.cpp index 679ff8f6a..242d278f6 100755 --- a/src/core/sp_main.cpp +++ b/src/core/sp_main.cpp @@ -58,6 +58,7 @@ #include "manager.h" #include "modules/listeners/listeners_manager.h" +#include "modules/cvars/cvars.h" #include "utilities/conversions.h" #include "modules/entities/entities_entity.h" #include "modules/core/core.h" @@ -401,6 +402,9 @@ void CSourcePython::Unload( void ) DevMsg(1, MSG_PREFIX "Clearing convar changed listener...\n"); GetOnConVarChangedListenerManager()->clear(); + DevMsg(1, MSG_PREFIX "Clearing convar changed callbacks...\n"); + ConVarExt::ClearCallback(); + DevMsg(1, MSG_PREFIX "Unhooking all functions...\n"); GetHookManager()->UnhookAllFunctions(); From 3f0734591468fbfbdb8e51059e4e3b97f6f4358c Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Sun, 3 Oct 2021 23:55:48 +0900 Subject: [PATCH 5/9] Changed ConVarExt::ClearCallback. --- src/core/modules/cvars/cvars.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/modules/cvars/cvars.cpp b/src/core/modules/cvars/cvars.cpp index 1d87c0de6..6bcc4add3 100755 --- a/src/core/modules/cvars/cvars.cpp +++ b/src/core/modules/cvars/cvars.cpp @@ -201,9 +201,12 @@ void ConVarExt::RemoveChangedCallback(ConVar* pConVar, PyObject* pCallable) void ConVarExt::ClearCallback() { - g_ConVarMap.clear(); if (installed) + { + g_ConVarMap.clear(); g_pCVar->RemoveGlobalChangeCallback(ChangedCallback); + installed = false; + } } bool ConVarExt::installed = false; From 96145c7d65ce1f48a6ff94188024ab7c32744685 Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Mon, 4 Oct 2021 21:58:33 +0900 Subject: [PATCH 6/9] Check if the callback can be called. --- addons/source-python/packages/source-python/cvars/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/source-python/packages/source-python/cvars/__init__.py b/addons/source-python/packages/source-python/cvars/__init__.py index fdf30f472..516a2a380 100755 --- a/addons/source-python/packages/source-python/cvars/__init__.py +++ b/addons/source-python/packages/source-python/cvars/__init__.py @@ -64,6 +64,10 @@ def __init__(self, *convars): def __call__(self, callback): """Store the callback and add it to convars.""" + # Is the callback callable? + if not callable(callback): + raise ValueError('Given callback is not callable.') + # Store the callback self.callback = callback From 94e24badfcd2272e854cf010b1c656e15eac8b7f Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Tue, 5 Oct 2021 00:03:36 +0900 Subject: [PATCH 7/9] Changed to check if ConVar is a valid ConVar. --- .../packages/source-python/cvars/__init__.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/addons/source-python/packages/source-python/cvars/__init__.py b/addons/source-python/packages/source-python/cvars/__init__.py index 516a2a380..f9dba0936 100755 --- a/addons/source-python/packages/source-python/cvars/__init__.py +++ b/addons/source-python/packages/source-python/cvars/__init__.py @@ -48,15 +48,16 @@ def __init__(self, *convars): _convars = [] for convar in convars: - if not isinstance(convar, (str, ConVar)): + if isinstance(convar, str): + convar_name = convar + elif isinstance(convar, ConVar): + convar_name = convar.name + else: raise ValueError('Given convar is not ConVar or ConVar name.') - elif isinstance(convar, str): - convar_name = convar - convar = cvar.find_var(convar_name) - if convar is None: - raise ValueError( - f'"{convar_name}" is not a valid ConVar name.') + convar = cvar.find_var(convar_name) + if convar is None: + raise ValueError(f'"{convar_name}" is not a valid ConVar.') _convars.append(convar) From 6fea4b507e9f71e95e2e0837d7737f90a21874be Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Tue, 5 Oct 2021 00:56:42 +0900 Subject: [PATCH 8/9] Revert "Changed to check if ConVar is a valid ConVar." This reverts commit 94e24badfcd2272e854cf010b1c656e15eac8b7f. --- .../packages/source-python/cvars/__init__.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/addons/source-python/packages/source-python/cvars/__init__.py b/addons/source-python/packages/source-python/cvars/__init__.py index f9dba0936..516a2a380 100755 --- a/addons/source-python/packages/source-python/cvars/__init__.py +++ b/addons/source-python/packages/source-python/cvars/__init__.py @@ -48,16 +48,15 @@ def __init__(self, *convars): _convars = [] for convar in convars: - if isinstance(convar, str): - convar_name = convar - elif isinstance(convar, ConVar): - convar_name = convar.name - else: + if not isinstance(convar, (str, ConVar)): raise ValueError('Given convar is not ConVar or ConVar name.') - convar = cvar.find_var(convar_name) - if convar is None: - raise ValueError(f'"{convar_name}" is not a valid ConVar.') + elif isinstance(convar, str): + convar_name = convar + convar = cvar.find_var(convar_name) + if convar is None: + raise ValueError( + f'"{convar_name}" is not a valid ConVar name.') _convars.append(convar) From 080d8cad384ace6658b128f508a46f6778755276 Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Tue, 5 Oct 2021 01:03:49 +0900 Subject: [PATCH 9/9] Changed to raise an exception if ConCommand already exists when creating ConVar. --- src/core/modules/cvars/cvars.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/modules/cvars/cvars.cpp b/src/core/modules/cvars/cvars.cpp index 6bcc4add3..0dc945a32 100755 --- a/src/core/modules/cvars/cvars.cpp +++ b/src/core/modules/cvars/cvars.cpp @@ -67,6 +67,11 @@ boost::shared_ptr ConVarExt::__init__(const char* name, const char* valu ConVar *pConVar = g_pCVar->FindVar(name); if (!pConVar) { + // Find if the command already exists + ConCommand* pConCommand = g_pCVar->FindCommand(name); + if (pConCommand) + BOOST_RAISE_EXCEPTION(PyExc_ValueError, "ConCommand already exists.") + ConVar* pConVar = new ConVar(strdup(name), strdup(value), flags, strdup(description), !min_value.is_none(), fMin, !max_value.is_none(), fMax);