Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added lazy-loading support to ListenerManager. #307

Merged
merged 3 commits into from Mar 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 3 additions & 4 deletions addons/source-python/packages/source-python/__init__.py
Expand Up @@ -158,26 +158,25 @@ 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
warn(
'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


# =============================================================================
Expand Down
Expand Up @@ -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
Expand Down Expand Up @@ -91,6 +93,7 @@
'OnEntityCreated',
'OnEntityDeleted',
'OnEntityOutput',
'OnEntityOutputListenerManager',
'OnEntityPreSpawned',
'OnEntitySpawned',
'OnLevelInit',
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually doesn't remove the hook, but just the hook handler.


on_entity_output_listener_manager = OnEntityOutputListenerManager()


class OnEntityOutput(ListenerManagerDecorator):
"""Register/unregister an EntityOutput listener."""

Expand Down
28 changes: 28 additions & 0 deletions src/core/modules/listeners/listeners_manager.cpp
Expand Up @@ -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 {
Expand All @@ -64,6 +67,9 @@ void CListenerManager::UnregisterListener(PyObject* pCallable)
}
else {
m_vecCallables.Remove(index);

if (!GetCount())
Finalize();
}
}

Expand Down Expand Up @@ -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.
//-----------------------------------------------------------------------------
Expand Down
5 changes: 4 additions & 1 deletion src/core/modules/listeners/listeners_manager.h
Expand Up @@ -79,7 +79,7 @@
//-----------------------------------------------------------------------------
// CListenerManager class.
//-----------------------------------------------------------------------------
class CListenerManager
class CListenerManager: public wrapper<CListenerManager>
{
public:
void RegisterListener(PyObject* pCallable);
Expand All @@ -90,6 +90,9 @@ class CListenerManager
object __getitem__(unsigned int index);
void clear();

virtual void Initialize();
virtual void Finalize();

int FindCallback(object oCallback);

public:
Expand Down
10 changes: 10 additions & 0 deletions src/core/modules/listeners/listeners_wrap.cpp
Expand Up @@ -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()));
Expand Down