Enhance output of common FML errors in crash reports and server GUI.

This commit is contained in:
Lex Manos 2015-03-27 01:40:23 -07:00
parent c2f11ecc35
commit ddcc6a1aa4
10 changed files with 146 additions and 15 deletions

View File

@ -14,6 +14,7 @@ package cpw.mods.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 cpw.mods.fml.common.EnhancedRuntimeException;
import cpw.mods.fml.common.IFMLHandledException; import cpw.mods.fml.common.IFMLHandledException;
import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly; import cpw.mods.fml.relauncher.SideOnly;
@ -29,16 +30,16 @@ import cpw.mods.fml.relauncher.SideOnly;
* *
*/ */
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
public abstract class CustomModLoadingErrorDisplayException extends RuntimeException implements IFMLHandledException public abstract class CustomModLoadingErrorDisplayException extends EnhancedRuntimeException implements IFMLHandledException
{ {
public CustomModLoadingErrorDisplayException() { public CustomModLoadingErrorDisplayException() {
} }
public CustomModLoadingErrorDisplayException(String message, Throwable cause) public CustomModLoadingErrorDisplayException(String message, Throwable cause)
{ {
super(message, cause); super(message, cause);
} }
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
@ -62,4 +63,6 @@ public abstract class CustomModLoadingErrorDisplayException extends RuntimeExcep
* @param tickTime tick time * @param tickTime tick time
*/ */
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.
} }

View File

@ -13,6 +13,9 @@
package cpw.mods.fml.common; package cpw.mods.fml.common;
import java.io.File; import java.io.File;
import java.util.Map.Entry;
import cpw.mods.fml.common.EnhancedRuntimeException.WrappedPrintStream;
import com.google.common.collect.SetMultimap; import com.google.common.collect.SetMultimap;
@ -24,4 +27,14 @@ public class DuplicateModsFoundException extends LoaderException {
this.dupes = dupes; this.dupes = dupes;
} }
@Override
protected void printStackTrace(WrappedPrintStream stream)
{
stream.println("Duplicate Mods:");
for (Entry<ModContainer, File> e : dupes.entries())
{
stream.println(String.format("\t%s : %s", e.getKey().getModId(), e.getValue().getAbsolutePath()));
}
stream.println("");
}
} }

View File

@ -0,0 +1,92 @@
/*
* Forge Mod Loader
* Copyright (c) 2012-2016 Forge Dev LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/
package cpw.mods.fml.common;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* RuntimeException that gives subclasses the simple opportunity to write extra data when printing the stack trace.
* Mainly a helper class as printsStackTrace has multiple signatures.
*/
public abstract class EnhancedRuntimeException extends RuntimeException
{
private static final long serialVersionUID = 1L;
public EnhancedRuntimeException() { super(); }
public EnhancedRuntimeException(String message) { super(message); }
public EnhancedRuntimeException(String message, Throwable cause) { super(message, cause); }
public EnhancedRuntimeException(Throwable cause) { super(cause); }
protected EnhancedRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
@Override
public String getMessage()
{
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
if (stack.length > 2 && stack[2].getClassName().startsWith("org.apache.logging.log4j."))
{
// This is a bit of a hack to force ourselves to be able to give a extended description when log4j prints this out.
// Sadly this text is displayed AFTER the initial exception line, and before the stack trace. But as the intention
// is to print this to the end user this is what we need to do.
final StringWriter buf = new StringWriter();
String msg = super.getMessage();
if (msg != null)
buf.append(msg);
buf.append('\n');
this.printStackTrace(new WrappedPrintStream()
{
@Override
void println(String line)
{
buf.append(line).append('\n');
}
});
return buf.toString();
}
return super.getMessage();
}
@Override
public void printStackTrace(final PrintWriter s)
{
printStackTrace(new WrappedPrintStream()
{
@Override
void println(String line)
{
s.println(line);
}
});
super.printStackTrace(s);
}
public void printStackTrace(final PrintStream s)
{
printStackTrace(new WrappedPrintStream()
{
@Override
void println(String line)
{
s.println(line);
}
});
super.printStackTrace(s);
}
protected abstract void printStackTrace(WrappedPrintStream stream);
public static abstract class WrappedPrintStream
{
abstract void println(String line);
}
}

View File

@ -96,7 +96,7 @@ public interface ILanguageAdapter {
// If we come here we could not find a setter for this proxy. // If we come here we could not find a setter for this proxy.
FMLLog.severe("Failed loading proxy into %s.%s, could not find setter function. Did you declare the field with 'val' instead of 'var'?", proxyTarget.getSimpleName(), target.getName()); FMLLog.severe("Failed loading proxy into %s.%s, could not find setter function. Did you declare the field with 'val' instead of 'var'?", proxyTarget.getSimpleName(), target.getName());
throw new LoaderException(); throw new LoaderException(String.format("Failed loading proxy into %s.%s, could not find setter function. Did you declare the field with 'val' instead of 'var'?", proxyTarget.getSimpleName(), target.getName()));
} }
@Override @Override
@ -141,7 +141,7 @@ public interface ILanguageAdapter {
if (!target.getType().isAssignableFrom(proxy.getClass())) if (!target.getType().isAssignableFrom(proxy.getClass()))
{ {
FMLLog.severe("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, proxyTarget.getSimpleName(), target.getName()); FMLLog.severe("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, proxyTarget.getSimpleName(), target.getName());
throw new LoaderException(); throw new LoaderException(String.format("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, proxyTarget.getSimpleName(), target.getName()));
} }
setProxy(target, proxyTarget, proxy); setProxy(target, proxyTarget, proxy);

View File

@ -182,7 +182,7 @@ public class Loader
if (!mccversion.equals(MC_VERSION)) if (!mccversion.equals(MC_VERSION))
{ {
FMLLog.severe("This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file", mccversion, MC_VERSION); FMLLog.severe("This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file", mccversion, MC_VERSION);
throw new LoaderException(); throw new LoaderException(String.format("This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file", mccversion, MC_VERSION));
} }
minecraft = new MinecraftDummyContainer(MC_VERSION); minecraft = new MinecraftDummyContainer(MC_VERSION);
@ -418,7 +418,7 @@ public class Loader
if (!dirMade) if (!dirMade)
{ {
FMLLog.severe("Unable to create the mod directory %s", canonicalModsPath); FMLLog.severe("Unable to create the mod directory %s", canonicalModsPath);
throw new LoaderException(); throw new LoaderException(String.format("Unable to create the mod directory %s", canonicalModsPath));
} }
FMLLog.info("Mod directory created successfully"); FMLLog.info("Mod directory created successfully");
} }
@ -676,7 +676,7 @@ public class Loader
if (parseFailure) if (parseFailure)
{ {
FMLLog.log(Level.WARN, "Unable to parse dependency string %s", dependencyString); FMLLog.log(Level.WARN, "Unable to parse dependency string %s", dependencyString);
throw new LoaderException(); throw new LoaderException(String.format("Unable to parse dependency string %s", dependencyString));
} }
} }

View File

@ -5,14 +5,14 @@
* are made available under the terms of the GNU Lesser Public License v2.1 * are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* *
* Contributors: * Contributors:
* cpw - implementation * cpw - implementation
*/ */
package cpw.mods.fml.common; package cpw.mods.fml.common;
public class LoaderException extends RuntimeException public class LoaderException extends EnhancedRuntimeException
{ {
/** /**
* *
@ -27,4 +27,10 @@ public class LoaderException extends RuntimeException
public LoaderException() public LoaderException()
{ {
} }
public LoaderException(String message)
{
super(message);
}
@Override protected void printStackTrace(WrappedPrintStream stream){}
} }

View File

@ -16,7 +16,7 @@ import java.util.Set;
import cpw.mods.fml.common.versioning.ArtifactVersion; import cpw.mods.fml.common.versioning.ArtifactVersion;
public class MissingModsException extends RuntimeException public class MissingModsException extends EnhancedRuntimeException
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public final Set<ArtifactVersion> missingMods; public final Set<ArtifactVersion> missingMods;
@ -25,4 +25,15 @@ public class MissingModsException extends RuntimeException
{ {
this.missingMods = missingMods; this.missingMods = missingMods;
} }
@Override
protected void printStackTrace(WrappedPrintStream stream)
{
stream.println("Missing Mods:");
for (ArtifactVersion v : missingMods)
{
stream.println(String.format("\t%s : %s", v.getLabel(), v.getRangeString()));
}
stream.println("");
}
} }

View File

@ -45,7 +45,7 @@ public class ProxyInjector
{ {
// Impossible? // Impossible?
FMLLog.severe("Attempted to load a proxy type into %s.%s but the field was not found", targ.getClassName(), targ.getObjectName()); FMLLog.severe("Attempted to load a proxy type into %s.%s but the field was not found", targ.getClassName(), targ.getObjectName());
throw new LoaderException(); throw new LoaderException(String.format("Attempted to load a proxy type into %s.%s but the field was not found", targ.getClassName(), targ.getObjectName()));
} }
target.setAccessible(true); target.setAccessible(true);
@ -61,12 +61,12 @@ public class ProxyInjector
if (languageAdapter.supportsStatics() && (target.getModifiers() & Modifier.STATIC) == 0 ) if (languageAdapter.supportsStatics() && (target.getModifiers() & Modifier.STATIC) == 0 )
{ {
FMLLog.severe("Attempted to load a proxy type %s into %s.%s, but the field is not static", targetType, targ.getClassName(), targ.getObjectName()); FMLLog.severe("Attempted to load a proxy type %s into %s.%s, but the field is not static", targetType, targ.getClassName(), targ.getObjectName());
throw new LoaderException(); throw new LoaderException(String.format("Attempted to load a proxy type %s into %s.%s, but the field is not static", targetType, targ.getClassName(), targ.getObjectName()));
} }
if (!target.getType().isAssignableFrom(proxy.getClass())) if (!target.getType().isAssignableFrom(proxy.getClass()))
{ {
FMLLog.severe("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, targ.getClassName(), targ.getObjectName()); FMLLog.severe("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, targ.getClassName(), targ.getObjectName());
throw new LoaderException(); throw new LoaderException(String.format("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, targ.getClassName(), targ.getObjectName()));
} }
languageAdapter.setProxy(target, proxyTarget, proxy); languageAdapter.setProxy(target, proxyTarget, proxy);
} }

View File

@ -59,6 +59,11 @@ public class EntitySpawnHandler extends SimpleChannelInboundHandler<FMLMessage.E
{ {
ModContainer mc = Loader.instance().getIndexedModList().get(spawnMsg.modId); ModContainer mc = Loader.instance().getIndexedModList().get(spawnMsg.modId);
EntityRegistration er = EntityRegistry.instance().lookupModSpawn(mc, spawnMsg.modEntityTypeId); EntityRegistration er = EntityRegistry.instance().lookupModSpawn(mc, spawnMsg.modEntityTypeId);
if (er == null)
{
throw new RuntimeException( "Could not spawn mod entity ModID: " + spawnMsg.modId + " EntityID: " + spawnMsg.modEntityTypeId +
" at ( " + spawnMsg.scaledX + "," + spawnMsg.scaledY + ", " + spawnMsg.scaledZ + ") Please contact mod author or server admin.");
}
WorldClient wc = FMLClientHandler.instance().getWorldClient(); WorldClient wc = FMLClientHandler.instance().getWorldClient();
Class<? extends Entity> cls = er.getEntityClass(); Class<? extends Entity> cls = er.getEntityClass();
try try
@ -117,7 +122,7 @@ public class EntitySpawnHandler extends SimpleChannelInboundHandler<FMLMessage.E
wc.addEntityToWorld(spawnMsg.entityId, entity); wc.addEntityToWorld(spawnMsg.entityId, entity);
} catch (Exception e) } catch (Exception e)
{ {
FMLLog.log(Level.ERROR, e, "A severe problem occurred during the spawning of an entity"); FMLLog.log(Level.ERROR, e, "A severe problem occurred during the spawning of an entity at ( " + spawnMsg.scaledX + "," + spawnMsg.scaledY + ", " + spawnMsg.scaledZ +")");
throw Throwables.propagate(e); throw Throwables.propagate(e);
} }
} }

View File

@ -3,6 +3,7 @@ package cpw.mods.fml.common.registry;
public class IncompatibleSubstitutionException extends RuntimeException { public class IncompatibleSubstitutionException extends RuntimeException {
public IncompatibleSubstitutionException(String fromName, Object replacement, Object original) public IncompatibleSubstitutionException(String fromName, Object replacement, Object original)
{ {
super(String.format("The substitute %s for %s (type %s) is type incompatible.", replacement.getClass().getName(), fromName, original.getClass().getName()));
} }
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;