fix dependency resolving, fix minecraft version parsing

(since 1.21 isn't valid semver but we can expand it)
This commit is contained in:
moehreag 2024-06-15 19:59:27 +02:00
parent a3aab3d87c
commit f0f742925b
4 changed files with 78 additions and 50 deletions

View file

@ -115,7 +115,7 @@ public class FrogLoaderImpl implements FrogLoader {
gamePlugin = plugin; gamePlugin = plugin;
} }
private void loadModProviders() { private void loadModProviders() throws Exception {
PluginLoader.discoverModProviders(gameDir, mods, modIds, modProviders); PluginLoader.discoverModProviders(gameDir, mods, modIds, modProviders);
} }

View file

@ -5,13 +5,17 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.stream.Collectors;
import dev.frogmc.frogloader.api.FrogLoader; import dev.frogmc.frogloader.api.FrogLoader;
import dev.frogmc.frogloader.api.mod.ModProperties; import dev.frogmc.frogloader.api.mod.ModProperties;
import dev.frogmc.frogloader.api.plugin.FrogGamePlugin; import dev.frogmc.frogloader.api.plugin.FrogGamePlugin;
import dev.frogmc.frogloader.api.plugin.FrogModProvider; import dev.frogmc.frogloader.api.plugin.FrogModProvider;
import dev.frogmc.frogloader.impl.gui.LoaderGui;
import dev.frogmc.frogloader.impl.mixin.AWProcessor; import dev.frogmc.frogloader.impl.mixin.AWProcessor;
import dev.frogmc.frogloader.impl.mod.BuiltinExtensions; import dev.frogmc.frogloader.impl.mod.BuiltinExtensions;
import dev.frogmc.frogloader.impl.mod.ModDependencyResolver;
import dev.frogmc.frogloader.impl.util.CrashReportGenerator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.Mixins; import org.spongepowered.asm.mixin.Mixins;
@ -19,7 +23,7 @@ import org.spongepowered.asm.mixin.Mixins;
public class PluginLoader { public class PluginLoader {
private static final Logger LOGGER = LoggerFactory.getLogger("FrogLoader/Plugins"); private static final Logger LOGGER = LoggerFactory.getLogger("FrogLoader/Plugins");
public static void discoverModProviders(Path gameDir, Map<String, Map<String, ModProperties>> mods, Collection<String> modIds, Collection<FrogModProvider> modProviders) { public static void discoverModProviders(Path gameDir, Map<String, Map<String, ModProperties>> mods, Collection<String> modIds, Collection<FrogModProvider> modProviders) throws ModDependencyResolver.ResolverException {
LOGGER.info("Discovering mod providers..."); LOGGER.info("Discovering mod providers...");
for (FrogModProvider plugin : ServiceLoader.load(FrogModProvider.class)) { for (FrogModProvider plugin : ServiceLoader.load(FrogModProvider.class)) {
@ -44,6 +48,16 @@ public class PluginLoader {
LOGGER.error("Error during plugin initialisation: ", e); LOGGER.error("Error during plugin initialisation: ", e);
} }
} }
Collection<ModProperties> properties = mods.values().stream().map(Map::values).flatMap(Collection::stream).collect(Collectors.toUnmodifiableSet());
try {
Collection<ModProperties> solved = new ModDependencyResolver(properties).solve();
mods.forEach((s, map) -> map.values().retainAll(solved));
} catch (ModDependencyResolver.UnfulfilledDependencyException e) {
LoaderGui.execUnfulfilledDep(CrashReportGenerator.writeReport(e, properties), e, false);
} catch (ModDependencyResolver.BreakingModException e) {
LoaderGui.execBreakingDep(CrashReportGenerator.writeReport(e, properties), e, false);
}
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})

View file

@ -230,18 +230,10 @@ public class ModDependencyResolver {
throw new IllegalArgumentException(comparator); throw new IllegalArgumentException(comparator);
} }
var type = DependencyType.of(matcher.group(1)); var type = DependencyType.of(matcher.group(1));
StringBuilder version = new StringBuilder(matcher.group(2)); var version = matcher.group(2);
while (version.length() < 5) {
if (version.charAt(version.length() - 1) == '.') {
version.append('0');
} else {
version.append('.');
}
}
try { try {
return new Comparator(type, SemVerImpl.parse(version.toString())); return new Comparator(type, SemVerImpl.parse(version));
} catch (SemVerParseException e) { } catch (SemVerParseException e) {
throw new UncheckedIOException(e); throw new UncheckedIOException(e);
} }
@ -325,6 +317,7 @@ public class ModDependencyResolver {
public record VersionRange(Collection<ComparatorSet> sets) { public record VersionRange(Collection<ComparatorSet> sets) {
private static final Pattern NUMBER_EXTRACTOR = Pattern.compile("[^~]?(\\d+)(?:\\.(?:([\\dxX*]+)(?:\\.([\\dxX*]+)?)?)?)?(.*)"); private static final Pattern NUMBER_EXTRACTOR = Pattern.compile("[^~]?(\\d+)(?:\\.(?:([\\dxX*]+)(?:\\.([\\dxX*]+)?)?)?)?(.*)");
private static final Pattern FILL_PATTERN = Pattern.compile("[><=]+(\\d+)\\.?(\\d+)?\\.?(\\d+)?");
public static VersionRange parse(String range) throws ResolverException { public static VersionRange parse(String range) throws ResolverException {
@ -365,13 +358,7 @@ public class ModDependencyResolver {
private static void handleTilde(String s, List<String> ranges) throws ResolverException { private static void handleTilde(String s, List<String> ranges) throws ResolverException {
{ {
StringBuilder builder = new StringBuilder(">=" + s.substring(1)); StringBuilder builder = new StringBuilder(">=" + s.substring(1));
while (builder.length() < 7) { fillVersion(builder);
if (builder.charAt(builder.length() - 1) == '.') {
builder.append('0');
} else {
builder.append('.');
}
}
ranges.add(builder.toString()); ranges.add(builder.toString());
} }
ranges.add(" "); ranges.add(" ");
@ -393,13 +380,7 @@ public class ModDependencyResolver {
private static void handleXRanges(String s, List<String> ranges) throws ResolverException { private static void handleXRanges(String s, List<String> ranges) throws ResolverException {
{ {
StringBuilder builder = new StringBuilder(">=" + s.replaceAll("[xX*]", "0")); StringBuilder builder = new StringBuilder(">=" + s.replaceAll("[xX*]", "0"));
while (builder.length() < 7) { fillVersion(builder);
if (builder.charAt(builder.length() - 1) == '.') {
builder.append('0');
} else {
builder.append('.');
}
}
ranges.add(builder.toString()); ranges.add(builder.toString());
} }
@ -424,13 +405,7 @@ public class ModDependencyResolver {
break; break;
} }
} }
while (builder.length() < 6) { fillVersion(builder);
if (builder.charAt(builder.length() - 1) == '.') {
builder.append('0');
} else {
builder.append('.');
}
}
ranges.add(builder.toString()); ranges.add(builder.toString());
} }
} }
@ -456,26 +431,21 @@ public class ModDependencyResolver {
break; break;
} }
} }
while (builder.length() < 6) { fillVersion(builder);
/*while (builder.length() < 6) {
if (builder.charAt(builder.length() - 1) == '.') { if (builder.charAt(builder.length() - 1) == '.') {
builder.append('0'); builder.append('0');
} else { } else {
builder.append('.'); builder.append('.');
} }
} }*/
ranges.add(builder.toString()); ranges.add(builder.toString());
} }
private static void handleHyphenRange(String s, List<String> ranges, String end) throws ResolverException { private static void handleHyphenRange(String s, List<String> ranges, String end) throws ResolverException {
{ {
StringBuilder builder = new StringBuilder(">=" + s); StringBuilder builder = new StringBuilder(">=" + s);
while (builder.length() < 7) { fillVersion(builder);
if (builder.charAt(builder.length() - 1) == '.') {
builder.append('0');
} else {
builder.append('.');
}
}
ranges.add(builder.toString()); ranges.add(builder.toString());
ranges.add(" "); ranges.add(" ");
} }
@ -499,19 +469,35 @@ public class ModDependencyResolver {
break; break;
} }
} }
while (builder.length() < 6) { fillVersion(builder);
if (builder.charAt(builder.length() - 1) == '.') {
builder.append('0');
} else {
builder.append('.');
}
}
ranges.add(builder.toString()); ranges.add(builder.toString());
} else { } else {
ranges.add("<=" + end); ranges.add("<=" + end);
} }
} }
private static void fillVersion(StringBuilder builder) {
Matcher matcher = FILL_PATTERN.matcher(builder);
if (!matcher.find()) {
return;
}
if (matcher.group(3) != null) {
return;
}
if (builder.charAt(builder.length() - 1) != '.') {
builder.append(".");
}
if (matcher.group(2) == null) {
builder.append("0.0");
return;
}
builder.append("0");
}
private static @NotNull List<String> extractRanges(String range) { private static @NotNull List<String> extractRanges(String range) {
if (!range.contains(" ") && !range.contains(" - ") && !range.contains("||")) { if (!range.contains(" ") && !range.contains(" - ") && !range.contains("||")) {
return List.of(range); return List.of(range);

View file

@ -1,5 +1,8 @@
package dev.frogmc.frogloader.impl.plugin.game.minecraft; package dev.frogmc.frogloader.impl.plugin.game.minecraft;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import dev.frogmc.frogloader.api.mod.SemVer; import dev.frogmc.frogloader.api.mod.SemVer;
import dev.frogmc.frogloader.impl.SemVerParseException; import dev.frogmc.frogloader.impl.SemVerParseException;
import dev.frogmc.frogloader.impl.mod.SemVerImpl; import dev.frogmc.frogloader.impl.mod.SemVerImpl;
@ -7,6 +10,7 @@ import org.jetbrains.annotations.NotNull;
public class MinecraftSemVerImpl implements SemVer { public class MinecraftSemVerImpl implements SemVer {
private static final Pattern FILL_PATTERN = Pattern.compile("(\\d+)\\.?(\\d+)?\\.?(\\d+)?");
private final String version; private final String version;
private MinecraftSemVerImpl(String version) { private MinecraftSemVerImpl(String version) {
@ -15,12 +19,36 @@ public class MinecraftSemVerImpl implements SemVer {
static SemVer get(String version) { static SemVer get(String version) {
try { try {
return SemVerImpl.parse(version); StringBuilder builder = new StringBuilder(version);
fillVersion(builder);
return SemVerImpl.parse(builder.toString());
} catch (SemVerParseException e) { } catch (SemVerParseException e) {
return new MinecraftSemVerImpl(version); return new MinecraftSemVerImpl(version);
} }
} }
private static void fillVersion(StringBuilder builder) {
Matcher matcher = FILL_PATTERN.matcher(builder);
if (!matcher.find()) {
return;
}
if (matcher.group(3) != null) {
return;
}
if (builder.charAt(builder.length() - 1) != '.') {
builder.append(".");
}
if (matcher.group(2) == null) {
builder.append("0.0");
return;
}
builder.append("0");
}
@Override @Override
public int major() { public int major() {
throw new UnsupportedOperationException("Minecraft version " + version + " does not represent a semver-compatible version"); throw new UnsupportedOperationException("Minecraft version " + version + " does not represent a semver-compatible version");