From bf46d3c2b05b8c959c5ebe247284f2b4e4a11447 Mon Sep 17 00:00:00 2001 From: Luca Martinelli Date: Mon, 18 Nov 2024 21:57:21 +0100 Subject: [PATCH] removed recursion from hook call sequence --- addons/mod_loader/api/hook.gd | 58 +++++++---------------------- addons/mod_loader/internal/hooks.gd | 8 ++-- 2 files changed, 16 insertions(+), 50 deletions(-) diff --git a/addons/mod_loader/api/hook.gd b/addons/mod_loader/api/hook.gd index 4214c52b..6546d5f0 100644 --- a/addons/mod_loader/api/hook.gd +++ b/addons/mod_loader/api/hook.gd @@ -8,16 +8,14 @@ extends RefCounted ## If the hooked method is [code]static[/code], it will contain the [GDScript] itself. var reference_object: Object -# The mod hook callable or vanilla method -var _method: Callable -var _next_hook: ModLoaderHook +var _callbacks := [] +var _callback_index :=-1 -func _init(method: Callable, next_hook: ModLoaderHook = null) -> void: - _method = method - _next_hook = next_hook - reference_object = _next_hook.reference_object if _next_hook else _method.get_object() - +func _init(reference_object:Object, callbacks : Array) -> void: + self.reference_object = reference_object + _callbacks = callbacks + _callback_index = callbacks.size() ## Will execute the next mod hook callable or vanilla method and return the result.[br] ## Make sure to call this method [i]somewhere[/i] in the [param mod_callable] you pass to [method ModLoaderMod.add_hook]. [br] @@ -27,43 +25,13 @@ func _init(method: Callable, next_hook: ModLoaderHook = null) -> void: ## ## [br][b]Returns:[/b] [Variant][br][br] func execute_next(args := []) -> Variant: - if _next_hook: - return _next_hook._execute(args) - - return null - - -# _execute just brings the logic to the current hook -# instead of having it all "external" in the previous hook's execute_next -func _execute(args := []) -> Variant: - # No next hook means we are at the end of the chain and call the vanilla method directly - if not _next_hook: - return _method.callv(args) + _callback_index -= 1 + assert(_callback_index >= 0, "_callback_index should never be negative. ModLoaderHook was modified in an unsupported way.") - return _method.callv([self] + args) + var callback = _callbacks[_callback_index] + #Vanilla call is always at index 0 and needs to be called without the hooked being passed + if _callback_index == 0: + return callback.callv(args) -# This starts the chain of hooks, which goes as follows: -# _execute 1 -# calls _method, the stored mod_callable -# if that method is a mod hook, it passes the ModLoaderHook object along -# mod_callable 1 -# the mod hook is implemented by modders, here they can change parameters -# it needs to call execute_next, otherwise the chain breaks -# execute_next 1 -# that then calls _execute on the next hook -# _execute 2 -# calls _method -# if _method contains the vanilla method, it is called directly -# otherwise we go another layer deeper -# _method (vanilla) returns -# _execute 2 returns -# execute_next 1 returns -# mod_callable 1 -# at this point the final return value can be modded again -# mod_callable 1 returns -# _execute 1 returns the final value -# and _execute_chain spits it back out to _ModLoaderHooks.call_hooks -# which was called from the processed vanilla method -func _execute_chain(args := []) -> Variant: - return _execute(args) + return callback.callv([self] + args) \ No newline at end of file diff --git a/addons/mod_loader/internal/hooks.gd b/addons/mod_loader/internal/hooks.gd index db9ce744..dd0c090f 100644 --- a/addons/mod_loader/internal/hooks.gd +++ b/addons/mod_loader/internal/hooks.gd @@ -30,11 +30,9 @@ static func call_hooks(vanilla_method: Callable, args: Array, hook_hash: int) -> return vanilla_method.callv(args) # Create a hook chain which will recursively call down until the vanilla method is reached - hooks.reverse() - var chain_hook := ModLoaderHook.new(vanilla_method) - for mod_func in hooks: - chain_hook = ModLoaderHook.new(mod_func, chain_hook) - + var callbacks = [vanilla_method] + callbacks.append_array(callbacks) + var chain_hook := ModLoaderHook.new(vanilla_method.get_object(), callbacks) return chain_hook._execute_chain(args)