Skip to content

feat: script extensions sorter checks load order #382

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion addons/mod_loader/api/mod.gd
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const LOG_NAME := "ModLoader:Mod"
#
# Returns: void
static func install_script_extension(child_script_path: String) -> void:
var mod_id: String = ModLoaderUtils.get_string_in_between(child_script_path, "res://mods-unpacked/", "/")

var mod_id: String = _ModLoaderPath.get_mod_dir(child_script_path)
var mod_data: ModData = get_mod_data(mod_id)
if not ModLoaderStore.saved_extension_paths.has(mod_data.manifest.get_mod_id()):
ModLoaderStore.saved_extension_paths[mod_data.manifest.get_mod_id()] = []
Expand Down
19 changes: 0 additions & 19 deletions addons/mod_loader/internal/mod_loader_utils.gd
Original file line number Diff line number Diff line change
Expand Up @@ -98,22 +98,3 @@ static func _is_valid_global_class_dict(global_class_dict: Dictionary) -> bool:
return false

return true


## Returns the [String] in between two strings in a provided [String]
static func get_string_in_between(string: String, initial: String, ending: String) -> String:
var start_index: int = string.find(initial)
if start_index == -1:
ModLoaderLog.error("Initial string not found.", LOG_NAME)
return ""

start_index += initial.length()

var end_index: int = string.find(ending, start_index)
if end_index == -1:
ModLoaderLog.error("Ending string not found.", LOG_NAME)
return ""

var found_string: String = string.substr(start_index, end_index - start_index)

return found_string
22 changes: 22 additions & 0 deletions addons/mod_loader/internal/path.gd
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,26 @@ static func get_path_to_mod_configs_dir(mod_id: String) -> String:
static func get_path_to_mod_config_file(mod_id: String, config_name: String) -> String:
var mod_config_dir := get_path_to_mod_configs_dir(mod_id)


return mod_config_dir.path_join(config_name + ".json")


# Returns the mod directory name ("some-mod") from a given path (e.g. "res://mods-unpacked/some-mod/extensions/extension.gd")
static func get_mod_dir(path: String) -> String:
var initial := ModLoaderStore.UNPACKED_DIR
var ending := "/"
var start_index: int = path.find(initial)
if start_index == -1:
ModLoaderLog.error("Initial string not found.", LOG_NAME)
return ""

start_index += initial.length()

var end_index: int = path.find(ending, start_index)
if end_index == -1:
ModLoaderLog.error("Ending string not found.", LOG_NAME)
return ""

var found_string: String = path.substr(start_index, end_index - start_index)

return found_string
22 changes: 20 additions & 2 deletions addons/mod_loader/internal/script_extension.gd
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ static func handle_script_extensions() -> void:
# a script extending script B if A is an ancestor of B.
class InheritanceSorting:
var stack_cache := {}
# This dictionary's keys are mod_ids and it stores the corresponding position in the load_order
var load_order := {}

func _init(inheritance_array_to_sort: Array) -> void:
_populate_load_order_table()
inheritance_array_to_sort.sort_custom(check_inheritances)

# Comparator function. return true if a should go before b. This may
Expand All @@ -50,10 +53,10 @@ class InheritanceSorting:
return a_stack[index] < b_stack[index]
last_index = index

if last_index < b_stack.size():
if last_index < b_stack.size() - 1:
return true

return extension_a < extension_b
return compare_mods_order(extension_a, extension_b)

# Returns a list of scripts representing all the ancestors of the extension
# script with the most recent ancestor last.
Expand All @@ -74,6 +77,21 @@ class InheritanceSorting:
stack_cache[extension_path] = stack
return stack

# Secondary comparator function for resolving scripts extending the same vanilla script
# Will return whether a comes before b in the load order
func compare_mods_order(extension_a: String, extension_b: String) -> bool:
var mod_a_id: String = _ModLoaderPath.get_mod_dir(extension_a)
var mod_b_id: String = _ModLoaderPath.get_mod_dir(extension_b)

return load_order[mod_a_id] < load_order[mod_b_id]

# Populate a load order dictionary for faster access and comparison between mod ids
func _populate_load_order_table() -> void:
var mod_index := 0
for mod in ModLoaderStore.mod_load_order:
load_order[mod.dir_name] = mod_index
mod_index += 1


static func apply_extension(extension_path: String) -> Script:
# Check path to file exists
Expand Down