1+ @tool
12class_name _ModLoaderModHookPreProcessor
23extends RefCounted
34
@@ -13,15 +14,18 @@ const HASH_COLLISION_ERROR := \
1314 "MODDING HOOKS ERROR: Hash collision between %s and %s . The collision can be resolved by renaming one of the methods or changing their script's path."
1415const MOD_LOADER_HOOKS_START_STRING := \
1516 "\n # ModLoader Hooks - The following code has been automatically added by the Godot Mod Loader."
17+ const ENGINE_VERSION_HEX_4_2_2 := 0x040202
1618
1719## \\bfunc\\b\\s+ -> Match the word 'func' and one or more whitespace characters
1820## \\b%s\\b -> the function name
1921## (?:.*\\n*)*?\\s*\\( -> Match any character between zero and unlimited times, but be lazy
2022## and only do this until a '(' is found.
2123const REGEX_MATCH_FUNC_WITH_WHITESPACE := "\\ bfunc\\ b\\ s+\\ b%s \\ b(?:.*\\ n*)*?\\ s*\\ ("
2224
25+ static var engine_version_hex : int = Engine .get_version_info ().hex
26+
2327## finds function names used as setters and getters (excluding inline definitions)
24- ## group 2 and 4 contain the xetter names
28+ ## group 2 and 4 contain the setter/getter names
2529var regex_getter_setter := RegEx .create_from_string ("(.*?[sg]et\\ s*=\\ s*)(\\ w+)(\\ g<1>)?(\\ g<2>)?" )
2630
2731## finds every instance where super() is called
@@ -198,7 +202,8 @@ func is_func_async(func_body_text: String) -> bool:
198202 var in_multiline_string := false
199203 var current_multiline_delimiter := ""
200204
201- for line : String in lines :
205+ for _line in lines :
206+ var line : String = _line
202207 var char_index := 0
203208 while char_index < line .length ():
204209 if in_multiline_string :
@@ -327,13 +332,33 @@ func edit_vanilla_method(
327332 return text
328333
329334
330- func fix_method_super (method_name : String , func_body : RegExMatch , text : String ) -> String :
335+ func fix_method_super (method_name : String , func_body : RegExMatch , text : String ) -> String :
336+ if engine_version_hex < ENGINE_VERSION_HEX_4_2_2 :
337+ return fix_method_super_before_4_2_2 (method_name , func_body , text )
338+
331339 return regex_super_call .sub (
332340 text , "super.%s " % method_name ,
333341 true , func_body .get_start (), func_body .get_end ()
334342 )
335343
336344
345+ # https://github.com/godotengine/godot/pull/86052
346+ # Quote:
347+ # When the end argument of RegEx.sub was used,
348+ # it would truncate the Subject String before even doing the substitution.
349+ func fix_method_super_before_4_2_2 (method_name : String , func_body : RegExMatch , text : String ) -> String :
350+ var text_after_func_body_end := text .substr (func_body .get_end ())
351+
352+ text = regex_super_call .sub (
353+ text , "super.%s " % method_name ,
354+ true , func_body .get_start (), func_body .get_end ()
355+ )
356+
357+ text = text + text_after_func_body_end
358+
359+ return text
360+
361+
337362static func get_func_body_start_index (closing_paren_index : int , source_code : String ) -> int :
338363 if closing_paren_index == - 1 :
339364 return - 1
@@ -495,7 +520,7 @@ static func get_return_type_string(return_data: Dictionary) -> String:
495520 if return_data .has ("class_name" ) and not str (return_data .class_name ).is_empty ():
496521 type_base = str (return_data .class_name )
497522 else :
498- type_base = type_string (return_data .type )
523+ type_base = get_type_name (return_data .type )
499524
500525 var type_hint : String = "" if return_data .hint_string .is_empty () else ("[%s ]" % return_data .hint_string )
501526
@@ -535,3 +560,90 @@ static func get_hook_check_else_string(
535560 "METHOD_ARGS" : method_arg_string_names_only
536561 }
537562 )
563+
564+
565+ # This function was taken from
566+ # https://github.com/godotengine/godot/blob/7e67b496ff7e35f66b88adcbdd5b252d01739cbb/modules/gdscript/tests/scripts/utils.notest.gd#L69
567+ # It is used instead of type_string because type_string does not exist in Godot 4.1
568+ static func get_type_name (type : Variant .Type ) -> String :
569+ match type :
570+ TYPE_NIL :
571+ return "Nil" # `Nil` in core, `null` in GDScript.
572+ TYPE_BOOL :
573+ return "bool"
574+ TYPE_INT :
575+ return "int"
576+ TYPE_FLOAT :
577+ return "float"
578+ TYPE_STRING :
579+ return "String"
580+ TYPE_VECTOR2 :
581+ return "Vector2"
582+ TYPE_VECTOR2I :
583+ return "Vector2i"
584+ TYPE_RECT2 :
585+ return "Rect2"
586+ TYPE_RECT2I :
587+ return "Rect2i"
588+ TYPE_VECTOR3 :
589+ return "Vector3"
590+ TYPE_VECTOR3I :
591+ return "Vector3i"
592+ TYPE_TRANSFORM2D :
593+ return "Transform2D"
594+ TYPE_VECTOR4 :
595+ return "Vector4"
596+ TYPE_VECTOR4I :
597+ return "Vector4i"
598+ TYPE_PLANE :
599+ return "Plane"
600+ TYPE_QUATERNION :
601+ return "Quaternion"
602+ TYPE_AABB :
603+ return "AABB"
604+ TYPE_BASIS :
605+ return "Basis"
606+ TYPE_TRANSFORM3D :
607+ return "Transform3D"
608+ TYPE_PROJECTION :
609+ return "Projection"
610+ TYPE_COLOR :
611+ return "Color"
612+ TYPE_STRING_NAME :
613+ return "StringName"
614+ TYPE_NODE_PATH :
615+ return "NodePath"
616+ TYPE_RID :
617+ return "RID"
618+ TYPE_OBJECT :
619+ return "Object"
620+ TYPE_CALLABLE :
621+ return "Callable"
622+ TYPE_SIGNAL :
623+ return "Signal"
624+ TYPE_DICTIONARY :
625+ return "Dictionary"
626+ TYPE_ARRAY :
627+ return "Array"
628+ TYPE_PACKED_BYTE_ARRAY :
629+ return "PackedByteArray"
630+ TYPE_PACKED_INT32_ARRAY :
631+ return "PackedInt32Array"
632+ TYPE_PACKED_INT64_ARRAY :
633+ return "PackedInt64Array"
634+ TYPE_PACKED_FLOAT32_ARRAY :
635+ return "PackedFloat32Array"
636+ TYPE_PACKED_FLOAT64_ARRAY :
637+ return "PackedFloat64Array"
638+ TYPE_PACKED_STRING_ARRAY :
639+ return "PackedStringArray"
640+ TYPE_PACKED_VECTOR2_ARRAY :
641+ return "PackedVector2Array"
642+ TYPE_PACKED_VECTOR3_ARRAY :
643+ return "PackedVector3Array"
644+ TYPE_PACKED_COLOR_ARRAY :
645+ return "PackedColorArray"
646+ 38 : # TYPE_PACKED_VECTOR4_ARRAY
647+ return "PackedVector4Array"
648+ push_error ("Argument `type` is invalid. Use `TYPE_*` constants." )
649+ return "<unknown type %s >" % type
0 commit comments