diff --git a/addons/source-python/docs/source-python/source/developing/module_tutorials/listeners.rst b/addons/source-python/docs/source-python/source/developing/module_tutorials/listeners.rst index ce79c9bb1..cbd4e39b1 100644 --- a/addons/source-python/docs/source-python/source/developing/module_tutorials/listeners.rst +++ b/addons/source-python/docs/source-python/source/developing/module_tutorials/listeners.rst @@ -202,6 +202,20 @@ Called when an entity has been created. pass +OnNetworkedEntityCreated +--------------- + +Called when a networked entity has been created. + +.. code-block:: python + + from listeners import OnNetworkedEntityCreated + + @OnNetworkedEntityCreated + def on_networked_entity_created(entity): + pass + + OnEntityDeleted --------------- @@ -216,6 +230,20 @@ Called when an entity gets deleted. pass +OnNetworkedEntityDeleted +--------------- + +Called when a networked entity gets deleted. + +.. code-block:: python + + from listeners import OnNetworkedEntityDeleted + + @OnNetworkedEntityDeleted + def on_networked_entity_deleted(entity): + pass + + OnEntityOutput -------------- @@ -252,6 +280,22 @@ Called before an entity has been spawned. .. note:: This listener gets only called in Black Mesa: Source. +OnNetworkedEntityPreSpawned +------------------ + +Called before a networked entity has been spawned. + +.. code-block:: python + + from listeners import OnNetworkedEntityPreSpawned + + @OnNetworkedEntityPreSpawned + def on_networked_entity_pre_spawned(entity): + pass + +.. note:: This listener gets only called in Black Mesa: Source. + + OnEntitySpawned --------------- @@ -266,6 +310,20 @@ Called when an entity has been spawned. pass +OnNetworkedEntitySpawned +--------------- + +Called when a networked entity has been spawned. + +.. code-block:: python + + from listeners import OnNetworkedEntitySpawned + + @OnNetworkedEntitySpawned + def on_networked_entity_spawned(entity): + pass + + OnLevelInit ----------- diff --git a/addons/source-python/packages/source-python/entities/_base.py b/addons/source-python/packages/source-python/entities/_base.py index eec4b211a..346004a0c 100644 --- a/addons/source-python/packages/source-python/entities/_base.py +++ b/addons/source-python/packages/source-python/entities/_base.py @@ -785,18 +785,12 @@ def set_parent(self, parent, attachment=INVALID_ATTACHMENT_INDEX): # ============================================================================= # NOTE: This callback is called by sp_main.cpp after all registered entity # deletion listeners have been called. -def _on_entity_deleted(base_entity): - """Called when an entity is removed. +def _on_networked_entity_deleted(index): + """Called when a networked entity is removed. - :param BaseEntity base_entity: - The removed entity. + :param int index: + The removed entity index. """ - try: - # Get the index of the entity... - index = base_entity.index - except ValueError: - return - # Loop through all delays... for delay in _entity_delays.pop(index, ()): diff --git a/addons/source-python/packages/source-python/entities/dictionary.py b/addons/source-python/packages/source-python/entities/dictionary.py index 922e361dd..4fd66359a 100644 --- a/addons/source-python/packages/source-python/entities/dictionary.py +++ b/addons/source-python/packages/source-python/entities/dictionary.py @@ -16,7 +16,7 @@ from entities.entity import Entity from entities.helpers import index_from_inthandle # Listeners -from listeners import on_entity_deleted_listener_manager +from listeners import on_networked_entity_deleted_listener_manager # ============================================================================ @@ -42,8 +42,8 @@ def __init__(self, factory=Entity, *args, **kwargs): self._kwargs = kwargs # Register our OnEntityDeleted listener... - on_entity_deleted_listener_manager.register_listener( - self._on_entity_deleted) + on_networked_entity_deleted_listener_manager.register_listener( + self._on_networked_entity_deleted) # Initialize the dictionary... super().__init__() @@ -79,22 +79,27 @@ def from_inthandle(self, inthandle): def on_automatically_removed(self, index): """Called when an index is automatically removed.""" - def _on_entity_deleted(self, base_entity): - """OnEntityDeleted listener callback.""" - try: - # Get the index of the entity... - index = base_entity.index - except ValueError: + def _on_networked_entity_deleted(self, entity): + """Internal networked entity deletion callback. + + :param Entity entity: + The networked entity being removed. + """ + # Get the index of the entity + index = entity.index + + # No need to go further if there is no object associated to this index + if index not in self: return - if index in self: + try: # Call the deletion callback for the index... self.on_automatically_removed(index) - + finally: # Remove the index from the dictionary... super().__delitem__(index) def _unload_instance(self): - """Unregister our OnEntityDeleted listener.""" - on_entity_deleted_listener_manager.unregister_listener( - self._on_entity_deleted) + """Unregister our networked entity deletion listener.""" + on_networked_entity_deleted_listener_manager.unregister_listener( + self._on_networked_entity_deleted) diff --git a/addons/source-python/packages/source-python/entities/hooks.py b/addons/source-python/packages/source-python/entities/hooks.py index 1ae44f2c5..ab944521e 100644 --- a/addons/source-python/packages/source-python/entities/hooks.py +++ b/addons/source-python/packages/source-python/entities/hooks.py @@ -14,7 +14,7 @@ # Filters from filters.entities import EntityIter # Listeners -from listeners import OnEntityCreated +from listeners import OnNetworkedEntityCreated # Entities from entities.entity import Entity # Players @@ -219,9 +219,7 @@ def initialize(self, index): # ============================================================================= # >> LISTENERS # ============================================================================= -@OnEntityCreated -def on_entity_created(base_entity): - """Called when a new entity has been created.""" - if not base_entity.is_networked(): - return - _waiting_entity_hooks.initialize(base_entity.index) +@OnNetworkedEntityCreated +def on_networked_entity_created(entity): + """Called when a new networked entity has been created.""" + _waiting_entity_hooks.initialize(entity.index) diff --git a/addons/source-python/packages/source-python/listeners/__init__.py b/addons/source-python/packages/source-python/listeners/__init__.py index d1682744e..8aec4f521 100644 --- a/addons/source-python/packages/source-python/listeners/__init__.py +++ b/addons/source-python/packages/source-python/listeners/__init__.py @@ -58,9 +58,13 @@ from _listeners import on_edict_allocated_listener_manager from _listeners import on_edict_freed_listener_manager from _listeners import on_entity_pre_spawned_listener_manager +from _listeners import on_networked_entity_pre_spawned_listener_manager from _listeners import on_entity_created_listener_manager +from _listeners import on_networked_entity_created_listener_manager from _listeners import on_entity_spawned_listener_manager +from _listeners import on_networked_entity_spawned_listener_manager from _listeners import on_entity_deleted_listener_manager +from _listeners import on_networked_entity_deleted_listener_manager from _listeners import on_data_loaded_listener_manager from _listeners import on_combiner_pre_cache_listener_manager from _listeners import on_data_unloaded_listener_manager @@ -91,11 +95,15 @@ 'OnEdictAllocated', 'OnEdictFreed', 'OnEntityCreated', + 'OnNetworkedEntityCreated', 'OnEntityDeleted', + 'OnNetworkedEntityDeleted', 'OnEntityOutput', 'OnEntityOutputListenerManager', 'OnEntityPreSpawned', + 'OnNetworkedEntityPreSpawned', 'OnEntitySpawned', + 'OnNetworkedEntitySpawned', 'OnLevelInit', 'OnLevelShutdown', 'OnLevelEnd', @@ -125,10 +133,14 @@ 'on_edict_allocated_listener_manager', 'on_edict_freed_listener_manager', 'on_entity_created_listener_manager', + 'on_networked_entity_created_listener_manager', 'on_entity_deleted_listener_manager', + 'on_networked_entity_deleted_listener_manager', 'on_entity_output_listener_manager', 'on_entity_pre_spawned_listener_manager', + 'on_networked_entity_pre_spawned_listener_manager', 'on_entity_spawned_listener_manager', + 'on_networked_entity_spawned_listener_manager', 'on_level_end_listener_manager', 'on_level_init_listener_manager', 'on_level_shutdown_listener_manager', @@ -355,24 +367,48 @@ class OnEntityPreSpawned(ListenerManagerDecorator): manager = on_entity_pre_spawned_listener_manager +class OnNetworkedEntityPreSpawned(ListenerManagerDecorator): + """Register/unregister a OnNetworkedEntityPreSpawned listener.""" + + manager = on_networked_entity_pre_spawned_listener_manager + + class OnEntityCreated(ListenerManagerDecorator): """Register/unregister a OnEntityCreated listener.""" manager = on_entity_created_listener_manager +class OnNetworkedEntityCreated(ListenerManagerDecorator): + """Register/unregister a OnNetworkedEntityCreated listener.""" + + manager = on_networked_entity_created_listener_manager + + class OnEntitySpawned(ListenerManagerDecorator): """Register/unregister a OnEntitySpawned listener.""" manager = on_entity_spawned_listener_manager +class OnNetworkedEntitySpawned(ListenerManagerDecorator): + """Register/unregister a OnNetworkedEntitySpawned listener.""" + + manager = on_networked_entity_spawned_listener_manager + + class OnEntityDeleted(ListenerManagerDecorator): """Register/unregister a OnEntityDeleted listener.""" manager = on_entity_deleted_listener_manager +class OnNetworkedEntityDeleted(ListenerManagerDecorator): + """Register/unregister a OnNetworkedEntityDeleted listener.""" + + manager = on_networked_entity_deleted_listener_manager + + class OnDataLoaded(ListenerManagerDecorator): """Register/unregister a OnDataLoaded listener.""" diff --git a/src/core/modules/listeners/listeners_wrap.cpp b/src/core/modules/listeners/listeners_wrap.cpp index 1bfc1546f..d40f48b41 100644 --- a/src/core/modules/listeners/listeners_wrap.cpp +++ b/src/core/modules/listeners/listeners_wrap.cpp @@ -51,9 +51,13 @@ DEFINE_MANAGER_ACCESSOR(OnQueryCvarValueFinished) DEFINE_MANAGER_ACCESSOR(OnServerActivate) DEFINE_MANAGER_ACCESSOR(OnTick) DEFINE_MANAGER_ACCESSOR(OnEntityPreSpawned) +DEFINE_MANAGER_ACCESSOR(OnNetworkedEntityPreSpawned) DEFINE_MANAGER_ACCESSOR(OnEntityCreated) +DEFINE_MANAGER_ACCESSOR(OnNetworkedEntityCreated) DEFINE_MANAGER_ACCESSOR(OnEntitySpawned) +DEFINE_MANAGER_ACCESSOR(OnNetworkedEntitySpawned) DEFINE_MANAGER_ACCESSOR(OnEntityDeleted) +DEFINE_MANAGER_ACCESSOR(OnNetworkedEntityDeleted) DEFINE_MANAGER_ACCESSOR(OnDataLoaded) DEFINE_MANAGER_ACCESSOR(OnCombinerPreCache) DEFINE_MANAGER_ACCESSOR(OnDataUnloaded) @@ -153,9 +157,13 @@ void export_listener_managers(scope _listeners) _listeners.attr("on_tick_listener_manager") = object(ptr(GetOnTickListenerManager())); _listeners.attr("on_entity_pre_spawned_listener_manager") = object(ptr(GetOnEntityPreSpawnedListenerManager())); + _listeners.attr("on_networked_entity_pre_spawned_listener_manager") = object(ptr(GetOnNetworkedEntityPreSpawnedListenerManager())); _listeners.attr("on_entity_created_listener_manager") = object(ptr(GetOnEntityCreatedListenerManager())); + _listeners.attr("on_networked_entity_created_listener_manager") = object(ptr(GetOnNetworkedEntityCreatedListenerManager())); _listeners.attr("on_entity_spawned_listener_manager") = object(ptr(GetOnEntitySpawnedListenerManager())); + _listeners.attr("on_networked_entity_spawned_listener_manager") = object(ptr(GetOnNetworkedEntitySpawnedListenerManager())); _listeners.attr("on_entity_deleted_listener_manager") = object(ptr(GetOnEntityDeletedListenerManager())); + _listeners.attr("on_networked_entity_deleted_listener_manager") = object(ptr(GetOnNetworkedEntityDeletedListenerManager())); _listeners.attr("on_data_loaded_listener_manager") = object(ptr(GetOnDataLoadedListenerManager())); _listeners.attr("on_combiner_pre_cache_listener_manager") = object(ptr(GetOnCombinerPreCacheListenerManager())); diff --git a/src/core/sp_main.cpp b/src/core/sp_main.cpp index 2e582c3fa..adca9d0b3 100644 --- a/src/core/sp_main.cpp +++ b/src/core/sp_main.cpp @@ -604,6 +604,17 @@ void CSourcePython::OnEdictFreed( const edict_t *edict ) void CSourcePython::OnEntityPreSpawned( CBaseEntity *pEntity ) { CALL_LISTENERS(OnEntityPreSpawned, ptr((CBaseEntityWrapper*) pEntity)); + + GET_LISTENER_MANAGER(OnNetworkedEntityPreSpawned, on_networked_entity_pre_spawned_manager); + if (!on_networked_entity_pre_spawned_manager->GetCount()) + return; + + unsigned int uiIndex; + if (!IndexFromBaseEntity(pEntity, uiIndex)) + return; + + static object Entity = import("entities").attr("entity").attr("Entity"); + CALL_LISTENERS_WITH_MNGR(on_networked_entity_pre_spawned_manager, Entity(uiIndex)); } #endif @@ -619,21 +630,53 @@ void CSourcePython::OnEntityCreated( CBaseEntity *pEntity ) InitHooks(pEntity); CALL_LISTENERS(OnEntityCreated, ptr((CBaseEntityWrapper*) pEntity)); + + GET_LISTENER_MANAGER(OnNetworkedEntityCreated, on_networked_entity_created_manager); + if (!on_networked_entity_created_manager->GetCount()) + return; + + unsigned int uiIndex; + if (!IndexFromBaseEntity(pEntity, uiIndex)) + return; + + static object Entity = import("entities").attr("entity").attr("Entity"); + CALL_LISTENERS_WITH_MNGR(on_networked_entity_created_manager, Entity(uiIndex)); } void CSourcePython::OnEntitySpawned( CBaseEntity *pEntity ) { CALL_LISTENERS(OnEntitySpawned, ptr((CBaseEntityWrapper*) pEntity)); + + GET_LISTENER_MANAGER(OnNetworkedEntitySpawned, on_networked_entity_spawned_manager); + if (!on_networked_entity_spawned_manager->GetCount()) + return; + + unsigned int uiIndex; + if (!IndexFromBaseEntity(pEntity, uiIndex)) + return; + + static object Entity = import("entities").attr("entity").attr("Entity"); + CALL_LISTENERS_WITH_MNGR(on_networked_entity_spawned_manager, Entity(uiIndex)); } void CSourcePython::OnEntityDeleted( CBaseEntity *pEntity ) { - object oEntity(ptr((CBaseEntityWrapper*) pEntity)); - CALL_LISTENERS(OnEntityDeleted, oEntity); + CALL_LISTENERS(OnEntityDeleted, ptr((CBaseEntityWrapper*) pEntity)); + + unsigned int uiIndex; + if (!IndexFromBaseEntity(pEntity, uiIndex)) + return; + + GET_LISTENER_MANAGER(OnNetworkedEntityDeleted, on_networked_entity_deleted_manager); + if (on_networked_entity_deleted_manager->GetCount()) + { + static object Entity = import("entities").attr("entity").attr("Entity"); + CALL_LISTENERS_WITH_MNGR(on_networked_entity_deleted_manager, Entity(uiIndex)); + } // Invalidate the internal entity cache once all callbacks have been called. - static object _on_entity_deleted = import("entities").attr("_base").attr("_on_entity_deleted"); - _on_entity_deleted(oEntity); + static object _on_networked_entity_deleted = import("entities").attr("_base").attr("_on_networked_entity_deleted"); + _on_networked_entity_deleted(uiIndex); } void CSourcePython::OnDataLoaded( MDLCacheDataType_t type, MDLHandle_t handle )