1
1
extends EditorExportPlugin
2
2
3
3
const REQUIRE_EXPLICIT_ADDITION := false
4
- const METHOD_PREFIX := "GodotModLoader "
5
-
4
+ const METHOD_PREFIX := "vanilla_ "
5
+ const HASH_COLLISION_ERROR := "MODDING EXPORT ERROR: Hash collision between %s and %s . The collision can be resolved by renaming one of the methods or changing their scripts path."
6
6
var hashmap := {}
7
7
8
8
func _get_name () -> String :
@@ -15,15 +15,17 @@ func _export_file(path: String, type: String, features: PackedStringArray) -> vo
15
15
if path .begins_with ("res://addons" ) or path .begins_with ("res://mods-unpacked" ):
16
16
return
17
17
18
- if not type = = "GDScript" :
18
+ if type ! = "GDScript" :
19
19
return
20
20
21
21
var current_script := load (path ) as GDScript
22
22
var source_code := current_script .source_code
23
23
var source_code_additions := ""
24
24
25
+ # we need to stop all vanilla methods from forming inheritance chains
26
+ # since the generated methods will fulfill inheritance requirements
27
+ var class_prefix = str (hash (path ))
25
28
var method_store : Array [String ] = []
26
-
27
29
var mod_loader_hooks_start_string := """
28
30
# ModLoader Hooks - The following code has been automatically added by the Godot Mod Loader export plugin.
29
31
"""
@@ -39,13 +41,11 @@ func _export_file(path: String, type: String, features: PackedStringArray) -> vo
39
41
var method_first_line_start := get_index_at_method_start (method .name , source_code )
40
42
if method_first_line_start == - 1 or method .name in method_store :
41
43
continue
42
-
43
- if not is_func_moddable (method_first_line_start , source_code ):
44
- continue
45
-
46
- if is_setter (method .name , source_code ):
44
+
45
+ if not is_func_moddable (method .name , method_first_line_start , source_code ):
47
46
continue
48
-
47
+
48
+ # print(method.flags)
49
49
var type_string := get_return_type_string (method .return )
50
50
var is_static := true if method .flags == METHOD_FLAG_STATIC + METHOD_FLAG_NORMAL else false
51
51
var method_arg_string_with_defaults_and_types := get_function_parameters (method .name , source_code , is_static )
@@ -56,9 +56,9 @@ func _export_file(path: String, type: String, features: PackedStringArray) -> vo
56
56
var hash_before_data = [path , method .name ,true ]
57
57
var hash_after_data = [path , method .name ,false ]
58
58
if hashmap .has (hash_before ):
59
- push_error ("MODDING EXPORT ERROR: hash collision between %s and %s ." % [hashmap [hash_before ], hash_before_data ])
59
+ push_error (HASH_COLLISION_ERROR % [hashmap [hash_before ], hash_before_data ])
60
60
if hashmap .has (hash_after ):
61
- push_error ("MODDING EXPORT ERROR: hash collision between %s and %s ." % [hashmap [hash_after ], hash_after_data ])
61
+ push_error (HASH_COLLISION_ERROR % [hashmap [hash_after ], hash_after_data ])
62
62
hashmap [hash_before ] = hash_before_data
63
63
hashmap [hash_after ] = hash_after_data
64
64
@@ -72,6 +72,7 @@ func _export_file(path: String, type: String, features: PackedStringArray) -> vo
72
72
path ,
73
73
hash_before ,
74
74
hash_after ,
75
+ METHOD_PREFIX + class_prefix ,
75
76
)
76
77
77
78
# Store the method name
@@ -80,13 +81,13 @@ func _export_file(path: String, type: String, features: PackedStringArray) -> vo
80
81
# including the methods from the scripts it extends,
81
82
# which leads to multiple entries in the list if they are overridden by the child script.
82
83
method_store .push_back (method .name )
83
- source_code = prefix_method_name (method .name , is_static , source_code )
84
+ source_code = prefix_method_name (method .name , is_static , source_code , METHOD_PREFIX + class_prefix )
84
85
source_code_additions += "\n %s " % mod_loader_hook_string
85
-
86
+
86
87
# if we have some additions to the code, append them at the end
87
88
if source_code_additions != "" :
88
89
source_code = "%s \n %s \n %s " % [source_code ,mod_loader_hooks_start_string , source_code_additions ]
89
-
90
+
90
91
skip ()
91
92
add_file (path , source_code .to_utf8_buffer (), false )
92
93
@@ -111,7 +112,7 @@ static func get_function_arg_name_string(args: Array) -> String:
111
112
arg_string += args [x ].name
112
113
else :
113
114
arg_string += "%s , " % args [x ].name
114
-
115
+
115
116
return arg_string
116
117
117
118
@@ -180,7 +181,6 @@ static func prefix_method_name(method_name: String, is_static: bool, text: Strin
180
181
print ("WHAT?!" )
181
182
return text
182
183
183
-
184
184
static func get_mod_loader_hook (
185
185
method_name : String ,
186
186
method_arg_string_names_only : String ,
@@ -198,7 +198,7 @@ static func get_mod_loader_hook(
198
198
var self_string := "null" if is_static else "self"
199
199
var return_var := "var %s = " % "return_var" if not method_type .is_empty () or return_prop_usage == 131072 else ""
200
200
var method_return := "return %s " % "return_var" if not method_type .is_empty () or return_prop_usage == 131072 else ""
201
-
201
+
202
202
return """
203
203
{%STATIC%}func {%METHOD_NAME%}({%METHOD_PARAMS%}){%RETURN_TYPE_STRING%}:
204
204
ModLoaderMod.call_hooks({%SELF%}, [{%METHOD_ARGS%}], {%HOOK_ID_BEFORE%})
@@ -231,7 +231,7 @@ static func get_previous_line_to(text: String, index: int) -> String:
231
231
232
232
if start_index == 0 :
233
233
return ""
234
-
234
+
235
235
start_index -= 1
236
236
237
237
# Find the start of the previous line
@@ -241,7 +241,9 @@ static func get_previous_line_to(text: String, index: int) -> String:
241
241
242
242
return text .substr (start_index , end_index - start_index + 1 )
243
243
244
- static func is_func_moddable (method_start_idx , text ) -> bool :
244
+ static func is_func_moddable (method_name , method_start_idx , text ) -> bool :
245
+ if is_setter (method_name , text ) or is_getter (method_name ,text ):
246
+ return false
245
247
if not REQUIRE_EXPLICIT_ADDITION :
246
248
return true
247
249
return get_previous_line_to (text , method_start_idx ).contains ("@moddable" )
@@ -278,16 +280,15 @@ static func get_return_type_string(return_data: Dictionary) -> String:
278
280
return ""
279
281
var type_base
280
282
if return_data .has ("class_name" ) and not str (return_data .class_name ).is_empty ():
281
- type_base = str (return_data .class_name )
283
+ type_base = str (return_data .class_name )
282
284
else :
283
285
type_base = type_string (return_data .type )
284
-
286
+
285
287
var type_hint = "" if return_data .hint_string .is_empty () else ("[%s ]" % return_data .hint_string )
286
288
287
289
return "%s%s " % [type_base , type_hint ]
288
290
289
-
290
- func is_setter (method_name : String , text : String , offset := 0 ) -> bool :
291
+ static func is_setter (method_name : String , text : String , offset := 0 ) -> bool :
291
292
var pattern := "set\\ s*=\\ s*%s " % method_name
292
293
var regex := RegEx .new ()
293
294
regex .compile (pattern )
@@ -304,3 +305,22 @@ func is_setter(method_name: String, text: String, offset := 0) -> bool:
304
305
return true
305
306
306
307
return false
308
+
309
+
310
+ static func is_getter (method_name : String , text : String , offset := 0 ) -> bool :
311
+ var pattern := "get\\ s*=\\ s*%s " % method_name
312
+ var regex := RegEx .new ()
313
+ regex .compile (pattern )
314
+
315
+ var result := regex .search (text , offset )
316
+
317
+ if result :
318
+ var line_start_index := text .rfind ("\n " , result .get_start ()) + 1
319
+ var line_start_string := text .substr (result .get_start (), result .get_start () - line_start_index )
320
+ if line_start_string .contains ("#" ):
321
+
322
+ return is_setter (method_name , text , result .get_end ())
323
+
324
+ return true
325
+
326
+ return false
0 commit comments