Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions addons/source-python/packages/source-python/memory/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@
# =============================================================================
# >> IMPORTS
# =============================================================================
# Python
from contextlib import contextmanager

# Source.Python Imports
# Core
from core import AutoUnload
# Memory
from _memory import HookType
from _memory import set_hooks_disabled
from _memory import get_hooks_disabled
from memory import Function


Expand All @@ -19,6 +24,9 @@
__all__ = ('HookType',
'PostHook',
'PreHook',
'set_hooks_disabled',
'get_hooks_disabled',
'hooks_disabled'
)


Expand Down Expand Up @@ -73,3 +81,44 @@ class PostHook(_Hook):
"""Decorator class used to create post hooks that auto unload."""

hook_type = HookType.POST


# =============================================================================
# >> FUNCTIONS
# =============================================================================
@contextmanager
def hooks_disabled(disabled=True):
"""Temporarily disable or enable all hook callbacks. By default hooks are
enabled. Thus, this context manager is mainly used to temporarily disable
hook callbacks. If the context ends, the original value is restored. This
can be used e. g. to avoid recursive calls when damaging a player in a
``on_take_damage`` hook or ``player_hurt`` event.

.. note::

This would only disable hooks created with Source.Python. Hooks that
have been created by other server plugins will still be called.

Example:

.. code:: python

from players.entity import Player
from memory.hooks import hooks_disabled

# Get a Player instance of the player with index 1
player = Player(1)

# Damage the player. This would call e. g. on_take_damage hooks
player.take_damage(5)

# To avoid calling the on_take_damage hooks, use the following:
with hooks_disabled()
player.take_damage(5)
"""
old = get_hooks_disabled()
set_hooks_disabled(disabled)
try:
yield
finally:
set_hooks_disabled(old)
5 changes: 5 additions & 0 deletions src/core/modules/memory/memory_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ using namespace boost::python;
// g_mapCallbacks[<CHook *>][<HookType_t>] -> [<object>, <object>, ...]
std::map<CHook *, std::map<HookType_t, std::list<object> > > g_mapCallbacks;

bool g_HooksDisabled;


// ============================================================================
// >> HELPER FUNCTIONS
Expand Down Expand Up @@ -80,6 +82,9 @@ object GetArgument(CHook* pHook, int iIndex)
// ============================================================================
bool SP_HookHandler(HookType_t eHookType, CHook* pHook)
{
if (g_HooksDisabled)
return false;

std::list<object> callbacks = g_mapCallbacks[pHook][eHookType];

// No need to do all this stuff, if there is no callback registered
Expand Down
12 changes: 12 additions & 0 deletions src/core/modules/memory/memory_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,16 @@ class CStackData
//---------------------------------------------------------------------------------
bool SP_HookHandler(HookType_t eHookType, CHook* pHook);

extern bool g_HooksDisabled;

inline void SetHooksDisabled(bool value)
{
g_HooksDisabled = value;
}

inline bool GetHooksDisabled()
{
return g_HooksDisabled;
}

#endif // MEMORY_HOOKS_H
14 changes: 14 additions & 0 deletions src/core/modules/memory/memory_wrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ void export_protection(scope);
// ============================================================================
DECLARE_SP_MODULE(_memory)
{
SetHooksDisabled(false);

export_function_info(_memory);
export_binary_file(_memory);
export_pointer(_memory);
Expand Down Expand Up @@ -956,6 +958,18 @@ void export_functions(scope _memory)
":param DataType data_type: The data type you would like to get the size of.\n"
":param int alignment: The alignment that should be used."
);

def("get_hooks_disabled",
&GetHooksDisabled,
"Return whether or not hook callbacks are disabled.\n"
"\n"
":rtype: bool");

def("set_hooks_disabled",
&SetHooksDisabled,
"Set whether or not hook callbacks are disabled.\n"
"\n"
":param bool disabled: If ``True``, hook callbacks are disabled.");
}


Expand Down