diff --git a/addons/source-python/packages/source-python/__init__.py b/addons/source-python/packages/source-python/__init__.py index 286dd4952..62e608f0f 100644 --- a/addons/source-python/packages/source-python/__init__.py +++ b/addons/source-python/packages/source-python/__init__.py @@ -158,10 +158,10 @@ def setup_data(): 'BaseEntityOutput', GameConfigObj(SP_DATA_PATH / 'entity_output' / 'CBaseEntityOutput.ini')) + from _entities import BaseEntityOutput try: _fire_output = entities._BaseEntityOutput.fire_output - from _entities import BaseEntityOutput BaseEntityOutput.fire_output = _fire_output except ValueError: from warnings import warn @@ -169,15 +169,14 @@ def setup_data(): 'Did not find address for BaseEntityOutput.fire_output. ' 'OnEntityOutput listener will not fire.' ) + BaseEntityOutput.fire_output = NotImplemented except AttributeError: from warnings import warn warn( 'BaseEntityOutput.fire_output not found. ' 'OnEntityOutput listener will not fire.' ) - else: - import listeners - _fire_output.add_pre_hook(listeners._pre_fire_output) + BaseEntityOutput.fire_output = NotImplemented # ============================================================================= diff --git a/addons/source-python/packages/source-python/listeners/__init__.py b/addons/source-python/packages/source-python/listeners/__init__.py index c7c19e220..d1682744e 100644 --- a/addons/source-python/packages/source-python/listeners/__init__.py +++ b/addons/source-python/packages/source-python/listeners/__init__.py @@ -24,6 +24,8 @@ from cvars import cvar # Engines from engines.server import server_game_dll +# Entities +from entities import BaseEntityOutput from entities.datamaps import Variant from entities.helpers import find_output_name # Memory @@ -91,6 +93,7 @@ 'OnEntityCreated', 'OnEntityDeleted', 'OnEntityOutput', + 'OnEntityOutputListenerManager', 'OnEntityPreSpawned', 'OnEntitySpawned', 'OnLevelInit', @@ -157,7 +160,6 @@ on_plugin_loading_manager = ListenerManager() on_plugin_unloading_manager = ListenerManager() on_level_end_listener_manager = ListenerManager() -on_entity_output_listener_manager = ListenerManager() _check_for_update = ConVar( 'sp_check_for_update', @@ -281,6 +283,36 @@ class OnClientSettingsChanged(ListenerManagerDecorator): manager = on_client_settings_changed_listener_manager +class OnEntityOutputListenerManager(ListenerManager): + """Register/unregister an EntityOutput listener.""" + + def initialize(self): + """Called when the first callback is being registered.""" + # Get the fire_output method + fire_output = BaseEntityOutput.fire_output + + # If the fire_output method is not implemented, exit the call + if fire_output is NotImplemented: + return + + # Register the hook on fire_output + fire_output.add_pre_hook(_pre_fire_output) + + def finalize(self): + """Called when the last callback is being unregistered.""" + # Get the fire_output method + fire_output = BaseEntityOutput.fire_output + + # If the fire_output method is not implemented, exit the call + if fire_output is NotImplemented: + return + + # Unregister the hook on fire_output + fire_output.remove_pre_hook(_pre_fire_output) + +on_entity_output_listener_manager = OnEntityOutputListenerManager() + + class OnEntityOutput(ListenerManagerDecorator): """Register/unregister an EntityOutput listener.""" diff --git a/src/core/modules/listeners/listeners_manager.cpp b/src/core/modules/listeners/listeners_manager.cpp index 4beb53eba..e86966c6f 100644 --- a/src/core/modules/listeners/listeners_manager.cpp +++ b/src/core/modules/listeners/listeners_manager.cpp @@ -41,6 +41,9 @@ void CListenerManager::RegisterListener(PyObject* pCallable) // Is the callable already in the vector? if( !IsRegistered(oCallable) ) { + if (!GetCount()) + Initialize(); + m_vecCallables.AddToTail(oCallable); } else { @@ -64,6 +67,9 @@ void CListenerManager::UnregisterListener(PyObject* pCallable) } else { m_vecCallables.Remove(index); + + if (!GetCount()) + Finalize(); } } @@ -92,6 +98,28 @@ int CListenerManager::GetCount() } +//----------------------------------------------------------------------------- +// Called when the first callback is being registered. +//----------------------------------------------------------------------------- +void CListenerManager::Initialize() +{ + override initialize = get_override("initialize"); + if (!initialize.is_none()) + initialize(); +} + + +//----------------------------------------------------------------------------- +// Called when the last callback is being unregistered. +//----------------------------------------------------------------------------- +void CListenerManager::Finalize() +{ + override finalize = get_override("finalize"); + if (!finalize.is_none()) + finalize(); +} + + //----------------------------------------------------------------------------- // Return whether or not the given callback is registered. //----------------------------------------------------------------------------- diff --git a/src/core/modules/listeners/listeners_manager.h b/src/core/modules/listeners/listeners_manager.h index ac10c87cc..31dfa8e9a 100644 --- a/src/core/modules/listeners/listeners_manager.h +++ b/src/core/modules/listeners/listeners_manager.h @@ -79,7 +79,7 @@ //----------------------------------------------------------------------------- // CListenerManager class. //----------------------------------------------------------------------------- -class CListenerManager +class CListenerManager: public wrapper { public: void RegisterListener(PyObject* pCallable); @@ -90,6 +90,9 @@ class CListenerManager object __getitem__(unsigned int index); void clear(); + virtual void Initialize(); + virtual void Finalize(); + int FindCallback(object oCallback); public: diff --git a/src/core/modules/listeners/listeners_wrap.cpp b/src/core/modules/listeners/listeners_wrap.cpp index 8df591e2a..1bfc1546f 100644 --- a/src/core/modules/listeners/listeners_wrap.cpp +++ b/src/core/modules/listeners/listeners_wrap.cpp @@ -119,6 +119,16 @@ void export_listener_managers(scope _listeners) &CListenerManager::clear, "Remove all registered callbacks." ) + + .def("initialize", + &CListenerManager::Initialize, + "Called when the first callback is being registered." + ) + + .def("finalize", + &CListenerManager::Finalize, + "Called when the last callback is being unregistered." + ) ; _listeners.attr("on_client_active_listener_manager") = object(ptr(GetOnClientActiveListenerManager()));