Revert "Give immediate and complete error messages when there is a crash during startup (#4869)"

This reverts commit a38f5fd6a2.
This commit is contained in:
mezz 2018-05-12 22:36:45 -07:00
parent dae7bcee4b
commit ad099a4bfe
12 changed files with 255 additions and 300 deletions

View File

@ -1,44 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* 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 com.google.common.eventbus;
import com.google.common.base.Preconditions;
/**
* Event bus that allows exceptions thrown by the exception handler to propagate.
* TODO remove this in 1.13 and stop using the guava event bus
*/
public class FMLThrowingEventBus extends EventBus
{
private final SubscriberExceptionHandler exceptionHandler;
public FMLThrowingEventBus(SubscriberExceptionHandler exceptionHandler)
{
this.exceptionHandler = Preconditions.checkNotNull(exceptionHandler);
}
@Override
void handleSubscriberException(Throwable e, SubscriberExceptionContext context)
{
Preconditions.checkNotNull(e);
Preconditions.checkNotNull(context);
exceptionHandler.handleException(e, context);
}
}

View File

@ -21,7 +21,6 @@ package net.minecraftforge.fml.client;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.common.EnhancedRuntimeException;
import net.minecraftforge.fml.common.IFMLHandledException;
import net.minecraftforge.fml.relauncher.Side;
@ -38,7 +37,7 @@ import net.minecraftforge.fml.relauncher.SideOnly;
*
*/
@SideOnly(Side.CLIENT)
public abstract class CustomModLoadingErrorDisplayException extends EnhancedRuntimeException implements IFMLHandledException, IDisplayableError
public abstract class CustomModLoadingErrorDisplayException extends EnhancedRuntimeException implements IFMLHandledException
{
public CustomModLoadingErrorDisplayException() {
}
@ -73,10 +72,4 @@ public abstract class CustomModLoadingErrorDisplayException extends EnhancedRunt
public abstract void drawScreen(GuiErrorScreen errorScreen, FontRenderer fontRenderer, int mouseRelX, int mouseRelY, float tickTime);
@Override public void printStackTrace(EnhancedRuntimeException.WrappedPrintStream s){}; // Do Nothing unless the modder wants to.
@Override
public final GuiScreen createGui()
{
return new GuiCustomModLoadingErrorScreen(this);
}
}

View File

@ -112,7 +112,6 @@ import net.minecraftforge.registries.GameData;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.FormattedMessage;
import org.lwjgl.LWJGLUtil;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
@ -172,13 +171,19 @@ public class FMLClientHandler implements IFMLSidedHandler
private DummyModContainer optifineContainer;
@Deprecated // TODO remove in 1.13. mods are referencing this to get around client-only dependencies in old Forge versions
private MissingModsException modsMissing;
private ModSortingException modSorting;
private boolean loading = true;
@Nullable
private IDisplayableError errorToDisplay;
private WrongMinecraftVersionException wrongMC;
private CustomModLoadingErrorDisplayException customError;
private DuplicateModsFoundException dupesFound;
private MultipleModsErrored multipleModsErrored;
private boolean serverShouldBeKilledQuietly;
@ -204,6 +209,7 @@ public class FMLClientHandler implements IFMLSidedHandler
* @param resourcePackList The resource pack list we will populate with mods
* @param resourceManager The resource manager
*/
@SuppressWarnings("unchecked")
public void beginMinecraftLoading(Minecraft minecraft, List<IResourcePack> resourcePackList, IReloadableResourceManager resourceManager, MetadataSerializer metaSerializer)
{
detectOptifine();
@ -224,11 +230,30 @@ public class FMLClientHandler implements IFMLSidedHandler
{
Loader.instance().loadMods(injectedModContainers);
}
catch (WrongMinecraftVersionException | DuplicateModsFoundException | MissingModsException | ModSortingException | CustomModLoadingErrorDisplayException | MultipleModsErrored e)
catch (WrongMinecraftVersionException wrong)
{
FMLLog.log.error("An exception was thrown, the game will display an error screen and halt.", e);
errorToDisplay = e;
MinecraftForge.EVENT_BUS.shutdown();
wrongMC = wrong;
}
catch (DuplicateModsFoundException dupes)
{
dupesFound = dupes;
}
catch (MissingModsException missing)
{
modsMissing = missing;
}
catch (ModSortingException sorting)
{
modSorting = sorting;
}
catch (CustomModLoadingErrorDisplayException custom)
{
FMLLog.log.error("A custom exception was thrown by a mod, the game will now halt", custom);
customError = custom;
}
catch (MultipleModsErrored multiple)
{
multipleModsErrored = multiple;
}
catch (LoaderException le)
{
@ -249,9 +274,8 @@ public class FMLClientHandler implements IFMLSidedHandler
if (le.getCause() instanceof CustomModLoadingErrorDisplayException)
{
CustomModLoadingErrorDisplayException custom = (CustomModLoadingErrorDisplayException) le.getCause();
FMLLog.log.error("A custom exception was thrown by a mod, the game will display an error screen and halt.", custom);
errorToDisplay = custom;
MinecraftForge.EVENT_BUS.shutdown();
FMLLog.log.error("A custom exception was thrown by a mod, the game will now halt", custom);
customError = custom;
}
else
{
@ -260,7 +284,6 @@ public class FMLClientHandler implements IFMLSidedHandler
}
}
@SuppressWarnings("unchecked")
Map<String,Map<String,String>> sharedModList = (Map<String, Map<String, String>>) Launch.blackboard.get("modList");
if (sharedModList == null)
{
@ -309,7 +332,7 @@ public class FMLClientHandler implements IFMLSidedHandler
public boolean hasError()
{
return errorToDisplay != null;
return modsMissing != null || wrongMC != null || customError != null || dupesFound != null || modSorting != null || multipleModsErrored != null;
}
/**
@ -333,9 +356,8 @@ public class FMLClientHandler implements IFMLSidedHandler
if (le.getCause() instanceof CustomModLoadingErrorDisplayException)
{
CustomModLoadingErrorDisplayException custom = (CustomModLoadingErrorDisplayException) le.getCause();
FMLLog.log.error("A custom exception was thrown by a mod, the game will display an error screen and halt.", custom);
errorToDisplay = custom;
MinecraftForge.EVENT_BUS.shutdown();
FMLLog.log.error("A custom exception was thrown by a mod, the game will now halt", custom);
customError = custom;
}
else
{
@ -347,7 +369,6 @@ public class FMLClientHandler implements IFMLSidedHandler
// This call is being phased out for performance reasons in 1.12,
// but we are keeping an option here in case something needs it for a little longer.
// See https://github.com/MinecraftForge/MinecraftForge/pull/4032
// TODO remove in 1.13
if (Boolean.parseBoolean(System.getProperty("fml.reloadResourcesOnStart", "false")))
{
client.refreshResources();
@ -380,7 +401,7 @@ public class FMLClientHandler implements IFMLSidedHandler
}
loading = false;
client.gameSettings.loadOptions(); //Reload options to load any mod added keybindings.
if (!hasError())
if (customError == null)
Loader.instance().loadingComplete();
SplashProgress.finish();
}
@ -418,10 +439,29 @@ public class FMLClientHandler implements IFMLSidedHandler
// re-sync TEXTURE_2D, splash screen disables it with a direct GL call
GlStateManager.disableTexture2D();
GlStateManager.enableTexture2D();
if (errorToDisplay != null)
if (wrongMC != null)
{
GuiScreen errorScreen = errorToDisplay.createGui();
showGuiScreen(errorScreen);
showGuiScreen(new GuiWrongMinecraft(wrongMC));
}
else if (modsMissing != null)
{
showGuiScreen(new GuiModsMissing(modsMissing));
}
else if (dupesFound != null)
{
showGuiScreen(new GuiDupesFound(dupesFound));
}
else if (modSorting != null)
{
showGuiScreen(new GuiSortingProblem(modSorting));
}
else if (customError != null)
{
showGuiScreen(new GuiCustomModLoadingErrorScreen(customError));
}
else if (multipleModsErrored != null)
{
showGuiScreen(new GuiMultipleModsErrored(multipleModsErrored));
}
else
{
@ -576,10 +616,6 @@ public class FMLClientHandler implements IFMLSidedHandler
return client.getIntegratedServer();
}
/**
* TODO remove in 1.13
*/
@Deprecated
public void displayMissingMods(Object modMissingPacket)
{
// showGuiScreen(new GuiModsMissingForServer(modMissingPacket));
@ -643,8 +679,7 @@ public class FMLClientHandler implements IFMLSidedHandler
}
catch (Exception e)
{
FormattedMessage message = new FormattedMessage("An unexpected exception occurred constructing the custom resource pack for {} ({})", container.getName(), container.getModId());
throw new RuntimeException(message.getFormattedMessage(), e);
throw new RuntimeException("An unexpected exception occurred constructing the custom resource pack for " + container.getName(), e);
}
}
}
@ -663,6 +698,14 @@ public class FMLClientHandler implements IFMLSidedHandler
@Override
public void serverStopped()
{
// If the server crashes during startup, it might hang the client - reset the client so it can abend properly.
MinecraftServer server = getServer();
if (server != null && !server.serverIsInRunLoop())
{
// ObfuscationReflectionHelper.setPrivateValue(MinecraftServer.class, server, true, "field_71296"+"_Q","serverIs"+"Running");
}
GameData.revertToFrozen();
}

View File

@ -1,11 +0,0 @@
package net.minecraftforge.fml.client;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public interface IDisplayableError
{
@SideOnly(Side.CLIENT)
GuiScreen createGui();
}

View File

@ -23,14 +23,8 @@ import java.io.File;
import java.util.Map.Entry;
import com.google.common.collect.SetMultimap;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.GuiDupesFound;
import net.minecraftforge.fml.client.IDisplayableError;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class DuplicateModsFoundException extends LoaderException implements IDisplayableError
{
public class DuplicateModsFoundException extends LoaderException {
private static final long serialVersionUID = 1L;
public SetMultimap<ModContainer,File> dupes;
@ -48,11 +42,4 @@ public class DuplicateModsFoundException extends LoaderException implements IDis
}
stream.println("");
}
@Override
@SideOnly(Side.CLIENT)
public GuiScreen createGui()
{
return new GuiDupesFound(this);
}
}

View File

@ -36,7 +36,6 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
import com.google.common.base.Throwables;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Config;
import net.minecraftforge.common.config.ConfigManager;
@ -74,7 +73,6 @@ import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.apache.logging.log4j.message.FormattedMessage;
import javax.annotation.Nullable;
@ -382,7 +380,8 @@ public class FMLModContainer implements ModContainer
}
@Nullable
private Method gatherAnnotations(Class<?> clazz)
@SuppressWarnings("unchecked")
private Method gatherAnnotations(Class<?> clazz) throws Exception
{
Method factoryMethod = null;
for (Method m : clazz.getDeclaredMethods())
@ -394,9 +393,7 @@ public class FMLModContainer implements ModContainer
if (m.getParameterTypes().length == 1 && FMLEvent.class.isAssignableFrom(m.getParameterTypes()[0]))
{
m.setAccessible(true);
@SuppressWarnings("unchecked")
Class<? extends FMLEvent> parameterType = (Class<? extends FMLEvent>) m.getParameterTypes()[0];
eventMethods.put(parameterType, m);
eventMethods.put((Class<? extends FMLEvent>)m.getParameterTypes()[0], m);
}
else
{
@ -424,7 +421,7 @@ public class FMLModContainer implements ModContainer
return factoryMethod;
}
private void processFieldAnnotations(ASMDataTable asmDataTable) throws IllegalAccessException
private void processFieldAnnotations(ASMDataTable asmDataTable) throws Exception
{
SetMultimap<String, ASMData> annotations = asmDataTable.getAnnotationsFor(this);
@ -506,110 +503,86 @@ public class FMLModContainer implements ModContainer
@Subscribe
public void constructMod(FMLConstructionEvent event)
{
BlamingTransformer.addClasses(getModId(), candidate.getClassList());
ModClassLoader modClassLoader = event.getModClassLoader();
try
{
BlamingTransformer.addClasses(getModId(), candidate.getClassList());
ModClassLoader modClassLoader = event.getModClassLoader();
modClassLoader.addFile(source);
}
catch (MalformedURLException e)
{
FormattedMessage message = new FormattedMessage("{} Failed to add file to classloader: {}", getModId(), source);
throw new LoaderException(message.getFormattedMessage(), e);
}
modClassLoader.clearNegativeCacheFor(candidate.getClassList());
modClassLoader.clearNegativeCacheFor(candidate.getClassList());
//Only place I could think to add this...
MinecraftForge.preloadCrashClasses(event.getASMHarvestedData(), getModId(), candidate.getClassList());
//Only place I could think to add this...
MinecraftForge.preloadCrashClasses(event.getASMHarvestedData(), getModId(), candidate.getClassList());
Class<?> clazz;
try
{
clazz = Class.forName(className, true, modClassLoader);
}
catch (ClassNotFoundException e)
{
FormattedMessage message = new FormattedMessage("{} Failed load class: {}", getModId(), className);
throw new LoaderException(message.getFormattedMessage(), e);
}
Class<?> clazz = Class.forName(className, true, modClassLoader);
Certificate[] certificates = clazz.getProtectionDomain().getCodeSource().getCertificates();
ImmutableList<String> certList = CertificateHelper.getFingerprints(certificates);
sourceFingerprints = ImmutableSet.copyOf(certList);
Certificate[] certificates = clazz.getProtectionDomain().getCodeSource().getCertificates();
ImmutableList<String> certList = CertificateHelper.getFingerprints(certificates);
sourceFingerprints = ImmutableSet.copyOf(certList);
String expectedFingerprint = (String)descriptor.get("certificateFingerprint");
String expectedFingerprint = (String)descriptor.get("certificateFingerprint");
fingerprintNotPresent = true;
fingerprintNotPresent = true;
if (expectedFingerprint != null && !expectedFingerprint.isEmpty())
{
if (!sourceFingerprints.contains(expectedFingerprint))
if (expectedFingerprint != null && !expectedFingerprint.isEmpty())
{
Level warnLevel = source.isDirectory() ? Level.TRACE : Level.ERROR;
FMLLog.log.log(warnLevel, "The mod {} is expecting signature {} for source {}, however there is no signature matching that description", getModId(), expectedFingerprint, source.getName());
if (!sourceFingerprints.contains(expectedFingerprint))
{
Level warnLevel = Level.ERROR;
if (source.isDirectory())
{
warnLevel = Level.TRACE;
}
FMLLog.log.log(warnLevel, "The mod {} is expecting signature {} for source {}, however there is no signature matching that description", getModId(), expectedFingerprint, source.getName());
}
else
{
certificate = certificates[certList.indexOf(expectedFingerprint)];
fingerprintNotPresent = false;
}
}
@SuppressWarnings("unchecked")
List<Map<String, Object>> props = (List<Map<String, Object>>)descriptor.get("customProperties");
if (props != null)
{
com.google.common.collect.ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
for (Map<String, Object> p : props)
{
builder.put((String)p.get("k"), (String)p.get("v"));
}
customModProperties = builder.build();
}
else
{
certificate = certificates[certList.indexOf(expectedFingerprint)];
fingerprintNotPresent = false;
customModProperties = EMPTY_PROPERTIES;
}
}
@SuppressWarnings("unchecked")
List<Map<String, String>> props = (List<Map<String, String>>)descriptor.get("customProperties");
if (props != null)
{
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
for (Map<String, String> p : props)
Boolean hasDisableableFlag = (Boolean)descriptor.get("canBeDeactivated");
boolean hasReverseDepends = !event.getReverseDependencies().get(getModId()).isEmpty();
if (hasDisableableFlag != null && hasDisableableFlag)
{
builder.put(p.get("k"), p.get("v"));
disableability = hasReverseDepends ? Disableable.DEPENDENCIES : Disableable.YES;
}
customModProperties = builder.build();
}
else
{
customModProperties = EMPTY_PROPERTIES;
}
else
{
disableability = hasReverseDepends ? Disableable.DEPENDENCIES : Disableable.RESTART;
}
Method factoryMethod = gatherAnnotations(clazz);
modInstance = getLanguageAdapter().getNewInstance(this, clazz, modClassLoader, factoryMethod);
NetworkRegistry.INSTANCE.register(this, clazz, (String)(descriptor.getOrDefault("acceptableRemoteVersions", null)), event.getASMHarvestedData());
if (fingerprintNotPresent)
{
eventBus.post(new FMLFingerprintViolationEvent(source.isDirectory(), source, ImmutableSet.copyOf(this.sourceFingerprints), expectedFingerprint));
}
ProxyInjector.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide(), getLanguageAdapter());
AutomaticEventSubscriber.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide());
ConfigManager.sync(this.getModId(), Config.Type.INSTANCE);
Boolean hasDisableableFlag = (Boolean)descriptor.get("canBeDeactivated");
boolean hasReverseDepends = !event.getReverseDependencies().get(getModId()).isEmpty();
if (hasDisableableFlag != null && hasDisableableFlag)
{
disableability = hasReverseDepends ? Disableable.DEPENDENCIES : Disableable.YES;
}
else
{
disableability = hasReverseDepends ? Disableable.DEPENDENCIES : Disableable.RESTART;
}
Method factoryMethod = gatherAnnotations(clazz);
ILanguageAdapter languageAdapter = getLanguageAdapter();
try
{
modInstance = languageAdapter.getNewInstance(this, clazz, modClassLoader, factoryMethod);
}
catch (Exception e)
{
Throwables.throwIfUnchecked(e);
FormattedMessage message = new FormattedMessage("{} Failed to load new mod instance.", getModId());
throw new LoaderException(message.getFormattedMessage(), e);
}
NetworkRegistry.INSTANCE.register(this, clazz, (String)(descriptor.getOrDefault("acceptableRemoteVersions", null)), event.getASMHarvestedData());
if (fingerprintNotPresent)
{
eventBus.post(new FMLFingerprintViolationEvent(source.isDirectory(), source, ImmutableSet.copyOf(this.sourceFingerprints), expectedFingerprint));
}
ProxyInjector.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide(), languageAdapter);
AutomaticEventSubscriber.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide());
ConfigManager.sync(this.getModId(), Config.Type.INSTANCE);
try
{
processFieldAnnotations(event.getASMHarvestedData());
}
catch (IllegalAccessException e)
catch (Throwable e)
{
FormattedMessage message = new FormattedMessage("{} Failed to process field annotations.", getModId());
throw new LoaderException(message.getFormattedMessage(), e);
controller.errorOccurred(this, e);
}
}

View File

@ -20,14 +20,15 @@
package net.minecraftforge.fml.common;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.TextTable;
import net.minecraftforge.fml.common.LoaderState.ModState;
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
@ -38,10 +39,9 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLStateEvent;
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.message.FormattedMessage;
import com.google.common.base.Throwables;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
@ -53,8 +53,9 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.FMLThrowingEventBus;
import com.google.common.eventbus.Subscribe;
import com.google.common.eventbus.SubscriberExceptionHandler;
import com.google.common.eventbus.SubscriberExceptionContext;
import javax.annotation.Nullable;
@ -62,9 +63,11 @@ public class LoadController
{
private Loader loader;
private EventBus masterChannel;
private ImmutableMap<String, EventBus> eventChannels;
private ImmutableMap<String,EventBus> eventChannels;
private LoaderState state;
private Multimap<String, ModState> modStates = ArrayListMultimap.create();
private Multimap<String, Throwable> errors = ArrayListMultimap.create();
private Map<String, String> modNames = Maps.newHashMap();
private List<ModContainer> activeModList = Lists.newArrayList();
private ModContainer activeContainer;
private BiMap<ModContainer, Object> modObjectList;
@ -73,13 +76,13 @@ public class LoadController
public LoadController(Loader loader)
{
this.loader = loader;
this.masterChannel = new FMLThrowingEventBus((exception, context) -> {
Throwables.throwIfUnchecked(exception);
// should not happen, but add some extra context for checked exceptions
Method method = context.getSubscriberMethod();
String parameterNames = Stream.of(method.getParameterTypes()).map(Class::getName).collect(Collectors.joining(", "));
String message = "Exception thrown during LoadController." + method.getName() + '(' + parameterNames + ')';
throw new LoaderExceptionModCrash(message, exception);
this.masterChannel = new EventBus(new SubscriberExceptionHandler()
{
@Override
public void handleException(Throwable exception, SubscriberExceptionContext context)
{
FMLLog.log.error("Could not dispatch event: {} to {}", context.getSubscriberMethod(), exception);
}
});
this.masterChannel.register(this);
@ -94,12 +97,14 @@ public class LoadController
String modId = mod.getModId();
EventBus bus = temporary.remove(modId);
bus.post(new FMLModDisabledEvent());
eventChannels = ImmutableMap.copyOf(temporary);
modStates.put(modId, ModState.DISABLED);
modObjectList.remove(mod);
activeModList.remove(mod);
if (errors.get(modId).isEmpty())
{
eventChannels = ImmutableMap.copyOf(temporary);
modStates.put(modId, ModState.DISABLED);
modObjectList.remove(mod);
activeModList.remove(mod);
}
}
@Subscribe
public void buildModList(FMLLoadEvent event)
{
@ -107,7 +112,15 @@ public class LoadController
for (final ModContainer mod : loader.getModList())
{
EventBus bus = new FMLThrowingEventBus((exception, context) -> this.errorOccurred(mod, exception));
//Create mod logger, and make the EventBus logger a child of it.
EventBus bus = new EventBus(new SubscriberExceptionHandler()
{
@Override
public void handleException(final Throwable exception, final SubscriberExceptionContext context)
{
LoadController.this.errorOccurred(mod, exception);
}
});
boolean isActive = mod.registerBus(bus, this);
if (isActive)
@ -123,6 +136,7 @@ public class LoadController
modStates.put(mod.getModId(), ModState.UNLOADED);
modStates.put(mod.getModId(), ModState.DISABLED);
}
modNames.put(mod.getModId(), mod.getName());
}
eventChannels = eventBus.build();
@ -145,13 +159,13 @@ public class LoadController
}
LoaderState oldState = state;
state = state.transition(false);
state = state.transition(!errors.isEmpty());
if (state != desiredState)
{
if (!forceState)
{
FormattedMessage message = new FormattedMessage("A fatal error occurred during the state transition from {} to {}. State became {} instead. Loading cannot continue.", oldState, desiredState, state);
throw new LoaderException(message.getFormattedMessage());
FMLLog.log.fatal("Fatal errors were detected during the transition from {} to {}. Loading cannot continue", oldState, desiredState);
throw throwStoredErrors();
}
else
{
@ -164,11 +178,60 @@ public class LoadController
@Deprecated // TODO remove in 1.13
public void checkErrorsAfterAvailable()
{
checkErrors();
}
@Deprecated // TODO remove in 1.13
public void checkErrors()
{
if (errors.size() > 0)
{
FMLLog.log.fatal("Fatal errors were detected during {}. Loading cannot continue.", state);
MinecraftForge.EVENT_BUS.shutdown();
state = state.transition(true);
throw throwStoredErrors();
}
}
private RuntimeException throwStoredErrors()
{
Entry<String, Throwable> toThrow = null;
StringBuilder sb = new StringBuilder();
printModStates(sb);
FMLLog.log.fatal(sb.toString());
if (errors.size() > 0)
{
FMLLog.log.fatal("The following problems were captured during this phase");
for (Entry<String, Throwable> entry : errors.entries())
{
String modId = entry.getKey();
String modName = modNames.get(modId);
Throwable error = entry.getValue();
FMLLog.log.error("Caught exception from {} ({})", modId, modName, error);
if (error instanceof IFMLHandledException)
{
toThrow = entry;
}
else if (toThrow == null)
{
toThrow = entry;
}
}
}
if (toThrow == null)
{
FMLLog.log.fatal("The ForgeModLoader state engine has become corrupted. Probably, a state was missed by and invalid modification to a base class" +
"ForgeModLoader depends on. This is a critical error and not recoverable. Investigate any modifications to base classes outside of" +
"ForgeModLoader, especially Optifine, to see if there are fixes available.");
throw new RuntimeException("The ForgeModLoader state engine is invalid");
}
else
{
String modId = toThrow.getKey();
String modName = modNames.get(modId);
String errMsg = String.format("Caught exception from %s (%s)", modName, modId);
throw new LoaderExceptionModCrash(errMsg, toThrow.getValue());
}
}
@Nullable
@ -181,7 +244,6 @@ public class LoadController
{
activeContainer = container;
}
@Subscribe
public void propogateStateMessage(FMLEvent stateEvent)
{
@ -201,10 +263,10 @@ public class LoadController
private void sendEventToModContainer(FMLEvent stateEvent, ModContainer mc)
{
String modId = mc.getModId();
Collection<String> requirements = mc.getRequirements().stream().map(ArtifactVersion::getLabel).collect(Collectors.toCollection(HashSet::new));
Collection<String> requirements = mc.getRequirements().stream().map(ArtifactVersion::getLabel).collect(Collectors.toCollection(HashSet::new));
for (ArtifactVersion av : mc.getDependencies())
{
if (av.getLabel() != null && requirements.contains(av.getLabel()) && modStates.containsEntry(av.getLabel(), ModState.ERRORED))
if (av.getLabel()!= null && requirements.contains(av.getLabel()) && modStates.containsEntry(av.getLabel(),ModState.ERRORED))
{
FMLLog.log.error("Skipping event {} and marking errored mod {} since required dependency {} has errored", stateEvent.getEventType(), modId, av.getLabel());
modStates.put(modId, ModState.ERRORED);
@ -221,7 +283,14 @@ public class LoadController
activeContainer = null;
if (stateEvent instanceof FMLStateEvent)
{
modStates.put(modId, ((FMLStateEvent) stateEvent).getModState());
if (!errors.containsKey(modId))
{
modStates.put(modId, ((FMLStateEvent)stateEvent).getModState());
}
else
{
modStates.put(modId, ModState.ERRORED);
}
}
}
@ -230,7 +299,7 @@ public class LoadController
ImmutableBiMap.Builder<ModContainer, Object> builder = ImmutableBiMap.builder();
for (ModContainer mc : activeModList)
{
if (!mc.isImmutable() && mc.getMod() != null)
if (!mc.isImmutable() && mc.getMod()!=null)
{
builder.put(mc, mc.getMod());
List<String> packages = mc.getOwnedPackages();
@ -239,10 +308,13 @@ public class LoadController
packageOwners.put(pkg, mc);
}
}
if (mc.getMod() == null && !mc.isImmutable() && state != LoaderState.CONSTRUCTING)
if (mc.getMod()==null && !mc.isImmutable() && state!=LoaderState.CONSTRUCTING)
{
FormattedMessage message = new FormattedMessage("There is a severe problem with {} ({}) - it appears not to have constructed correctly", mc.getName(), mc.getModId());
this.errorOccurred(mc, new RuntimeException(message.getFormattedMessage()));
FMLLog.log.fatal("There is a severe problem with {} - it appears not to have constructed correctly", mc.getModId());
if (state != LoaderState.CONSTRUCTING)
{
this.errorOccurred(mc, new RuntimeException());
}
}
}
return builder.build();
@ -250,19 +322,14 @@ public class LoadController
public void errorOccurred(ModContainer modContainer, Throwable exception)
{
String modId = modContainer.getModId();
String modName = modContainer.getName();
modStates.put(modId, ModState.ERRORED);
if (exception instanceof InvocationTargetException)
{
exception = exception.getCause();
errors.put(modContainer.getModId(), exception.getCause());
}
if (exception instanceof LoaderException) // avoid wrapping loader exceptions multiple times
else
{
throw (LoaderException) exception;
errors.put(modContainer.getModId(), exception);
}
FormattedMessage message = new FormattedMessage("Caught exception from {} ({})", modName, modId);
throw new LoaderExceptionModCrash(message.getFormattedMessage(), exception);
}
public void printModStates(StringBuilder ret)
@ -307,16 +374,15 @@ public class LoadController
public void distributeStateMessage(Class<?> customEvent)
{
Object eventInstance;
try
{
eventInstance = customEvent.newInstance();
masterChannel.post(customEvent.newInstance());
}
catch (InstantiationException | IllegalAccessException e)
catch (Exception e)
{
throw new LoaderException("Failed to create new event instance for " + customEvent.getName(), e);
FMLLog.log.error("An unexpected exception", e);
throw new LoaderException(e);
}
masterChannel.post(eventInstance);
}
public BiMap<ModContainer, Object> getModObjectList()
@ -334,9 +400,8 @@ public class LoadController
return this.state == state;
}
boolean hasReachedState(LoaderState state)
{
return this.state.ordinal() >= state.ordinal() && this.state != LoaderState.ERRORED;
boolean hasReachedState(LoaderState state) {
return this.state.ordinal()>=state.ordinal() && this.state!=LoaderState.ERRORED;
}
void forceState(LoaderState newState)
@ -354,7 +419,7 @@ public class LoadController
{
continue;
}
String pkg = c.getName().substring(0, idx);
String pkg = c.getName().substring(0,idx);
if (packageOwners.containsKey(pkg))
{
return packageOwners.get(pkg).get(0);
@ -363,7 +428,6 @@ public class LoadController
return null;
}
private FMLSecurityManager accessibleManager = new FMLSecurityManager();
class FMLSecurityManager extends SecurityManager

View File

@ -547,10 +547,9 @@ public class Loader
ObjectHolderRegistry.INSTANCE.findObjectHolders(new ASMDataTable());
modController.forceActiveContainer(containers[0]);
}
/**
* Called from the hook to start mod loading. We trigger the
* {@link #identifyMods(List)} and Constructing, Preinitalization, and Initalization phases here. Finally,
* {@link #identifyMods()} and Constructing, Preinitalization, and Initalization phases here. Finally,
* the mod list is frozen completely and is consider immutable from then on.
* @param injectedModContainers containers to inject
*/
@ -625,6 +624,7 @@ public class Loader
ItemStackHolderInjector.INSTANCE.findHolders(discoverer.getASMTable());
CapabilityManager.INSTANCE.injectCapabilities(discoverer.getASMTable());
modController.distributeStateMessage(LoaderState.PREINITIALIZATION, discoverer.getASMTable(), canonicalConfigDir);
modController.checkErrors();
GameData.fireRegistryEvents(rl -> !rl.equals(GameData.RECIPES));
FMLCommonHandler.instance().fireSidedRegistryEvents();
ObjectHolderRegistry.INSTANCE.applyObjectHolders();
@ -750,6 +750,7 @@ public class Loader
progressBar.step("Finishing up");
modController.transition(LoaderState.AVAILABLE, false);
modController.distributeStateMessage(LoaderState.AVAILABLE);
modController.checkErrors();
GameData.freezeData();
FMLLog.log.info("Forge Mod Loader has successfully loaded {} mod{}", mods.size(), mods.size() == 1 ? "" : "s");
progressBar.step("Completing Minecraft initialization");

View File

@ -28,15 +28,9 @@ import java.util.Set;
import java.util.stream.Collectors;
import com.google.common.base.Preconditions;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.GuiModsMissing;
import net.minecraftforge.fml.client.IDisplayableError;
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class MissingModsException extends EnhancedRuntimeException implements IDisplayableError
public class MissingModsException extends EnhancedRuntimeException
{
private static final long serialVersionUID = 1L;
private final String id;
@ -107,13 +101,6 @@ public class MissingModsException extends EnhancedRuntimeException implements ID
stream.println("");
}
@Override
@SideOnly(Side.CLIENT)
public GuiScreen createGui()
{
return new GuiModsMissing(this);
}
public static class MissingModInfo
{
private final ArtifactVersion acceptedVersion;
@ -145,5 +132,4 @@ public class MissingModsException extends EnhancedRuntimeException implements ID
return required;
}
}
}

View File

@ -21,13 +21,7 @@ package net.minecraftforge.fml.common;
import java.util.List;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.GuiMultipleModsErrored;
import net.minecraftforge.fml.client.IDisplayableError;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class MultipleModsErrored extends EnhancedRuntimeException implements IDisplayableError
public class MultipleModsErrored extends EnhancedRuntimeException
{
public final List<WrongMinecraftVersionException> wrongMinecraftExceptions;
public final List<MissingModsException> missingModsExceptions;
@ -37,13 +31,6 @@ public class MultipleModsErrored extends EnhancedRuntimeException implements IDi
this.missingModsExceptions = missingModsExceptions;
}
@Override
@SideOnly(Side.CLIENT)
public GuiScreen createGui()
{
return new GuiMultipleModsErrored(this);
}
@Override
protected void printStackTrace(WrappedPrintStream stream)
{

View File

@ -19,13 +19,7 @@
package net.minecraftforge.fml.common;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.GuiWrongMinecraft;
import net.minecraftforge.fml.client.IDisplayableError;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class WrongMinecraftVersionException extends EnhancedRuntimeException implements IDisplayableError
public class WrongMinecraftVersionException extends EnhancedRuntimeException
{
private static final long serialVersionUID = 1L;
public ModContainer mod;
@ -48,10 +42,4 @@ public class WrongMinecraftVersionException extends EnhancedRuntimeException imp
stream.println("");
}
@Override
@SideOnly(Side.CLIENT)
public GuiScreen createGui()
{
return new GuiWrongMinecraft(this);
}
}

View File

@ -21,15 +21,10 @@ package net.minecraftforge.fml.common.toposort;
import java.util.Set;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.GuiSortingProblem;
import net.minecraftforge.fml.client.IDisplayableError;
import net.minecraftforge.fml.common.EnhancedRuntimeException;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class ModSortingException extends EnhancedRuntimeException implements IDisplayableError
public class ModSortingException extends EnhancedRuntimeException
{
private static final long serialVersionUID = 1L;
@ -81,11 +76,4 @@ public class ModSortingException extends EnhancedRuntimeException implements IDi
}
}
@Override
@SideOnly(Side.CLIENT)
public GuiScreen createGui()
{
return new GuiSortingProblem(this);
}
}