From d5e04dbcb5cdfa07f8e978ff7c9e2f03323cf8df Mon Sep 17 00:00:00 2001 From: cpw Date: Thu, 4 Oct 2018 00:57:08 -0400 Subject: [PATCH] Better error passing from early to game client launch. --- build.gradle | 6 +- .../minecraftforge/common/ForgeVersion.java | 13 ++++ .../fml/FMLWorldPersistenceHook.java | 9 +-- .../net/minecraftforge/fml/ForgeI18n.java | 1 + .../fml/MavenVersionStringHelper.java | 77 +++++++++++++++++++ .../net/minecraftforge/fml/ModLoader.java | 10 +-- .../fml/ModLoadingException.java | 4 +- .../fml/client/gui/GuiModList.java | 10 +-- .../fml/client/gui/GuiSlotModList.java | 6 +- .../fml/common/toposort/TopologicalSort.java | 10 +++ .../fml/loading/EarlyLoadingException.java | 36 ++++++--- .../fml/loading/FMLClientLaunchProvider.java | 26 +++++-- .../fml/loading/LanguageLoadingProvider.java | 2 +- .../fml/loading/MavenVersionAdapter.java | 67 ---------------- .../minecraftforge/fml/loading/ModSorter.java | 24 ++++-- .../resources/assets/forge/lang/en_us.json | 1 + 16 files changed, 183 insertions(+), 119 deletions(-) create mode 100644 src/main/java/net/minecraftforge/fml/MavenVersionStringHelper.java diff --git a/build.gradle b/build.gradle index 65165ff35..1bb587eb5 100644 --- a/build.gradle +++ b/build.gradle @@ -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', diff --git a/src/main/java/net/minecraftforge/common/ForgeVersion.java b/src/main/java/net/minecraftforge/common/ForgeVersion.java index 5d522590e..b21ad69cb 100644 --- a/src/main/java/net/minecraftforge/common/ForgeVersion.java +++ b/src/main/java/net/minecraftforge/common/ForgeVersion.java @@ -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; + } } diff --git a/src/main/java/net/minecraftforge/fml/FMLWorldPersistenceHook.java b/src/main/java/net/minecraftforge/fml/FMLWorldPersistenceHook.java index 37da82591..23ae5f880 100644 --- a/src/main/java/net/minecraftforge/fml/FMLWorldPersistenceHook.java +++ b/src/main/java/net/minecraftforge/fml/FMLWorldPersistenceHook.java @@ -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())); } } } diff --git a/src/main/java/net/minecraftforge/fml/ForgeI18n.java b/src/main/java/net/minecraftforge/fml/ForgeI18n.java index 581936563..1e1bfe48e 100644 --- a/src/main/java/net/minecraftforge/fml/ForgeI18n.java +++ b/src/main/java/net/minecraftforge/fml/ForgeI18n.java @@ -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) { diff --git a/src/main/java/net/minecraftforge/fml/MavenVersionStringHelper.java b/src/main/java/net/minecraftforge/fml/MavenVersionStringHelper.java new file mode 100644 index 000000000..8b3f0ccdd --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/MavenVersionStringHelper.java @@ -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)); + } +} diff --git a/src/main/java/net/minecraftforge/fml/ModLoader.java b/src/main/java/net/minecraftforge/fml/ModLoader.java index 4856d9a7d..6dcc4b86e 100644 --- a/src/main/java/net/minecraftforge/fml/ModLoader.java +++ b/src/main/java/net/minecraftforge/fml/ModLoader.java @@ -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 modContainerStream = loadingModList.getModFiles().stream(). map(ModFileInfo::getFile). map(mf -> buildMods(mf, modClassLoader)). diff --git a/src/main/java/net/minecraftforge/fml/ModLoadingException.java b/src/main/java/net/minecraftforge/fml/ModLoadingException.java index 9b667aab9..7ebbdfa49 100644 --- a/src/main/java/net/minecraftforge/fml/ModLoadingException.java +++ b/src/main/java/net/minecraftforge/fml/ModLoadingException.java @@ -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 fromEarlyException(final EarlyLoadingException e) { + return e.getAllData().stream().map(ed->new ModLoadingException(null, ModLoadingStage.VALIDATE, ed.getI18message(), e.getCause(), ed.getArgs())); } public String getI18NMessage() { diff --git a/src/main/java/net/minecraftforge/fml/client/gui/GuiModList.java b/src/main/java/net/minecraftforge/fml/client/gui/GuiModList.java index b19bf4785..63c0024da 100644 --- a/src/main/java/net/minecraftforge/fml/client/gui/GuiModList.java +++ b/src/main/java/net/minecraftforge/fml/client/gui/GuiModList.java @@ -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"))); diff --git a/src/main/java/net/minecraftforge/fml/client/gui/GuiSlotModList.java b/src/main/java/net/minecraftforge/fml/client/gui/GuiSlotModList.java index db92165ac..b39ae4ee8 100644 --- a/src/main/java/net/minecraftforge/fml/client/gui/GuiSlotModList.java +++ b/src/main/java/net/minecraftforge/fml/client/gui/GuiSlotModList.java @@ -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 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); diff --git a/src/main/java/net/minecraftforge/fml/common/toposort/TopologicalSort.java b/src/main/java/net/minecraftforge/fml/common/toposort/TopologicalSort.java index cf12b589c..874edff47 100644 --- a/src/main/java/net/minecraftforge/fml/common/toposort/TopologicalSort.java +++ b/src/main/java/net/minecraftforge/fml/common/toposort/TopologicalSort.java @@ -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 toExceptionData(Function nodeMapper) { + return Collections.singletonList( + new EarlyLoadingException.ExceptionData("fml.messages.cycleproblem", + nodeMapper.apply(node), + visitedNodes.stream().map(nodeMapper).collect(Collectors.joining(",")))); + } } public TopoSortException(TopoSortExceptionData data) diff --git a/src/main/java/net/minecraftforge/fml/loading/EarlyLoadingException.java b/src/main/java/net/minecraftforge/fml/loading/EarlyLoadingException.java index 560ecd38f..ca1ce909f 100644 --- a/src/main/java/net/minecraftforge/fml/loading/EarlyLoadingException.java +++ b/src/main/java/net/minecraftforge/fml/loading/EarlyLoadingException.java @@ -8,20 +8,34 @@ import java.util.List; * or server. */ public class EarlyLoadingException extends RuntimeException { - private final String i18nMessage; - private final List 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 errorMessages; + + public List getAllData() { + return errorMessages; + } + + EarlyLoadingException(final String message, final Throwable originalException, List errorMessages) { super(message, originalException); - this.i18nMessage = i18nMessage; - this.context = Arrays.asList(context); + this.errorMessages = errorMessages; } - public String getI18NMessage() { - return this.i18nMessage; - } - public List getContext() { - return this.context; - } } diff --git a/src/main/java/net/minecraftforge/fml/loading/FMLClientLaunchProvider.java b/src/main/java/net/minecraftforge/fml/loading/FMLClientLaunchProvider.java index c6138897b..29cdcbb11 100644 --- a/src/main/java/net/minecraftforge/fml/loading/FMLClientLaunchProvider.java +++ b/src/main/java/net/minecraftforge/fml/loading/FMLClientLaunchProvider.java @@ -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}; } diff --git a/src/main/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java b/src/main/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java index 220b27843..35d705819 100644 --- a/src/main/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java +++ b/src/main/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java @@ -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))); diff --git a/src/main/java/net/minecraftforge/fml/loading/MavenVersionAdapter.java b/src/main/java/net/minecraftforge/fml/loading/MavenVersionAdapter.java index 7947e5b64..0c6a9fcd3 100644 --- a/src/main/java/net/minecraftforge/fml/loading/MavenVersionAdapter.java +++ b/src/main/java/net/minecraftforge/fml/loading/MavenVersionAdapter.java @@ -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()); - } - } - } } diff --git a/src/main/java/net/minecraftforge/fml/loading/ModSorter.java b/src/main/java/net/minecraftforge/fml/loading/ModSorter.java index 47b8e4bd1..42f4a04c0 100644 --- a/src/main/java/net/minecraftforge/fml/loading/ModSorter.java +++ b/src/main/java/net/minecraftforge/fml/loading/ModSorter.java @@ -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> 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> sorted; try @@ -81,7 +81,7 @@ public class ModSorter { TopologicalSort.TopoSortException.TopoSortExceptionData> 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>> 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 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 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); } } diff --git a/src/main/resources/assets/forge/lang/en_us.json b/src/main/resources/assets/forge/lang/en_us.json index 4f81ed553..174e43bfb 100644 --- a/src/main/resources/assets/forge/lang/en_us.json +++ b/src/main/resources/assets/forge/lang/en_us.json @@ -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",