diff --git a/src/main/java/net/minecraftforge/fml/client/GuiModsMissing.java b/src/main/java/net/minecraftforge/fml/client/GuiModsMissing.java index bad93f6b0e..1676c3912a 100644 --- a/src/main/java/net/minecraftforge/fml/client/GuiModsMissing.java +++ b/src/main/java/net/minecraftforge/fml/client/GuiModsMissing.java @@ -19,9 +19,13 @@ package net.minecraftforge.fml.client; +import java.util.List; + import net.minecraft.client.resources.I18n; import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.MissingModsException; +import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.versioning.ArtifactVersion; import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion; @@ -38,31 +42,49 @@ public class GuiModsMissing extends GuiErrorBase public void drawScreen(int mouseX, int mouseY, float partialTicks) { this.drawDefaultBackground(); - int offset = Math.max(85 - modsMissing.missingMods.size() * 10, 10); - String modMissingDependenciesText = I18n.format("fml.messages.mod.missing.dependencies", TextFormatting.BOLD + modsMissing.getModName() + TextFormatting.RESET); + List missingModsVersions = modsMissing.getMissingModInfos(); + int offset = Math.max(85 - missingModsVersions.size() * 10, 10); + String modMissingDependenciesText = I18n.format("fml.messages.mod.missing.dependencies.compatibility", TextFormatting.BOLD + modsMissing.getModName() + TextFormatting.RESET); this.drawCenteredString(this.fontRenderer, modMissingDependenciesText, this.width / 2, offset, 0xFFFFFF); - offset+=10; - String fixMissingDependenciesText = I18n.format("fml.messages.mod.missing.dependencies.fix", modsMissing.getModName()); - this.drawCenteredString(this.fontRenderer, fixMissingDependenciesText, this.width / 2, offset, 0xFFFFFF); offset+=5; - for (ArtifactVersion v : modsMissing.missingMods) + for (MissingModsException.MissingModInfo versionInfo : missingModsVersions) { - offset+=10; - if (v instanceof DefaultArtifactVersion) + ArtifactVersion acceptedVersion = versionInfo.getAcceptedVersion(); + String acceptedModId = acceptedVersion.getLabel(); + ArtifactVersion currentVersion = versionInfo.getCurrentVersion(); + String missingReason; + if (currentVersion == null) { - DefaultArtifactVersion dav = (DefaultArtifactVersion)v; + missingReason = I18n.format("fml.messages.mod.missing.dependencies.missing"); + } + else + { + missingReason = I18n.format("fml.messages.mod.missing.dependencies.you.have", currentVersion.getVersionString()); + } + String acceptedModVersionString = acceptedVersion.getRangeString(); + if (acceptedVersion instanceof DefaultArtifactVersion) + { + DefaultArtifactVersion dav = (DefaultArtifactVersion)acceptedVersion; if (dav.getRange() != null) { - String message = String.format(TextFormatting.BOLD + "%s " + TextFormatting.RESET + "%s", v.getLabel(), dav.getRange().toStringFriendly()); - this.drawCenteredString(this.fontRenderer, message, this.width / 2, offset, 0xEEEEEE); - continue; + acceptedModVersionString = dav.getRange().toStringFriendly(); } } - this.drawCenteredString(this.fontRenderer, String.format(TextFormatting.BOLD + "%s" + TextFormatting.RESET + " : %s", v.getLabel(), v.getRangeString()), this.width / 2, offset, 0xEEEEEE); + ModContainer acceptedMod = Loader.instance().getIndexedModList().get(acceptedModId); + String acceptedModName = acceptedMod != null ? acceptedMod.getName() : acceptedModId; + String versionInfoText = String.format(TextFormatting.BOLD + "%s " + TextFormatting.RESET + "%s (%s)", acceptedModName, acceptedModVersionString, missingReason); + String message; + if (versionInfo.isRequired()) + { + message = I18n.format("fml.messages.mod.missing.dependencies.requires", versionInfoText); + } + else + { + message = I18n.format("fml.messages.mod.missing.dependencies.compatible.with", versionInfoText); + } + offset += 10; + this.drawCenteredString(this.fontRenderer, message, this.width / 2, offset, 0xEEEEEE); } - offset+=20; - String seeLogText = I18n.format("fml.messages.mod.missing.dependencies.see.log", GuiErrorBase.logFile.getName()); - this.drawCenteredString(this.fontRenderer, seeLogText, this.width / 2, offset, 0xFFFFFF); super.drawScreen(mouseX, mouseY, partialTicks); } } diff --git a/src/main/java/net/minecraftforge/fml/client/GuiModsMissingForServer.java b/src/main/java/net/minecraftforge/fml/client/GuiModsMissingForServer.java index c65cb8f18f..a8a6e24dec 100644 --- a/src/main/java/net/minecraftforge/fml/client/GuiModsMissingForServer.java +++ b/src/main/java/net/minecraftforge/fml/client/GuiModsMissingForServer.java @@ -19,6 +19,8 @@ package net.minecraftforge.fml.client; +import java.util.List; + import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.resources.I18n; @@ -52,15 +54,17 @@ public class GuiModsMissingForServer extends GuiScreen public void drawScreen(int mouseX, int mouseY, float partialTicks) { this.drawDefaultBackground(); - int offset = Math.max(85 - modsMissing.missingMods.size() * 10, 10); + List missingModsVersions = modsMissing.getMissingModInfos(); + int offset = Math.max(85 - missingModsVersions.size() * 10, 10); this.drawCenteredString(this.fontRenderer, "Forge Mod Loader could not connect to this server", this.width / 2, offset, 0xFFFFFF); offset += 10; this.drawCenteredString(this.fontRenderer, "The mods and versions listed below could not be found", this.width / 2, offset, 0xFFFFFF); offset += 10; this.drawCenteredString(this.fontRenderer, "They are required to play on this server", this.width / 2, offset, 0xFFFFFF); offset += 5; - for (ArtifactVersion v : modsMissing.missingMods) + for (MissingModsException.MissingModInfo info : missingModsVersions) { + ArtifactVersion v = info.getAcceptedVersion(); offset += 10; this.drawCenteredString(this.fontRenderer, String.format("%s : %s", v.getLabel(), v.getRangeString()), this.width / 2, offset, 0xEEEEEE); } diff --git a/src/main/java/net/minecraftforge/fml/client/GuiMultipleModsErrored.java b/src/main/java/net/minecraftforge/fml/client/GuiMultipleModsErrored.java index 82a1190130..51d7a24299 100644 --- a/src/main/java/net/minecraftforge/fml/client/GuiMultipleModsErrored.java +++ b/src/main/java/net/minecraftforge/fml/client/GuiMultipleModsErrored.java @@ -26,6 +26,7 @@ import net.minecraft.client.resources.I18n; import net.minecraft.util.text.TextFormatting; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.MissingModsException; +import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.MultipleModsErrored; import net.minecraftforge.fml.common.WrongMinecraftVersionException; import net.minecraftforge.fml.common.versioning.ArtifactVersion; @@ -51,12 +52,12 @@ public class GuiMultipleModsErrored extends GuiErrorBase public void initGui() { super.initGui(); - int additionalSize = missingModsExceptions.isEmpty()||wrongMinecraftExceptions.isEmpty() ? 20 : 55; - for(MissingModsException exception : missingModsExceptions) + int additionalSize = missingModsExceptions.isEmpty() || wrongMinecraftExceptions.isEmpty() ? 20 : 55; + for (MissingModsException exception : missingModsExceptions) { - additionalSize+=exception.missingMods.size()*10; + additionalSize += exception.getMissingModInfos().size() * 10; } - list = new GuiList(wrongMinecraftExceptions.size()*10+missingModsExceptions.size()*15+additionalSize); + list = new GuiList(wrongMinecraftExceptions.size() * 10 + missingModsExceptions.size() * 15 + additionalSize); } @Override @@ -139,26 +140,50 @@ public class GuiMultipleModsErrored extends GuiErrorBase } if (!missingModsExceptions.isEmpty()) { - renderer.drawString(TextFormatting.UNDERLINE + I18n.format("fml.messages.mod.missing.dependencies.multiple"), this.left, offset, 0xFFFFFF); + renderer.drawString(I18n.format("fml.messages.mod.missing.dependencies.multiple.issues"), this.left, offset, 0xFFFFFF); offset+=15; for (MissingModsException exception : missingModsExceptions) { - renderer.drawString(I18n.format("fml.messages.mod.missing.dependencies.fix", TextFormatting.BOLD + exception.getModName() + TextFormatting.RESET), this.left, offset, 0xFFFFFF); - for (ArtifactVersion v : exception.missingMods) + renderer.drawString(exception.getModName() + ":", this.left, offset, 0xFFFFFF); + for (MissingModsException.MissingModInfo versionInfo : exception.getMissingModInfos()) { - offset+=10; - if (v instanceof DefaultArtifactVersion) + ArtifactVersion acceptedVersion = versionInfo.getAcceptedVersion(); + String acceptedModId = acceptedVersion.getLabel(); + ArtifactVersion currentVersion = versionInfo.getCurrentVersion(); + String missingReason; + if (currentVersion == null) { - DefaultArtifactVersion dav = (DefaultArtifactVersion)v; + missingReason = I18n.format("fml.messages.mod.missing.dependencies.missing"); + } + else + { + missingReason = I18n.format("fml.messages.mod.missing.dependencies.you.have", currentVersion.getVersionString()); + } + String acceptedModVersionString = acceptedVersion.getRangeString(); + if (acceptedVersion instanceof DefaultArtifactVersion) + { + DefaultArtifactVersion dav = (DefaultArtifactVersion)acceptedVersion; if (dav.getRange() != null) { - String message = String.format(TextFormatting.BOLD + "%s " + TextFormatting.RESET + "%s", v.getLabel(), dav.getRange().toStringFriendly()); - renderer.drawString(message, this.left, offset, 0xEEEEEE); - continue; + acceptedModVersionString = dav.getRange().toStringFriendly(); } } - renderer.drawString(String.format(TextFormatting.BOLD + "%s" + TextFormatting.RESET + " : %s", v.getLabel(), v.getRangeString()), this.left, offset, 0xEEEEEE); + ModContainer acceptedMod = Loader.instance().getIndexedModList().get(acceptedModId); + String acceptedModName = acceptedMod != null ? acceptedMod.getName() : acceptedModId; + String versionInfoText = String.format(TextFormatting.BOLD + "%s " + TextFormatting.RESET + "%s (%s)", acceptedModName, acceptedModVersionString, missingReason); + String message; + if (versionInfo.isRequired()) + { + message = I18n.format("fml.messages.mod.missing.dependencies.requires", versionInfoText); + } + else + { + message = I18n.format("fml.messages.mod.missing.dependencies.compatible.with", versionInfoText); + } + offset += 10; + renderer.drawString(message, this.left, offset, 0xEEEEEE); } + offset += 15; } } diff --git a/src/main/java/net/minecraftforge/fml/common/Loader.java b/src/main/java/net/minecraftforge/fml/common/Loader.java index 0d6cb7d9a7..4617283d2d 100644 --- a/src/main/java/net/minecraftforge/fml/common/Loader.java +++ b/src/main/java/net/minecraftforge/fml/common/Loader.java @@ -231,8 +231,8 @@ public class Loader private void sortModList() { FMLLog.log.trace("Verifying mod requirements are satisfied"); - List wrongMinecraftExceptions = new ArrayList(); - List missingModsExceptions = new ArrayList(); + List wrongMinecraftExceptions = new ArrayList<>(); + List missingModsExceptions = new ArrayList<>(); try { BiMap modVersions = HashBiMap.create(); @@ -253,39 +253,42 @@ public class Loader continue; } Map names = Maps.uniqueIndex(mod.getRequirements(), ArtifactVersion::getLabel); - Set versionMissingMods = Sets.newHashSet(); Set missingMods = Sets.difference(names.keySet(), modVersions.keySet()); if (!missingMods.isEmpty()) { + MissingModsException missingModsException = new MissingModsException(mod.getModId(), mod.getName()); FMLLog.log.fatal("The mod {} ({}) requires mods {} to be available", mod.getModId(), mod.getName(), missingMods); for (String modid : missingMods) { - versionMissingMods.add(names.get(modid)); + ArtifactVersion acceptedVersion = names.get(modid); + ArtifactVersion currentVersion = modVersions.get(modid); + boolean required = mod.getRequirements().contains(acceptedVersion); + missingModsException.addMissingMod(acceptedVersion, currentVersion, required); } - MissingModsException ret = new MissingModsException(versionMissingMods, mod.getModId(), mod.getName()); - FMLLog.log.fatal(ret.getMessage()); - missingModsExceptions.add(ret); + FMLLog.log.fatal(missingModsException.getMessage()); + missingModsExceptions.add(missingModsException); continue; } reqList.putAll(mod.getModId(), names.keySet()); ImmutableList allDeps = ImmutableList.builder().addAll(mod.getDependants()).addAll(mod.getDependencies()).build(); - for (ArtifactVersion v : allDeps) + MissingModsException missingModsException = new MissingModsException(mod.getModId(), mod.getName()); + for (ArtifactVersion acceptedVersion : allDeps) { - if (modVersions.containsKey(v.getLabel())) + if (modVersions.containsKey(acceptedVersion.getLabel())) { - if (!v.containsVersion(modVersions.get(v.getLabel()))) + ArtifactVersion currentVersion = modVersions.get(acceptedVersion.getLabel()); + if (!acceptedVersion.containsVersion(currentVersion)) { - versionMissingMods.add(v); + boolean required = mod.getRequirements().contains(acceptedVersion); + missingModsException.addMissingMod(acceptedVersion, currentVersion, required); } } } - if (!versionMissingMods.isEmpty()) + if (!missingModsException.getMissingModInfos().isEmpty()) { - FMLLog.log.fatal("The mod {} ({}) requires mod versions {} to be available", mod.getModId(), mod.getName(), versionMissingMods); - MissingModsException ret = new MissingModsException(versionMissingMods, mod.getModId(), mod.getName()); - FMLLog.log.fatal(ret.toString()); - missingModsExceptions.add(ret); + FMLLog.log.fatal(missingModsException.toString()); + missingModsExceptions.add(missingModsException); } } @@ -306,7 +309,7 @@ public class Loader throw new MultipleModsErrored(wrongMinecraftExceptions, missingModsExceptions); } - reverseDependencies = Multimaps.invertFrom(reqList, ArrayListMultimap.create()); + reverseDependencies = Multimaps.invertFrom(reqList, ArrayListMultimap.create()); ModSorter sorter = new ModSorter(getActiveModList(), namedMods); try diff --git a/src/main/java/net/minecraftforge/fml/common/MissingModsException.java b/src/main/java/net/minecraftforge/fml/common/MissingModsException.java index 4a555ea217..c70ee69031 100644 --- a/src/main/java/net/minecraftforge/fml/common/MissingModsException.java +++ b/src/main/java/net/minecraftforge/fml/common/MissingModsException.java @@ -19,36 +19,117 @@ package net.minecraftforge.fml.common; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import com.google.common.base.Preconditions; import net.minecraftforge.fml.common.versioning.ArtifactVersion; public class MissingModsException extends EnhancedRuntimeException { private static final long serialVersionUID = 1L; + private final String id; + private final String name; + /** @deprecated use {@link #getMissingModInfos()} */ + @Deprecated // TODO remove in 1.13 public final Set missingMods; + private final List missingModsInfos; private final String modName; + public MissingModsException(String id, String name) + { + this(new HashSet<>(), id, name); + } + + /** + * @deprecated use {@link #MissingModsException(String, String)} + */ + @Deprecated // TODO remove in 1.13 public MissingModsException(Set missingMods, String id, String name) { - super(String.format("Mod %s (%s) requires %s", id, name, missingMods)); + this.id = id; + this.name = name; this.missingMods = missingMods; + this.missingModsInfos = new ArrayList<>(); + for (ArtifactVersion artifactVersion : missingMods) + { + missingModsInfos.add(new MissingModInfo(artifactVersion, null, true)); + } this.modName = name; } + @Override + public String getMessage() + { + Set missingMods = missingModsInfos.stream().map(MissingModInfo::getAcceptedVersion).collect(Collectors.toSet()); + return String.format("Mod %s (%s) requires %s", id, name, missingMods); + } + + public void addMissingMod(ArtifactVersion acceptedVersion, @Nullable ArtifactVersion currentVersion, boolean required) + { + MissingModInfo missingModInfo = new MissingModInfo(acceptedVersion, currentVersion, required); + this.missingModsInfos.add(missingModInfo); + this.missingMods.add(acceptedVersion); + } + public String getModName() { return modName; } + public List getMissingModInfos() + { + return Collections.unmodifiableList(this.missingModsInfos); + } + @Override protected void printStackTrace(WrappedPrintStream stream) { stream.println("Missing Mods:"); - for (ArtifactVersion v : missingMods) + for (MissingModInfo info : this.missingModsInfos) { - stream.println(String.format("\t%s : %s", v.getLabel(), v.getRangeString())); + ArtifactVersion acceptedVersion = info.getAcceptedVersion(); + ArtifactVersion currentVersion = info.getCurrentVersion(); + String currentString = currentVersion != null ? currentVersion.getVersionString() : "missing"; + stream.println(String.format("\t%s : need %s: have %s", acceptedVersion.getVersionString(), acceptedVersion.getRangeString(), currentString)); } stream.println(""); } + + public static class MissingModInfo + { + private final ArtifactVersion acceptedVersion; + @Nullable + private final ArtifactVersion currentVersion; + private final boolean required; + + private MissingModInfo(ArtifactVersion acceptedVersion, @Nullable ArtifactVersion currentVersion, boolean required) + { + Preconditions.checkNotNull(acceptedVersion, "acceptedVersion"); + this.acceptedVersion = acceptedVersion; + this.currentVersion = currentVersion; + this.required = required; + } + + @Nullable + public ArtifactVersion getCurrentVersion() + { + return currentVersion; + } + + public ArtifactVersion getAcceptedVersion() + { + return acceptedVersion; + } + + public boolean isRequired() + { + return required; + } + } } diff --git a/src/main/java/net/minecraftforge/fml/common/MultipleModsErrored.java b/src/main/java/net/minecraftforge/fml/common/MultipleModsErrored.java index aee354f96b..470a9d2b64 100644 --- a/src/main/java/net/minecraftforge/fml/common/MultipleModsErrored.java +++ b/src/main/java/net/minecraftforge/fml/common/MultipleModsErrored.java @@ -21,13 +21,26 @@ package net.minecraftforge.fml.common; import java.util.List; -public class MultipleModsErrored extends RuntimeException +public class MultipleModsErrored extends EnhancedRuntimeException { public final List wrongMinecraftExceptions; - public final ListmissingModsExceptions; + public final List missingModsExceptions; public MultipleModsErrored(List wrongMinecraftExceptions, List missingModsExceptions) { this.wrongMinecraftExceptions = wrongMinecraftExceptions; this.missingModsExceptions = missingModsExceptions; } + + @Override + protected void printStackTrace(WrappedPrintStream stream) + { + for (WrongMinecraftVersionException wrongMinecraftVersionException : this.wrongMinecraftExceptions) + { + wrongMinecraftVersionException.printStackTrace(stream); + } + for (MissingModsException missingModsException : this.missingModsExceptions) + { + missingModsException.printStackTrace(stream); + } + } } diff --git a/src/main/java/net/minecraftforge/fml/common/versioning/DefaultArtifactVersion.java b/src/main/java/net/minecraftforge/fml/common/versioning/DefaultArtifactVersion.java index 1cfe6ff723..ec0d0e3351 100644 --- a/src/main/java/net/minecraftforge/fml/common/versioning/DefaultArtifactVersion.java +++ b/src/main/java/net/minecraftforge/fml/common/versioning/DefaultArtifactVersion.java @@ -102,7 +102,11 @@ public class DefaultArtifactVersion implements ArtifactVersion @Override public String toString() { - return label == null ? comparableVersion.toString() : label + ( unbounded ? "" : "@" + range); + if (label == null) + { + return getVersionString(); + } + return label + (unbounded ? "" : "@" + range); } public VersionRange getRange() diff --git a/src/main/java/net/minecraftforge/fml/common/versioning/VersionRange.java b/src/main/java/net/minecraftforge/fml/common/versioning/VersionRange.java index 65c6150aa3..4f1ea56a28 100644 --- a/src/main/java/net/minecraftforge/fml/common/versioning/VersionRange.java +++ b/src/main/java/net/minecraftforge/fml/common/versioning/VersionRange.java @@ -478,7 +478,7 @@ public class VersionRange { if ( recommendedVersion != null ) { - return recommendedVersion.toString(); + return recommendedVersion.getVersionString(); } else { diff --git a/src/main/resources/assets/forge/lang/en_US.lang b/src/main/resources/assets/forge/lang/en_US.lang index 58efbf388b..e55a0168fd 100644 --- a/src/main/resources/assets/forge/lang/en_US.lang +++ b/src/main/resources/assets/forge/lang/en_US.lang @@ -203,8 +203,14 @@ item.forge.bucketFilled.name=%s Bucket fml.messages.mod.missing.dependencies=%s is missing mods it depends on. fml.messages.mod.missing.dependencies.fix=Include the following mods or remove %s. +fml.messages.mod.missing.dependencies.compatibility=You must include the right dependencies for %s: +fml.messages.mod.missing.dependencies.missing=missing +fml.messages.mod.missing.dependencies.compatible.with=Only compatible with %s +fml.messages.mod.missing.dependencies.requires=Requires %s +fml.messages.mod.missing.dependencies.you.have=you have %s fml.messages.mod.missing.dependencies.see.log=See '%s' for technical information. fml.messages.mod.missing.dependencies.multiple=Some mods are missing mods they depends on. +fml.messages.mod.missing.dependencies.multiple.issues=You must include the right dependencies for the following mods: fml.messages.mod.missing.multiple=There were %s errors loading Minecraft fml.messages.mod.wrongminecraft=The mods listed below can't run in Minecraft version %s fml.messages.mod.wrongminecraft.requirement=%s (%s) requires Minecraft %s