From d3a61ca974f95f5ad4089563a02a7ec1338b1b49 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Sun, 22 Jun 2025 20:44:23 -0400 Subject: [PATCH] squish changes from 'WilderForge/master' discoverMods() now returns a ModDiscoveryInfo. This object allows you to detect what mods were found, and if there are any mod resolution issues. --- .../loader/impl/FabricLoaderImpl.java | 11 ++++- .../loader/impl/discovery/ModDiscoverer.java | 34 +++++++-------- .../impl/discovery/ModDiscoveryInfo.java | 41 +++++++++++++++++++ .../loader/impl/game/GameDefinition.java | 32 +++++++++++++++ .../loader/impl/game/GameProvider.java | 9 +--- .../impl/discovery/GetNonFabricModsTest.java | 9 +++- 6 files changed, 108 insertions(+), 28 deletions(-) create mode 100644 src/main/java/net/fabricmc/loader/impl/discovery/ModDiscoveryInfo.java create mode 100644 src/main/java/net/fabricmc/loader/impl/game/GameDefinition.java diff --git a/src/main/java/net/fabricmc/loader/impl/FabricLoaderImpl.java b/src/main/java/net/fabricmc/loader/impl/FabricLoaderImpl.java index a7c373635..afb196eb2 100644 --- a/src/main/java/net/fabricmc/loader/impl/FabricLoaderImpl.java +++ b/src/main/java/net/fabricmc/loader/impl/FabricLoaderImpl.java @@ -51,6 +51,7 @@ import net.fabricmc.loader.impl.discovery.DirectoryModCandidateFinder; import net.fabricmc.loader.impl.discovery.ModCandidateImpl; import net.fabricmc.loader.impl.discovery.ModDiscoverer; +import net.fabricmc.loader.impl.discovery.ModDiscoveryInfo; import net.fabricmc.loader.impl.discovery.ModResolutionException; import net.fabricmc.loader.impl.discovery.ModResolver; import net.fabricmc.loader.impl.discovery.RuntimeModRemapper; @@ -207,13 +208,19 @@ private void setup() throws ModResolutionException { // discover mods - ModDiscoverer discoverer = new ModDiscoverer(versionOverrides, depOverrides); + ModDiscoverer discoverer = new ModDiscoverer(this.provider, this.isDevelopmentEnvironment(), this.getEnvironmentType(), versionOverrides, depOverrides); discoverer.addCandidateFinder(new ClasspathModCandidateFinder()); discoverer.addCandidateFinder(new DirectoryModCandidateFinder(getModsDirectory0(), remapRegularMods)); discoverer.addCandidateFinder(new ArgumentModCandidateFinder(remapRegularMods)); Map> envDisabledMods = new HashMap<>(); - modCandidates = discoverer.discoverMods(this, envDisabledMods); + final ModDiscoveryInfo discoveryInfo = discoverer.discoverMods(envDisabledMods); + + if (!discoveryInfo.launchable()) { + throw discoveryInfo.getException(); + } + + modCandidates = discoveryInfo.getFoundMods(); // dump version and dependency overrides info diff --git a/src/main/java/net/fabricmc/loader/impl/discovery/ModDiscoverer.java b/src/main/java/net/fabricmc/loader/impl/discovery/ModDiscoverer.java index 1dd742c6a..a8d8673b4 100644 --- a/src/main/java/net/fabricmc/loader/impl/discovery/ModDiscoverer.java +++ b/src/main/java/net/fabricmc/loader/impl/discovery/ModDiscoverer.java @@ -49,9 +49,9 @@ import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.SemanticVersion; import net.fabricmc.loader.api.metadata.ModMetadata; -import net.fabricmc.loader.impl.FabricLoaderImpl; import net.fabricmc.loader.impl.FormattedException; import net.fabricmc.loader.impl.discovery.ModCandidateFinder.ModCandidateConsumer; +import net.fabricmc.loader.impl.game.GameDefinition; import net.fabricmc.loader.impl.game.GameProvider.BuiltinMod; import net.fabricmc.loader.impl.metadata.BuiltinModMetadata; import net.fabricmc.loader.impl.metadata.DependencyOverrides; @@ -71,25 +71,31 @@ public final class ModDiscoverer { private final VersionOverrides versionOverrides; private final DependencyOverrides depOverrides; private final List candidateFinders = new ArrayList<>(); - private final EnvType envType = FabricLoaderImpl.INSTANCE.getEnvironmentType(); + private final EnvType envType; private final Map jijDedupMap = new ConcurrentHashMap<>(); // avoids reading the same jar twice private final List nestedModInitDatas = Collections.synchronizedList(new ArrayList<>()); // breaks potential cycles from deduplication private final List nonFabricMods = Collections.synchronizedList(new ArrayList<>()); + private final GameDefinition gameDefinition; + private final boolean isDevelopment; - public ModDiscoverer(VersionOverrides versionOverrides, DependencyOverrides depOverrides) { + public ModDiscoverer(GameDefinition gameDefinition, boolean isDevelopment, EnvType environment, VersionOverrides versionOverrides, DependencyOverrides depOverrides) { this.versionOverrides = versionOverrides; this.depOverrides = depOverrides; + this.envType = environment; + this.gameDefinition = gameDefinition; + this.isDevelopment = isDevelopment; } public void addCandidateFinder(ModCandidateFinder f) { candidateFinders.add(f); } - public List discoverMods(FabricLoaderImpl loader, Map> envDisabledModsOut) throws ModResolutionException { + public ModDiscoveryInfo discoverMods(Map> envDisabledModsOut) throws ModResolutionException { long startTime = System.nanoTime(); ForkJoinPool pool = new ForkJoinPool(); Set processedPaths = new HashSet<>(); // suppresses duplicate paths List> futures = new ArrayList<>(); + List exceptions = new ArrayList<>(); ModCandidateConsumer taskSubmitter = (paths, requiresRemap) -> { List pendingPaths = new ArrayList<>(paths.size()); @@ -114,12 +120,12 @@ public List discoverMods(FabricLoaderImpl loader, Map candidates = new ArrayList<>(); // add builtin mods - for (BuiltinMod mod : loader.getGameProvider().getBuiltinMods()) { + for (BuiltinMod mod : gameDefinition.getBuiltinMods()) { if (!(mod.metadata.getVersion() instanceof SemanticVersion)) { String error = String.format("%s uses the non-semantic version %s, which doesn't support range comparisons and may cause mod dependencies against it to fail unexpectedly. Consider updating Fabric Loader or explicitly specifying the game version with the fabric.gameVersion system property.", mod.metadata.getId(), mod.metadata.getVersion()); - if (loader.isDevelopmentEnvironment()) { // fail hard in-dev + if (isDevelopment) { // fail hard in-dev throw new FormattedException("Invalid game version", error); } else { Log.warn(LogCategory.GENERAL, error); @@ -127,11 +133,11 @@ public List discoverMods(FabricLoaderImpl loader, Map discoverMods(FabricLoaderImpl loader, Map disabledModIds = findDisabledModIds(); @@ -214,7 +216,7 @@ public List discoverMods(FabricLoaderImpl loader, Map(ret); + return new ModDiscoveryInfo(new ArrayList<>(ret), exception); } public List getNonFabricMods() { @@ -372,7 +374,7 @@ public RewindableInputStream getInputStream() throws IOException { private ZipEntry currentEntry; }); - if (!nestedJarPaths.isEmpty() && FabricLoaderImpl.INSTANCE.isDevelopmentEnvironment()) { + if (!nestedJarPaths.isEmpty() && isDevelopment) { Log.warn(LogCategory.METADATA, "Mod %s %s references missing nested jars: %s", metadata.getId(), metadata.getVersion(), nestedJarPaths); } } @@ -450,7 +452,7 @@ public RewindableInputStream getInputStream() throws IOException { }); } - if (!nestedJarPaths.isEmpty() && FabricLoaderImpl.INSTANCE.isDevelopmentEnvironment()) { + if (!nestedJarPaths.isEmpty() && isDevelopment) { Log.warn(LogCategory.METADATA, "Mod %s %s references missing nested jars: %s", metadata.getId(), metadata.getVersion(), nestedJarPaths); } } @@ -507,7 +509,7 @@ private List computeNestedMods(ZipEntrySource entrySource) throws I } private LoaderModMetadata parseMetadata(InputStream is, String localPath) throws ParseMetadataException { - return ModMetadataParser.parseMetadata(is, localPath, parentPaths, versionOverrides, depOverrides, FabricLoaderImpl.INSTANCE.isDevelopmentEnvironment()); + return ModMetadataParser.parseMetadata(is, localPath, parentPaths, versionOverrides, depOverrides, isDevelopment); } } diff --git a/src/main/java/net/fabricmc/loader/impl/discovery/ModDiscoveryInfo.java b/src/main/java/net/fabricmc/loader/impl/discovery/ModDiscoveryInfo.java new file mode 100644 index 000000000..30fe790d9 --- /dev/null +++ b/src/main/java/net/fabricmc/loader/impl/discovery/ModDiscoveryInfo.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.loader.impl.discovery; + +import java.util.List; + +public class ModDiscoveryInfo { + private final List modsFound; + private final ModResolutionException exception; + + public ModDiscoveryInfo(List discoveredMods, ModResolutionException exception) { + this.modsFound = discoveredMods; + this.exception = exception; + } + + public List getFoundMods() { + return modsFound; + } + + public ModResolutionException getException() { + return exception; + } + + public boolean launchable() { + return exception == null; + } +} diff --git a/src/main/java/net/fabricmc/loader/impl/game/GameDefinition.java b/src/main/java/net/fabricmc/loader/impl/game/GameDefinition.java new file mode 100644 index 000000000..3d14e6a4f --- /dev/null +++ b/src/main/java/net/fabricmc/loader/impl/game/GameDefinition.java @@ -0,0 +1,32 @@ +/* + * Copyright 2016 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.loader.impl.game; + +import java.nio.file.Path; +import java.util.Collection; + +import net.fabricmc.loader.impl.game.GameProvider.BuiltinMod; + +public interface GameDefinition { + String getGameId(); + String getGameName(); + String getRawGameVersion(); + String getNormalizedGameVersion(); + Collection getBuiltinMods(); + Path getLaunchDirectory(); +} + diff --git a/src/main/java/net/fabricmc/loader/impl/game/GameProvider.java b/src/main/java/net/fabricmc/loader/impl/game/GameProvider.java index 1495ad004..317de7502 100644 --- a/src/main/java/net/fabricmc/loader/impl/game/GameProvider.java +++ b/src/main/java/net/fabricmc/loader/impl/game/GameProvider.java @@ -17,7 +17,6 @@ package net.fabricmc.loader.impl.game; import java.nio.file.Path; -import java.util.Collection; import java.util.List; import java.util.Objects; @@ -27,15 +26,9 @@ import net.fabricmc.loader.impl.util.Arguments; import net.fabricmc.loader.impl.util.LoaderUtil; -public interface GameProvider { // name directly referenced in net.fabricmc.loader.impl.launch.knot.Knot.findEmbedddedGameProvider() and service loader records - String getGameId(); - String getGameName(); - String getRawGameVersion(); - String getNormalizedGameVersion(); - Collection getBuiltinMods(); +public interface GameProvider extends GameDefinition { // name directly referenced in net.fabricmc.loader.impl.launch.knot.Knot.findEmbedddedGameProvider() and service loader records String getEntrypoint(); - Path getLaunchDirectory(); boolean isObfuscated(); boolean requiresUrlClassLoader(); diff --git a/src/test/java/net/fabricmc/loader/impl/discovery/GetNonFabricModsTest.java b/src/test/java/net/fabricmc/loader/impl/discovery/GetNonFabricModsTest.java index 636440eaa..2dd99f162 100644 --- a/src/test/java/net/fabricmc/loader/impl/discovery/GetNonFabricModsTest.java +++ b/src/test/java/net/fabricmc/loader/impl/discovery/GetNonFabricModsTest.java @@ -63,7 +63,7 @@ public void setUp() { loaderConstruction = Mockito.mockConstructionWithAnswer(FabricLoaderImpl.class, invocation -> loader); - discoverer = new ModDiscoverer(mock(), mock()); + discoverer = new ModDiscoverer(provider, loader.isDevelopmentEnvironment(), loader.getEnvironmentType(), mock(), mock()); discoverer.addCandidateFinder(new MockCandidateFinder()); } @@ -77,7 +77,12 @@ public void tearDown() { */ @Test public void testGetNonFabricMods() throws ModResolutionException { - List acceptedMods = discoverer.discoverMods(loader, new HashMap>()); + ModDiscoveryInfo discoveryInfo = discoverer.discoverMods(new HashMap>()); + List acceptedMods = discoveryInfo.getFoundMods(); + + if (!discoveryInfo.launchable()) { + throw discoveryInfo.getException(); + } boolean foundDummyFabricMod = false;