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 <cpw+github@weeksfamily.ca>
This commit is contained in:
cpw 2020-11-07 20:47:12 -05:00
parent 45e38859ed
commit 160f3f88f9
No known key found for this signature in database
GPG key ID: 8EB3DF749553B1B7
4 changed files with 65 additions and 34 deletions

View file

@ -29,8 +29,6 @@ import java.util.List;
*/ */
public class EarlyLoadingException extends RuntimeException { public class EarlyLoadingException extends RuntimeException {
public static class ExceptionData { public static class ExceptionData {
private final IModInfo modInfo; private final IModInfo modInfo;
private final String i18message; private final String i18message;
private final Object[] args; private final Object[] args;

View file

@ -170,7 +170,7 @@ public class LanguageLoadingProvider
LOGGER.error("Missing language {} version {} wanted by {}", modLoader, modLoaderVersion, languageFileName); 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"))); 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()); 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()))); 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())));
} }

View file

@ -36,17 +36,11 @@ import org.apache.logging.log4j.util.StringBuilderFormattable;
import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import java.util.AbstractMap; import java.util.*;
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.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING; import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
@ -65,26 +59,41 @@ public class ModSorter
public static LoadingModList sort(List<ModFile> mods) public static LoadingModList sort(List<ModFile> mods)
{ {
final ModSorter ms = new ModSorter(mods); final ModSorter ms = new ModSorter(mods);
try {
ms.buildUniqueList();
} 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<EarlyLoadingException.ExceptionData> missingLangs = ms.findLanguages();
List<EarlyLoadingException.ExceptionData> missingDeps = ms.verifyDependencyVersions();
final List<ExceptionData> 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; EarlyLoadingException earlyLoadingException = null;
try { try {
ms.findLanguages();
ms.buildUniqueList();
ms.verifyDependencyVersions();
ms.sort(); ms.sort();
} catch (EarlyLoadingException ele) { } catch (EarlyLoadingException e) {
earlyLoadingException = ele; earlyLoadingException = e;
ms.sortedList = Collections.emptyList();
try {
ms.buildUniqueList();
} catch (EarlyLoadingException ele2) {
//IGNORE
}
} }
return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException); return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException);
} }
}
private void findLanguages() { private List<EarlyLoadingException.ExceptionData> findLanguages() {
modFiles.forEach(ModFile::identifyLanguage); List<EarlyLoadingException.ExceptionData> errorData = new ArrayList<>();
modFiles.forEach(modFile -> {
try {
modFile.identifyLanguage();
} catch (EarlyLoadingException e) {
errorData.addAll(e.getAllData());
}
});
return errorData;
} }
@SuppressWarnings("UnstableApiUsage") @SuppressWarnings("UnstableApiUsage")
@ -218,7 +227,7 @@ public class ModSorter
return new AbstractMap.SimpleImmutableEntry<>(fullList.getKey(), modInfoList.get(0)); return new AbstractMap.SimpleImmutableEntry<>(fullList.getKey(), modInfoList.get(0));
} }
private void verifyDependencyVersions() private List<EarlyLoadingException.ExceptionData> verifyDependencyVersions()
{ {
final Map<String, ArtifactVersion> modVersions = modFiles final Map<String, ArtifactVersion> modVersions = modFiles
.stream() .stream()
@ -242,24 +251,24 @@ public class ModSorter
LOGGER.debug(LOADING, "Found {} mandatory requirements", mandatoryModVersions.size()); LOGGER.debug(LOADING, "Found {} mandatory requirements", mandatoryModVersions.size());
final Set<IModInfo.ModVersion> missingVersions = mandatoryModVersions final Set<IModInfo.ModVersion> missingVersions = mandatoryModVersions
.stream() .stream()
.filter(mv->this.modVersionMatches(mv, modVersions)) .filter(mv->this.modVersionNotContained(mv, modVersions))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
LOGGER.debug(LOADING, "Found {} mandatory mod requirements missing", missingVersions.size()); LOGGER.debug(LOADING, "Found {} mandatory mod requirements missing", missingVersions.size());
if (!missingVersions.isEmpty()) { if (!missingVersions.isEmpty()) {
final List<EarlyLoadingException.ExceptionData> exceptionData = missingVersions return missingVersions
.stream() .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(), mv.getModId(), mv.getOwner().getModId(), mv.getVersionRange(),
modVersions.getOrDefault(mv.getModId(), new DefaultArtifactVersion("null")))) modVersions.getOrDefault(mv.getModId(), new DefaultArtifactVersion("null"))))
.collect(Collectors.toList()); .collect(Collectors.toList());
throw new EarlyLoadingException("Missing mods", null, exceptionData);
} }
return Collections.emptyList();
} }
private boolean modVersionMatches(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions) private boolean modVersionNotContained(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
{ {
return !(modVersions.containsKey(mv.getModId()) && return !(VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod", (modId, range) -> modVersions.containsKey(modId) &&
(mv.getVersionRange().containsVersion(modVersions.get(mv.getModId())) || modVersions.get(mv.getModId()).toString().equals("NONE"))); (range.containsVersion(modVersions.get(modId)) || modVersions.get(modId).toString().equals("NONE"))));
} }
} }

View file

@ -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<String, ArtifactVersion> 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 <T> boolean testVersionSupportMatrix(VersionRange declaredRange, String lookupId, String type, BiPredicate<String, VersionRange> standardLookup) {
return standardLookup.test(lookupId, declaredRange) || overrideVersions.containsKey(type +"." +lookupId) && declaredRange.containsVersion(overrideVersions.get(type +"." +lookupId));
}
}