diff --git a/src/core/modules/commands/commands_client.cpp b/src/core/modules/commands/commands_client.cpp index 3f774ea31..6a7b75d2f 100644 --- a/src/core/modules/commands/commands_client.cpp +++ b/src/core/modules/commands/commands_client.cpp @@ -30,6 +30,7 @@ // This is required for accessing m_nFlags without patching convar.h #define private public +#include "boost/unordered_map.hpp" #include "commands_client.h" #include "commands.h" #include "edict.h" @@ -115,36 +116,35 @@ PLUGIN_RESULT DispatchClientCommand(edict_t* pEntity, const CCommand &command) if (!IndexFromEdict(pEntity, iIndex)) return PLUGIN_CONTINUE; - // Loop through all registered Client Command Filters - for(int i = 0; i < s_ClientCommandFilters.m_vecCallables.Count(); i++) - { - BEGIN_BOOST_PY() - - // Get the PyObject instance of the callable - PyObject* pCallable = s_ClientCommandFilters.m_vecCallables[i].ptr(); - - // Call the callable and store its return value - object returnValue = CALL_PY_FUNC(pCallable, boost::ref(command), iIndex); + bool block = false; + + CListenerManager* mngr = &s_ClientCommandFilters; + FOREACH_CALLBACK_WITH_MNGR( + mngr, + object returnValue, + if( !returnValue.is_none() && extract(returnValue) == (int)BLOCK) + { + block = true; + }, + boost::ref(command), iIndex + ) - // Does the Client Command Filter want to block the command? - if( !returnValue.is_none() && extract(returnValue) == (int)BLOCK) - { - // Block the command - return PLUGIN_STOP; - } - - END_BOOST_PY_NORET() - } + if (block) + return PLUGIN_STOP; + block = false; ClientCommandMap::iterator iter; if (find_manager(g_ClientCommandMap, command.Arg(0), iter)) { if( !iter->second->Dispatch(command, iIndex)) { - // Block the command - return PLUGIN_STOP; + block = true; } } + + if (block) + return PLUGIN_STOP; + return PLUGIN_CONTINUE; } @@ -169,15 +169,7 @@ CClientCommandManager::~CClientCommandManager() //----------------------------------------------------------------------------- void CClientCommandManager::AddCallback( PyObject* pCallable ) { - // Get the object instance of the callable - object oCallable = object(handle<>(borrowed(pCallable))); - - // Is the callable already in the vector? - if( !m_vecCallables.HasElement(oCallable) ) - { - // Add the callable to the vector - m_vecCallables.AddToTail(oCallable); - } + m_vecCallables.RegisterListener(pCallable); } //----------------------------------------------------------------------------- @@ -185,14 +177,10 @@ void CClientCommandManager::AddCallback( PyObject* pCallable ) //----------------------------------------------------------------------------- void CClientCommandManager::RemoveCallback( PyObject* pCallable ) { - // Get the object instance of the callable - object oCallable = object(handle<>(borrowed(pCallable))); - - // Remove the callback from the CClientCommandManager instance - m_vecCallables.FindAndRemove(oCallable); + m_vecCallables.UnregisterListener(pCallable); // Are there any more callbacks registered for this command? - if( !m_vecCallables.Count() ) + if( !m_vecCallables.GetCount() ) { // Remove the CClientCommandManager instance RemoveCClientCommandManager(m_Name); @@ -204,26 +192,21 @@ void CClientCommandManager::RemoveCallback( PyObject* pCallable ) //----------------------------------------------------------------------------- CommandReturn CClientCommandManager::Dispatch( const CCommand& command, int iIndex ) { - // Loop through all callables registered for the CClientCommandManager instance - for(int i = 0; i < m_vecCallables.Count(); i++) - { - BEGIN_BOOST_PY() - - // Get the PyObject instance of the callable - PyObject* pCallable = m_vecCallables[i].ptr(); - - // Call the callable and store its return value - object returnValue = CALL_PY_FUNC(pCallable, boost::ref(command), iIndex); - - // Does the callable wish to block the command? - if( !returnValue.is_none() && extract(returnValue) == (int) BLOCK) - { - // Block the command - return BLOCK; - } + bool block = false; + + CListenerManager* mngr = &m_vecCallables; + FOREACH_CALLBACK_WITH_MNGR( + mngr, + object returnValue, + if( !returnValue.is_none() && extract(returnValue) == (int) BLOCK) + { + block = true; + }, + boost::ref(command), iIndex + ) - END_BOOST_PY_NORET() - } + if (block) + return BLOCK; return CONTINUE; } diff --git a/src/core/modules/commands/commands_client.h b/src/core/modules/commands/commands_client.h index d9050e694..8048b905d 100644 --- a/src/core/modules/commands/commands_client.h +++ b/src/core/modules/commands/commands_client.h @@ -29,16 +29,16 @@ //----------------------------------------------------------------------------- // Includes //----------------------------------------------------------------------------- -#include "boost/unordered_map.hpp" #include "sp_python.h" #include "utilities/sp_util.h" #include "utilities/wrap_macros.h" -#include "utlvector.h" #include "edict.h" #include "convar.h" #include "commands.h" #include "game/server/iplayerinfo.h" +#include "modules/listeners/listeners_manager.h" + //----------------------------------------------------------------------------- // Client Command Manager class. @@ -57,7 +57,7 @@ class CClientCommandManager const char* GetName(); private: - CUtlVector m_vecCallables; + CListenerManager m_vecCallables; const char* m_Name; }; diff --git a/src/core/modules/commands/commands_say.cpp b/src/core/modules/commands/commands_say.cpp index 61459bfdb..a81e9ee8f 100644 --- a/src/core/modules/commands/commands_say.cpp +++ b/src/core/modules/commands/commands_say.cpp @@ -38,10 +38,12 @@ #include "utilities/call_python.h" #include "boost/python/call.hpp" #include "boost/shared_array.hpp" +#include "boost/unordered_map.hpp" #include "sp_main.h" #include "modules/listeners/listeners_manager.h" #include "convar.h" + //----------------------------------------------------------------------------- // Global say command mapping. //----------------------------------------------------------------------------- @@ -243,37 +245,35 @@ void SayConCommand::Dispatch( const CCommand& command ) return; } - // Loop through all registered Say Filter callbacks - for(int i = 0; i < s_SayFilters.m_vecCallables.Count(); i++) - { - BEGIN_BOOST_PY() - - // Get the PyObject instance of the callable - PyObject* pCallable = s_SayFilters.m_vecCallables[i].ptr(); - - // Call the callable and store its return value - object returnValue = CALL_PY_FUNC(pCallable, boost::ref(stripped_command), iIndex, bTeamOnly); + bool block = false; - // Does the current Say Filter wish to block the command? - if( !returnValue.is_none() && extract(returnValue) == (int) BLOCK) - { - // Block the command - return; - } + // Loop through all registered Say Filter callbacks + CListenerManager* mngr = &s_SayFilters; + FOREACH_CALLBACK_WITH_MNGR( + mngr, + object returnValue, + if( !returnValue.is_none() && extract(returnValue) == (int) BLOCK) + { + block = true; + }, + boost::ref(stripped_command), iIndex, bTeamOnly + ) - END_BOOST_PY_NORET() - } + if (block) + return; - + block = false; SayCommandMap::iterator iter; if (find_manager(g_SayCommandMap, stripped_command[0], iter)) { - if(iter->second->Dispatch(stripped_command, iIndex, bTeamOnly) == BLOCK) + if(iter->second->Dispatch(stripped_command, iIndex, bTeamOnly) == BLOCK) { - // Block the command - return; + block = true; } } + + if (block) + return; // Was the command previously registered? if( m_pOldCommand ) @@ -304,15 +304,7 @@ CSayCommandManager::~CSayCommandManager() //----------------------------------------------------------------------------- void CSayCommandManager::AddCallback( PyObject* pCallable ) { - // Get the object instance of the callable - object oCallable = object(handle<>(borrowed(pCallable))); - - // Is the callable already in the vector? - if( !m_vecCallables.HasElement(oCallable) ) - { - // Add the callable to the vector - m_vecCallables.AddToTail(oCallable); - } + m_vecCallables.RegisterListener(pCallable); } //----------------------------------------------------------------------------- @@ -320,14 +312,10 @@ void CSayCommandManager::AddCallback( PyObject* pCallable ) //----------------------------------------------------------------------------- void CSayCommandManager::RemoveCallback( PyObject* pCallable ) { - // Get the object instance of the callable - object oCallable = object(handle<>(borrowed(pCallable))); - - // Remove the callback from the CSayCommandManager instance - m_vecCallables.FindAndRemove(oCallable); + m_vecCallables.UnregisterListener(pCallable); // Are there any more callbacks registered for this command? - if( !m_vecCallables.Count() ) + if( !m_vecCallables.GetCount() ) { // Remove the CSayCommandManager instance RemoveCSayCommandManager(m_Name); @@ -339,26 +327,21 @@ void CSayCommandManager::RemoveCallback( PyObject* pCallable ) //----------------------------------------------------------------------------- CommandReturn CSayCommandManager::Dispatch( const CCommand& command, int iIndex, bool bTeamOnly) { - // Loop through all callables registered for the CSayCommandManager instance - for(int i = 0; i < m_vecCallables.Count(); i++) - { - BEGIN_BOOST_PY() - - // Get the PyObject instance of the callable - PyObject* pCallable = m_vecCallables[i].ptr(); - - // Call the callable and store its return value - object returnValue = CALL_PY_FUNC(pCallable, boost::ref(command), iIndex, bTeamOnly); + bool block = false; - // Does the callable wish to block the command? - if( !returnValue.is_none() && extract(returnValue) == (int) BLOCK) - { - // Block the command - return BLOCK; - } + CListenerManager* mngr = &m_vecCallables; + FOREACH_CALLBACK_WITH_MNGR( + mngr, + object returnValue, + if( !returnValue.is_none() && extract(returnValue) == (int) BLOCK) + { + block = true; + }, + boost::ref(command), iIndex, bTeamOnly + ) - END_BOOST_PY_NORET() - } + if (block) + return BLOCK; return CONTINUE; } diff --git a/src/core/modules/commands/commands_say.h b/src/core/modules/commands/commands_say.h index 5dd060121..0d3b88576 100644 --- a/src/core/modules/commands/commands_say.h +++ b/src/core/modules/commands/commands_say.h @@ -29,13 +29,13 @@ //----------------------------------------------------------------------------- // Includes //----------------------------------------------------------------------------- -#include "boost/unordered_map.hpp" #include "utilities/sp_util.h" #include "commands.h" -#include "utlvector.h" #include "edict.h" #include "game/server/iplayerinfo.h" +#include "modules/listeners/listeners_manager.h" + //----------------------------------------------------------------------------- // Say ConCommand instance class. @@ -88,7 +88,7 @@ class CSayCommandManager private: const char* m_Name; - CUtlVector m_vecCallables; + CListenerManager m_vecCallables; }; #endif // _COMMANDS_SAY_H diff --git a/src/core/modules/commands/commands_server.cpp b/src/core/modules/commands/commands_server.cpp index 1f27dbfc4..8dcf98ab8 100644 --- a/src/core/modules/commands/commands_server.cpp +++ b/src/core/modules/commands/commands_server.cpp @@ -149,6 +149,9 @@ CServerCommandManager::CServerCommandManager(ConCommand* pConCommand, m_pOldCommand(pConCommand) { m_Name = strdup(szName); + + m_vecCallables[HOOKTYPE_PRE] = new CListenerManager(); + m_vecCallables[HOOKTYPE_POST] = new CListenerManager(); } //----------------------------------------------------------------------------- @@ -170,6 +173,9 @@ CServerCommandManager::~CServerCommandManager() } free((char*)m_Name); + + delete m_vecCallables[HOOKTYPE_PRE]; + delete m_vecCallables[HOOKTYPE_POST]; } //----------------------------------------------------------------------------- @@ -183,34 +189,20 @@ void CServerCommandManager::Init() //----------------------------------------------------------------------------- // Adds a callable to a CServerCommandManager instance. //----------------------------------------------------------------------------- -void CServerCommandManager::AddCallback( PyObject* pCallable ) +void CServerCommandManager::AddCallback( PyObject* pCallable, HookType_t type ) { - // Get the object instance of the callable - object oCallable = object(handle<>(borrowed(pCallable))); - - // Is the callable already in the vector? - if( !m_vecCallables.HasElement(oCallable) ) - { - // Add the callable to the vector - m_vecCallables.AddToTail(oCallable); - } + m_vecCallables[type]->RegisterListener(pCallable); } //----------------------------------------------------------------------------- // Removes a callable from a CServerCommandManager instance. //----------------------------------------------------------------------------- -void CServerCommandManager::RemoveCallback( PyObject* pCallable ) +void CServerCommandManager::RemoveCallback( PyObject* pCallable, HookType_t type ) { - // Get the object instance of the callable object oCallable = object(handle<>(borrowed(pCallable))); - - // Remove the callback from the CServerCommandManager instance - m_vecCallables.FindAndRemove(oCallable); - - // Are there any more callbacks registered for this command? - if( !m_vecCallables.Count() ) + m_vecCallables[type]->UnregisterListener(pCallable); + if( !m_vecCallables[HOOKTYPE_PRE]->GetCount() && !m_vecCallables[HOOKTYPE_POST]->GetCount() ) { - // Remove the CServerCommandManager instance RemoveCServerCommandManager(m_Name); } } @@ -220,40 +212,30 @@ void CServerCommandManager::RemoveCallback( PyObject* pCallable ) //----------------------------------------------------------------------------- void CServerCommandManager::Dispatch( const CCommand& command ) { - // Loop through all registered callbacks for the command - // (use equals also to know when to call the old callback) - for(int i = 0; i <= m_vecCallables.Count(); i++) - { + bool block = false; - // Is the current iteration for a registered callback? - if( i < m_vecCallables.Count() ) + // Pre hook callbacks + FOREACH_CALLBACK_WITH_MNGR( + m_vecCallables[HOOKTYPE_PRE], + object returnValue, + if( !returnValue.is_none() && extract(returnValue) == (int) BLOCK) { - - BEGIN_BOOST_PY() - - // Get the PyObject instance of the callable - PyObject* pCallable = m_vecCallables[i].ptr(); - - // Call the callable and store its return value - object returnValue = CALL_PY_FUNC(pCallable, boost::ref(command)); - - // Does the callable wish to block the command? - if( !returnValue.is_none() && extract(returnValue) == (int) BLOCK) - { - // Block the command - break; - } + block = true; + }, + boost::ref(command) + ) - END_BOOST_PY_NORET() - } + if (block) + return; - // Was the command previously registered? - else if(m_pOldCommand) - { - // Call the old callback - m_pOldCommand->Dispatch(command); - } + // Was the command previously registered? + if(m_pOldCommand) + { + m_pOldCommand->Dispatch(command); } + + // Post hook callbacks + CALL_LISTENERS_WITH_MNGR(m_vecCallables[HOOKTYPE_POST], boost::ref(command)) } //----------------------------------------------------------------------------- diff --git a/src/core/modules/commands/commands_server.h b/src/core/modules/commands/commands_server.h index f655f9482..d2f8ecc94 100644 --- a/src/core/modules/commands/commands_server.h +++ b/src/core/modules/commands/commands_server.h @@ -29,9 +29,11 @@ //----------------------------------------------------------------------------- // Includes //----------------------------------------------------------------------------- -#include "utlvector.h" #include "convar.h" +#include "modules/listeners/listeners_manager.h" +#include "hook.h" + //----------------------------------------------------------------------------- // Server Command Manager class. //----------------------------------------------------------------------------- @@ -42,15 +44,15 @@ class CServerCommandManager : public ConCommand ~CServerCommandManager(); virtual void Init(); - void AddCallback(PyObject* pCallable); - void RemoveCallback(PyObject* pCallable); + void AddCallback(PyObject* pCallable, HookType_t type); + void RemoveCallback(PyObject* pCallable, HookType_t type); protected: void Dispatch( const CCommand& command); private: CServerCommandManager(ConCommand* pConCommand, const char* szName, const char* szHelpString = 0, int iFlags = 0); - CUtlVector m_vecCallables; + std::map< HookType_t, CListenerManager* > m_vecCallables; const char* m_Name; ConCommand* m_pOldCommand; }; diff --git a/src/core/modules/commands/commands_server_wrap.cpp b/src/core/modules/commands/commands_server_wrap.cpp index bd07fed4d..2a57e1721 100644 --- a/src/core/modules/commands/commands_server_wrap.cpp +++ b/src/core/modules/commands/commands_server_wrap.cpp @@ -82,13 +82,13 @@ void export_server_command_manager(scope _server) .def("add_callback", &CServerCommandManager::AddCallback, "Adds a callback to the server command's list.", - args("callable") + (arg("callable"), arg("hook_type")=HOOKTYPE_PRE) ) .def("remove_callback", &CServerCommandManager::RemoveCallback, "Removes a callback from the server command's list.", - args("callable") + (arg("callable"), arg("hook_type")=HOOKTYPE_PRE) ) ADD_MEM_TOOLS(CServerCommandManager) diff --git a/src/core/modules/listeners/listeners_manager.h b/src/core/modules/listeners/listeners_manager.h index ff8361baa..ac10c87cc 100644 --- a/src/core/modules/listeners/listeners_manager.h +++ b/src/core/modules/listeners/listeners_manager.h @@ -48,10 +48,26 @@ // Calls all listeners of the given manager #define CALL_LISTENERS(name, ...) \ extern CListenerManager* Get##name##ListenerManager(); \ - for(int i = 0; i < Get##name##ListenerManager()->m_vecCallables.Count(); i++) \ + CALL_LISTENERS_WITH_MNGR(Get##name##ListenerManager(), ##__VA_ARGS__) + +#define CALL_LISTENERS_WITH_MNGR(mngr, ...) \ + for(int i = 0; i < mngr->m_vecCallables.Count(); i++) \ + { \ + BEGIN_BOOST_PY() \ + CALL_PY_FUNC(mngr->m_vecCallables[i].ptr(), ##__VA_ARGS__); \ + END_BOOST_PY_NORET() \ + } + +#define FOREACH_CALLBACK(name, return_var, action, ...) \ + extern CListenerManager* Get##name##ListenerManager(); \ + FOREACH_CALLBACK_WITH_MNGR(Get##name##ListenerManager(), return_var, action, ##__VA_ARGS__) + +#define FOREACH_CALLBACK_WITH_MNGR(mngr, return_var, action, ...) \ + for(int i = 0; i < mngr->m_vecCallables.Count(); i++) \ { \ BEGIN_BOOST_PY() \ - CALL_PY_FUNC(Get##name##ListenerManager()->m_vecCallables[i].ptr(), ##__VA_ARGS__); \ + return_var = CALL_PY_FUNC(mngr->m_vecCallables[i].ptr(), ##__VA_ARGS__); \ + action \ END_BOOST_PY_NORET() \ }