Better error passing from early to game client launch.

This commit is contained in:
cpw 2018-10-04 00:57:08 -04:00
parent c6e7bbe18b
commit d5e04dbcb5
16 changed files with 183 additions and 119 deletions

View File

@ -180,7 +180,11 @@ project(':forge') {
main 'net.minecraftforge.fml.LaunchTesting'
systemProperties = [
"org.lwjgl.util.Debug": "true",
"org.lwjgl.util.DebugLoader": "true"
"org.lwjgl.util.DebugLoader": "true",
"mc.version": "${MC_VERSION}",
"mcp.version": "${MCP_VERSION}",
"forge.version": "${project.version}",
"forge.spec":"${SPEC_VERSION}"
]
environment += [
target:'fmldevclient',

View File

@ -39,14 +39,23 @@ public class ForgeVersion
private static final String forgeVersion;
private static final String forgeSpec;
static {
String vers = ForgeVersion.class.getPackage().getImplementationVersion();
if (vers == null) {
vers = System.getProperty("forge.version");
}
if (vers == null) throw new RuntimeException("Missing forge version, cannot continue");
String spec = ForgeVersion.class.getPackage().getSpecificationVersion();
if (spec == null) {
spec = System.getProperty("forge.spec");
}
if (spec == null) throw new RuntimeException("Missing forge spec, cannot continue");
forgeVersion = vers;
forgeSpec = spec;
LOGGER.info(CORE, "Found Forge version {}", forgeVersion);
LOGGER.info(CORE, "Found Forge spec {}", forgeSpec);
}
public static String getVersion()
@ -64,5 +73,9 @@ public class ForgeVersion
{
return "";
}
public static String getSpec() {
return forgeSpec;
}
}

View File

@ -21,11 +21,10 @@ package net.minecraftforge.fml;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import com.google.common.collect.Multimap;
import net.minecraft.nbt.INBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.ResourceLocation;
@ -65,7 +64,7 @@ public final class FMLWorldPersistenceHook implements WorldPersistenceHooks.Worl
{
final NBTTagCompound mod = new NBTTagCompound();
mod.setString("ModId", mi.getModId());
mod.setString("ModVersion", mi.getVersion().getVersionString());
mod.setString("ModVersion", MavenVersionStringHelper.artifactVersionToString(mi.getVersion()));
modList.add(mod);
});
fmlData.setTag("LoadingModList", modList);
@ -98,9 +97,9 @@ public final class FMLWorldPersistenceHook implements WorldPersistenceHooks.Worl
LOGGER.error(WORLDPERSISTENCE,"This world was saved with mod {} which appears to be missing, things may not work well", modId);
continue;
}
if (!modVersion.equals(container.get().getModInfo().getVersion().getVersionString()))
if (!Objects.equals(modVersion, MavenVersionStringHelper.artifactVersionToString(container.get().getModInfo().getVersion())))
{
LOGGER.info(WORLDPERSISTENCE,"This world was saved with mod {} version {} and it is now at version {}, things may not work well", modId, modVersion, container.get().getModInfo().getVersion().getVersionString());
LOGGER.info(WORLDPERSISTENCE,"This world was saved with mod {} version {} and it is now at version {}, things may not work well", modId, modVersion, MavenVersionStringHelper.artifactVersionToString(container.get().getModInfo().getVersion()));
}
}
}

View File

@ -42,6 +42,7 @@ public class ForgeI18n {
customFactories.put("lower", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> stringBuffer.append(StringUtils.toLowerCase((String)objectToParse))));
customFactories.put("upper", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> stringBuffer.append(StringUtils.toUpperCase((String)objectToParse))));
customFactories.put("exc", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> parseException(formatString, stringBuffer, objectToParse)));
customFactories.put("vr", (name, formatString, locale) -> new CustomReadOnlyFormat(((stringBuffer, o) -> MavenVersionStringHelper.parseVersionRange(formatString, stringBuffer, o))));
}
private static void parseException(final String formatString, final StringBuffer stringBuffer, final Object objectToParse) {

View File

@ -0,0 +1,77 @@
package net.minecraftforge.fml;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.Restriction;
import org.apache.maven.artifact.versioning.VersionRange;
import java.util.Objects;
import java.util.stream.Collectors;
public class MavenVersionStringHelper {
public static String artifactVersionToString(final ArtifactVersion artifactVersion) {
return artifactVersion.toString();
}
public static String versionRangeToString(final VersionRange range) {
return range.getRestrictions().stream().map(MavenVersionStringHelper::restrictionToString).collect(Collectors.joining(","));
}
public static String restrictionToString(final Restriction restriction) {
if ( restriction.getLowerBound() == null && restriction.getUpperBound() == null )
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.any");
}
else if ( restriction.getLowerBound() != null && restriction.getUpperBound() != null )
{
if (Objects.equals(artifactVersionToString(restriction.getLowerBound()), artifactVersionToString(restriction.getUpperBound())))
{
return artifactVersionToString(restriction.getLowerBound());
}
else
{
if (restriction.isLowerBoundInclusive() && restriction.isUpperBoundInclusive())
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.bounded.inclusive", restriction.getLowerBound(), restriction.getUpperBound());
}
else if (restriction.isLowerBoundInclusive())
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.bounded.upperexclusive", restriction.getLowerBound(), restriction.getUpperBound());
}
else if (restriction.isUpperBoundInclusive())
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.bounded.lowerexclusive", restriction.getLowerBound(), restriction.getUpperBound());
}
else
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.bounded.exclusive", restriction.getLowerBound(), restriction.getUpperBound());
}
}
}
else if ( restriction.getLowerBound() != null )
{
if ( restriction.isLowerBoundInclusive() )
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.lower.inclusive", restriction.getLowerBound());
}
else
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.lower.exclusive", restriction.getLowerBound());
}
}
else
{
if ( restriction.isUpperBoundInclusive() )
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.upper.inclusive", restriction.getUpperBound());
}
else
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.upper.exclusive", restriction.getUpperBound());
}
}
}
public static void parseVersionRange(final String formatString, final StringBuffer stringBuffer, final Object range) {
stringBuffer.append(versionRangeToString((VersionRange) range));
}
}

View File

@ -60,7 +60,7 @@ public class ModLoader
this.loadingModList = FMLLoader.getLoadingModList();
this.modClassLoader = new ModLoadingClassLoader(this.launchClassLoader);
this.loadingExceptions = FMLLoader.getLoadingModList().
getErrors().stream().map(ModLoadingException::fromEarlyException).collect(Collectors.toList());
getErrors().stream().flatMap(ModLoadingException::fromEarlyException).collect(Collectors.toList());
Thread.currentThread().setContextClassLoader(this.modClassLoader);
}
@ -75,9 +75,6 @@ public class ModLoader
}
public void loadMods() {
if (!this.loadingExceptions.isEmpty()) {
throw new LoadingFailedException(loadingExceptions);
}
final ModList modList = ModList.of(loadingModList.getModFiles().stream().map(ModFileInfo::getFile).collect(Collectors.toList()), loadingModList.getMods());
ModContainer forgeModContainer;
try
@ -88,9 +85,12 @@ public class ModLoader
catch (ClassNotFoundException | IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException e)
{
LOGGER.error(CORE,"Unable to load the Forge Mod Container", e);
loadingExceptions.add(new ModLoadingException(DefaultModInfos.forgeModInfo, ModLoadingStage.CONSTRUCT, "fml.modloading.failedtoloadforge", e));
loadingExceptions.add(new ModLoadingException(DefaultModInfos.forgeModInfo, ModLoadingStage.VALIDATE, "fml.modloading.failedtoloadforge", e));
forgeModContainer = null;
}
if (!this.loadingExceptions.isEmpty()) {
throw new LoadingFailedException(loadingExceptions);
}
final Stream<ModContainer> modContainerStream = loadingModList.getModFiles().stream().
map(ModFileInfo::getFile).
map(mf -> buildMods(mf, modClassLoader)).

View File

@ -59,8 +59,8 @@ public class ModLoadingException extends RuntimeException
this.context = Arrays.asList(context);
}
static ModLoadingException fromEarlyException(final EarlyLoadingException e) {
return new ModLoadingException(null, ModLoadingStage.VALIDATE, e.getI18NMessage(), e, e.getContext().toArray());
static Stream<ModLoadingException> fromEarlyException(final EarlyLoadingException e) {
return e.getAllData().stream().map(ed->new ModLoadingException(null, ModLoadingStage.VALIDATE, ed.getI18message(), e.getCause(), ed.getArgs()));
}
public String getI18NMessage() {

View File

@ -37,14 +37,10 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.fml.ForgeI18n;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.VersionChecker;
import net.minecraftforge.fml.*;
import net.minecraftforge.fml.client.ConfigGuiHandler;
import net.minecraftforge.fml.client.ResourcePackLoader;
import net.minecraftforge.fml.language.IModInfo;
import net.minecraftforge.fml.loading.MavenVersionAdapter;
import net.minecraftforge.fml.loading.StringUtils;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import org.apache.commons.lang3.tuple.Pair;
@ -291,7 +287,7 @@ public class GuiModList extends GuiScreen
for (ModInfo mod : mods)
{
listWidth = Math.max(listWidth,getFontRenderer().getStringWidth(mod.getDisplayName()) + 10);
listWidth = Math.max(listWidth,getFontRenderer().getStringWidth(MavenVersionAdapter.artifactVersionToString(mod.getVersion())) + 5);
listWidth = Math.max(listWidth,getFontRenderer().getStringWidth(MavenVersionStringHelper.artifactVersionToString(mod.getVersion())) + 5);
}
listWidth = Math.min(listWidth, 150);
listWidth += listWidth % numButtons != 0 ? (numButtons - listWidth % numButtons) : 0;
@ -455,7 +451,7 @@ public class GuiModList extends GuiScreen
}).orElse(Pair.of(null, new Dimension(0, 0)));
lines.add(selectedMod.getDisplayName());
lines.add(ForgeI18n.parseMessage("fml.menu.mods.info.version", MavenVersionAdapter.artifactVersionToString(selectedMod.getVersion())));
lines.add(ForgeI18n.parseMessage("fml.menu.mods.info.version", MavenVersionStringHelper.artifactVersionToString(selectedMod.getVersion())));
lines.add(ForgeI18n.parseMessage("fml.menu.mods.info.idstate", selectedMod.getModId(), ModList.get().getModContainerById(selectedMod.getModId()).
map(ModContainer::getCurrentState).map(Object::toString).orElse("NONE")));

View File

@ -19,16 +19,14 @@
package net.minecraftforge.fml.client.gui;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiListExtended;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.ForgeVersion;
import net.minecraftforge.fml.MavenVersionStringHelper;
import net.minecraftforge.fml.VersionChecker;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
@ -97,7 +95,7 @@ public class GuiSlotModList extends GuiListExtended<GuiSlotModList.ModEntry>
int top = this.getY();
int left = this.getX();
String name = stripControlCodes(modInfo.getDisplayName());
String version = stripControlCodes(modInfo.getVersion().getVersionString());
String version = stripControlCodes(MavenVersionStringHelper.artifactVersionToString(modInfo.getVersion()));
VersionChecker.CheckResult vercheck = VersionChecker.getResult(modInfo);
FontRenderer font = this.parent.getFontRenderer();
font.drawString(font.trimStringToWidth(name, listWidth),left + 3, top + 2, 0xFFFFFF);

View File

@ -20,6 +20,7 @@
package net.minecraftforge.fml.common.toposort;
import com.google.common.collect.Sets;
import net.minecraftforge.fml.loading.EarlyLoadingException;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.util.StringBuilderFormattable;
@ -35,6 +36,8 @@ import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Topological sort for mod loading
@ -250,6 +253,13 @@ public class TopologicalSort
buffer.append("Explored node set : {}\n").append(expandedNodes);
buffer.append("Likely cycle is in : {}\n").append(Sets.difference(visitedNodes, expandedNodes));
}
public List<EarlyLoadingException.ExceptionData> toExceptionData(Function<T, String> nodeMapper) {
return Collections.singletonList(
new EarlyLoadingException.ExceptionData("fml.messages.cycleproblem",
nodeMapper.apply(node),
visitedNodes.stream().map(nodeMapper).collect(Collectors.joining(","))));
}
}
public <T> TopoSortException(TopoSortExceptionData<T> data)

View File

@ -8,20 +8,34 @@ import java.util.List;
* or server.
*/
public class EarlyLoadingException extends RuntimeException {
private final String i18nMessage;
private final List<Object> context;
public static class ExceptionData {
public EarlyLoadingException(final String message, final String i18nMessage, final Throwable originalException, Object... context) {
private final String i18message;
private final Object[] args;
public ExceptionData(final String message, Object... args) {
this.i18message = message;
this.args = args;
}
public String getI18message() {
return i18message;
}
public Object[] getArgs() {
return args;
}
}
private final List<ExceptionData> errorMessages;
public List<ExceptionData> getAllData() {
return errorMessages;
}
EarlyLoadingException(final String message, final Throwable originalException, List<ExceptionData> errorMessages) {
super(message, originalException);
this.i18nMessage = i18nMessage;
this.context = Arrays.asList(context);
this.errorMessages = errorMessages;
}
public String getI18NMessage() {
return this.i18nMessage;
}
public List<Object> getContext() {
return this.context;
}
}

View File

@ -31,6 +31,7 @@ import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@ -51,14 +52,20 @@ public class FMLClientLaunchProvider extends FMLCommonLaunchHandler implements I
"net.minecraftforge.fml.common.versioning."
);
static {
Path forgePath1 = null;
Path patchedBinariesPath1 = null;
Path srgMcPath1 = null;
try {
forgePath = Paths.get(FMLClientLaunchProvider.class.getProtectionDomain().getCodeSource().getLocation().toURI());
patchedBinariesPath = forgePath.resolveSibling("forge-"+MCPVersion.getMCVersion()+"-"+ForgeVersion.getVersion()+"-client.jar");
Path libs = forgePath.getParent().getParent().getParent().getParent().getParent();
srgMcPath = libs.resolve(Paths.get("net","minecraft", "client", MCPVersion.getMCPandMCVersion(), "client-"+MCPVersion.getMCPandMCVersion()+"-srg.jar")).toAbsolutePath();
forgePath1 = Paths.get(FMLClientLaunchProvider.class.getProtectionDomain().getCodeSource().getLocation().toURI());
patchedBinariesPath1 = forgePath1.resolveSibling("forge-"+MCPVersion.getMCVersion()+"-"+ForgeVersion.getVersion()+"-client.jar");
Path libs = forgePath1.getParent().getParent().getParent().getParent().getParent();
srgMcPath1 = libs.resolve(Paths.get("net","minecraft", "client", MCPVersion.getMCPandMCVersion(), "client-"+MCPVersion.getMCPandMCVersion()+"-srg.jar")).toAbsolutePath();
} catch (URISyntaxException e) {
throw new RuntimeException("Unable to locate myself!");
}
forgePath = forgePath1;
patchedBinariesPath = patchedBinariesPath1;
srgMcPath = srgMcPath1;
}
@Override
public String name()
@ -69,9 +76,12 @@ public class FMLClientLaunchProvider extends FMLCommonLaunchHandler implements I
@Override
public Path[] identifyTransformationTargets()
{
LOGGER.info("Found SRG MC at {}", srgMcPath.toString());
LOGGER.info("Found Forge patches at {}", patchedBinariesPath.toString());
LOGGER.info("Found Forge at {}", forgePath.toString());
LOGGER.info("SRG MC at {} is {}", srgMcPath.toString(), Files.exists(srgMcPath) ? "present" : "missing");
LOGGER.info("Forge patches at {} is {}", patchedBinariesPath.toString(), Files.exists(patchedBinariesPath) ? "present" : "missing");
LOGGER.info("Forge at {} is {}", forgePath.toString(), Files.exists(forgePath) ? "present" : "missing");
if (!(Files.exists(srgMcPath) && Files.exists(patchedBinariesPath) && Files.exists(forgePath))) {
throw new RuntimeException("Failed to find patched jars");
}
return new Path[] {forgePath, patchedBinariesPath, srgMcPath};
}

View File

@ -79,7 +79,7 @@ public class LanguageLoadingProvider
final Package pkg = lp.getClass().getPackage();
String implementationVersion = pkg.getImplementationVersion();
if (implementationVersion == null) {
implementationVersion = ForgeVersion.getVersion();
implementationVersion = ForgeVersion.getSpec();
}
LOGGER.debug(CORE, "Found system classpath language provider {}, version {}", lp.name(), implementationVersion);
languageProviderMap.put(lp.name(), new ModLanguageWrapper(lp, new DefaultArtifactVersion(implementationVersion)));

View File

@ -1,16 +1,10 @@
package net.minecraftforge.fml.loading;
import net.minecraftforge.fml.ForgeI18n;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.Restriction;
import org.apache.maven.artifact.versioning.VersionRange;
import java.util.Objects;
import java.util.stream.Collectors;
import static net.minecraftforge.fml.Logging.CORE;
public final class MavenVersionAdapter {
@ -25,66 +19,5 @@ public final class MavenVersionAdapter {
throw new RuntimeException("Failed to parse spec", e);
}
}
public static String artifactVersionToString(final ArtifactVersion artifactVersion) {
return artifactVersion.toString();
}
public static String versionRangeToString(final VersionRange range) {
return range.getRestrictions().stream().map(MavenVersionAdapter::restrictionToString).collect(Collectors.joining(","));
}
public static String restrictionToString(final Restriction restriction) {
if ( restriction.getLowerBound() == null && restriction.getUpperBound() == null )
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.any");
}
else if ( restriction.getLowerBound() != null && restriction.getUpperBound() != null )
{
if (Objects.equals(artifactVersionToString(restriction.getLowerBound()), artifactVersionToString(restriction.getUpperBound())))
{
return artifactVersionToString(restriction.getLowerBound());
}
else
{
if (restriction.isLowerBoundInclusive() && restriction.isUpperBoundInclusive())
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.bounded.inclusive", restriction.getLowerBound(), restriction.getUpperBound());
}
else if (restriction.isLowerBoundInclusive())
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.bounded.upperexclusive", restriction.getLowerBound(), restriction.getUpperBound());
}
else if (restriction.isUpperBoundInclusive())
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.bounded.lowerexclusive", restriction.getLowerBound(), restriction.getUpperBound());
}
else
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.bounded.exclusive", restriction.getLowerBound(), restriction.getUpperBound());
}
}
}
else if ( restriction.getLowerBound() != null )
{
if ( restriction.isLowerBoundInclusive() )
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.lower.inclusive", restriction.getLowerBound());
}
else
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.lower.exclusive", restriction.getLowerBound());
}
}
else
{
if ( restriction.isUpperBoundInclusive() )
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.upper.inclusive", restriction.getUpperBound());
}
else
{
return ForgeI18n.parseMessage("fml.messages.version.restriction.upper.exclusive", restriction.getUpperBound());
}
}
}
}

View File

@ -28,11 +28,9 @@ import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -62,6 +60,7 @@ public class ModSorter
ms.sort();
} catch (EarlyLoadingException ele) {
earlyLoadingException = ele;
ms.sortedList = Collections.emptyList();
}
return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException);
}
@ -70,7 +69,8 @@ public class ModSorter
{
final TopologicalSort.DirectedGraph<Supplier<ModFileInfo>> topoGraph = new TopologicalSort.DirectedGraph<>();
modFiles.stream().map(ModFile::getModFileInfo).map(ModFileInfo.class::cast).forEach(mi -> topoGraph.addNode(() -> mi));
modFiles.stream().map(ModFile::getModInfos).flatMap(Collection::stream).map(IModInfo::getDependencies).flatMap(Collection::stream).
modFiles.stream().map(ModFile::getModInfos).flatMap(Collection::stream).
map(IModInfo::getDependencies).flatMap(Collection::stream).
forEach(dep -> addDependency(topoGraph, dep));
final List<Supplier<ModFileInfo>> sorted;
try
@ -81,7 +81,7 @@ public class ModSorter
{
TopologicalSort.TopoSortException.TopoSortExceptionData<Supplier<ModInfo>> data = e.getData();
LOGGER.error(LOADING, ()-> data);
throw new EarlyLoadingException("Sorting error", "fml.modloading.sortingerror", e, e.getData());
throw new EarlyLoadingException("Sorting error", e, data.toExceptionData(mi-> mi.get().getModId()));
}
this.sortedList = sorted.stream().map(Supplier::get).map(ModFileInfo::getMods).
flatMap(Collection::stream).map(ModInfo.class::cast).collect(Collectors.toList());
@ -111,7 +111,10 @@ public class ModSorter
final List<Map.Entry<String, List<ModInfo>>> dupedMods = modIds.entrySet().stream().filter(e -> e.getValue().size() > 1).collect(Collectors.toList());
if (!dupedMods.isEmpty()) {
throw new EarlyLoadingException("Duplicate mods found", "fml.modloading.dupesfound", null, dupedMods);
final List<EarlyLoadingException.ExceptionData> duplicateModErrors = dupedMods.stream().
map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod", dm.getValue().get(0))).
collect(Collectors.toList());
throw new EarlyLoadingException("Duplicate mods found", null, duplicateModErrors);
}
modIdNameLookup = modIds.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
@ -131,7 +134,12 @@ public class ModSorter
LOGGER.debug(LOADING, "Found {} mandatory mod requirements missing", missingVersions.size());
if (!missingVersions.isEmpty()) {
throw new EarlyLoadingException("Missing mods", "fml.modloading.missingmods", null, missingVersions);
final List<EarlyLoadingException.ExceptionData> exceptionData = missingVersions.stream().map(mv ->
new EarlyLoadingException.ExceptionData("fml.modloading.missingdependency", mv.getModId(),
mv.getOwner().getModId(), mv.getVersionRange(),
modVersions.containsKey(mv.getModId()) ? modVersions.get(mv.getModId()) : "NONE" )).
collect(Collectors.toList());
throw new EarlyLoadingException("Missing mods", null, exceptionData);
}
}

View File

@ -23,6 +23,7 @@
"fml.modloading.failedtoloadmod":"{0,modinfo,name} ({0,modinfo,id}) has failed to load correctly\n\u00a77{2,exc,msg}",
"fml.modloading.errorduringevent":"{0,modinfo,name} ({0,modinfo,id}) encountered an error during the {1,lower} event phase\n\u00a77{2,exc,msg}",
"fml.modloading.failedtoloadforge": "Failed to load forge",
"fml.modloading.missingdependency": "Mod {4} has missing dependency {3}\n\u00a77Want {5,vr}, have {6}",
"fml.messages.version.restriction.any":"any",
"fml.messages.version.restriction.lower.inclusive":"{0} or above",