Find more intuitive orderings when there are multiple possible toposorts
The toposort will now try to get the "smallest" element as early into the output as possible. (The previous behavior was finding the lexicographically smallest toposort, which is not the same).
Here is an example. For the following graph:
The previous toposort would yield 3 5 0 1 2 4. The new toposort yields 5 0 1 2 3 4. Intuitively, we try to get the 0 as early as possible into the result.
This does change the complexity of the toposort from linear to quadratic. For our use cases (mod sorting, creative tab sorting, resource reload listener sorting), that should still be fast enough.
This PR also adds basic tests.
- [x] Publish PR to GitHub Packages
Last commit published: 3454345fcdb5eedbf1e70b3142bb9c96b4427961.
PR Publishing
The artifacts published by this PR:
- :package:
net.neoforged.fancymodloader:junit-fml:4.0.22-pr-180-more-intuitive-toposort - :package:
net.neoforged.fancymodloader:earlydisplay:4.0.22-pr-180-more-intuitive-toposort - :package:
net.neoforged.fancymodloader:loader:4.0.22-pr-180-more-intuitive-toposort
Repository Declaration
In order to use the artifacts published by the PR, add the following repository to your buildscript:
repositories {
maven {
name 'Maven for PR #180' // https://github.com/neoforged/FancyModLoader/pull/180
url 'https://prmaven.neoforged.net/FancyModLoader/pr180'
content {
includeModule('net.neoforged.fancymodloader', 'junit-fml')
includeModule('net.neoforged.fancymodloader', 'earlydisplay')
includeModule('net.neoforged.fancymodloader', 'loader')
}
}
}
creative tab sorting
How does the new topo-sort algorithm affect this? Do we have a before/after comparison chart?
How does the new topo-sort algorithm affect this? Do we have a before/after comparison chart?
I did not think of that. It would probably be interesting to do.
I did a quick try using All The Mods 10, version 0.12, with darkmodeeverywhere-1.21-1.3.0.jar disabled. I manually upgraded NeoForge to 21.0.95-beta.
I uses PrismLauncher to override the default FancyModLoader jar with the jar from this PR.
My latest.log ends at
[15Jul2024 21:16:40.093] [main/ERROR] [net.neoforged.fml.loading.ModSorter/LOADING]: Mod Sorting failed.
Detected Cycles: [[net.neoforged.fml.loading.moddiscovery.ModInfo@37303f12, net.neoforged.fml.loading.moddiscovery.ModInfo@6bbe50c9]]
then game crashes with
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:109)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at io.github.zekerzhayard.forgewrapper.installer.Main.main(Main.java:67)
at org.prismlauncher.launcher.impl.StandardLauncher.launch(StandardLauncher.java:87)
at org.prismlauncher.EntryPoint.listen(EntryPoint.java:130)
at org.prismlauncher.EntryPoint.main(EntryPoint.java:70)
Caused by: java.lang.ClassCastException: class net.neoforged.fml.loading.moddiscovery.ModInfo cannot be cast to class net.neoforged.fml.loading.moddiscovery.ModFileInfo (net.neoforged.fml.loading.moddiscovery.ModInfo and net.neoforged.fml.loading.moddiscovery.ModFileInfo are in module [email protected] of loader 'MC-BOOTSTRAP' @3578436e)
at java.base/java.util.stream.ReferencePipeline$11$1.accept(ReferencePipeline.java:450)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at java.base/java.util.stream.ReferencePipeline$11$1.accept(ReferencePipeline.java:450)
at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1715)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575)
at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
at MC-BOOTSTRAP/[email protected]/net.neoforged.fml.loading.ModSorter.sort(ModSorter.java:136)
at MC-BOOTSTRAP/[email protected]/net.neoforged.fml.loading.ModSorter.sort(ModSorter.java:78)
at MC-BOOTSTRAP/[email protected]/net.neoforged.fml.loading.moddiscovery.ModValidator.stage2Validation(ModValidator.java:96)
at MC-BOOTSTRAP/[email protected]/net.neoforged.fml.loading.FMLLoader.completeScan(FMLLoader.java:132)
at MC-BOOTSTRAP/[email protected]/net.neoforged.fml.loading.FMLServiceProvider.completeScan(FMLServiceProvider.java:90)
at MC-BOOTSTRAP/[email protected]/cpw.mods.modlauncher.TransformationServiceDecorator.onCompleteScan(TransformationServiceDecorator.java:103)
at MC-BOOTSTRAP/[email protected]/cpw.mods.modlauncher.TransformationServicesHandler.lambda$triggerScanCompletion$23(TransformationServicesHandler.java:139)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1787)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575)
at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
at MC-BOOTSTRAP/[email protected]/cpw.mods.modlauncher.TransformationServicesHandler.triggerScanCompletion(TransformationServicesHandler.java:141)
at MC-BOOTSTRAP/[email protected]/cpw.mods.modlauncher.Launcher.run(Launcher.java:91)
at MC-BOOTSTRAP/[email protected]/cpw.mods.modlauncher.Launcher.main(Launcher.java:74)
at MC-BOOTSTRAP/[email protected]/cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:26)
at MC-BOOTSTRAP/[email protected]/cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:23)
at [email protected]/cpw.mods.bootstraplauncher.BootstrapLauncher.run(BootstrapLauncher.java:210)
at [email protected]/cpw.mods.bootstraplauncher.BootstrapLauncher.main(BootstrapLauncher.java:69)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
... 5 more
without generate a proper crash report.
Restore the FancyModLoader version will let game startup advance a bit further, then crash with an error related to Night Config, with a proper crash report. Was there a breaking change related to config?
This PR is no longer needed as we use a different separate toposort algorithm in NeoForge itself for reload listeners.