Skip to content

Commit 1746bc9

Browse files
KANAjetztQubus0
andauthored
feat: ✨ support async hooks for methods using await (#470)
* feat: ✨ support async hooks for methods using await * privatization --------- Co-authored-by: Qubus0 <steen.rickmer@gmx.de>
1 parent c4691c5 commit 1746bc9

File tree

2 files changed

+47
-13
lines changed

2 files changed

+47
-13
lines changed

addons/mod_loader/api/hook_chain.gd

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,49 @@ func _init(reference_object: Object, callbacks: Array) -> void:
3131
##
3232
## [br][b]Returns:[/b] [Variant][br][br]
3333
func execute_next(args := []) -> Variant:
34-
_callback_index -= 1
34+
var callback := _get_next_callback()
35+
if not callback:
36+
return
37+
38+
# Vanilla needs to be called without the hook chain being passed
39+
if _is_callback_vanilla():
40+
return callback.callv(args)
41+
42+
return callback.callv([self] + args)
3543

36-
if _callback_index < 0:
44+
45+
## Same as [method execute_next], but asynchronous - it can be used if a method uses [code]await[/code]. [br]
46+
## This hook needs to be used if the vanilla method uses [code]await[/code] somewhere. [br]
47+
## Make sure to call this method [i][color=orange]once[/color][/i] somewhere in the [param mod_callable] you pass to [method ModLoaderMod.add_hook]. [br]
48+
##
49+
## [br][b]Parameters:[/b][br]
50+
## - [param args] ([Array]): An array of all arguments passed into the vanilla function. [br]
51+
##
52+
## [br][b]Returns:[/b] [Variant][br][br]
53+
func execute_next_async(args := []) -> Variant:
54+
var callback := _get_next_callback()
55+
if not callback:
56+
return
57+
58+
# Vanilla needs to be called without the hook chain being passed
59+
if _is_callback_vanilla():
60+
return await callback.callv(args)
61+
62+
return await callback.callv([self] + args)
63+
64+
65+
func _get_next_callback() -> Variant:
66+
_callback_index -= 1
67+
if not _callback_index >= 0:
3768
ModLoaderLog.fatal(
3869
"The hook chain index should never be negative. " +
3970
"A mod hook has called execute_next twice or ModLoaderHookChain was modified in an unsupported way.",
4071
LOG_NAME
4172
)
4273
return
4374

44-
var callback := _callbacks[_callback_index]
75+
return _callbacks[_callback_index]
4576

46-
# Vanilla call is always at index 0 and needs to be called without the hook chain being passed
47-
if _callback_index == 0:
48-
return callback.callv(args)
4977

50-
return callback.callv([self] + args)
78+
func _is_callback_vanilla() -> bool:
79+
return _callback_index == 0

addons/mod_loader/internal/hooks.gd

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ const LOG_NAME := "ModLoader:Hooks"
1111
## To add hooks from a mod use [method ModLoaderMod.add_hook].
1212
static func add_hook(mod_callable: Callable, script_path: String, method_name: String) -> void:
1313
ModLoaderStore.any_mod_hooked = true
14-
var hash = get_hook_hash(script_path, method_name)
15-
14+
var hash := get_hook_hash(script_path, method_name)
1615
if not ModLoaderStore.modding_hooks.has(hash):
1716
ModLoaderStore.modding_hooks[hash] = []
1817
ModLoaderStore.modding_hooks[hash].push_back(mod_callable)
@@ -29,13 +28,19 @@ static func call_hooks(vanilla_method: Callable, args: Array, hook_hash: int) ->
2928
if hooks.is_empty():
3029
return vanilla_method.callv(args)
3130

32-
# Create a hook chain which will call down until the vanilla method is reached
33-
var callbacks = [vanilla_method]
34-
callbacks.append_array(hooks)
35-
var chain := ModLoaderHookChain.new(vanilla_method.get_object(), callbacks)
31+
var chain := ModLoaderHookChain.new(vanilla_method.get_object(), [vanilla_method] + hooks)
3632
return chain.execute_next(args)
3733

3834

35+
static func call_hooks_async(vanilla_method: Callable, args: Array, hook_hash: int) -> Variant:
36+
var hooks: Array = ModLoaderStore.modding_hooks.get(hook_hash, [])
37+
if hooks.is_empty():
38+
return await vanilla_method.callv(args)
39+
40+
var chain := ModLoaderHookChain.new(vanilla_method.get_object(), [vanilla_method] + hooks)
41+
return await chain.execute_next_async(args)
42+
43+
3944
static func get_hook_hash(path: String, method: String) -> int:
4045
return hash(path + method)
4146

0 commit comments

Comments
 (0)