diff --git a/src/main/java/net/minecraftforge/fml/ForgeI18n.java b/src/main/java/net/minecraftforge/fml/ForgeI18n.java index 1e1bfe48e..0bcaa7f6b 100644 --- a/src/main/java/net/minecraftforge/fml/ForgeI18n.java +++ b/src/main/java/net/minecraftforge/fml/ForgeI18n.java @@ -38,11 +38,20 @@ public class ForgeI18n { static { customFactories = new HashMap<>(); + // {0,modinfo,id} -> modid from ModInfo object; {0,modinfo,name} -> displayname from ModInfo object customFactories.put("modinfo", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> parseModInfo(formatString, stringBuffer, objectToParse))); + // {0,lower} -> lowercase supplied string customFactories.put("lower", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> stringBuffer.append(StringUtils.toLowerCase((String)objectToParse)))); + // {0,upper> -> uppercase supplied string customFactories.put("upper", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> stringBuffer.append(StringUtils.toUpperCase((String)objectToParse)))); + // {0,exc,class} -> class of exception; {0,exc,msg} -> message from exception customFactories.put("exc", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> parseException(formatString, stringBuffer, objectToParse))); + // {0,vr} -> transform VersionRange into cleartext string using fml.messages.version.restriction.* strings customFactories.put("vr", (name, formatString, locale) -> new CustomReadOnlyFormat(((stringBuffer, o) -> MavenVersionStringHelper.parseVersionRange(formatString, stringBuffer, o)))); + // {0,i18n,fml.message} -> pass object to i18n string 'fml.message' + customFactories.put("i18n", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, o) -> stringBuffer.append(ForgeI18n.parseMessage(formatString, o)))); + // {0,ornull,fml.absent} -> append String value of o, or i18n string 'fml.absent' (message format transforms nulls into the string literal "null") + customFactories.put("ornull", ((name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, o) -> stringBuffer.append(Objects.equals(String.valueOf(o),"null") ? ForgeI18n.parseMessage(formatString) : String.valueOf(o))))); } private static void parseException(final String formatString, final StringBuffer stringBuffer, final Object objectToParse) { diff --git a/src/main/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java b/src/main/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java index 35d705819..57cf8e6b6 100644 --- a/src/main/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java +++ b/src/main/java/net/minecraftforge/fml/loading/LanguageLoadingProvider.java @@ -21,6 +21,7 @@ package net.minecraftforge.fml.loading; import net.minecraftforge.common.ForgeVersion; import net.minecraftforge.fml.language.IModLanguageProvider; +import net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator; import net.minecraftforge.fml.loading.moddiscovery.ModFile; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -29,11 +30,7 @@ import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.artifact.versioning.VersionRange; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; +import java.util.*; import java.util.function.Consumer; import java.util.stream.Stream; @@ -93,13 +90,16 @@ public class LanguageLoadingProvider serviceLoader.reload(); } - public IModLanguageProvider findLanguage(String modLoader, VersionRange modLoaderVersion) { + public IModLanguageProvider findLanguage(ModFile mf, String modLoader, VersionRange modLoaderVersion) { + final String languageFileName = mf.getLocator() instanceof ExplodedDirectoryLocator ? "in-development" : mf.getFileName(); final ModLanguageWrapper mlw = languageProviderMap.get(modLoader); if (mlw == null) { - throw new MissingLanguageException("Missing language "+modLoader); + 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())) { - throw new MissingLanguageException("Missing language "+ modLoader + " matching range "+modLoaderVersion + " found "+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()))); } return mlw.getModLanguageProvider(); diff --git a/src/main/java/net/minecraftforge/fml/loading/MissingLanguageException.java b/src/main/java/net/minecraftforge/fml/loading/MissingLanguageException.java deleted file mode 100644 index ab881426e..000000000 --- a/src/main/java/net/minecraftforge/fml/loading/MissingLanguageException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2018. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.fml.loading; - -public class MissingLanguageException extends RuntimeException -{ - public MissingLanguageException(String message) - { - super(message); - } -} diff --git a/src/main/java/net/minecraftforge/fml/loading/ModSorter.java b/src/main/java/net/minecraftforge/fml/loading/ModSorter.java index 42f4a04c0..379623015 100644 --- a/src/main/java/net/minecraftforge/fml/loading/ModSorter.java +++ b/src/main/java/net/minecraftforge/fml/loading/ModSorter.java @@ -55,6 +55,7 @@ public class ModSorter final ModSorter ms = new ModSorter(mods); EarlyLoadingException earlyLoadingException = null; try { + ms.findLanguages(); ms.buildUniqueList(); ms.verifyDependencyVersions(); ms.sort(); @@ -65,6 +66,10 @@ public class ModSorter return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException); } + private void findLanguages() { + modFiles.stream().forEach(mf->mf.identifyLanguage()); + } + private void sort() { final TopologicalSort.DirectedGraph> topoGraph = new TopologicalSort.DirectedGraph<>(); @@ -136,8 +141,7 @@ public class ModSorter if (!missingVersions.isEmpty()) { 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" )). + mv.getOwner().getModId(), mv.getVersionRange(), modVersions.getOrDefault(mv.getModId(), new DefaultArtifactVersion("null")))). collect(Collectors.toList()); throw new EarlyLoadingException("Missing mods", null, exceptionData); } diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java index a3dfe9c0a..b1e83fa48 100644 --- a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java @@ -73,6 +73,10 @@ public class ModFile return locator.findPath(this, className); } + public void identifyLanguage() { + this.loader = FMLLoader.getLanguageLoadingProvider().findLanguage(this, this.modFileInfo.getModLoader(), this.modFileInfo.getModLoaderVersion()); + } + public enum Type { MOD, LIBRARY, LANGPROVIDER } @@ -124,7 +128,6 @@ public class ModFile this.coreMods = ModFileParser.getCoreMods(this); this.coreMods.forEach(mi-> LOGGER.debug(LOADING,"Found coremod {}", mi.getPath())); this.accessTransformer = locator.findPath(this, "META-INF", "accesstransformer.cfg"); - this.loader = FMLLoader.getLanguageLoadingProvider().findLanguage(this.modFileInfo.getModLoader(), this.modFileInfo.getModLoaderVersion()); return true; } diff --git a/src/main/resources/assets/forge/lang/en_us.json b/src/main/resources/assets/forge/lang/en_us.json index 174e43bfb..b8acadcff 100644 --- a/src/main/resources/assets/forge/lang/en_us.json +++ b/src/main/resources/assets/forge/lang/en_us.json @@ -23,8 +23,11 @@ "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.modloading.missingdependency": "Mod {4} has missing dependency {3}\n\u00a77Want {5,vr}, have {6,i18n,fml.messages.artifactversion}", + "fml.language.missingversion": "Mod File {5} needs language provider {3}:{4,vr}\n\u00a77Found {6,i18n,fml.messages.artifactversion}", + "fml.messages.artifactversion":"{0,ornull,fml.messages.artifactversion.none}", + "fml.messages.artifactversion.none":"none", "fml.messages.version.restriction.any":"any", "fml.messages.version.restriction.lower.inclusive":"{0} or above", "fml.messages.version.restriction.lower.exclusive":"above {0}",