From bccace9116827f5e2357242244c5b917ed995fbe Mon Sep 17 00:00:00 2001 From: Acuadragon100 <30689683+Acuadragon100@users.noreply.github.com> Date: Tue, 28 Apr 2026 13:13:23 +0200 Subject: [PATCH 1/2] Use forge load order. --- .../xyz/bluspring/kilt/loader/KiltLoader.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/xyz/bluspring/kilt/loader/KiltLoader.kt b/src/main/kotlin/xyz/bluspring/kilt/loader/KiltLoader.kt index 4e477165b..2fe30ba22 100644 --- a/src/main/kotlin/xyz/bluspring/kilt/loader/KiltLoader.kt +++ b/src/main/kotlin/xyz/bluspring/kilt/loader/KiltLoader.kt @@ -479,9 +479,26 @@ class KiltLoader : KnitModLoader(Kilt.MOD_ID, "Forge") { } } + /** + * The natural order of Forge mods (if no dependencies are marked) is whichever order they get placed in a hash map. + * See: https://github.com/MinecraftForge/MinecraftForge/blob/1.20.1/fmlloader/src/main/java/net/minecraftforge/fml/loading/UniqueModListBuilder.java#L42 + * We want to use this order since some Forge mods might not declare their dependencies properly and just blindly rely on the default sorting. + */ + fun getForgeNaturalOrder(): Comparator { + val modOrder = hashMapOf() + for (mod in this.mods) { + modOrder[mod.modId] = 0 + } + var index = 0 + for (modEntry in modOrder) { + modEntry.setValue(index++) + } + return Comparator.comparing { modOrder[it.modId] ?: 0 } + } + override fun finishModScanning() { val graph = this.mods.buildGraph() - val sorted = TopologicalSort.topologicalSort(graph, null) + val sorted = TopologicalSort.topologicalSort(graph, getForgeNaturalOrder()) // Sort the mods, otherwise stuff breaks. val modsRef = this.mods as MutableList From bb1ae09d5997325978486a1a88d09afa672d76cf Mon Sep 17 00:00:00 2001 From: Acuadragon100 <30689683+Acuadragon100@users.noreply.github.com> Date: Sun, 17 May 2026 00:42:58 +0200 Subject: [PATCH 2/2] Sort by hash keys instead. --- .../xyz/bluspring/kilt/loader/KiltLoader.kt | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/xyz/bluspring/kilt/loader/KiltLoader.kt b/src/main/kotlin/xyz/bluspring/kilt/loader/KiltLoader.kt index 2fe30ba22..d060407fc 100644 --- a/src/main/kotlin/xyz/bluspring/kilt/loader/KiltLoader.kt +++ b/src/main/kotlin/xyz/bluspring/kilt/loader/KiltLoader.kt @@ -479,21 +479,20 @@ class KiltLoader : KnitModLoader(Kilt.MOD_ID, "Forge") { } } + // Copied from HashMap::hash + fun hash(key: Any?): Int { + val h: Int + return if (key == null) 0 else (key.hashCode().also { h = it }) xor (h ushr 16) + } + /** - * The natural order of Forge mods (if no dependencies are marked) is whichever order they get placed in a hash map. + * Forge mods are sorted based on the order of keys in a hash map. * See: https://github.com/MinecraftForge/MinecraftForge/blob/1.20.1/fmlloader/src/main/java/net/minecraftforge/fml/loading/UniqueModListBuilder.java#L42 - * We want to use this order since some Forge mods might not declare their dependencies properly and just blindly rely on the default sorting. + * This won't sort the mods in exactly the same order, but it will be close enough to hopefully resolve most issues caused by mods not explicitly denoting their dependencies. + * Users can always explicitly override this order with dependency overrides. */ fun getForgeNaturalOrder(): Comparator { - val modOrder = hashMapOf() - for (mod in this.mods) { - modOrder[mod.modId] = 0 - } - var index = 0 - for (modEntry in modOrder) { - modEntry.setValue(index++) - } - return Comparator.comparing { modOrder[it.modId] ?: 0 } + return Comparator.comparing { hash(it.modId) } } override fun finishModScanning() {