Skip to content

Commit 286f296

Browse files
fix: Transitive Comparator for script sorting (#277)
* Transitive Comparator for script sorting The current algorithm returns a random result unless a is in b's type hierarchy. Random results are disallowed in the sort_custom API https://docs.godotengine.org/en/3.5/classes/class_array.html?highlight=sort_custom The new algorithm sorts alphabetically by names in the type hierarchy paths until one of the trees stop then it sorts the shorter tree first. Aims to fix the following errors that gets spammed at startup (and i think causes startup crashes): E 0:00:00.815 SortArray<class Variant,struct _ArrayVariantSortCustom,1>::partitioner: bad comparison function; sorting will be broken <C++ Source> .\core/sort_array.h:179 @ SortArray<class Variant,struct _ArrayVariantSortCustom,1>::partitioner() <Stack Trace> script_extension.gd:39 @ handle_script_extensions() mod_loader.gd:164 @ _load_mods() mod_loader.gd:67 @ _init() * reverse the type order to be ancestor first * Add static types, remove unused manual cache * pop the last ele
1 parent a01a703 commit 286f296

File tree

2 files changed

+28
-30
lines changed

2 files changed

+28
-30
lines changed

addons/mod_loader/internal/script_extension.gd

+28-27
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ static func handle_script_extensions() -> void:
2525
var parent_script: Script = child_script.get_base_script()
2626
var parent_script_path: String = parent_script.resource_path
2727

28-
if not ModLoaderStore.loaded_vanilla_parents_cache.keys().has(parent_script_path):
29-
ModLoaderStore.loaded_vanilla_parents_cache[parent_script_path] = parent_script
30-
3128
script_extension_data_array.push_back(
3229
ScriptExtensionData.new(extension_path, parent_script_path, mod_id)
3330
)
@@ -38,9 +35,6 @@ static func handle_script_extensions() -> void:
3835
# Inheritance is more important so this called last
3936
script_extension_data_array.sort_custom(InheritanceSorting, "_check_inheritances")
4037

41-
# This saved some bugs in the past.
42-
ModLoaderStore.loaded_vanilla_parents_cache.clear()
43-
4438
# Load and install all extensions
4539
for extension in script_extension_data_array:
4640
var script: Script = apply_extension(extension.extension_path)
@@ -49,28 +43,35 @@ static func handle_script_extensions() -> void:
4943

5044
# Inner class so the sort function can be called by handle_script_extensions()
5145
class InheritanceSorting:
52-
# Go up extension_a's inheritance tree to find if any parent shares the same vanilla path as extension_b
53-
static func _check_inheritances(extension_a: ScriptExtensionData, extension_b: ScriptExtensionData)->bool:
54-
var a_child_script: Script
55-
56-
if ModLoaderStore.loaded_vanilla_parents_cache.keys().has(extension_a.parent_script_path):
57-
a_child_script = ResourceLoader.load(extension_a.parent_script_path)
58-
else:
59-
a_child_script = ResourceLoader.load(extension_a.parent_script_path)
60-
ModLoaderStore.loaded_vanilla_parents_cache[extension_a.parent_script_path] = a_child_script
61-
62-
var a_parent_script: Script = a_child_script.get_base_script()
63-
64-
if a_parent_script == null:
46+
47+
static func _check_inheritances(extension_a:ScriptExtensionData, extension_b:ScriptExtensionData)->bool:
48+
var a_stack := []
49+
var parent_script: Script = load(extension_a.extension_path)
50+
while parent_script:
51+
a_stack.push_front(parent_script.resource_path)
52+
parent_script = parent_script.get_base_script()
53+
a_stack.pop_back()
54+
55+
var b_stack := []
56+
parent_script = load(extension_b.extension_path)
57+
while parent_script:
58+
b_stack.push_front(parent_script.resource_path)
59+
parent_script = parent_script.get_base_script()
60+
b_stack.pop_back()
61+
62+
var last_index: int
63+
for index in a_stack.size():
64+
if index >= b_stack.size():
65+
return false
66+
if a_stack[index] != b_stack[index]:
67+
return a_stack[index] < b_stack[index]
68+
last_index = index
69+
70+
if last_index < b_stack.size():
71+
# 'a' has a shorter stack
6572
return true
66-
67-
var a_parent_script_path = a_parent_script.resource_path
68-
if a_parent_script_path == extension_b.parent_script_path:
69-
return false
70-
71-
else:
72-
return _check_inheritances(ScriptExtensionData.new(extension_a.extension_path, a_parent_script_path, extension_a.mod_id), extension_b)
73-
73+
74+
return extension_a.extension_path < extension_b.extension_path
7475

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

addons/mod_loader/mod_loader_store.gd

-3
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,6 @@ var has_shown_editor_zips_warning := false
5353
# Things to keep to ensure they are not garbage collected (used by `save_scene`)
5454
var saved_objects := []
5555

56-
# Store vanilla classes for script extension sorting
57-
var loaded_vanilla_parents_cache := {}
58-
5956
# Stores all the taken over scripts for restoration
6057
var saved_scripts := {}
6158

0 commit comments

Comments
 (0)