Skip to content
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

feat: ✨ added _remove_extension #198

Merged
merged 9 commits into from
Mar 30, 2023
94 changes: 94 additions & 0 deletions addons/mod_loader/mod_loader.gd
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ var loaded_vanilla_parents_cache := {}
# Helps to decide whether a script extension should go through the _handle_script_extensions process
var is_initializing := true

# Stores all the taken over scripts for restoration
var _saved_scripts := {}

# Main
# =============================================================================
Expand Down Expand Up @@ -691,6 +693,11 @@ func _apply_extension(extension_path)->Script:
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
Expand All @@ -703,12 +710,92 @@ func _apply_extension(extension_path)->Script:

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 _saved_scripts.has(parent_script_path):
_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
_saved_scripts[parent_script_path].append(parent_script.duplicate())
_saved_scripts[parent_script_path].append(child_script)

ModLoaderUtils.log_info("Installing script extension: %s <- %s" % [parent_script_path, extension_path], LOG_NAME)
child_script.take_over_path(parent_script_path)

return child_script


# Used to remove a specific extension
func _remove_extension(extension_path: String):
otDan marked this conversation as resolved.
Show resolved Hide resolved
# Check path to file exists
if not File.new().file_exists(extension_path):
otDan marked this conversation as resolved.
Show resolved Hide resolved
ModLoaderUtils.log_error("The extension script path \"%s\" does not exist" % [extension_path], LOG_NAME)
return null

var extension_script: Script = ResourceLoader.load(extension_path)
var parent_script: Script = extension_script.get_base_script()
var parent_script_path: String = parent_script.resource_path

# Check if the script to reset has been extended
if not _saved_scripts.has(parent_script_path):
ModLoaderUtils.log_error("The extension parent script path \"%s\" has not been extended" % [parent_script_path], LOG_NAME)
return

# Check if the script to reset has anything actually saved
# If we ever encounter this it means something went very wrong in extending
if not _saved_scripts[parent_script_path].size() > 0:
ModLoaderUtils.log_error("The extension script path \"%s\" does not have the base script saved, this should never happen, if you encounter this please create an issue in the github repository" % [parent_script_path], LOG_NAME)
return

var parent_script_extensions: Array = _saved_scripts[parent_script_path].duplicate()
parent_script_extensions.remove(0)

# Searching for the extension that we want to remove
var found_script_extension: Script = null
otDan marked this conversation as resolved.
Show resolved Hide resolved
for script_extension in parent_script_extensions:
if script_extension.get_meta("extension_script_path") == extension_path:
found_script_extension = script_extension
break

if found_script_extension == null:
ModLoaderUtils.log_error("The extension script path \"%s\" has not been found in the saved extension of the base script" % [parent_script_path], LOG_NAME)
return
parent_script_extensions.erase(found_script_extension)

# Preparing the script to have all other extensions reapllied
_reset_extension(parent_script_path)

# Reapplying all the extensions without the removed one
for script_extension in parent_script_extensions:
_apply_extension(script_extension.get_meta("extension_script_path"))


# Used to fully reset the provided script to a state prior of any extension
func _reset_extension(parent_script_path: String):
otDan marked this conversation as resolved.
Show resolved Hide resolved
# Check path to file exists
if not ModLoaderUtils.file_exists(parent_script_path):
ModLoaderUtils.log_error("The parent script path \"%s\" does not exist" % [parent_script_path], LOG_NAME)
return

# Check if the script to reset has been extended
if not _saved_scripts.has(parent_script_path):
ModLoaderUtils.log_error("The parent script path \"%s\" has not been extended" % [parent_script_path], LOG_NAME)
return

# Check if the script to reset has anything actually saved
# If we ever encounter this it means something went very wrong in extending
if not _saved_scripts[parent_script_path].size() > 0:
ModLoaderUtils.log_error("The parent script path \"%s\" does not have the base script saved, \nthis should never happen, if you encounter this please create an issue in the github repository" % [parent_script_path], LOG_NAME)
return

var parent_script: Script = _saved_scripts[parent_script_path][0]
parent_script.take_over_path(parent_script_path)

# Remove the script after it has been reset so we do not do it again
_saved_scripts.erase(parent_script_path)


# Helpers
# =============================================================================

Expand All @@ -732,6 +819,13 @@ func install_script_extension(child_script_path:String):
_apply_extension(child_script_path)


func uninstall_script_extension(extension_script_path: String):
otDan marked this conversation as resolved.
Show resolved Hide resolved

# Currently this is the only thing we do, but it is better to expose
# this function like this for further changes
_remove_extension(extension_script_path)


# Register an array of classes to the global scope, since Godot only does that in the editor.
# Format: { "base": "ParentClass", "class": "ClassName", "language": "GDScript", "path": "res://path/class_name.gd" }
# You can find these easily in the project.godot file under "_global_script_classes"
Expand Down