Skip to content

Commit 04de099

Browse files
committed
Added callbacks clean-up.
1 parent 3672a3b commit 04de099

File tree

5 files changed

+229
-165
lines changed

5 files changed

+229
-165
lines changed

src/CMakeLists.txt

100644100755
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ Set(SOURCEPYTHON_CVARS_MODULE_HEADERS
171171
)
172172

173173
Set(SOURCEPYTHON_CVARS_MODULE_SOURCES
174+
core/modules/cvars/cvars.cpp
174175
core/modules/cvars/cvars_wrap.cpp
175176
)
176177

src/core/modules/cvars/cvars.cpp

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/**
2+
* =============================================================================
3+
* Source Python
4+
* Copyright (C) 2012-2015 Source Python Development Team. All rights reserved.
5+
* =============================================================================
6+
*
7+
* This program is free software; you can redistribute it and/or modify it under
8+
* the terms of the GNU General Public License, version 3.0, as published by the
9+
* Free Software Foundation.
10+
*
11+
* This program is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14+
* details.
15+
*
16+
* You should have received a copy of the GNU General Public License along with
17+
* this program. If not, see <http://www.gnu.org/licenses/>.
18+
*
19+
* As a special exception, the Source Python Team gives you permission
20+
* to link the code of this program (as well as its derivative works) to
21+
* "Half-Life 2," the "Source Engine," and any Game MODs that run on software
22+
* by the Valve Corporation. You must obey the GNU General Public License in
23+
* all respects for all other code used. Additionally, the Source.Python
24+
* Development Team grants this exception to all derivative works.
25+
*/
26+
27+
//-----------------------------------------------------------------------------
28+
// Includes.
29+
//-----------------------------------------------------------------------------
30+
#include "cvars.h"
31+
32+
33+
//-----------------------------------------------------------------------------
34+
// Global ConVar changed callback mapping.
35+
//-----------------------------------------------------------------------------
36+
typedef std::vector<object> ChangedCallbacks;
37+
typedef std::unordered_map<std::string, ChangedCallbacks> ConVarMap;
38+
ConVarMap g_ConVarMap;
39+
40+
41+
//-----------------------------------------------------------------------------
42+
// ConVar extension class.
43+
//-----------------------------------------------------------------------------
44+
boost::shared_ptr<ConVar> ConVarExt::__init__(const char* name, const char* value,
45+
const char* description, int flags, object min_value, object max_value)
46+
{
47+
if (!name || name[0] == '\0')
48+
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "An empty string is not a valid ConVar name.")
49+
50+
float fMin = 0;
51+
float fMax = 0;
52+
53+
try {
54+
fMin = extract<float>(min_value);
55+
}
56+
catch (...) {
57+
PyErr_Clear();
58+
}
59+
60+
try {
61+
fMax = extract<float>(max_value);
62+
}
63+
catch (...) {
64+
PyErr_Clear();
65+
}
66+
67+
ConVar *pConVar = g_pCVar->FindVar(name);
68+
if (!pConVar)
69+
{
70+
ConVar* pConVar = new ConVar(strdup(name), strdup(value), flags,
71+
strdup(description), !min_value.is_none(), fMin, !max_value.is_none(), fMax);
72+
73+
return boost::shared_ptr<ConVar>(pConVar, &NeverDeleteDeleter<ConVar *>);
74+
}
75+
76+
return boost::shared_ptr<ConVar>(pConVar, &NeverDeleteDeleter<ConVar *>);
77+
}
78+
79+
bool ConVarExt::HasMin(ConVar* pConVar)
80+
{
81+
float fMin;
82+
return pConVar->GetMin(fMin);
83+
}
84+
85+
bool ConVarExt::HasMax(ConVar* pConVar)
86+
{
87+
float fMax;
88+
return pConVar->GetMax(fMax);
89+
}
90+
91+
float ConVarExt::GetMin(ConVar* pConVar)
92+
{
93+
float fMin;
94+
pConVar->GetMin(fMin);
95+
return fMin;
96+
}
97+
98+
float ConVarExt::GetMax(ConVar* pConVar)
99+
{
100+
float fMax;
101+
pConVar->GetMax(fMax);
102+
return fMax;
103+
}
104+
105+
void ConVarExt::SetValue(ConVar* pConVar, bool bValue)
106+
{
107+
pConVar->SetValue(bValue);
108+
}
109+
110+
void ConVarExt::MakePublic(ConVar* pConVar)
111+
{
112+
pConVar->m_nFlags |= FCVAR_NOTIFY;
113+
g_pCVar->CallGlobalChangeCallbacks(pConVar, pConVar->GetString(), pConVar->GetFloat());
114+
}
115+
116+
void ConVarExt::RemovePublic(ConVar* pConVar)
117+
{
118+
pConVar->m_nFlags &= ~FCVAR_NOTIFY;
119+
g_pCVar->CallGlobalChangeCallbacks(pConVar, pConVar->GetString(), pConVar->GetFloat());
120+
}
121+
122+
void ConVarExt::ChangedCallback(IConVar* var, const char* pOldValue, float flOldValue)
123+
{
124+
ConVarMap::iterator map_it = g_ConVarMap.find(var->GetName());
125+
if (map_it == g_ConVarMap.end())
126+
return;
127+
128+
ConVar* pConVar = static_cast<ConVar*>(var);
129+
130+
ChangedCallbacks& callables = map_it->second;
131+
for (ChangedCallbacks::iterator it = callables.begin(); it != callables.end(); ++it)
132+
{
133+
BEGIN_BOOST_PY()
134+
(*it)(ptr(pConVar), pOldValue, pConVar->GetString());
135+
END_BOOST_PY_NORET()
136+
}
137+
}
138+
139+
void ConVarExt::AddChangedCallback(ConVar* pConVar, PyObject* pCallable)
140+
{
141+
// Get the object instance of the callable
142+
object oCallable = object(handle<>(borrowed(pCallable)));
143+
144+
ChangedCallbacks& callables = g_ConVarMap[pConVar->GetName()];
145+
if (!callables.size())
146+
{
147+
if (!installed)
148+
{
149+
g_pCVar->InstallGlobalChangeCallback(ChangedCallback);
150+
installed = true;
151+
}
152+
}
153+
else
154+
{
155+
for (ChangedCallbacks::iterator it = callables.begin(); it != callables.end(); ++it)
156+
{
157+
if (is_same_func(oCallable, *it))
158+
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback already registered.")
159+
}
160+
}
161+
162+
callables.push_back(oCallable);
163+
}
164+
165+
void ConVarExt::RemoveChangedCallback(ConVar* pConVar, PyObject* pCallable)
166+
{
167+
ConVarMap::iterator map_it = g_ConVarMap.find(pConVar->GetName());
168+
if (map_it == g_ConVarMap.end())
169+
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback not registered.")
170+
171+
// Get the object instance of the callable
172+
object oCallable = object(handle<>(borrowed(pCallable)));
173+
174+
ChangedCallbacks& callables = map_it->second;
175+
for (ChangedCallbacks::iterator it = callables.begin();;)
176+
{
177+
if(it == callables.end())
178+
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Callback not registered.")
179+
180+
if (is_same_func(oCallable, *it))
181+
{
182+
callables.erase(it);
183+
break;
184+
}
185+
else
186+
{
187+
++it;
188+
}
189+
}
190+
191+
if (!callables.size())
192+
{
193+
g_ConVarMap.erase(map_it);
194+
if (!g_ConVarMap.size())
195+
{
196+
g_pCVar->RemoveGlobalChangeCallback(ChangedCallback);
197+
installed = false;
198+
}
199+
}
200+
}
201+
202+
void ConVarExt::ClearCallback()
203+
{
204+
g_ConVarMap.clear();
205+
if (installed)
206+
g_pCVar->RemoveGlobalChangeCallback(ChangedCallback);
207+
}
208+
209+
bool ConVarExt::installed = false;

0 commit comments

Comments
 (0)