Skip to content

Commit bad077b

Browse files
committed
feat: 🚧 improved runtime performance by pre-hashing dict-lookup
Also refactored some of the function/field names to improved the modding experience
1 parent f8c6dbe commit bad077b

File tree

3 files changed

+40
-21
lines changed

3 files changed

+40
-21
lines changed

addons/mod_loader/_export_plugin/export_plugin.gd

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ extends EditorExportPlugin
33
const REQUIRE_EXPLICIT_ADDITION := false
44
const METHOD_PREFIX := "GodotModLoader"
55

6+
var hashmap := {}
7+
68
func _get_name() -> String:
79
return "Godot Mod Loader Export Plugin"
810

11+
func _export_begin(features: PackedStringArray, is_debug: bool, path: String, flags: int) -> void:
12+
hashmap.clear()
913

1014
func _export_file(path: String, type: String, features: PackedStringArray) -> void:
1115
if path.begins_with("res://addons") or path.begins_with("res://mods-unpacked"):
@@ -46,14 +50,28 @@ func _export_file(path: String, type: String, features: PackedStringArray) -> vo
4650
var is_static := true if method.flags == METHOD_FLAG_STATIC + METHOD_FLAG_NORMAL else false
4751
var method_arg_string_with_defaults_and_types := get_function_parameters(method.name, source_code, is_static)
4852
var method_arg_string_names_only := get_function_arg_name_string(method.args)
53+
54+
var hash_before = ModLoaderMod.get_hook_hash(path, method.name, true)
55+
var hash_after = ModLoaderMod.get_hook_hash(path, method.name, false)
56+
var hash_before_data = [path, method.name,true]
57+
var hash_after_data = [path, method.name,false]
58+
if hashmap.has(hash_before):
59+
push_error("MODDING EXPORT ERROR: hash collision between %s and %s." %[hashmap[hash_before], hash_before_data])
60+
if hashmap.has(hash_after):
61+
push_error("MODDING EXPORT ERROR: hash collision between %s and %s." %[hashmap[hash_after], hash_after_data])
62+
hashmap[hash_before] = hash_before_data
63+
hashmap[hash_after] = hash_after_data
64+
4965
var mod_loader_hook_string := get_mod_loader_hook(
5066
method.name,
5167
method_arg_string_names_only,
5268
method_arg_string_with_defaults_and_types,
5369
type_string,
5470
method.return.usage,
5571
is_static,
56-
path
72+
path,
73+
hash_before,
74+
hash_after,
5775
)
5876

5977
# Store the method name
@@ -171,6 +189,8 @@ static func get_mod_loader_hook(
171189
return_prop_usage: int,
172190
is_static: bool,
173191
script_path: String,
192+
hash_before:int,
193+
hash_after:int,
174194
method_prefix := METHOD_PREFIX) -> String:
175195
var type_string := " -> %s" % method_type if not method_type.is_empty() else ""
176196
var static_string := "static " if is_static else ""
@@ -181,9 +201,9 @@ static func get_mod_loader_hook(
181201

182202
return """
183203
{%STATIC%}func {%METHOD_NAME%}({%METHOD_PARAMS%}){%RETURN_TYPE_STRING%}:
184-
ModLoaderMod.call_from_callable_stack({%SELF%}, [{%METHOD_ARGS%}], "{%SCRIPT_PATH%}", "{%METHOD_NAME%}", true)
204+
ModLoaderMod.call_hooks({%SELF%}, [{%METHOD_ARGS%}], {%HOOK_ID_BEFORE%})
185205
{%METHOD_RETURN_VAR%}{%METHOD_PREFIX%}_{%METHOD_NAME%}({%METHOD_ARGS%})
186-
ModLoaderMod.call_from_callable_stack({%SELF%}, [{%METHOD_ARGS%}], "{%SCRIPT_PATH%}", "{%METHOD_NAME%}", false)
206+
ModLoaderMod.call_hooks({%SELF%}, [{%METHOD_ARGS%}], {%HOOK_ID_AFTER%})
187207
{%METHOD_RETURN%}
188208
""".format({
189209
"%METHOD_PREFIX%": method_prefix,
@@ -196,6 +216,8 @@ static func get_mod_loader_hook(
196216
"%METHOD_RETURN%": method_return,
197217
"%STATIC%": static_string,
198218
"%SELF%": self_string,
219+
"%HOOK_ID_BEFORE%" : hash_before,
220+
"%HOOK_ID_AFTER%" : hash_after,
199221
})
200222

201223
static func get_previous_line_to(text: String, index: int) -> String:

addons/mod_loader/api/mod.gd

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,24 @@ extends Object
1111
const LOG_NAME := "ModLoader:Mod"
1212

1313

14-
static func set_callable_stack(new_callable_stack: Dictionary) -> void:
15-
ModLoaderStore.callable_stack = new_callable_stack
14+
static func set_modding_hooks(new_callable_stack: Dictionary) -> void:
15+
ModLoaderStore.modding_hooks = new_callable_stack
1616

1717

18-
static func add_to_callable_stack(mod_callable: Callable, script_path: String, method_name: String, is_before := false) -> void:
19-
if not ModLoaderStore.callable_stack.has(script_path):
20-
ModLoaderStore.callable_stack[script_path] = {}
21-
if not ModLoaderStore.callable_stack[script_path].has(method_name):
22-
ModLoaderStore.callable_stack[script_path][method_name] = { "before": [], "after": []}
23-
ModLoaderStore.callable_stack[script_path][method_name]["before" if is_before else "after"].push_back(mod_callable)
18+
static func add_hook(mod_callable: Callable, script_path: String, method_name: String, is_before := false) -> void:
19+
var hash = get_hook_hash(script_path,method_name,is_before)
20+
if not ModLoaderStore.modding_hooks.has(hash):
21+
ModLoaderStore.modding_hooks[hash] = []
22+
ModLoaderStore.modding_hooks[hash].push_back(mod_callable)
2423

24+
static func call_hooks(self_object: Object, args: Array, hook_hash:int) -> void:
25+
var hooks = ModLoaderStore.modding_hooks.get(hook_hash, null)
26+
if hooks:
27+
for mod_func in hooks:
28+
mod_func.call(self_object)
2529

26-
static func call_from_callable_stack(self_object: Object, args: Array, script_path: String, method_name: String, is_before := false) -> void:
27-
if not ModLoaderStore.callable_stack.has(script_path):
28-
return
29-
30-
if not ModLoaderStore.callable_stack[script_path].has(method_name):
31-
return
32-
33-
for mod_func in ModLoaderStore.callable_stack[script_path][method_name]["before" if is_before else "after"]:
34-
mod_func.call(self_object)
30+
static func get_hook_hash(path:String, method:String, is_before:bool) -> int:
31+
return hash(path + method + ("before" if is_before else "after"))
3532

3633

3734
## Installs a script extension that extends a vanilla script.[br]

addons/mod_loader/mod_loader_store.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const LOG_NAME = "ModLoader:Store"
4040
# }
4141
# }
4242

43-
var callable_stack := {}
43+
var modding_hooks := {}
4444

4545
# Order for mods to be loaded in, set by `get_load_order`
4646
var mod_load_order := []

0 commit comments

Comments
 (0)