Skip to content
Draft
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
11 changes: 9 additions & 2 deletions src/main/java/net/fabricmc/loader/impl/FabricLoaderImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String, Set<ModCandidateImpl>> 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

Expand Down
34 changes: 18 additions & 16 deletions src/main/java/net/fabricmc/loader/impl/discovery/ModDiscoverer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -71,25 +71,31 @@ public final class ModDiscoverer {
private final VersionOverrides versionOverrides;
private final DependencyOverrides depOverrides;
private final List<ModCandidateFinder> candidateFinders = new ArrayList<>();
private final EnvType envType = FabricLoaderImpl.INSTANCE.getEnvironmentType();
private final EnvType envType;
private final Map<Long, ModScanTask> jijDedupMap = new ConcurrentHashMap<>(); // avoids reading the same jar twice
private final List<NestedModInitData> nestedModInitDatas = Collections.synchronizedList(new ArrayList<>()); // breaks potential cycles from deduplication
private final List<Path> 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<ModCandidateImpl> discoverMods(FabricLoaderImpl loader, Map<String, Set<ModCandidateImpl>> envDisabledModsOut) throws ModResolutionException {
public ModDiscoveryInfo discoverMods(Map<String, Set<ModCandidateImpl>> envDisabledModsOut) throws ModResolutionException {
long startTime = System.nanoTime();
ForkJoinPool pool = new ForkJoinPool();
Set<Path> processedPaths = new HashSet<>(); // suppresses duplicate paths
List<Future<ModCandidateImpl>> futures = new ArrayList<>();
List<Exception> exceptions = new ArrayList<>();

ModCandidateConsumer taskSubmitter = (paths, requiresRemap) -> {
List<Path> pendingPaths = new ArrayList<>(paths.size());
Expand All @@ -114,24 +120,24 @@ public List<ModCandidateImpl> discoverMods(FabricLoaderImpl loader, Map<String,
List<ModCandidateImpl> 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);
}
}

ModCandidateImpl candidate = ModCandidateImpl.createBuiltin(mod, versionOverrides, depOverrides);
candidates.add(MetadataVerifier.verifyIndev(candidate, loader.isDevelopmentEnvironment()));
candidates.add(MetadataVerifier.verifyIndev(candidate, isDevelopment));
}

// Add the current Java version
candidates.add(MetadataVerifier.verifyIndev(createJavaMod(), loader.isDevelopmentEnvironment()));
candidates.add(MetadataVerifier.verifyIndev(createJavaMod(), isDevelopment));

ModResolutionException exception = null;

Expand Down Expand Up @@ -178,10 +184,6 @@ public List<ModCandidateImpl> discoverMods(FabricLoaderImpl loader, Map<String,
throw new FormattedException("Mod discovery interrupted!", e);
}

if (exception != null) {
throw exception;
}

// get optional set of disabled mod ids
Set<String> disabledModIds = findDisabledModIds();

Expand Down Expand Up @@ -214,7 +216,7 @@ public List<ModCandidateImpl> discoverMods(FabricLoaderImpl loader, Map<String,

Log.debug(LogCategory.DISCOVERY, "Mod discovery time: %.1f ms", (endTime - startTime) * 1e-6);

return new ArrayList<>(ret);
return new ModDiscoveryInfo(new ArrayList<>(ret), exception);
}

public List<Path> getNonFabricMods() {
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -507,7 +509,7 @@ private List<ModScanTask> 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);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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<ModCandidateImpl> modsFound;
private final ModResolutionException exception;

public ModDiscoveryInfo(List<ModCandidateImpl> discoveredMods, ModResolutionException exception) {
this.modsFound = discoveredMods;
this.exception = exception;
}

public List<ModCandidateImpl> getFoundMods() {
return modsFound;
}

public ModResolutionException getException() {
return exception;
}

public boolean launchable() {
return exception == null;
}
}
32 changes: 32 additions & 0 deletions src/main/java/net/fabricmc/loader/impl/game/GameDefinition.java
Original file line number Diff line number Diff line change
@@ -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<BuiltinMod> getBuiltinMods();
Path getLaunchDirectory();
}

Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<BuiltinMod> 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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand All @@ -77,7 +77,12 @@ public void tearDown() {
*/
@Test
public void testGetNonFabricMods() throws ModResolutionException {
List<ModCandidateImpl> acceptedMods = discoverer.discoverMods(loader, new HashMap<String, Set<ModCandidateImpl>>());
ModDiscoveryInfo discoveryInfo = discoverer.discoverMods(new HashMap<String, Set<ModCandidateImpl>>());
List<ModCandidateImpl> acceptedMods = discoveryInfo.getFoundMods();

if (!discoveryInfo.launchable()) {
throw discoveryInfo.getException();
}

boolean foundDummyFabricMod = false;

Expand Down