From 71a482880957abd5fad800bc70e87f60b97049b3 Mon Sep 17 00:00:00 2001 From: cpw Date: Mon, 16 Sep 2019 20:14:21 -0400 Subject: [PATCH] Some tweaks around the code base. A functional consumer for networking - return a bool from your consumer function, rather than setPacketHandled. Tweak the server modloading behaviour to try and be a bit clearer that a mod errored. Signed-off-by: cpw --- .../fml/loading/Java9BackportUtils.java | 10 +++++++ .../minecraftforge/fml/loading/ModSorter.java | 23 +++++++++++---- .../fml/loading/moddiscovery/Scanner.java | 6 ++-- .../common/DimensionManager.java | 4 +++ .../fml/LoadingFailedException.java | 6 ++++ .../fml/network/simple/SimpleChannel.java | 17 +++++++++++ .../fml/server/ServerModLoader.java | 29 ++++++++++++++----- 7 files changed, 80 insertions(+), 15 deletions(-) diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/Java9BackportUtils.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/Java9BackportUtils.java index 9f28aab99..0ce0d7f1a 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/Java9BackportUtils.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/Java9BackportUtils.java @@ -19,7 +19,9 @@ package net.minecraftforge.fml.loading; +import java.util.Optional; import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collector; import java.util.stream.Stream; @@ -40,4 +42,12 @@ public class Java9BackportUtils downstream.combiner(), downstream.finisher(), downstream.characteristics().toArray(new Collector.Characteristics[0])); } + + public static void ifPresentOrElse(Optional optional, Consumer action, Runnable emptyAction) { + if (optional.isPresent()) { + action.accept(optional.get()); + } else { + emptyAction.run(); + } + } } diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/ModSorter.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/ModSorter.java index 8654db9fb..6cea6a004 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/ModSorter.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/ModSorter.java @@ -144,20 +144,31 @@ public class ModSorter private void buildUniqueList() { - final Stream modInfos = modFiles.stream().map(ModFile::getModInfos).flatMap(Collection::stream).map(ModInfo.class::cast); + final Stream modInfos = modFiles.stream() + .map(ModFile::getModInfos) + .flatMap(Collection::stream) + .map(ModInfo.class::cast); final Map> modIds = modInfos.collect(Collectors.groupingBy(IModInfo::getModId)); // TODO: make this figure out dupe handling better - final List>> dupedMods = modIds.entrySet().stream().filter(e -> e.getValue().size() > 1).collect(Collectors.toList()); + final List>> dupedMods = modIds + .entrySet() + .stream() + .filter(e -> e.getValue().size() > 1) + .collect(Collectors.toList()); if (!dupedMods.isEmpty()) { - final List duplicateModErrors = dupedMods.stream(). - map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod", dm.getValue().get(0))). - collect(Collectors.toList()); + 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))); + modIdNameLookup = modIds + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0))); } private void verifyDependencyVersions() diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/moddiscovery/Scanner.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/moddiscovery/Scanner.java index 0fa8dcbc8..e55d623b6 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/moddiscovery/Scanner.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/moddiscovery/Scanner.java @@ -45,8 +45,10 @@ public class Scanner { result.addModFileInfo(fileToScan.getModFileInfo()); fileToScan.scanFile(p -> fileVisitor(p, result)); final IModLanguageProvider loader = fileToScan.getLoader(); - LOGGER.debug(SCAN, "Scanning {} with language loader {}", fileToScan.getFilePath(), loader.name()); - loader.getFileVisitor().accept(result); + if (loader != null) { + LOGGER.debug(SCAN, "Scanning {} with language loader {}", fileToScan.getFilePath(), loader.name()); + loader.getFileVisitor().accept(result); + } return result; } diff --git a/src/main/java/net/minecraftforge/common/DimensionManager.java b/src/main/java/net/minecraftforge/common/DimensionManager.java index a8310b303..120d96bbf 100644 --- a/src/main/java/net/minecraftforge/common/DimensionManager.java +++ b/src/main/java/net/minecraftforge/common/DimensionManager.java @@ -60,6 +60,7 @@ import net.minecraft.world.dimension.DimensionType; import net.minecraftforge.event.world.RegisterDimensionsEvent; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.StartupQuery; +import net.minecraftforge.fml.server.ServerModLoader; import net.minecraftforge.registries.ClearableRegistry; import net.minecraftforge.registries.ForgeRegistries; @@ -160,6 +161,9 @@ public class DimensionManager Validate.notNull(server, "Must provide server when creating world"); Validate.notNull(dim, "Dimension type must not be null"); + if (ServerModLoader.hasErrors()) { + throw new RuntimeException("The server has failed to initialize correctly due to mod loading errors. Examine the crash report for more details."); + } // If we're in the early stages of loading, we need to return null so CommandSource can work properly for command function if (StartupQuery.pendingQuery()) { return null; diff --git a/src/main/java/net/minecraftforge/fml/LoadingFailedException.java b/src/main/java/net/minecraftforge/fml/LoadingFailedException.java index 0ac298511..72aad6c30 100644 --- a/src/main/java/net/minecraftforge/fml/LoadingFailedException.java +++ b/src/main/java/net/minecraftforge/fml/LoadingFailedException.java @@ -20,6 +20,7 @@ package net.minecraftforge.fml; import java.util.List; +import java.util.stream.Collectors; public class LoadingFailedException extends RuntimeException { private final List loadingExceptions; @@ -31,4 +32,9 @@ public class LoadingFailedException extends RuntimeException { public List getErrors() { return this.loadingExceptions; } + + @Override + public String getMessage() { + return "Loading errors encountered: " + this.loadingExceptions.stream().map(ModLoadingException::getMessage).collect(Collectors.joining(",\n\t", "[\n\t", "\n]")); + } } diff --git a/src/main/java/net/minecraftforge/fml/network/simple/SimpleChannel.java b/src/main/java/net/minecraftforge/fml/network/simple/SimpleChannel.java index 030d68069..0e88fad26 100644 --- a/src/main/java/net/minecraftforge/fml/network/simple/SimpleChannel.java +++ b/src/main/java/net/minecraftforge/fml/network/simple/SimpleChannel.java @@ -182,6 +182,23 @@ public class SimpleChannel return this; } + public interface ToBooleanBiFunction { + boolean applyAsBool(T first, U second); + } + + /** + * Function returning a boolean "packet handled" indication, for simpler channel building. + * @param handler a handler + * @return this + */ + public MessageBuilder consumer(ToBooleanBiFunction> handler) { + this.consumer = (msg, ctx) -> { + boolean handled = handler.applyAsBool(msg, ctx); + ctx.get().setPacketHandled(handled); + }; + return this; + } + public void add() { final IndexedMessageCodec.MessageHandler message = this.channel.registerMessage(this.id, this.type, this.encoder, this.decoder, this.consumer); if (this.loginIndexSetter != null) { diff --git a/src/main/java/net/minecraftforge/fml/server/ServerModLoader.java b/src/main/java/net/minecraftforge/fml/server/ServerModLoader.java index 3ea725344..7ad5c3312 100644 --- a/src/main/java/net/minecraftforge/fml/server/ServerModLoader.java +++ b/src/main/java/net/minecraftforge/fml/server/ServerModLoader.java @@ -21,10 +21,7 @@ package net.minecraftforge.fml.server; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.LogicalSidedProvider; -import net.minecraftforge.fml.ModLoader; -import net.minecraftforge.fml.ModLoadingWarning; -import net.minecraftforge.fml.SidedProvider; +import net.minecraftforge.fml.*; import net.minecraftforge.fml.network.FMLStatusPing; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -37,17 +34,31 @@ public class ServerModLoader { private static final Logger LOGGER = LogManager.getLogger(); private static DedicatedServer server; + private static boolean hasErrors = false; + public static void begin(DedicatedServer dedicatedServer) { ServerModLoader.server = dedicatedServer; SidedProvider.setServer(()->dedicatedServer); LogicalSidedProvider.setServer(()->dedicatedServer); LanguageHook.loadForgeAndMCLangs(); - ModLoader.get().gatherAndInitializeMods(null); - ModLoader.get().loadMods(Runnable::run, (a)->{}, (a)->{}); + try { + ModLoader.get().gatherAndInitializeMods(null); + ModLoader.get().loadMods(Runnable::run, (a)->{}, (a)->{}); + } catch (LoadingFailedException e) { + ServerModLoader.hasErrors = true; + throw e; + } } + public static void end() { - ModLoader.get().finishMods(Runnable::run); + try { + ModLoader.get().finishMods(Runnable::run); + } catch (LoadingFailedException e) { + ServerModLoader.hasErrors = true; + throw e; + + } List warnings = ModLoader.get().getWarnings(); if (!warnings.isEmpty()) { LOGGER.warn(LOADING, "Mods loaded with {} warnings", warnings.size()); @@ -56,4 +67,8 @@ public class ServerModLoader MinecraftForge.EVENT_BUS.start(); server.getServerStatusResponse().setForgeData(new FMLStatusPing()); //gathers NetworkRegistry data } + + public static boolean hasErrors() { + return ServerModLoader.hasErrors; + } }