diff --git a/gradle.properties b/gradle.properties index c478d5de3..7b435644f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,13 +5,13 @@ group = org.quiltmc description = The mod loading component of Quilt url = https://github.com/quiltmc/quilt-loader # Don't forget to change this in QuiltLoaderImpl as well -quilt_loader = 0.26.4-beta.1 +quilt_loader = 0.26.4 # Fabric & Quilt Libraries asm = 9.6 -sponge_mixin = 0.13.3+mixin.0.8.5 +sponge_mixin = 0.15.3+mixin.0.8.7 tiny_mappings_parser = 0.3.0+build.17 -tiny_remapper = 0.10.3 +tiny_remapper = 0.10.4 access_widener = 2.1.0 mapping_io = 0.6.1 quilt_json5 = 1.0.4+final @@ -27,4 +27,4 @@ annotations = 24.0.1 junit_bom = 5.9.3 github_api = 1.315 flexver = 1.1.0 -mixin_extras = 0.3.5 +mixin_extras = 0.4.1 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 48c0a02ca..19cfad969 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/minecraft/src/main/java/org/quiltmc/loader/impl/game/minecraft/BundlerClassPathCapture.java b/minecraft/src/main/java/org/quiltmc/loader/impl/game/minecraft/BundlerClassPathCapture.java index 2e67225fc..4c7ec3caf 100644 --- a/minecraft/src/main/java/org/quiltmc/loader/impl/game/minecraft/BundlerClassPathCapture.java +++ b/minecraft/src/main/java/org/quiltmc/loader/impl/game/minecraft/BundlerClassPathCapture.java @@ -16,8 +16,11 @@ package org.quiltmc.loader.impl.game.minecraft; +import java.io.IOException; +import java.net.JarURLConnection; import java.net.URL; import java.net.URLClassLoader; +import java.net.URLConnection; import java.util.concurrent.CompletableFuture; public final class BundlerClassPathCapture { @@ -26,9 +29,42 @@ public final class BundlerClassPathCapture { public static void main(String[] args) { // invoked by the bundler on a thread try { URLClassLoader cl = (URLClassLoader) Thread.currentThread().getContextClassLoader(); - FUTURE.complete(cl.getURLs()); + URL[] urls = cl.getURLs(); + + // suppress asm library since it conflicts with Loader's, needed for MC 24w33a + + URL asmUrl = cl.findResource("org/objectweb/asm/ClassReader.class"); + + if (asmUrl != null && (asmUrl = getJarUrl(asmUrl)) != null) { + for (int i = 0; i < urls.length; i++) { + if (urls[i].equals(asmUrl)) { + URL[] newUrls = new URL[urls.length - 1]; + System.arraycopy(urls, 0, newUrls, 0, i); + System.arraycopy(urls, i + 1, newUrls, i, urls.length - i - 1); + urls = newUrls; + break; + } + } + } + + FUTURE.complete(urls); } catch (Throwable t) { FUTURE.completeExceptionally(t); } } + + /** + * Transform jar:file url to its outer file url. + * + *

jar:file:/path/to.jar!/pkg/Cls.class -> file:/path/to.jar + */ + private static URL getJarUrl(URL url) throws IOException { + URLConnection connection = url.openConnection(); + + if (connection instanceof JarURLConnection) { + return ((JarURLConnection) connection).getJarFileURL(); + } + + return null; + } } diff --git a/minecraft/src/main/java/org/quiltmc/loader/impl/game/minecraft/McVersionLookup.java b/minecraft/src/main/java/org/quiltmc/loader/impl/game/minecraft/McVersionLookup.java index 8f5c9510b..185e4148f 100644 --- a/minecraft/src/main/java/org/quiltmc/loader/impl/game/minecraft/McVersionLookup.java +++ b/minecraft/src/main/java/org/quiltmc/loader/impl/game/minecraft/McVersionLookup.java @@ -284,7 +284,9 @@ protected static String getRelease(String version) { int year = Integer.parseInt(matcher.group(1)); int week = Integer.parseInt(matcher.group(2)); - if (year >= 24 && week >= 18) { + if (year >= 24 && week >= 33) { + return "1.21.2"; + } else if (year == 24 && week >= 18 && week <= 21) { return "1.21"; } else if (year == 23 && week >= 51 || year == 24 && week <= 14) { return "1.20.5"; diff --git a/src/fabric/api/java/net/fabricmc/loader/api/entrypoint/EntrypointContainer.java b/src/fabric/api/java/net/fabricmc/loader/api/entrypoint/EntrypointContainer.java index 9a6c3c9fe..d1aa33aee 100644 --- a/src/fabric/api/java/net/fabricmc/loader/api/entrypoint/EntrypointContainer.java +++ b/src/fabric/api/java/net/fabricmc/loader/api/entrypoint/EntrypointContainer.java @@ -36,4 +36,11 @@ public interface EntrypointContainer { * Returns the mod that provided this entrypoint. */ ModContainer getProvider(); + + /** + * Returns a string representation of the entrypoint's definition. + */ + default String getDefinition() { + return ""; + } } diff --git a/src/fabric/impl/java/net/fabricmc/loader/impl/entrypoint/EntrypointContainerImpl.java b/src/fabric/impl/java/net/fabricmc/loader/impl/entrypoint/EntrypointContainerImpl.java index 58ac00f1b..07a42d5a1 100644 --- a/src/fabric/impl/java/net/fabricmc/loader/impl/entrypoint/EntrypointContainerImpl.java +++ b/src/fabric/impl/java/net/fabricmc/loader/impl/entrypoint/EntrypointContainerImpl.java @@ -38,4 +38,9 @@ public T getEntrypoint() { public ModContainer getProvider() { return new ModContainerImpl(quilt.getProvider()); } + + @Override + public String getDefinition() { + return quilt.getDefinition(); + } } diff --git a/src/main/java/org/quiltmc/loader/api/entrypoint/EntrypointContainer.java b/src/main/java/org/quiltmc/loader/api/entrypoint/EntrypointContainer.java index 9252ba45d..2dacf897b 100644 --- a/src/main/java/org/quiltmc/loader/api/entrypoint/EntrypointContainer.java +++ b/src/main/java/org/quiltmc/loader/api/entrypoint/EntrypointContainer.java @@ -35,4 +35,11 @@ public interface EntrypointContainer { * Returns the mod that provided this entrypoint. */ ModContainer getProvider(); + + /** + * Returns a string representation of the entrypoint's definition. + */ + default String getDefinition() { + return ""; + } } diff --git a/src/main/java/org/quiltmc/loader/impl/QuiltLoaderImpl.java b/src/main/java/org/quiltmc/loader/impl/QuiltLoaderImpl.java index 0dd71764e..ca83ca2aa 100644 --- a/src/main/java/org/quiltmc/loader/impl/QuiltLoaderImpl.java +++ b/src/main/java/org/quiltmc/loader/impl/QuiltLoaderImpl.java @@ -131,7 +131,7 @@ public final class QuiltLoaderImpl { public static final int ASM_VERSION = Opcodes.ASM9; - public static final String VERSION = "0.26.4-beta.1"; + public static final String VERSION = "0.26.4"; public static final String MOD_ID = "quilt_loader"; public static final String DEFAULT_MODS_DIR = "mods"; public static final String DEFAULT_CACHE_DIR = ".cache"; diff --git a/src/main/java/org/quiltmc/loader/impl/entrypoint/EntrypointStorage.java b/src/main/java/org/quiltmc/loader/impl/entrypoint/EntrypointStorage.java index a068867f1..a298c53ef 100644 --- a/src/main/java/org/quiltmc/loader/impl/entrypoint/EntrypointStorage.java +++ b/src/main/java/org/quiltmc/loader/impl/entrypoint/EntrypointStorage.java @@ -39,6 +39,8 @@ interface Entry { boolean isOptional(); ModContainerExt getModContainer(); + + String getDefinition(); } @SuppressWarnings("deprecation") @@ -87,6 +89,11 @@ public boolean isOptional() { public ModContainerExt getModContainer() { return mod; } + + @Override + public String getDefinition() { + return value; + } } private static final class NewEntry implements Entry { @@ -131,6 +138,11 @@ public boolean isOptional() { public ModContainerExt getModContainer() { return mod; } + + @Override + public String getDefinition() { + return value; + } } private final Map> entryMap = new HashMap<>(); diff --git a/src/main/java/org/quiltmc/loader/impl/entrypoint/EntrypointUtils.java b/src/main/java/org/quiltmc/loader/impl/entrypoint/EntrypointUtils.java index 882bd594c..7bfd9d7a9 100644 --- a/src/main/java/org/quiltmc/loader/impl/entrypoint/EntrypointUtils.java +++ b/src/main/java/org/quiltmc/loader/impl/entrypoint/EntrypointUtils.java @@ -63,8 +63,8 @@ private static void invoke0(String name, Class type, Consumer new RuntimeException(String.format("Could not execute entrypoint stage '%s' due to errors, provided by '%s'!", - name, container.getProvider().metadata().id()), + exc -> new RuntimeException(String.format("Could not execute entrypoint stage '%s' due to errors, provided by '%s' at '%s'!", + name, container.getProvider().metadata().id(), container.getDefinition()), exc)); } } diff --git a/src/main/java/org/quiltmc/loader/impl/launch/common/QuiltMixinBootstrap.java b/src/main/java/org/quiltmc/loader/impl/launch/common/QuiltMixinBootstrap.java index f46e88047..e5352a99f 100644 --- a/src/main/java/org/quiltmc/loader/impl/launch/common/QuiltMixinBootstrap.java +++ b/src/main/java/org/quiltmc/loader/impl/launch/common/QuiltMixinBootstrap.java @@ -147,7 +147,7 @@ public static final class MixinConfigDecorator { // maximum loader version and bundled fabric mixin version, DESCENDING ORDER, LATEST FIRST // loader versions with new mixin versions need to be added here - // addVersion("0.13", FabricUtil.COMPATIBILITY_0_11_0); // example for next entry (latest first!) + addVersion("0.16.0", FabricUtil.COMPATIBILITY_0_14_0); addVersion("0.12.0-", FabricUtil.COMPATIBILITY_0_10_0); } @@ -173,9 +173,11 @@ public static int getMixinCompat(boolean isFabric, ModMetadata metadata) { List reqIntervals = Collections.singletonList(VersionInterval.INFINITE); if (!isFabric) { - // quilt or builtin mod, we can assume it uses latest compat - Log.debug(LogCategory.MIXIN, "Assuming Quilt mod %s uses latest mixin compatibility", metadata.id()); - return FabricUtil.COMPATIBILITY_LATEST; + // quilt or builtin mod, we can assume it uses latest (0.10.0 at the time) compat + // Except since , we can't assume that anymore! + // TODO - Handle Quilt mods like Fabric mods but with our own version ranges + Log.debug(LogCategory.MIXIN, "Assuming Quilt mod %s uses 0.10.0 mixin compatibility", metadata.id()); + return FabricUtil.COMPATIBILITY_0_10_0; } FabricLoaderModMetadata fabricMeta = ((InternalModMetadata) metadata).asFabricModMetadata(); @@ -202,11 +204,10 @@ public static int getMixinCompat(boolean isFabric, ModMetadata metadata) { if (minLoaderVersion.compareTo(version.loaderVersion) >= 0) { // lower bound is >= current version Log.debug(LogCategory.MIXIN, "Mod %s requires loader version %s, using mixin compatibility %s", metadata.id(), minLoaderVersion, version.mixinVersion); return version.mixinVersion; - } else { - Log.debug(LogCategory.MIXIN, "Mod %s requires loader version %s, using 0.9.2 mixin compatability", metadata.id(), minLoaderVersion); - return FabricUtil.COMPATIBILITY_0_9_2; } } + Log.debug(LogCategory.MIXIN, "Mod %s requires loader version %s, using 0.9.2 mixin compatability", metadata.id(), minLoaderVersion); + return FabricUtil.COMPATIBILITY_0_9_2; } // Mod doesn't declare a dependency on a loader version; use oldest mixin compat version diff --git a/src/main/java/org/quiltmc/loader/impl/launch/knot/MixinContainerHandleMod.java b/src/main/java/org/quiltmc/loader/impl/launch/knot/MixinContainerHandleMod.java deleted file mode 100644 index 99ad0d18a..000000000 --- a/src/main/java/org/quiltmc/loader/impl/launch/knot/MixinContainerHandleMod.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2016 FabricMC - * Copyright 2022-2023 QuiltMC - * - * 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 org.quiltmc.loader.impl.launch.knot; - -import java.util.Collection; -import java.util.Collections; - -import org.quiltmc.loader.impl.util.QuiltLoaderInternal; -import org.quiltmc.loader.impl.util.QuiltLoaderInternalType; -import org.spongepowered.asm.launch.platform.container.IContainerHandle; - -@QuiltLoaderInternal(QuiltLoaderInternalType.LEGACY_EXPOSED) -public class MixinContainerHandleMod implements IContainerHandle { - @Override - public String getAttribute(String name) { - return null; - } - - @Override - public Collection getNestedContainers() { - return Collections.emptyList(); - } -} diff --git a/src/main/java/org/quiltmc/loader/impl/launch/knot/MixinServiceKnot.java b/src/main/java/org/quiltmc/loader/impl/launch/knot/MixinServiceKnot.java index 88cea02e1..e92cd42f4 100644 --- a/src/main/java/org/quiltmc/loader/impl/launch/knot/MixinServiceKnot.java +++ b/src/main/java/org/quiltmc/loader/impl/launch/knot/MixinServiceKnot.java @@ -85,9 +85,14 @@ public ClassNode getClassNode(String name) throws ClassNotFoundException, IOExce @Override public ClassNode getClassNode(String name, boolean runTransformers) throws ClassNotFoundException, IOException { + return getClassNode(name, runTransformers, 0); + } + + @Override + public ClassNode getClassNode(String name, boolean runTransformers, int readerFlags) throws ClassNotFoundException, IOException { ClassReader reader = new ClassReader(getClassBytes(name, runTransformers)); ClassNode node = new ClassNode(); - reader.accept(node, 0); + reader.accept(node, readerFlags); return node; } diff --git a/src/main/java/org/quiltmc/loader/impl/plugin/QuiltPluginClassLoader.java b/src/main/java/org/quiltmc/loader/impl/plugin/QuiltPluginClassLoader.java index 3586e9dbe..f2133fea2 100644 --- a/src/main/java/org/quiltmc/loader/impl/plugin/QuiltPluginClassLoader.java +++ b/src/main/java/org/quiltmc/loader/impl/plugin/QuiltPluginClassLoader.java @@ -48,7 +48,11 @@ public QuiltPluginClassLoader(QuiltPluginContextImpl context, ClassLoader parent @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - Class c = loadClassInner(name); + Class c = findLoadedClass(name); + if (c != null) { + return c; + } + c = loadClassInner(name); if (c == null) { return super.loadClass(name, resolve); } diff --git a/src/main/java/org/quiltmc/loader/impl/plugin/QuiltPluginManagerImpl.java b/src/main/java/org/quiltmc/loader/impl/plugin/QuiltPluginManagerImpl.java index 512c940ae..f7845a9ad 100644 --- a/src/main/java/org/quiltmc/loader/impl/plugin/QuiltPluginManagerImpl.java +++ b/src/main/java/org/quiltmc/loader/impl/plugin/QuiltPluginManagerImpl.java @@ -1590,24 +1590,37 @@ ModSolveResultImpl getPartialSolution() throws ModSolvingError, TimeoutException Map, LoadOptionResult> extraResults; final Map, Map> optionMap = new HashMap<>(); - for (LoadOption option : solution) { + try { + for (LoadOption option : solution) { - boolean load = true; - if (LoadOption.isNegated(option)) { - option = option.negate(); - load = false; - } + boolean load = true; + if (LoadOption.isNegated(option)) { + option = option.negate(); + load = false; + } - if (load && option instanceof ModLoadOption) { - ModLoadOption mod = (ModLoadOption) option; - putMod(directModsMap, mod.id(), mod); + if (load && option instanceof ModLoadOption) { + ModLoadOption mod = (ModLoadOption) option; + putMod(directModsMap, mod.id(), mod); - for (ProvidedMod provided : mod.metadata().provides()) { - putMod(providedModsMap, provided.id(), mod); + for (ProvidedMod provided : mod.metadata().provides()) { + putMod(providedModsMap, provided.id(), mod); + } } - } - putHierarchy(option, load, optionMap); + putHierarchy(option, load, optionMap); + } + } catch (ModSolvingError cause) { + // Something went wrong during solving + StringBuilder errorDesc = new StringBuilder("The solver returned a solution with duplicate mods!\n"); + errorDesc.append(cause.getMessage()); + errorDesc.append("\n\nCurrent Solution:"); + for (LoadOption option : solution) { + errorDesc.append("\n\t-" + option); + } + errorDesc.append("\n\n"); + solver.appendRules(errorDesc); + throw new ModSolvingError(errorDesc.toString(), cause); } extraResults = new HashMap<>(); diff --git a/src/main/java/org/quiltmc/loader/impl/solver/Sat4jWrapper.java b/src/main/java/org/quiltmc/loader/impl/solver/Sat4jWrapper.java index 8380ee401..1749f4b42 100644 --- a/src/main/java/org/quiltmc/loader/impl/solver/Sat4jWrapper.java +++ b/src/main/java/org/quiltmc/loader/impl/solver/Sat4jWrapper.java @@ -241,6 +241,16 @@ public void cancel() { cancelled = true; } + // ############# + // # Debugging # + // ############# + + /** Appends all current rules and options using the {@link SolverPreProcessor} format. */ + public void appendRules(StringBuilder sb) { + InputRuleSet ruleSet = new InputRuleSet(optionToWeight, ruleToDefinitions); + SolverPreProcessor.appendRuleSet(ruleSet, ruleSet, str -> sb.append("\n" + str)); + } + // ############ // # Internal # // ############ @@ -525,7 +535,7 @@ boolean hasSolution() throws TimeoutException, ModSolvingError { } } Log.info(CATEGORY, "Constant values:"); - for (LoadOption option : processed.getConstantSolution()) { + for (String option : processed.getConstantSolution().stream().map(LoadOption::toString).sorted().toArray(String[]::new)) { Log.info(CATEGORY, option.toString()); } Log.info(CATEGORY, "Unknown values:"); diff --git a/src/main/java/org/quiltmc/loader/impl/solver/SolverPreProcessor.java b/src/main/java/org/quiltmc/loader/impl/solver/SolverPreProcessor.java index bc4dbbf83..95c0e6cc2 100644 --- a/src/main/java/org/quiltmc/loader/impl/solver/SolverPreProcessor.java +++ b/src/main/java/org/quiltmc/loader/impl/solver/SolverPreProcessor.java @@ -462,13 +462,13 @@ private ProcessedRuleSet process() throws ContradictionException, PreProcessExce remaining.add(currentMin); remaining.add(currentMax); remaining.remove(null); - final Set removing; if (remaining.size() == 1) { - removing = new HashSet<>(); + Set removing = new HashSet<>(); removing.addAll(rules); removing.removeAll(remaining); + removing.forEach(this::removeRule); } else { - removing = rules; + rules.forEach(this::removeRule); final Rule rule = remaining.iterator().next().rule; final LoadOption[] array = optionSet.toArray(new LoadOption[0]); if (max < optionSet.size()) { @@ -487,7 +487,6 @@ private ProcessedRuleSet process() throws ContradictionException, PreProcessExce // None of the rules affect the options } } - removing.forEach(this::removeRule); changed = true; } diff --git a/src/main/java/org/quiltmc/loader/impl/solver/SolverTester.java b/src/main/java/org/quiltmc/loader/impl/solver/SolverTester.java index 08e6ff1a3..6a396fa7d 100644 --- a/src/main/java/org/quiltmc/loader/impl/solver/SolverTester.java +++ b/src/main/java/org/quiltmc/loader/impl/solver/SolverTester.java @@ -21,26 +21,34 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.quiltmc.loader.api.gui.QuiltLoaderText; import org.quiltmc.loader.api.plugin.solver.LoadOption; +import org.quiltmc.loader.api.plugin.solver.Rule; +import org.quiltmc.loader.api.plugin.solver.RuleDefiner; import org.quiltmc.loader.impl.discovery.ModSolvingError; import org.quiltmc.loader.impl.solver.RuleSet.ProcessedRuleSet; import org.quiltmc.loader.impl.util.QuiltLoaderInternal; import org.quiltmc.loader.impl.util.QuiltLoaderInternalType; import org.quiltmc.loader.impl.util.log.Log; +import org.quiltmc.loader.util.sat4j.specs.TimeoutException; @QuiltLoaderInternal(QuiltLoaderInternalType.NEW_INTERNAL) public class SolverTester { - public static void main(String[] args) throws ModSolvingError, IOException { + static final boolean JUST_PRE_PROCESS = true; + static final boolean PRINT_COMPACT_OPTIONS = true; + + public static void main(String[] args) throws ModSolvingError, IOException, TimeoutException { Log.configureBuiltin(false, true); Log.disableBuiltinFormatting(); @@ -88,7 +96,13 @@ public static void main(String[] args) throws ModSolvingError, IOException { } else if (line.startsWith("Exactly")) { list.add(read1(line, option2def, (array, count) -> new RuleDefinition.Exactly(null, count, array))); } else if (line.startsWith("Between")) { - list.add(read2(line, option2def, (array, count1, count2) -> new RuleDefinition.Between(null, count1, count2, array))); + list.add( + read2( + line, option2def, (array, count1, count2) -> new RuleDefinition.Between( + null, count1, count2, array + ) + ) + ); } else { int colon1 = line.indexOf(':'); if (colon1 < 0) { @@ -133,18 +147,65 @@ public static void main(String[] args) throws ModSolvingError, IOException { System.out.println(line); } - RuleSet ruleSet = new RuleSet.ProcessedRuleSet(constants, aliases, options, list); - ProcessedRuleSet processed = SolverPreProcessor.preProcess(false, ruleSet); - System.out.println("Pre Process Success!"); - System.out.println("Constants:"); - Comparator> cmp = Comparator.comparing(entry -> optionKey(entry.getKey())); - for (Entry entry : processed.constants.entrySet().stream().sorted(cmp).collect(Collectors.toList())) { - LoadOption option = entry.getKey(); - String key = optionKey(option); - System.out.println(key + " = " + (entry.getValue() ? "true " : "false" ) + " " + ((ReadOption) option).text); + if (JUST_PRE_PROCESS) { + RuleSet ruleSet = new RuleSet.ProcessedRuleSet(constants, aliases, options, list); + ProcessedRuleSet processed = SolverPreProcessor.preProcess(true, ruleSet); + System.out.println("Pre Process Success!"); + System.out.println("Constants:"); + Comparator> cmp = Comparator.comparing(entry -> optionKey(entry.getKey())); + for (Entry entry : processed.constants.entrySet().stream().sorted(cmp).collect( + Collectors.toList() + )) { + LoadOption option = entry.getKey(); + String key = optionKey(option); + System.out.println( + key + " = " + (entry.getValue() ? "true " : "false") + " " + ((ReadOption) option).text + ); + } + System.out.println("Output Solution:"); + List soln = new ArrayList<>(); + for (LoadOption option : processed.getConstantSolution()) { + soln.add(" - " + option.describe()); + } + soln.sort(null); + soln.forEach(System.out::println); + System.out.println("Remaining problem:"); + SolverPreProcessor.appendRuleSet(processed, ruleSet, System.out::println); + } else { + Sat4jWrapper wrapper = new Sat4jWrapper(); + + for (Map.Entry option : options.entrySet()) { + wrapper.addOption(option.getKey()); + wrapper.setWeight(option.getKey(), null, option.getValue()); + } + + for (RuleDefinition def : list) { + wrapper.addRule(new PreDefinedRule(def)); + } + + if (wrapper.hasSolution()) { + System.out.println("Has Solution!"); + Collection solution = wrapper.getSolution(); + List out = new ArrayList<>(); + solution.forEach(option -> { + final boolean load; + if (LoadOption.isNegated(option)) { + option = option.negate(); + load = false; + } else { + load = true; + } + String key = optionKey(option); + out.add(key + " = " + (load ? "true " : "false") + " " + ((ReadOption) option).text); + }); + out.sort(null); + out.forEach(System.out::println); + } else { + System.out.println("No solution!"); + // TODO: Add debugging here? + // (Not sure its necessary, as we don't normally test that here) + } } - System.out.println("Remaining problem:"); - SolverPreProcessor.appendRuleSet(processed, ruleSet, System.out::println); } private static String optionKey(LoadOption option) { @@ -243,7 +304,7 @@ public ReadOption(String key, String text) { @Override public String toString() { - return key; + return PRINT_COMPACT_OPTIONS ? key : text; } @Override @@ -251,4 +312,71 @@ public QuiltLoaderText describe() { return QuiltLoaderText.of(text); } } + + @QuiltLoaderInternal(QuiltLoaderInternalType.NEW_INTERNAL) + static class PreDefinedRule extends Rule { + + final RuleDefinition definition; + + public PreDefinedRule(RuleDefinition definition) { + this.definition = definition; + } + + @Override + public boolean onLoadOptionAdded(LoadOption option) { + return false; + } + + @Override + public boolean onLoadOptionRemoved(LoadOption option) { + return false; + } + + @Override + public void define(RuleDefiner definer) { + if (definition instanceof RuleDefinition.AtLeastOneOf) { + definer.atLeast(1, ((RuleDefinition.AtLeastOneOf) definition).options); + } else if (definition instanceof RuleDefinition.AtLeast) { + RuleDefinition.AtLeast atLeast = (RuleDefinition.AtLeast) definition; + definer.atLeast(atLeast.count, atLeast.options); + } else if (definition instanceof RuleDefinition.AtMost) { + RuleDefinition.AtMost atMost = (RuleDefinition.AtMost) definition; + definer.atMost(atMost.count, atMost.options); + } else if (definition instanceof RuleDefinition.Exactly) { + RuleDefinition.Exactly exactly = (RuleDefinition.Exactly) definition; + definer.exactly(exactly.count, exactly.options); + } else { + RuleDefinition.Between between = (RuleDefinition.Between) definition; + definer.between(between.min, between.max, between.options); + } + } + + @Override + public String toString() { + return definition.toString(); + } + + @Override + public Collection getNodesFrom() { + // TODO Auto-generated method stub + throw new AbstractMethodError("// TODO: Implement this!"); + } + + @Override + public Collection getNodesTo() { + // TODO Auto-generated method stub + throw new AbstractMethodError("// TODO: Implement this!"); + } + + @Override + public void fallbackErrorDescription(StringBuilder errors) { + errors.append(toString()); + } + + @Override + public void appendRuleDescription(Consumer to) { + // TODO Auto-generated method stub + throw new AbstractMethodError("// TODO: Implement this!"); + } + } } diff --git a/src/main/resources/changelog/0.26.4.txt b/src/main/resources/changelog/0.26.4.txt index f1af64ab5..1e5d43cf9 100644 --- a/src/main/resources/changelog/0.26.4.txt +++ b/src/main/resources/changelog/0.26.4.txt @@ -1,3 +1,17 @@ Bug fixes: -- Fixed an oversight where Loader can try to open a GUI in a headless environment \ No newline at end of file +- Fixed an oversight where Loader can try to open a GUI in a headless environment +- Fixed the solver pre-processor sometimes removing a rule it's optimising when merging rules together. + +Changes: + +- Mixin compatibility level for quilt mods is currently set to 0.10.0. We'll add a way to change this in the future. +- Include the full solver pre-processor input and output state when it crashes. + +Changes from updating Fabric Loader from 0.15.11 to 0.16.4: + +- Updated mixin extras to 0.4.1 +- Updated mixin to 0.15.3+mixin.0.8.7 +- Added version parsing support for 1.21.2 +- Include full entrypoint definition in entrypoint crashes. +- Added support for ignoring newer ASM versions on dedicated servers for 24w33a and later. diff --git a/src/main/resources/quilt.mod.json b/src/main/resources/quilt.mod.json index f3f3b9e3b..6fadb3e7b 100644 --- a/src/main/resources/quilt.mod.json +++ b/src/main/resources/quilt.mod.json @@ -22,7 +22,7 @@ "provides": [ { "id": "fabricloader", - "version": "0.15.11" + "version": "0.16.4" } ], "depends": [