Skip to content

Commit

Permalink
Prioritize mods with higher provided versions if their main id differs
Browse files Browse the repository at this point in the history
  • Loading branch information
sfPlayer1 committed Nov 21, 2023
1 parent fe03387 commit 0917a45
Showing 1 changed file with 56 additions and 4 deletions.
60 changes: 56 additions & 4 deletions src/main/java/net/fabricmc/loader/impl/discovery/ModResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.sat4j.specs.TimeoutException;

import net.fabricmc.api.EnvType;
import net.fabricmc.loader.api.Version;
import net.fabricmc.loader.api.metadata.ModDependency;
import net.fabricmc.loader.api.metadata.ModDependency.Kind;
import net.fabricmc.loader.impl.discovery.ModSolver.InactiveReason;
Expand Down Expand Up @@ -212,6 +213,9 @@ private static List<ModCandidate> findCompatibleSet(Collection<ModCandidate> can
public int compare(ModCandidate a, ModCandidate b) {
// descending sort prio (less/earlier is higher prio):
// root mods first, lower id first, higher version first, less nesting first, parent cmp
// if the ids are different the id+version comparison will consider all id+version pairs from each mod and its provides
// multiple overlaps with provides use a comparison counter to give the mod with the most version advantages priority
// if the ids are equal the mod versions are assumed to represent desired priorities even if provided versions disagree

if (a.isRoot()) {
if (!b.isRoot()) {
Expand All @@ -223,11 +227,19 @@ public int compare(ModCandidate a, ModCandidate b) {

// sort id desc
int idCmp = a.getId().compareTo(b.getId());
if (idCmp != 0) return idCmp;

// sort version desc (lower version later)
int versionCmp = b.getVersion().compareTo(a.getVersion());
if (versionCmp != 0) return versionCmp;
if (idCmp != 0) {
if (a.getProvides().isEmpty() && b.getProvides().isEmpty()) {
return idCmp;
} else {
int cmp = compareOverlappingIds(a, b, idCmp);
if (cmp != 0) return cmp;
}
} else {
// sort version desc (lower version later)
int versionCmp = b.getVersion().compareTo(a.getVersion());
if (versionCmp != 0) return versionCmp;
}

// sort nestLevel asc
int nestCmp = a.getMinNestLevel() - b.getMinNestLevel(); // >0 if nest(a) > nest(b)
Expand All @@ -252,6 +264,46 @@ public int compare(ModCandidate a, ModCandidate b) {
}
};

private static int compareOverlappingIds(ModCandidate a, ModCandidate b, int idCmp) {
assert !a.getId().equals(b.getId()); // should have been handled before
assert idCmp != 0;

int ret = 0; // sum of individual normalized pair comparisons, may cancel each other out
boolean matched = false; // whether any ids overlap, for falling back to main id comparison as if there were no provides

for (String provIdA : a.getProvides()) { // a-provides vs b
if (provIdA.equals(b.getId())) {
Version providedVersionA = a.getVersion();
ret += Integer.signum(b.getVersion().compareTo(providedVersionA));
matched = true;
}
}

for (String provIdB : b.getProvides()) {
if (provIdB.equals(a.getId())) { // a vs b-provides
Version providedVersionB = b.getVersion();
ret += Integer.signum(providedVersionB.compareTo(a.getVersion()));
matched = true;

continue;
}

for (String provIdA : a.getProvides()) { // a-provides vs b-provides
if (provIdB.equals(provIdA)) {
Version providedVersionA = a.getVersion();
Version providedVersionB = b.getVersion();

ret += Integer.signum(providedVersionB.compareTo(providedVersionA));
matched = true;

break;
}
}
}

return matched ? ret : idCmp; // idCmp is != 0, so no need to compare version
}

static void preselectMod(ModCandidate mod, List<ModCandidate> allModsSorted, Map<String, List<ModCandidate>> modsById,
Map<String, ModCandidate> selectedMods, List<ModCandidate> uniqueSelectedMods) throws ModResolutionException {
selectMod(mod, selectedMods, uniqueSelectedMods);
Expand Down

0 comments on commit 0917a45

Please sign in to comment.