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

This commit is contained in:
Lex Manos 2015-03-27 01:17:57 -07:00
parent b1f18107e6
commit 68c3a85fef
10 changed files with 147 additions and 15 deletions

View File

@ -14,6 +14,7 @@ package net.minecraftforge.fml.client;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraftforge.fml.common.EnhancedRuntimeException;
import net.minecraftforge.fml.common.IFMLHandledException;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@ -29,16 +30,16 @@ import net.minecraftforge.fml.relauncher.SideOnly;
*
*/
@SideOnly(Side.CLIENT)
public abstract class CustomModLoadingErrorDisplayException extends RuntimeException implements IFMLHandledException
public abstract class CustomModLoadingErrorDisplayException extends EnhancedRuntimeException implements IFMLHandledException
{
public CustomModLoadingErrorDisplayException() {
}
public CustomModLoadingErrorDisplayException(String message, Throwable cause)
{
super(message, cause);
}
private static final long serialVersionUID = 1L;
/**
@ -62,4 +63,6 @@ public abstract class CustomModLoadingErrorDisplayException extends RuntimeExcep
* @param tickTime tick time
*/
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 net.minecraftforge.fml.common;
import java.io.File;
import java.util.Map.Entry;
import net.minecraftforge.fml.common.EnhancedRuntimeException.WrappedPrintStream;
import com.google.common.collect.SetMultimap;
@ -24,4 +27,14 @@ public class DuplicateModsFoundException extends LoaderException {
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 net.minecraftforge.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

@ -97,7 +97,7 @@ public interface ILanguageAdapter {
// 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());
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
@ -142,7 +142,7 @@ public interface ILanguageAdapter {
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());
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);

View File

@ -183,7 +183,7 @@ public class Loader
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);
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);
@ -419,7 +419,7 @@ public class Loader
if (!dirMade)
{
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");
}
@ -677,7 +677,7 @@ public class Loader
if (parseFailure)
{
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
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
*
* Contributors:
* cpw - implementation
*/
package net.minecraftforge.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(String message)
{
super(message);
}
@Override protected void printStackTrace(WrappedPrintStream stream){}
}

View File

@ -14,9 +14,10 @@ package net.minecraftforge.fml.common;
import java.util.Set;
import net.minecraftforge.fml.common.EnhancedRuntimeException.WrappedPrintStream;
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
public class MissingModsException extends RuntimeException
public class MissingModsException extends EnhancedRuntimeException
{
private static final long serialVersionUID = 1L;
public final Set<ArtifactVersion> missingMods;
@ -26,4 +27,15 @@ public class MissingModsException extends RuntimeException
super(String.format("Mod %s (%s) requires %s", id, name, 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

@ -46,7 +46,7 @@ public class ProxyInjector
{
// Impossible?
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);
@ -62,12 +62,12 @@ public class ProxyInjector
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());
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()))
{
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);
}

View File

@ -80,6 +80,11 @@ public class EntitySpawnHandler extends SimpleChannelInboundHandler<FMLMessage.E
{
ModContainer mc = Loader.instance().getIndexedModList().get(spawnMsg.modId);
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();
Class<? extends Entity> cls = er.getEntityClass();
try
@ -138,7 +143,7 @@ public class EntitySpawnHandler extends SimpleChannelInboundHandler<FMLMessage.E
wc.addEntityToWorld(spawnMsg.entityId, entity);
} 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);
}
}

View File

@ -3,6 +3,7 @@ package net.minecraftforge.fml.common.registry;
public class IncompatibleSubstitutionException extends RuntimeException {
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;