From 160f3f88f9e540c86f788b55f5a11dffe9a79a1d Mon Sep 17 00:00:00 2001 From: cpw Date: Sat, 7 Nov 2020 20:47:12 -0500 Subject: [PATCH] Support backwards loading 1.16.3 mods in 1.16.4, because we are able to do that. Tweak loading a bit to be smarter about dependency errors of various kinds. Signed-off-by: cpw --- .../fml/loading/EarlyLoadingException.java | 2 - .../fml/loading/LanguageLoadingProvider.java | 2 +- .../minecraftforge/fml/loading/ModSorter.java | 71 +++++++++++-------- .../fml/loading/VersionSupportMatrix.java | 24 +++++++ 4 files changed, 65 insertions(+), 34 deletions(-) create mode 100644 src/fmllauncher/java/net/minecraftforge/fml/loading/VersionSupportMatrix.java diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/EarlyLoadingException.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/EarlyLoadingException.java index 905e60930..56753b54e 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/EarlyLoadingException.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/EarlyLoadingException.java @@ -29,8 +29,6 @@ import java.util.List; */ public class EarlyLoadingException extends RuntimeException { public static class ExceptionData { - - private final IModInfo modInfo; private final String i18message; private final Object[] args; diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java index a8074054d..a55813f06 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java @@ -170,7 +170,7 @@ public class LanguageLoadingProvider LOGGER.error("Missing language {} version {} wanted by {}", modLoader, modLoaderVersion, languageFileName); throw new EarlyLoadingException("Missing language "+modLoader, null, Collections.singletonList(new EarlyLoadingException.ExceptionData("fml.language.missingversion", modLoader, modLoaderVersion, languageFileName, "null"))); } - if (!modLoaderVersion.containsVersion(mlw.getVersion())) { + if (!VersionSupportMatrix.testVersionSupportMatrix(modLoaderVersion, modLoader, "languageloader", (llid, range) -> range.containsVersion(mlw.getVersion()))) { LOGGER.error("Missing language {} version {} wanted by {}, found {}", modLoader, modLoaderVersion, languageFileName, mlw.getVersion()); throw new EarlyLoadingException("Missing language "+ modLoader + " matching range "+modLoaderVersion + " found "+mlw.getVersion(), null, Collections.singletonList(new EarlyLoadingException.ExceptionData("fml.language.missingversion", modLoader, modLoaderVersion, languageFileName, mlw.getVersion()))); } diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/ModSorter.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/ModSorter.java index aa4d39198..bb613313e 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/ModSorter.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/ModSorter.java @@ -36,17 +36,11 @@ import org.apache.logging.log4j.util.StringBuilderFormattable; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; -import java.util.AbstractMap; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import static net.minecraftforge.fml.loading.LogMarkers.LOADING; @@ -65,26 +59,41 @@ public class ModSorter public static LoadingModList sort(List mods) { final ModSorter ms = new ModSorter(mods); - EarlyLoadingException earlyLoadingException = null; try { - ms.findLanguages(); ms.buildUniqueList(); - ms.verifyDependencyVersions(); - ms.sort(); - } catch (EarlyLoadingException ele) { - earlyLoadingException = ele; - ms.sortedList = Collections.emptyList(); - try { - ms.buildUniqueList(); - } catch (EarlyLoadingException ele2) { - //IGNORE - } + } catch (EarlyLoadingException e) { + // We cannot build any list with duped mods. We have to abort immediately and report it + return LoadingModList.of(Collections.emptyList(), Collections.emptyList(), e); + } + // try and locate languages and validate dependencies + List missingLangs = ms.findLanguages(); + List missingDeps = ms.verifyDependencyVersions(); + final List failedList = Stream.concat(missingLangs.stream(), missingDeps.stream()).collect(Collectors.toList()); + // if we miss one or the other, we abort now + if (!failedList.isEmpty()) { + return LoadingModList.of(Collections.emptyList(), Collections.emptyList(), new EarlyLoadingException("failure to validate mod list", null, failedList)); + } else { + // Otherwise, lets try and sort the modlist and proceed + EarlyLoadingException earlyLoadingException = null; + try { + ms.sort(); + } catch (EarlyLoadingException e) { + earlyLoadingException = e; + } + return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException); } - return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException); } - private void findLanguages() { - modFiles.forEach(ModFile::identifyLanguage); + private List findLanguages() { + List errorData = new ArrayList<>(); + modFiles.forEach(modFile -> { + try { + modFile.identifyLanguage(); + } catch (EarlyLoadingException e) { + errorData.addAll(e.getAllData()); + } + }); + return errorData; } @SuppressWarnings("UnstableApiUsage") @@ -218,7 +227,7 @@ public class ModSorter return new AbstractMap.SimpleImmutableEntry<>(fullList.getKey(), modInfoList.get(0)); } - private void verifyDependencyVersions() + private List verifyDependencyVersions() { final Map modVersions = modFiles .stream() @@ -242,24 +251,24 @@ public class ModSorter LOGGER.debug(LOADING, "Found {} mandatory requirements", mandatoryModVersions.size()); final Set missingVersions = mandatoryModVersions .stream() - .filter(mv->this.modVersionMatches(mv, modVersions)) + .filter(mv->this.modVersionNotContained(mv, modVersions)) .collect(Collectors.toSet()); LOGGER.debug(LOADING, "Found {} mandatory mod requirements missing", missingVersions.size()); if (!missingVersions.isEmpty()) { - final List exceptionData = missingVersions + return missingVersions .stream() - .map(mv -> new EarlyLoadingException.ExceptionData("fml.modloading.missingdependency", mv.getOwner(), + .map(mv -> new ExceptionData("fml.modloading.missingdependency", mv.getOwner(), mv.getModId(), mv.getOwner().getModId(), mv.getVersionRange(), modVersions.getOrDefault(mv.getModId(), new DefaultArtifactVersion("null")))) .collect(Collectors.toList()); - throw new EarlyLoadingException("Missing mods", null, exceptionData); } + return Collections.emptyList(); } - private boolean modVersionMatches(final IModInfo.ModVersion mv, final Map modVersions) + private boolean modVersionNotContained(final IModInfo.ModVersion mv, final Map modVersions) { - return !(modVersions.containsKey(mv.getModId()) && - (mv.getVersionRange().containsVersion(modVersions.get(mv.getModId())) || modVersions.get(mv.getModId()).toString().equals("NONE"))); + return !(VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod", (modId, range) -> modVersions.containsKey(modId) && + (range.containsVersion(modVersions.get(modId)) || modVersions.get(modId).toString().equals("NONE")))); } } diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/VersionSupportMatrix.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/VersionSupportMatrix.java new file mode 100644 index 000000000..737cb6b5c --- /dev/null +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/VersionSupportMatrix.java @@ -0,0 +1,24 @@ +package net.minecraftforge.fml.loading; + +import net.minecraftforge.forgespi.language.MavenVersionAdapter; +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.apache.maven.artifact.versioning.VersionRange; + +import java.util.HashMap; +import java.util.function.BiPredicate; + +public class VersionSupportMatrix { + private static final HashMap overrideVersions = new HashMap<>(); + static { + final ArtifactVersion version = new DefaultArtifactVersion(FMLLoader.mcVersion); + if (MavenVersionAdapter.createFromVersionSpec("[1.16.4]").containsVersion(version)) { + overrideVersions.put("languageloader.javafml", new DefaultArtifactVersion("34")); // we also work with javafml 34 + overrideVersions.put("mod.minecraft", new DefaultArtifactVersion("1.16.3")); // we work with anything declaring 1.16.3 + overrideVersions.put("mod.forge", new DefaultArtifactVersion("34.1.42")); // we work with anything that supports forge 34.1.42 + } + } + public static boolean testVersionSupportMatrix(VersionRange declaredRange, String lookupId, String type, BiPredicate standardLookup) { + return standardLookup.test(lookupId, declaredRange) || overrideVersions.containsKey(type +"." +lookupId) && declaredRange.containsVersion(overrideVersions.get(type +"." +lookupId)); + } +}