-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[4.x] Duplicating a global named script class (i.e. in script_extension.gd
) causes "hides a global script class"
error
#345
Comments
script_extension.gd
) causes an error.script_extension.gd
) causes an error.
is this the cause for #338? |
commenting this part out: static func apply_extension(extension_path: String) -> Script:
# Check path to file exists
if not FileAccess.file_exists(extension_path):
ModLoaderLog.error("The child script path '%s' does not exist" % [extension_path], LOG_NAME)
return null
var child_script: Script = ResourceLoader.load(extension_path)
# Adding metadata that contains the extension script path
# We cannot get that path in any other way
# Passing the child_script as is would return the base script path
# Passing the .duplicate() would return a '' path
child_script.set_meta("extension_script_path", extension_path)
# Force Godot to compile the script now.
# We need to do this here to ensure that the inheritance chain is
# properly set up, and multiple mods can chain-extend the same
# class multiple times.
# This is also needed to make Godot instantiate the extended class
# when creating singletons.
# The actual instance is thrown away.
child_script.new()
var parent_script: Script = child_script.get_base_script()
var parent_script_path: String = parent_script.resource_path
# We want to save scripts for resetting later
# All the scripts are saved in order already
# if not ModLoaderStore.saved_scripts.has(parent_script_path):
# ModLoaderStore.saved_scripts[parent_script_path] = []
# # The first entry in the saved script array that has the path
# # used as a key will be the duplicate of the not modified script
# ModLoaderStore.saved_scripts[parent_script_path].append(parent_script.duplicate())
#
# ModLoaderStore.saved_scripts[parent_script_path].append(child_script)
ModLoaderLog.info(
"Installing script extension: %s <- %s" % [parent_script_path, extension_path], LOG_NAME
)
child_script.take_over_path(parent_script_path)
return child_script Results in a silent crash for me, in the console this error is logged:
*Edit
Log dump
*Edit 2: |
Nope. I can recreate that error when directly using |
Here is a minimal reproduction project that replicates the issue: As described above, loading the second script that extends the same-named class causes a crash, with the only hint being this error if the editor is run with the console window:
func _init() -> void:
var extend_0 = load("res://extends/extend0.gd")
extend_0.new()
extend_0.take_over_path("res://base.gd")
var extend_1 = load("res://extends/extend1.gd")
extend_1.new()
extend_1.take_over_path("res://base.gd") *Edit: |
I opened an issue, let's hope we find answers there 👀 I will hunt for a workaround in the meantime. I don't expect that this behavior will change anytime soon. Not being able to extend a script two times renders pretty much the whole mod loader useless. |
script_extension.gd
) causes an error.script_extension.gd
) causes an error.
I have limited Godot knowledge but I thought: "why not mess around with this". I'm wondering how feasible it is to modify the file causing errors at runtime. For example modifying func _init() -> void:
var file = FileAccess.open("res://base.gd", FileAccess.READ_WRITE)
file.seek(0)
file.store_string(' '.repeat(len("class_name Base")))
file.close()
var extend_0 = load("res://extends/extend0.gd")
extend_0.new()
extend_0.take_over_path("res://base.gd")
var extend_1 = load("res://extends/extend1.gd")
extend_1.new()
extend_1.take_over_path("res://base.gd") However this does create an annoying popup in the editor, but other than that the file seems unaffected. As far as adding back in the functionality of As an extra note I'm using Godot v4.1.3 |
The specific issue here doesn't seem to be related to if not ModLoaderStore.saved_scripts.has(parent_script_path):
ModLoaderStore.saved_scripts[parent_script_path] = []
# If the parent script has a global class name, then remove it and set it on the child script instead
# This prevents a "Class X hides a global script class" error when calling duplicate()
# and (potentially) fixes a take_over_path bug in Godot 4.
if parent_script.has_source_code() and parent_script is GDScript:
# Regexp to find a GDScript class name
var class_name_regex : RegEx = RegEx.create_from_string(r"(?m)^\s*class_name\s+(\S+)")
var source: String = parent_script.source_code
var _match: RegExMatch = class_name_regex.search(source)
if _match:
var global_name = _match.get_string(1) # Godot 4.3 has parent_script.get_global_name(), but we also don't need to know it
source = class_name_regex.sub(source, "#$0")
parent_script.source_code = source
parent_script.reload()
# Set the class_name directive on the child instead
# This doesn't work because the global class is still registered in the engine
#if child_script.has_source_code():
#source = _match.get_string(0) + "\n" + child_script.source_code
#child_script.source_code = source
#child_script.reload()
# The first entry in the saved script array that has the path
# used as a key will be the duplicate of the not modified script
ModLoaderStore.saved_scripts[parent_script_path].append(parent_script.duplicate()) The idea was to always keep the topmost script with the (Unrelated, but this also means that |
I created a plugin (Inheritance Chain Mender) for my project to alleviate this issue until the bug is fixed. It automatically converts your GDScript files at export to no longer use class_name. Hope it can be of use to others. |
script_extension.gd
) causes an error.script_extension.gd
) causes hides a global script class
script_extension.gd
) causes hides a global script class
script_extension.gd
) causes "hides a global script class"
error
In the process of extending a script, this is run:
godot-mod-loader/addons/mod_loader/internal/script_extension.gd
Lines 100 to 106 in e3e795b
This causes an error,
Parser Error: Class "ClassName" hides a global script class."
The text was updated successfully, but these errors were encountered: