Give immediate and complete error messages when there is a crash during startup (#4869)
This commit is contained in:
parent
ad099a4bfe
commit
979797a2a6
12 changed files with 309 additions and 256 deletions
|
@ -21,6 +21,7 @@ package net.minecraftforge.fml.client;
|
||||||
|
|
||||||
import net.minecraft.client.gui.FontRenderer;
|
import net.minecraft.client.gui.FontRenderer;
|
||||||
import net.minecraft.client.gui.GuiErrorScreen;
|
import net.minecraft.client.gui.GuiErrorScreen;
|
||||||
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
import net.minecraftforge.fml.common.EnhancedRuntimeException;
|
import net.minecraftforge.fml.common.EnhancedRuntimeException;
|
||||||
import net.minecraftforge.fml.common.IFMLHandledException;
|
import net.minecraftforge.fml.common.IFMLHandledException;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
@ -37,7 +38,7 @@ import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
public abstract class CustomModLoadingErrorDisplayException extends EnhancedRuntimeException implements IFMLHandledException
|
public abstract class CustomModLoadingErrorDisplayException extends EnhancedRuntimeException implements IFMLHandledException, IDisplayableError
|
||||||
{
|
{
|
||||||
public CustomModLoadingErrorDisplayException() {
|
public CustomModLoadingErrorDisplayException() {
|
||||||
}
|
}
|
||||||
|
@ -72,4 +73,10 @@ public abstract class CustomModLoadingErrorDisplayException extends EnhancedRunt
|
||||||
public abstract void drawScreen(GuiErrorScreen errorScreen, FontRenderer fontRenderer, int mouseRelX, int mouseRelY, float tickTime);
|
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 void printStackTrace(EnhancedRuntimeException.WrappedPrintStream s){}; // Do Nothing unless the modder wants to.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final GuiScreen createGui()
|
||||||
|
{
|
||||||
|
return new GuiCustomModLoadingErrorScreen(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,7 @@ import net.minecraftforge.registries.GameData;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.apache.logging.log4j.message.FormattedMessage;
|
||||||
import org.lwjgl.LWJGLUtil;
|
import org.lwjgl.LWJGLUtil;
|
||||||
import org.lwjgl.input.Mouse;
|
import org.lwjgl.input.Mouse;
|
||||||
import org.lwjgl.opengl.Display;
|
import org.lwjgl.opengl.Display;
|
||||||
|
@ -171,19 +172,13 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
|
|
||||||
private DummyModContainer optifineContainer;
|
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 MissingModsException modsMissing;
|
||||||
|
|
||||||
private ModSortingException modSorting;
|
|
||||||
|
|
||||||
private boolean loading = true;
|
private boolean loading = true;
|
||||||
|
|
||||||
private WrongMinecraftVersionException wrongMC;
|
@Nullable
|
||||||
|
private IDisplayableError errorToDisplay;
|
||||||
private CustomModLoadingErrorDisplayException customError;
|
|
||||||
|
|
||||||
private DuplicateModsFoundException dupesFound;
|
|
||||||
|
|
||||||
private MultipleModsErrored multipleModsErrored;
|
|
||||||
|
|
||||||
private boolean serverShouldBeKilledQuietly;
|
private boolean serverShouldBeKilledQuietly;
|
||||||
|
|
||||||
|
@ -209,7 +204,6 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
* @param resourcePackList The resource pack list we will populate with mods
|
* @param resourcePackList The resource pack list we will populate with mods
|
||||||
* @param resourceManager The resource manager
|
* @param resourceManager The resource manager
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void beginMinecraftLoading(Minecraft minecraft, List<IResourcePack> resourcePackList, IReloadableResourceManager resourceManager, MetadataSerializer metaSerializer)
|
public void beginMinecraftLoading(Minecraft minecraft, List<IResourcePack> resourcePackList, IReloadableResourceManager resourceManager, MetadataSerializer metaSerializer)
|
||||||
{
|
{
|
||||||
detectOptifine();
|
detectOptifine();
|
||||||
|
@ -230,30 +224,11 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
{
|
{
|
||||||
Loader.instance().loadMods(injectedModContainers);
|
Loader.instance().loadMods(injectedModContainers);
|
||||||
}
|
}
|
||||||
catch (WrongMinecraftVersionException wrong)
|
catch (WrongMinecraftVersionException | DuplicateModsFoundException | MissingModsException | ModSortingException | CustomModLoadingErrorDisplayException | MultipleModsErrored e)
|
||||||
{
|
{
|
||||||
wrongMC = wrong;
|
FMLLog.log.error("An exception was thrown, the game will display an error screen and halt.", e);
|
||||||
}
|
errorToDisplay = e;
|
||||||
catch (DuplicateModsFoundException dupes)
|
MinecraftForge.EVENT_BUS.shutdown();
|
||||||
{
|
|
||||||
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)
|
catch (LoaderException le)
|
||||||
{
|
{
|
||||||
|
@ -274,8 +249,9 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
if (le.getCause() instanceof CustomModLoadingErrorDisplayException)
|
if (le.getCause() instanceof CustomModLoadingErrorDisplayException)
|
||||||
{
|
{
|
||||||
CustomModLoadingErrorDisplayException custom = (CustomModLoadingErrorDisplayException) le.getCause();
|
CustomModLoadingErrorDisplayException custom = (CustomModLoadingErrorDisplayException) le.getCause();
|
||||||
FMLLog.log.error("A custom exception was thrown by a mod, the game will now halt", custom);
|
FMLLog.log.error("A custom exception was thrown by a mod, the game will display an error screen and halt.", custom);
|
||||||
customError = custom;
|
errorToDisplay = custom;
|
||||||
|
MinecraftForge.EVENT_BUS.shutdown();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -284,6 +260,7 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
Map<String,Map<String,String>> sharedModList = (Map<String, Map<String, String>>) Launch.blackboard.get("modList");
|
Map<String,Map<String,String>> sharedModList = (Map<String, Map<String, String>>) Launch.blackboard.get("modList");
|
||||||
if (sharedModList == null)
|
if (sharedModList == null)
|
||||||
{
|
{
|
||||||
|
@ -332,7 +309,7 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
|
|
||||||
public boolean hasError()
|
public boolean hasError()
|
||||||
{
|
{
|
||||||
return modsMissing != null || wrongMC != null || customError != null || dupesFound != null || modSorting != null || multipleModsErrored != null;
|
return errorToDisplay != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -356,8 +333,9 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
if (le.getCause() instanceof CustomModLoadingErrorDisplayException)
|
if (le.getCause() instanceof CustomModLoadingErrorDisplayException)
|
||||||
{
|
{
|
||||||
CustomModLoadingErrorDisplayException custom = (CustomModLoadingErrorDisplayException) le.getCause();
|
CustomModLoadingErrorDisplayException custom = (CustomModLoadingErrorDisplayException) le.getCause();
|
||||||
FMLLog.log.error("A custom exception was thrown by a mod, the game will now halt", custom);
|
FMLLog.log.error("A custom exception was thrown by a mod, the game will display an error screen and halt.", custom);
|
||||||
customError = custom;
|
errorToDisplay = custom;
|
||||||
|
MinecraftForge.EVENT_BUS.shutdown();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -369,6 +347,7 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
// This call is being phased out for performance reasons in 1.12,
|
// 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.
|
// but we are keeping an option here in case something needs it for a little longer.
|
||||||
// See https://github.com/MinecraftForge/MinecraftForge/pull/4032
|
// See https://github.com/MinecraftForge/MinecraftForge/pull/4032
|
||||||
|
// TODO remove in 1.13
|
||||||
if (Boolean.parseBoolean(System.getProperty("fml.reloadResourcesOnStart", "false")))
|
if (Boolean.parseBoolean(System.getProperty("fml.reloadResourcesOnStart", "false")))
|
||||||
{
|
{
|
||||||
client.refreshResources();
|
client.refreshResources();
|
||||||
|
@ -401,7 +380,7 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
}
|
}
|
||||||
loading = false;
|
loading = false;
|
||||||
client.gameSettings.loadOptions(); //Reload options to load any mod added keybindings.
|
client.gameSettings.loadOptions(); //Reload options to load any mod added keybindings.
|
||||||
if (customError == null)
|
if (!hasError())
|
||||||
Loader.instance().loadingComplete();
|
Loader.instance().loadingComplete();
|
||||||
SplashProgress.finish();
|
SplashProgress.finish();
|
||||||
}
|
}
|
||||||
|
@ -439,29 +418,10 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
// re-sync TEXTURE_2D, splash screen disables it with a direct GL call
|
// re-sync TEXTURE_2D, splash screen disables it with a direct GL call
|
||||||
GlStateManager.disableTexture2D();
|
GlStateManager.disableTexture2D();
|
||||||
GlStateManager.enableTexture2D();
|
GlStateManager.enableTexture2D();
|
||||||
if (wrongMC != null)
|
if (errorToDisplay != null)
|
||||||
{
|
{
|
||||||
showGuiScreen(new GuiWrongMinecraft(wrongMC));
|
GuiScreen errorScreen = errorToDisplay.createGui();
|
||||||
}
|
showGuiScreen(errorScreen);
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -616,6 +576,10 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
return client.getIntegratedServer();
|
return client.getIntegratedServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO remove in 1.13
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public void displayMissingMods(Object modMissingPacket)
|
public void displayMissingMods(Object modMissingPacket)
|
||||||
{
|
{
|
||||||
// showGuiScreen(new GuiModsMissingForServer(modMissingPacket));
|
// showGuiScreen(new GuiModsMissingForServer(modMissingPacket));
|
||||||
|
@ -679,7 +643,8 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("An unexpected exception occurred constructing the custom resource pack for " + container.getName(), 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -698,14 +663,6 @@ public class FMLClientHandler implements IFMLSidedHandler
|
||||||
@Override
|
@Override
|
||||||
public void serverStopped()
|
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();
|
GameData.revertToFrozen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
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();
|
||||||
|
}
|
|
@ -23,8 +23,14 @@ import java.io.File;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import com.google.common.collect.SetMultimap;
|
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 {
|
public class DuplicateModsFoundException extends LoaderException implements IDisplayableError
|
||||||
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
public SetMultimap<ModContainer,File> dupes;
|
public SetMultimap<ModContainer,File> dupes;
|
||||||
|
|
||||||
|
@ -42,4 +48,11 @@ public class DuplicateModsFoundException extends LoaderException {
|
||||||
}
|
}
|
||||||
stream.println("");
|
stream.println("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public GuiScreen createGui()
|
||||||
|
{
|
||||||
|
return new GuiDupesFound(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.common.config.Config;
|
import net.minecraftforge.common.config.Config;
|
||||||
import net.minecraftforge.common.config.ConfigManager;
|
import net.minecraftforge.common.config.ConfigManager;
|
||||||
|
@ -73,6 +74,7 @@ import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.SetMultimap;
|
import com.google.common.collect.SetMultimap;
|
||||||
import com.google.common.eventbus.EventBus;
|
import com.google.common.eventbus.EventBus;
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import org.apache.logging.log4j.message.FormattedMessage;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@ -380,8 +382,7 @@ public class FMLModContainer implements ModContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@SuppressWarnings("unchecked")
|
private Method gatherAnnotations(Class<?> clazz)
|
||||||
private Method gatherAnnotations(Class<?> clazz) throws Exception
|
|
||||||
{
|
{
|
||||||
Method factoryMethod = null;
|
Method factoryMethod = null;
|
||||||
for (Method m : clazz.getDeclaredMethods())
|
for (Method m : clazz.getDeclaredMethods())
|
||||||
|
@ -393,7 +394,9 @@ public class FMLModContainer implements ModContainer
|
||||||
if (m.getParameterTypes().length == 1 && FMLEvent.class.isAssignableFrom(m.getParameterTypes()[0]))
|
if (m.getParameterTypes().length == 1 && FMLEvent.class.isAssignableFrom(m.getParameterTypes()[0]))
|
||||||
{
|
{
|
||||||
m.setAccessible(true);
|
m.setAccessible(true);
|
||||||
eventMethods.put((Class<? extends FMLEvent>)m.getParameterTypes()[0], m);
|
@SuppressWarnings("unchecked")
|
||||||
|
Class<? extends FMLEvent> parameterType = (Class<? extends FMLEvent>) m.getParameterTypes()[0];
|
||||||
|
eventMethods.put(parameterType, m);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -421,7 +424,7 @@ public class FMLModContainer implements ModContainer
|
||||||
return factoryMethod;
|
return factoryMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processFieldAnnotations(ASMDataTable asmDataTable) throws Exception
|
private void processFieldAnnotations(ASMDataTable asmDataTable) throws IllegalAccessException
|
||||||
{
|
{
|
||||||
SetMultimap<String, ASMData> annotations = asmDataTable.getAnnotationsFor(this);
|
SetMultimap<String, ASMData> annotations = asmDataTable.getAnnotationsFor(this);
|
||||||
|
|
||||||
|
@ -503,86 +506,110 @@ public class FMLModContainer implements ModContainer
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void constructMod(FMLConstructionEvent event)
|
public void constructMod(FMLConstructionEvent event)
|
||||||
{
|
{
|
||||||
|
BlamingTransformer.addClasses(getModId(), candidate.getClassList());
|
||||||
|
ModClassLoader modClassLoader = event.getModClassLoader();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
BlamingTransformer.addClasses(getModId(), candidate.getClassList());
|
|
||||||
ModClassLoader modClassLoader = event.getModClassLoader();
|
|
||||||
modClassLoader.addFile(source);
|
modClassLoader.addFile(source);
|
||||||
modClassLoader.clearNegativeCacheFor(candidate.getClassList());
|
}
|
||||||
|
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());
|
||||||
|
|
||||||
//Only place I could think to add this...
|
//Only place I could think to add this...
|
||||||
MinecraftForge.preloadCrashClasses(event.getASMHarvestedData(), getModId(), candidate.getClassList());
|
MinecraftForge.preloadCrashClasses(event.getASMHarvestedData(), getModId(), candidate.getClassList());
|
||||||
|
|
||||||
Class<?> clazz = Class.forName(className, true, modClassLoader);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
Certificate[] certificates = clazz.getProtectionDomain().getCodeSource().getCertificates();
|
Certificate[] certificates = clazz.getProtectionDomain().getCodeSource().getCertificates();
|
||||||
ImmutableList<String> certList = CertificateHelper.getFingerprints(certificates);
|
ImmutableList<String> certList = CertificateHelper.getFingerprints(certificates);
|
||||||
sourceFingerprints = ImmutableSet.copyOf(certList);
|
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 (expectedFingerprint != null && !expectedFingerprint.isEmpty())
|
||||||
|
{
|
||||||
|
if (!sourceFingerprints.contains(expectedFingerprint))
|
||||||
{
|
{
|
||||||
if (!sourceFingerprints.contains(expectedFingerprint))
|
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());
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
customModProperties = EMPTY_PROPERTIES;
|
certificate = certificates[certList.indexOf(expectedFingerprint)];
|
||||||
|
fingerprintNotPresent = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Boolean hasDisableableFlag = (Boolean)descriptor.get("canBeDeactivated");
|
@SuppressWarnings("unchecked")
|
||||||
boolean hasReverseDepends = !event.getReverseDependencies().get(getModId()).isEmpty();
|
List<Map<String, String>> props = (List<Map<String, String>>)descriptor.get("customProperties");
|
||||||
if (hasDisableableFlag != null && hasDisableableFlag)
|
if (props != null)
|
||||||
|
{
|
||||||
|
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
|
||||||
|
for (Map<String, String> p : props)
|
||||||
{
|
{
|
||||||
disableability = hasReverseDepends ? Disableable.DEPENDENCIES : Disableable.YES;
|
builder.put(p.get("k"), p.get("v"));
|
||||||
}
|
}
|
||||||
else
|
customModProperties = builder.build();
|
||||||
{
|
}
|
||||||
disableability = hasReverseDepends ? Disableable.DEPENDENCIES : Disableable.RESTART;
|
else
|
||||||
}
|
{
|
||||||
Method factoryMethod = gatherAnnotations(clazz);
|
customModProperties = EMPTY_PROPERTIES;
|
||||||
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());
|
processFieldAnnotations(event.getASMHarvestedData());
|
||||||
}
|
}
|
||||||
catch (Throwable e)
|
catch (IllegalAccessException e)
|
||||||
{
|
{
|
||||||
controller.errorOccurred(this, e);
|
FormattedMessage message = new FormattedMessage("{} Failed to process field annotations.", getModId());
|
||||||
|
throw new LoaderException(message.getFormattedMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,15 +20,14 @@
|
||||||
package net.minecraftforge.fml.common;
|
package net.minecraftforge.fml.common;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
|
||||||
import net.minecraftforge.common.util.TextTable;
|
import net.minecraftforge.common.util.TextTable;
|
||||||
import net.minecraftforge.fml.common.LoaderState.ModState;
|
import net.minecraftforge.fml.common.LoaderState.ModState;
|
||||||
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
|
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
|
||||||
|
@ -39,9 +38,10 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||||
import net.minecraftforge.fml.common.event.FMLStateEvent;
|
import net.minecraftforge.fml.common.event.FMLStateEvent;
|
||||||
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.ThreadContext;
|
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.ArrayListMultimap;
|
||||||
import com.google.common.collect.BiMap;
|
import com.google.common.collect.BiMap;
|
||||||
import com.google.common.collect.ImmutableBiMap;
|
import com.google.common.collect.ImmutableBiMap;
|
||||||
|
@ -53,9 +53,8 @@ import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.eventbus.EventBus;
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.common.eventbus.FMLThrowingEventBus;
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.google.common.eventbus.SubscriberExceptionHandler;
|
|
||||||
import com.google.common.eventbus.SubscriberExceptionContext;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@ -63,11 +62,9 @@ public class LoadController
|
||||||
{
|
{
|
||||||
private Loader loader;
|
private Loader loader;
|
||||||
private EventBus masterChannel;
|
private EventBus masterChannel;
|
||||||
private ImmutableMap<String,EventBus> eventChannels;
|
private ImmutableMap<String, EventBus> eventChannels;
|
||||||
private LoaderState state;
|
private LoaderState state;
|
||||||
private Multimap<String, ModState> modStates = ArrayListMultimap.create();
|
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 List<ModContainer> activeModList = Lists.newArrayList();
|
||||||
private ModContainer activeContainer;
|
private ModContainer activeContainer;
|
||||||
private BiMap<ModContainer, Object> modObjectList;
|
private BiMap<ModContainer, Object> modObjectList;
|
||||||
|
@ -76,13 +73,13 @@ public class LoadController
|
||||||
public LoadController(Loader loader)
|
public LoadController(Loader loader)
|
||||||
{
|
{
|
||||||
this.loader = loader;
|
this.loader = loader;
|
||||||
this.masterChannel = new EventBus(new SubscriberExceptionHandler()
|
this.masterChannel = new FMLThrowingEventBus((exception, context) -> {
|
||||||
{
|
Throwables.throwIfUnchecked(exception);
|
||||||
@Override
|
// should not happen, but add some extra context for checked exceptions
|
||||||
public void handleException(Throwable exception, SubscriberExceptionContext context)
|
Method method = context.getSubscriberMethod();
|
||||||
{
|
String parameterNames = Stream.of(method.getParameterTypes()).map(Class::getName).collect(Collectors.joining(", "));
|
||||||
FMLLog.log.error("Could not dispatch event: {} to {}", context.getSubscriberMethod(), exception);
|
String message = "Exception thrown during LoadController." + method.getName() + '(' + parameterNames + ')';
|
||||||
}
|
throw new LoaderExceptionModCrash(message, exception);
|
||||||
});
|
});
|
||||||
this.masterChannel.register(this);
|
this.masterChannel.register(this);
|
||||||
|
|
||||||
|
@ -97,14 +94,12 @@ public class LoadController
|
||||||
String modId = mod.getModId();
|
String modId = mod.getModId();
|
||||||
EventBus bus = temporary.remove(modId);
|
EventBus bus = temporary.remove(modId);
|
||||||
bus.post(new FMLModDisabledEvent());
|
bus.post(new FMLModDisabledEvent());
|
||||||
if (errors.get(modId).isEmpty())
|
eventChannels = ImmutableMap.copyOf(temporary);
|
||||||
{
|
modStates.put(modId, ModState.DISABLED);
|
||||||
eventChannels = ImmutableMap.copyOf(temporary);
|
modObjectList.remove(mod);
|
||||||
modStates.put(modId, ModState.DISABLED);
|
activeModList.remove(mod);
|
||||||
modObjectList.remove(mod);
|
|
||||||
activeModList.remove(mod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void buildModList(FMLLoadEvent event)
|
public void buildModList(FMLLoadEvent event)
|
||||||
{
|
{
|
||||||
|
@ -112,15 +107,7 @@ public class LoadController
|
||||||
|
|
||||||
for (final ModContainer mod : loader.getModList())
|
for (final ModContainer mod : loader.getModList())
|
||||||
{
|
{
|
||||||
//Create mod logger, and make the EventBus logger a child of it.
|
EventBus bus = new FMLThrowingEventBus((exception, context) -> this.errorOccurred(mod, exception));
|
||||||
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);
|
boolean isActive = mod.registerBus(bus, this);
|
||||||
if (isActive)
|
if (isActive)
|
||||||
|
@ -136,7 +123,6 @@ public class LoadController
|
||||||
modStates.put(mod.getModId(), ModState.UNLOADED);
|
modStates.put(mod.getModId(), ModState.UNLOADED);
|
||||||
modStates.put(mod.getModId(), ModState.DISABLED);
|
modStates.put(mod.getModId(), ModState.DISABLED);
|
||||||
}
|
}
|
||||||
modNames.put(mod.getModId(), mod.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eventChannels = eventBus.build();
|
eventChannels = eventBus.build();
|
||||||
|
@ -159,13 +145,13 @@ public class LoadController
|
||||||
}
|
}
|
||||||
|
|
||||||
LoaderState oldState = state;
|
LoaderState oldState = state;
|
||||||
state = state.transition(!errors.isEmpty());
|
state = state.transition(false);
|
||||||
if (state != desiredState)
|
if (state != desiredState)
|
||||||
{
|
{
|
||||||
if (!forceState)
|
if (!forceState)
|
||||||
{
|
{
|
||||||
FMLLog.log.fatal("Fatal errors were detected during the transition from {} to {}. Loading cannot continue", oldState, desiredState);
|
FormattedMessage message = new FormattedMessage("A fatal error occurred during the state transition from {} to {}. State became {} instead. Loading cannot continue.", oldState, desiredState, state);
|
||||||
throw throwStoredErrors();
|
throw new LoaderException(message.getFormattedMessage());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -178,60 +164,11 @@ public class LoadController
|
||||||
@Deprecated // TODO remove in 1.13
|
@Deprecated // TODO remove in 1.13
|
||||||
public void checkErrorsAfterAvailable()
|
public void checkErrorsAfterAvailable()
|
||||||
{
|
{
|
||||||
checkErrors();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated // TODO remove in 1.13
|
||||||
public void checkErrors()
|
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
|
@Nullable
|
||||||
|
@ -244,6 +181,7 @@ public class LoadController
|
||||||
{
|
{
|
||||||
activeContainer = container;
|
activeContainer = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void propogateStateMessage(FMLEvent stateEvent)
|
public void propogateStateMessage(FMLEvent stateEvent)
|
||||||
{
|
{
|
||||||
|
@ -263,10 +201,10 @@ public class LoadController
|
||||||
private void sendEventToModContainer(FMLEvent stateEvent, ModContainer mc)
|
private void sendEventToModContainer(FMLEvent stateEvent, ModContainer mc)
|
||||||
{
|
{
|
||||||
String modId = mc.getModId();
|
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())
|
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());
|
FMLLog.log.error("Skipping event {} and marking errored mod {} since required dependency {} has errored", stateEvent.getEventType(), modId, av.getLabel());
|
||||||
modStates.put(modId, ModState.ERRORED);
|
modStates.put(modId, ModState.ERRORED);
|
||||||
|
@ -283,14 +221,7 @@ public class LoadController
|
||||||
activeContainer = null;
|
activeContainer = null;
|
||||||
if (stateEvent instanceof FMLStateEvent)
|
if (stateEvent instanceof FMLStateEvent)
|
||||||
{
|
{
|
||||||
if (!errors.containsKey(modId))
|
modStates.put(modId, ((FMLStateEvent) stateEvent).getModState());
|
||||||
{
|
|
||||||
modStates.put(modId, ((FMLStateEvent)stateEvent).getModState());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
modStates.put(modId, ModState.ERRORED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +230,7 @@ public class LoadController
|
||||||
ImmutableBiMap.Builder<ModContainer, Object> builder = ImmutableBiMap.builder();
|
ImmutableBiMap.Builder<ModContainer, Object> builder = ImmutableBiMap.builder();
|
||||||
for (ModContainer mc : activeModList)
|
for (ModContainer mc : activeModList)
|
||||||
{
|
{
|
||||||
if (!mc.isImmutable() && mc.getMod()!=null)
|
if (!mc.isImmutable() && mc.getMod() != null)
|
||||||
{
|
{
|
||||||
builder.put(mc, mc.getMod());
|
builder.put(mc, mc.getMod());
|
||||||
List<String> packages = mc.getOwnedPackages();
|
List<String> packages = mc.getOwnedPackages();
|
||||||
|
@ -308,13 +239,10 @@ public class LoadController
|
||||||
packageOwners.put(pkg, mc);
|
packageOwners.put(pkg, mc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mc.getMod()==null && !mc.isImmutable() && state!=LoaderState.CONSTRUCTING)
|
if (mc.getMod() == null && !mc.isImmutable() && state != LoaderState.CONSTRUCTING)
|
||||||
{
|
{
|
||||||
FMLLog.log.fatal("There is a severe problem with {} - it appears not to have constructed correctly", mc.getModId());
|
FormattedMessage message = new FormattedMessage("There is a severe problem with {} ({}) - it appears not to have constructed correctly", mc.getName(), mc.getModId());
|
||||||
if (state != LoaderState.CONSTRUCTING)
|
this.errorOccurred(mc, new RuntimeException(message.getFormattedMessage()));
|
||||||
{
|
|
||||||
this.errorOccurred(mc, new RuntimeException());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
|
@ -322,14 +250,19 @@ public class LoadController
|
||||||
|
|
||||||
public void errorOccurred(ModContainer modContainer, Throwable exception)
|
public void errorOccurred(ModContainer modContainer, Throwable exception)
|
||||||
{
|
{
|
||||||
|
String modId = modContainer.getModId();
|
||||||
|
String modName = modContainer.getName();
|
||||||
|
modStates.put(modId, ModState.ERRORED);
|
||||||
if (exception instanceof InvocationTargetException)
|
if (exception instanceof InvocationTargetException)
|
||||||
{
|
{
|
||||||
errors.put(modContainer.getModId(), exception.getCause());
|
exception = exception.getCause();
|
||||||
}
|
}
|
||||||
else
|
if (exception instanceof LoaderException) // avoid wrapping loader exceptions multiple times
|
||||||
{
|
{
|
||||||
errors.put(modContainer.getModId(), exception);
|
throw (LoaderException) exception;
|
||||||
}
|
}
|
||||||
|
FormattedMessage message = new FormattedMessage("Caught exception from {} ({})", modName, modId);
|
||||||
|
throw new LoaderExceptionModCrash(message.getFormattedMessage(), exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void printModStates(StringBuilder ret)
|
public void printModStates(StringBuilder ret)
|
||||||
|
@ -374,15 +307,16 @@ public class LoadController
|
||||||
|
|
||||||
public void distributeStateMessage(Class<?> customEvent)
|
public void distributeStateMessage(Class<?> customEvent)
|
||||||
{
|
{
|
||||||
|
Object eventInstance;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
masterChannel.post(customEvent.newInstance());
|
eventInstance = customEvent.newInstance();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (InstantiationException | IllegalAccessException e)
|
||||||
{
|
{
|
||||||
FMLLog.log.error("An unexpected exception", e);
|
throw new LoaderException("Failed to create new event instance for " + customEvent.getName(), e);
|
||||||
throw new LoaderException(e);
|
|
||||||
}
|
}
|
||||||
|
masterChannel.post(eventInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BiMap<ModContainer, Object> getModObjectList()
|
public BiMap<ModContainer, Object> getModObjectList()
|
||||||
|
@ -400,8 +334,9 @@ public class LoadController
|
||||||
return this.state == state;
|
return this.state == state;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasReachedState(LoaderState state) {
|
boolean hasReachedState(LoaderState state)
|
||||||
return this.state.ordinal()>=state.ordinal() && this.state!=LoaderState.ERRORED;
|
{
|
||||||
|
return this.state.ordinal() >= state.ordinal() && this.state != LoaderState.ERRORED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void forceState(LoaderState newState)
|
void forceState(LoaderState newState)
|
||||||
|
@ -419,7 +354,7 @@ public class LoadController
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String pkg = c.getName().substring(0,idx);
|
String pkg = c.getName().substring(0, idx);
|
||||||
if (packageOwners.containsKey(pkg))
|
if (packageOwners.containsKey(pkg))
|
||||||
{
|
{
|
||||||
return packageOwners.get(pkg).get(0);
|
return packageOwners.get(pkg).get(0);
|
||||||
|
@ -428,6 +363,7 @@ public class LoadController
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FMLSecurityManager accessibleManager = new FMLSecurityManager();
|
private FMLSecurityManager accessibleManager = new FMLSecurityManager();
|
||||||
|
|
||||||
class FMLSecurityManager extends SecurityManager
|
class FMLSecurityManager extends SecurityManager
|
||||||
|
|
|
@ -547,9 +547,10 @@ public class Loader
|
||||||
ObjectHolderRegistry.INSTANCE.findObjectHolders(new ASMDataTable());
|
ObjectHolderRegistry.INSTANCE.findObjectHolders(new ASMDataTable());
|
||||||
modController.forceActiveContainer(containers[0]);
|
modController.forceActiveContainer(containers[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from the hook to start mod loading. We trigger the
|
* Called from the hook to start mod loading. We trigger the
|
||||||
* {@link #identifyMods()} and Constructing, Preinitalization, and Initalization phases here. Finally,
|
* {@link #identifyMods(List)} and Constructing, Preinitalization, and Initalization phases here. Finally,
|
||||||
* the mod list is frozen completely and is consider immutable from then on.
|
* the mod list is frozen completely and is consider immutable from then on.
|
||||||
* @param injectedModContainers containers to inject
|
* @param injectedModContainers containers to inject
|
||||||
*/
|
*/
|
||||||
|
@ -624,7 +625,6 @@ public class Loader
|
||||||
ItemStackHolderInjector.INSTANCE.findHolders(discoverer.getASMTable());
|
ItemStackHolderInjector.INSTANCE.findHolders(discoverer.getASMTable());
|
||||||
CapabilityManager.INSTANCE.injectCapabilities(discoverer.getASMTable());
|
CapabilityManager.INSTANCE.injectCapabilities(discoverer.getASMTable());
|
||||||
modController.distributeStateMessage(LoaderState.PREINITIALIZATION, discoverer.getASMTable(), canonicalConfigDir);
|
modController.distributeStateMessage(LoaderState.PREINITIALIZATION, discoverer.getASMTable(), canonicalConfigDir);
|
||||||
modController.checkErrors();
|
|
||||||
GameData.fireRegistryEvents(rl -> !rl.equals(GameData.RECIPES));
|
GameData.fireRegistryEvents(rl -> !rl.equals(GameData.RECIPES));
|
||||||
FMLCommonHandler.instance().fireSidedRegistryEvents();
|
FMLCommonHandler.instance().fireSidedRegistryEvents();
|
||||||
ObjectHolderRegistry.INSTANCE.applyObjectHolders();
|
ObjectHolderRegistry.INSTANCE.applyObjectHolders();
|
||||||
|
@ -750,7 +750,6 @@ public class Loader
|
||||||
progressBar.step("Finishing up");
|
progressBar.step("Finishing up");
|
||||||
modController.transition(LoaderState.AVAILABLE, false);
|
modController.transition(LoaderState.AVAILABLE, false);
|
||||||
modController.distributeStateMessage(LoaderState.AVAILABLE);
|
modController.distributeStateMessage(LoaderState.AVAILABLE);
|
||||||
modController.checkErrors();
|
|
||||||
GameData.freezeData();
|
GameData.freezeData();
|
||||||
FMLLog.log.info("Forge Mod Loader has successfully loaded {} mod{}", mods.size(), mods.size() == 1 ? "" : "s");
|
FMLLog.log.info("Forge Mod Loader has successfully loaded {} mod{}", mods.size(), mods.size() == 1 ? "" : "s");
|
||||||
progressBar.step("Completing Minecraft initialization");
|
progressBar.step("Completing Minecraft initialization");
|
||||||
|
|
|
@ -28,9 +28,15 @@ import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
|
||||||
|
|
||||||
public class MissingModsException extends EnhancedRuntimeException
|
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
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private final String id;
|
private final String id;
|
||||||
|
@ -101,6 +107,13 @@ public class MissingModsException extends EnhancedRuntimeException
|
||||||
stream.println("");
|
stream.println("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public GuiScreen createGui()
|
||||||
|
{
|
||||||
|
return new GuiModsMissing(this);
|
||||||
|
}
|
||||||
|
|
||||||
public static class MissingModInfo
|
public static class MissingModInfo
|
||||||
{
|
{
|
||||||
private final ArtifactVersion acceptedVersion;
|
private final ArtifactVersion acceptedVersion;
|
||||||
|
@ -132,4 +145,5 @@ public class MissingModsException extends EnhancedRuntimeException
|
||||||
return required;
|
return required;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,13 @@ package net.minecraftforge.fml.common;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MultipleModsErrored extends EnhancedRuntimeException
|
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 final List<WrongMinecraftVersionException> wrongMinecraftExceptions;
|
public final List<WrongMinecraftVersionException> wrongMinecraftExceptions;
|
||||||
public final List<MissingModsException> missingModsExceptions;
|
public final List<MissingModsException> missingModsExceptions;
|
||||||
|
@ -31,6 +37,13 @@ public class MultipleModsErrored extends EnhancedRuntimeException
|
||||||
this.missingModsExceptions = missingModsExceptions;
|
this.missingModsExceptions = missingModsExceptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public GuiScreen createGui()
|
||||||
|
{
|
||||||
|
return new GuiMultipleModsErrored(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void printStackTrace(WrappedPrintStream stream)
|
protected void printStackTrace(WrappedPrintStream stream)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,13 @@
|
||||||
|
|
||||||
package net.minecraftforge.fml.common;
|
package net.minecraftforge.fml.common;
|
||||||
|
|
||||||
public class WrongMinecraftVersionException extends EnhancedRuntimeException
|
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
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
public ModContainer mod;
|
public ModContainer mod;
|
||||||
|
@ -42,4 +48,10 @@ public class WrongMinecraftVersionException extends EnhancedRuntimeException
|
||||||
stream.println("");
|
stream.println("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public GuiScreen createGui()
|
||||||
|
{
|
||||||
|
return new GuiWrongMinecraft(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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 net.minecraftforge.fml.common.eventhandler;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.common.eventbus.SubscriberExceptionHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
public FMLThrowingEventBus(final SubscriberExceptionHandler exceptionHandler)
|
||||||
|
{
|
||||||
|
super((exception, context) -> {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
exceptionHandler.handleException(exception, context);
|
||||||
|
}
|
||||||
|
catch (final Throwable t)
|
||||||
|
{
|
||||||
|
// this is a hack to break out of the catch statement in EventBus.handleSubscriberException
|
||||||
|
throw new RuntimeException()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,10 +21,15 @@ package net.minecraftforge.fml.common.toposort;
|
||||||
|
|
||||||
import java.util.Set;
|
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.EnhancedRuntimeException;
|
||||||
import net.minecraftforge.fml.common.ModContainer;
|
import net.minecraftforge.fml.common.ModContainer;
|
||||||
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
|
|
||||||
public class ModSortingException extends EnhancedRuntimeException
|
public class ModSortingException extends EnhancedRuntimeException implements IDisplayableError
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ -76,4 +81,11 @@ public class ModSortingException extends EnhancedRuntimeException
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public GuiScreen createGui()
|
||||||
|
{
|
||||||
|
return new GuiSortingProblem(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue