diff --git a/addons/mod_loader/internal/mod_hook_preprocessor.gd b/addons/mod_loader/internal/mod_hook_preprocessor.gd index 5b75e86f..1389d674 100644 --- a/addons/mod_loader/internal/mod_hook_preprocessor.gd +++ b/addons/mod_loader/internal/mod_hook_preprocessor.gd @@ -1,3 +1,4 @@ +@tool class_name _ModLoaderModHookPreProcessor extends RefCounted @@ -13,6 +14,7 @@ const HASH_COLLISION_ERROR := \ "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." const MOD_LOADER_HOOKS_START_STRING := \ "\n# ModLoader Hooks - The following code has been automatically added by the Godot Mod Loader." +const ENGINE_VERSION_HEX_4_2_2 := 0x040202 ## \\bfunc\\b\\s+ -> Match the word 'func' and one or more whitespace characters ## \\b%s\\b -> the function name @@ -20,8 +22,10 @@ const MOD_LOADER_HOOKS_START_STRING := \ ## and only do this until a '(' is found. const REGEX_MATCH_FUNC_WITH_WHITESPACE := "\\bfunc\\b\\s+\\b%s\\b(?:.*\\n*)*?\\s*\\(" +static var engine_version_hex: int = Engine.get_version_info().hex + ## finds function names used as setters and getters (excluding inline definitions) -## group 2 and 4 contain the xetter names +## group 2 and 4 contain the setter/getter names var regex_getter_setter := RegEx.create_from_string("(.*?[sg]et\\s*=\\s*)(\\w+)(\\g<1>)?(\\g<2>)?") ## finds every instance where super() is called @@ -198,7 +202,8 @@ func is_func_async(func_body_text: String) -> bool: var in_multiline_string := false var current_multiline_delimiter := "" - for line: String in lines: + for _line in lines: + var line: String = _line var char_index := 0 while char_index < line.length(): if in_multiline_string: @@ -327,13 +332,33 @@ func edit_vanilla_method( return text -func fix_method_super(method_name: String, func_body: RegExMatch, text: String) -> String: +func fix_method_super(method_name: String, func_body: RegExMatch, text: String) -> String: + if engine_version_hex < ENGINE_VERSION_HEX_4_2_2: + return fix_method_super_before_4_2_2(method_name, func_body, text) + return regex_super_call.sub( text, "super.%s" % method_name, true, func_body.get_start(), func_body.get_end() ) +# https://github.com/godotengine/godot/pull/86052 +# Quote: +# When the end argument of RegEx.sub was used, +# it would truncate the Subject String before even doing the substitution. +func fix_method_super_before_4_2_2(method_name: String, func_body: RegExMatch, text: String) -> String: + var text_after_func_body_end := text.substr(func_body.get_end()) + + text = regex_super_call.sub( + text, "super.%s" % method_name, + true, func_body.get_start(), func_body.get_end() + ) + + text = text + text_after_func_body_end + + return text + + static func get_func_body_start_index(closing_paren_index: int, source_code: String) -> int: if closing_paren_index == -1: return -1 @@ -495,7 +520,7 @@ static func get_return_type_string(return_data: Dictionary) -> String: if return_data.has("class_name") and not str(return_data.class_name).is_empty(): type_base = str(return_data.class_name) else: - type_base = type_string(return_data.type) + type_base = get_type_name(return_data.type) var type_hint: String = "" if return_data.hint_string.is_empty() else ("[%s]" % return_data.hint_string) @@ -535,3 +560,90 @@ static func get_hook_check_else_string( "METHOD_ARGS": method_arg_string_names_only } ) + + +# This function was taken from +# https://github.com/godotengine/godot/blob/7e67b496ff7e35f66b88adcbdd5b252d01739cbb/modules/gdscript/tests/scripts/utils.notest.gd#L69 +# It is used instead of type_string because type_string does not exist in Godot 4.1 +static func get_type_name(type: Variant.Type) -> String: + match type: + TYPE_NIL: + return "Nil" # `Nil` in core, `null` in GDScript. + TYPE_BOOL: + return "bool" + TYPE_INT: + return "int" + TYPE_FLOAT: + return "float" + TYPE_STRING: + return "String" + TYPE_VECTOR2: + return "Vector2" + TYPE_VECTOR2I: + return "Vector2i" + TYPE_RECT2: + return "Rect2" + TYPE_RECT2I: + return "Rect2i" + TYPE_VECTOR3: + return "Vector3" + TYPE_VECTOR3I: + return "Vector3i" + TYPE_TRANSFORM2D: + return "Transform2D" + TYPE_VECTOR4: + return "Vector4" + TYPE_VECTOR4I: + return "Vector4i" + TYPE_PLANE: + return "Plane" + TYPE_QUATERNION: + return "Quaternion" + TYPE_AABB: + return "AABB" + TYPE_BASIS: + return "Basis" + TYPE_TRANSFORM3D: + return "Transform3D" + TYPE_PROJECTION: + return "Projection" + TYPE_COLOR: + return "Color" + TYPE_STRING_NAME: + return "StringName" + TYPE_NODE_PATH: + return "NodePath" + TYPE_RID: + return "RID" + TYPE_OBJECT: + return "Object" + TYPE_CALLABLE: + return "Callable" + TYPE_SIGNAL: + return "Signal" + TYPE_DICTIONARY: + return "Dictionary" + TYPE_ARRAY: + return "Array" + TYPE_PACKED_BYTE_ARRAY: + return "PackedByteArray" + TYPE_PACKED_INT32_ARRAY: + return "PackedInt32Array" + TYPE_PACKED_INT64_ARRAY: + return "PackedInt64Array" + TYPE_PACKED_FLOAT32_ARRAY: + return "PackedFloat32Array" + TYPE_PACKED_FLOAT64_ARRAY: + return "PackedFloat64Array" + TYPE_PACKED_STRING_ARRAY: + return "PackedStringArray" + TYPE_PACKED_VECTOR2_ARRAY: + return "PackedVector2Array" + TYPE_PACKED_VECTOR3_ARRAY: + return "PackedVector3Array" + TYPE_PACKED_COLOR_ARRAY: + return "PackedColorArray" + 38: # TYPE_PACKED_VECTOR4_ARRAY + return "PackedVector4Array" + push_error("Argument `type` is invalid. Use `TYPE_*` constants.") + return "" % type diff --git a/addons/mod_loader/options/profiles/production_no_workshop.tres b/addons/mod_loader/options/profiles/production_no_workshop.tres index 12c283de..7b5856c0 100644 --- a/addons/mod_loader/options/profiles/production_no_workshop.tres +++ b/addons/mod_loader/options/profiles/production_no_workshop.tres @@ -1,19 +1,19 @@ -[gd_resource type="Resource" script_class="ModLoaderOptionsProfile" load_steps=2 format=4 uid="uid://bodsw0jyh6rn5"] +[gd_resource type="Resource" script_class="ModLoaderOptionsProfile" load_steps=2 format=3 uid="uid://bodsw0jyh6rn5"] [ext_resource type="Script" path="res://addons/mod_loader/resources/options_profile.gd" id="1"] [resource] script = ExtResource("1") enable_mods = true -locked_mods = Array[String]([]) +locked_mods = [] log_level = 2 -disabled_mods = Array[String]([]) +disabled_mods = [] allow_modloader_autoloads_anywhere = false steam_id = 0 override_path_to_mods = "" override_path_to_configs = "" override_path_to_workshop = "" ignore_deprecated_errors = false -ignored_mod_names_in_log = Array[String]([]) +ignored_mod_names_in_log = [] load_from_steam_workshop = false load_from_local = true diff --git a/addons/mod_loader/options/profiles/production_workshop.tres b/addons/mod_loader/options/profiles/production_workshop.tres index 9c2885f9..0b610bcb 100644 --- a/addons/mod_loader/options/profiles/production_workshop.tres +++ b/addons/mod_loader/options/profiles/production_workshop.tres @@ -1,19 +1,19 @@ -[gd_resource type="Resource" script_class="ModLoaderOptionsProfile" load_steps=2 format=4 uid="uid://cg0vv5k4o71rv"] +[gd_resource type="Resource" script_class="ModLoaderOptionsProfile" load_steps=2 format=3 uid="uid://cg0vv5k4o71rv"] [ext_resource type="Script" path="res://addons/mod_loader/resources/options_profile.gd" id="1"] [resource] script = ExtResource("1") enable_mods = true -locked_mods = Array[String]([]) +locked_mods = [] log_level = 2 -disabled_mods = Array[String]([]) +disabled_mods = [] allow_modloader_autoloads_anywhere = false steam_id = 0 override_path_to_mods = "" override_path_to_configs = "" override_path_to_workshop = "" ignore_deprecated_errors = false -ignored_mod_names_in_log = Array[String]([]) +ignored_mod_names_in_log = [] load_from_steam_workshop = true load_from_local = true