Skip to content

Commit

Permalink
Let fabric ModResolver handle duplicates
Browse files Browse the repository at this point in the history
Fix loading duplicate root and nested jars
  • Loading branch information
Su5eD committed Aug 20, 2023
1 parent 58474c3 commit 0fe1fb5
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 34 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ versionForge=47.1.3
versionForgeAutoRenamingTool=1.0.8
versionFabricLoader=2.3.2+0.14.21+1.20.1
versionAccessWidener=2.1.0
versionFabricApi=0.87.0+1.9.3+1.20.1
versionFabricApi=0.87.0+1.9.4+1.20.1
versionMixin=0.12.6+mixin.0.8.5

# Publishing
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package dev.su5ed.sinytra.connector.locator;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.mojang.logging.LogUtils;
import cpw.mods.jarhandling.SecureJar;
import dev.su5ed.sinytra.connector.ConnectorUtil;
Expand Down Expand Up @@ -29,12 +27,10 @@
import java.lang.invoke.MethodType;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.jar.Manifest;
import java.util.stream.Stream;
Expand Down Expand Up @@ -98,16 +94,14 @@ private List<IModFile> locateFabricMods(Iterable<IModFile> loadedMods) {
return discoverNestedJarsRecursive(tempDir, secureJar, metadata.getJars());
})
.toList();
// Remove duplicates and existing mods
List<JarTransformer.TransformableJar> uniqueNestedJars = handleDuplicateMods(Objects.requireNonNull(discoveredNestedJars), loadedModIds);
// Merge outer and nested jar lists
List<JarTransformer.TransformableJar> allJars = Stream.concat(discoveredJars.stream(), uniqueNestedJars.stream()).toList();
// Remove mods loaded by FML
List<JarTransformer.TransformableJar> uniqueJars = handleDuplicateMods(discoveredJars, discoveredNestedJars, loadedModIds);
// Ensure we have all required dependencies before transforming
DependencyResolver.resolveDependencies(allJars, loadedMods);
List<JarTransformer.TransformableJar> candidates = DependencyResolver.resolveDependencies(uniqueJars, loadedMods);
// Get renamer library classpath
List<Path> renameLibs = StreamSupport.stream(loadedMods.spliterator(), false).map(modFile -> modFile.getSecureJar().getRootPath()).toList();
// Run jar transformations (or get existing outputs from cache)
List<JarTransformer.FabricModPath> transformed = JarTransformer.transform(allJars, renameLibs);
List<JarTransformer.FabricModPath> transformed = JarTransformer.transform(candidates, renameLibs);
// Skip last step to save time if an error occured during transformation
if (ConnectorEarlyLoader.hasEncounteredException()) {
StartupNotificationManager.addModMessage("JAR TRANSFORMATION ERROR");
Expand Down Expand Up @@ -167,25 +161,19 @@ private static JarTransformer.TransformableJar prepareNestedJar(Path tempDir, St
}

// Removes any duplicates from located connector mods, as well as mods that are already located by FML.
private static List<JarTransformer.TransformableJar> handleDuplicateMods(List<JarTransformer.TransformableJar> mods, Collection<String> loadedModIds) {
Multimap<String, JarTransformer.TransformableJar> byId = HashMultimap.create();
for (JarTransformer.TransformableJar jar : mods) {
String id = jar.modPath().metadata().modMetadata().getId();
if (!loadedModIds.contains(id)) {
byId.put(id, jar);
}
else {
LOGGER.info(SCAN, "Removing duplicate mod {} from file {}", id, jar.modPath().path().toAbsolutePath());
}
}
List<JarTransformer.TransformableJar> list = new ArrayList<>();
byId.asMap().forEach((modid, candidates) -> {
JarTransformer.TransformableJar mostRecent = candidates.stream()
.max(Comparator.comparing(m -> m.modPath().metadata().modMetadata().getVersion()))
.orElseThrow();
list.add(mostRecent);
});
return list;
private static List<JarTransformer.TransformableJar> handleDuplicateMods(List<JarTransformer.TransformableJar> rootMods, List<JarTransformer.TransformableJar> nestedMods, Collection<String> loadedModIds) {
return Stream.concat(rootMods.stream(), nestedMods.stream())
.filter(jar -> {
String id = jar.modPath().metadata().modMetadata().getId();
if (!loadedModIds.contains(id)) {
return true;
}
else {
LOGGER.info(SCAN, "Removing duplicate mod {} in file {}", id, jar.modPath().path().toAbsolutePath());
return false;
}
})
.toList();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand All @@ -36,10 +37,15 @@ public final class DependencyResolver {
public static final VersionOverrides VERSION_OVERRIDES = new VersionOverrides();
public static final DependencyOverrides DEPENDENCY_OVERRIDES = new DependencyOverrides(FMLPaths.CONFIGDIR.get());

public static void resolveDependencies(List<JarTransformer.TransformableJar> jars, Iterable<IModFile> loadedMods) {
public static List<JarTransformer.TransformableJar> resolveDependencies(List<JarTransformer.TransformableJar> jars, Iterable<IModFile> loadedMods) {
Map<ModCandidate, JarTransformer.TransformableJar> candidateToJar = new HashMap<>();
// Fabric candidates
Stream<ModCandidate> candidates = jars.stream()
.map(jar -> ModCandidate.createPlain(List.of(jar.modPath().path()), jar.modPath().metadata().modMetadata(), false, List.of()));
.map(jar -> {
ModCandidate candidate = ModCandidate.createPlain(List.of(jar.modPath().path()), jar.modPath().metadata().modMetadata(), false, List.of());
candidateToJar.put(candidate, jar);
return candidate;
});
// Forge dependencies
Stream<ModCandidate> forgeCandidates = StreamSupport.stream(loadedMods.spliterator(), false)
.flatMap(modFile -> modFile.getModFileInfo() != null ? modFile.getModInfos().stream() : Stream.empty())
Expand All @@ -50,8 +56,13 @@ public static void resolveDependencies(List<JarTransformer.TransformableJar> jar

EnvType envType = FabricLoader.getInstance().getEnvironmentType();
try {
ModResolver.resolve(allCandidates, envType, Map.of());
LOGGER.info("Dependency resolution completed successfully");
List<ModCandidate> resolved = ModResolver.resolve(allCandidates, envType, Map.of());
List<JarTransformer.TransformableJar> candidateJars = resolved.stream()
.map(candidateToJar::get)
.filter(Objects::nonNull)
.toList();
LOGGER.info("Dependency resolution found {} candidates to load", candidateJars.size());
return candidateJars;
} catch (ModResolutionException e) {
throw ConnectorEarlyLoader.createLoadingException(e, e.getMessage().replaceAll("\t", " "));
}
Expand Down

0 comments on commit 0fe1fb5

Please sign in to comment.