    001    package net.minecraft.src;
    002
    003    import cpw.mods.fml.common.FMLCommonHandler;
    004    import cpw.mods.fml.common.Side;
    005    import cpw.mods.fml.common.asm.SideOnly;
    006    import java.io.File;
    007    import java.io.FileWriter;
    008    import java.io.IOException;
    009    import java.io.PrintWriter;
    010    import java.io.StringWriter;
    011    import java.text.SimpleDateFormat;
    012    import java.util.ArrayList;
    013    import java.util.Date;
    014    import java.util.Iterator;
    015    import java.util.List;
    016    import java.util.logging.Level;
    017    import java.util.logging.Logger;
    018
    019    public class CrashReport
    020    {
    021        /** Description of the crash report. */
    022        private final String description;
    023
    024        /** The Throwable that is the "cause" for this crash and Crash Report. */
    025        private final Throwable cause;
    026        private final CrashReportCategory field_85061_c = new CrashReportCategory(this, "System Details");
    027
    028        /** Holds the keys and values of all crash report sections. */
    029        private final List crashReportSections = new ArrayList();
    030
    031        /** File of crash report. */
    032        private File crashReportFile = null;
    033        private boolean field_85059_f = true;
    034        private StackTraceElement[] field_85060_g = new StackTraceElement[0];
    035
    036        public CrashReport(String par1Str, Throwable par2Throwable)
    037        {
    038            this.description = par1Str;
    039            this.cause = par2Throwable;
    040            this.func_71504_g();
    041        }
    042
    043        private void func_71504_g()
    044        {
    045            this.field_85061_c.addCrashSectionCallable("Minecraft Version", new CallableMinecraftVersion(this));
    046            this.field_85061_c.addCrashSectionCallable("Operating System", new CallableOSInfo(this));
    047            this.field_85061_c.addCrashSectionCallable("Java Version", new CallableJavaInfo(this));
    048            this.field_85061_c.addCrashSectionCallable("Java VM Version", new CallableJavaInfo2(this));
    049            this.field_85061_c.addCrashSectionCallable("Memory", new CallableMemoryInfo(this));
    050            this.field_85061_c.addCrashSectionCallable("JVM Flags", new CallableJVMFlags(this));
    051            this.field_85061_c.addCrashSectionCallable("AABB Pool Size", new CallableCrashMemoryReport(this));
    052            this.field_85061_c.addCrashSectionCallable("Suspicious classes", new CallableSuspiciousClasses(this));
    053            this.field_85061_c.addCrashSectionCallable("IntCache", new CallableIntCache(this));
    054            FMLCommonHandler.instance().enhanceCrashReport(this, this.field_85061_c);
    055        }
    056
    057        /**
    058         * Returns the description of the Crash Report.
    059         */
    060        public String getDescription()
    061        {
    062            return this.description;
    063        }
    064
    065        /**
    066         * Returns the Throwable object that is the cause for the crash and Crash Report.
    067         */
    068        public Throwable getCrashCause()
    069        {
    070            return this.cause;
    071        }
    072
    073        /**
    074         * Gets the various sections of the crash report into the given StringBuilder
    075         */
    076        public void getSectionsInStringBuilder(StringBuilder par1StringBuilder)
    077        {
    078            if (this.field_85060_g != null && this.field_85060_g.length > 0)
    079            {
    080                par1StringBuilder.append("-- Head --\n");
    081                par1StringBuilder.append("Stacktrace:\n");
    082                StackTraceElement[] var2 = this.field_85060_g;
    083                int var3 = var2.length;
    084
    085                for (int var4 = 0; var4 < var3; ++var4)
    086                {
    087                    StackTraceElement var5 = var2[var4];
    088                    par1StringBuilder.append("\t").append("at ").append(var5.toString());
    089                    par1StringBuilder.append("\n");
    090                }
    091
    092                par1StringBuilder.append("\n");
    093            }
    094
    095            Iterator var6 = this.crashReportSections.iterator();
    096
    097            while (var6.hasNext())
    098            {
    099                CrashReportCategory var7 = (CrashReportCategory)var6.next();
    100                var7.func_85072_a(par1StringBuilder);
    101                par1StringBuilder.append("\n\n");
    102            }
    103
    104            this.field_85061_c.func_85072_a(par1StringBuilder);
    105        }
    106
    107        /**
    108         * Gets the stack trace of the Throwable that caused this crash report, or if that fails, the cause .toString().
    109         */
    110        public String getCauseStackTraceOrString()
    111        {
    112            StringWriter var1 = null;
    113            PrintWriter var2 = null;
    114            String var3 = this.cause.toString();
    115
    116            try
    117            {
    118                var1 = new StringWriter();
    119                var2 = new PrintWriter(var1);
    120                this.cause.printStackTrace(var2);
    121                var3 = var1.toString();
    122            }
    123            finally
    124            {
    125                try
    126                {
    127                    if (var1 != null)
    128                    {
    129                        var1.close();
    130                    }
    131
    132                    if (var2 != null)
    133                    {
    134                        var2.close();
    135                    }
    136                }
    137                catch (IOException var10)
    138                {
    139                    ;
    140                }
    141            }
    142
    143            return var3;
    144        }
    145
    146        /**
    147         * Gets the complete report with headers, stack trace, and different sections as a string.
    148         */
    149        public String getCompleteReport()
    150        {
    151            StringBuilder var1 = new StringBuilder();
    152            var1.append("---- Minecraft Crash Report ----\n");
    153            var1.append("// ");
    154            var1.append(getWittyComment());
    155            var1.append("\n\n");
    156            var1.append("Time: ");
    157            var1.append((new SimpleDateFormat()).format(new Date()));
    158            var1.append("\n");
    159            var1.append("Description: ");
    160            var1.append(this.description);
    161            var1.append("\n\n");
    162            var1.append(this.getCauseStackTraceOrString());
    163            var1.append("\n\nA detailed walkthrough of the error, its code path and all known details is as follows:\n");
    164
    165            for (int var2 = 0; var2 < 87; ++var2)
    166            {
    167                var1.append("-");
    168            }
    169
    170            var1.append("\n\n");
    171            this.getSectionsInStringBuilder(var1);
    172            return var1.toString();
    173        }
    174
    175        @SideOnly(Side.CLIENT)
    176
    177        /**
    178         * Gets the file this crash report is saved into.
    179         */
    180        public File getFile()
    181        {
    182            return this.crashReportFile;
    183        }
    184
    185        /**
    186         * Saves the complete crash report to the given File.
    187         */
    188        public boolean saveToFile(File par1File)
    189        {
    190            if (this.crashReportFile != null)
    191            {
    192                return false;
    193            }
    194            else
    195            {
    196                if (par1File.getParentFile() != null)
    197                {
    198                    par1File.getParentFile().mkdirs();
    199                }
    200
    201                try
    202                {
    203                    FileWriter var2 = new FileWriter(par1File);
    204                    var2.write(this.getCompleteReport());
    205                    var2.close();
    206                    this.crashReportFile = par1File;
    207                    return true;
    208                }
    209                catch (Throwable var3)
    210                {
    211                    Logger.getLogger("Minecraft").log(Level.SEVERE, "Could not save crash report to " + par1File, var3);
    212                    return false;
    213                }
    214            }
    215        }
    216
    217        public CrashReportCategory func_85056_g()
    218        {
    219            return this.field_85061_c;
    220        }
    221
    222        public CrashReportCategory func_85058_a(String par1Str)
    223        {
    224            return this.func_85057_a(par1Str, 1);
    225        }
    226
    227        public CrashReportCategory func_85057_a(String par1Str, int par2)
    228        {
    229            CrashReportCategory var3 = new CrashReportCategory(this, par1Str);
    230
    231            if (this.field_85059_f)
    232            {
    233                int var4 = var3.func_85073_a(par2);
    234                StackTraceElement[] var5 = this.cause.getStackTrace();
    235                StackTraceElement var6 = null;
    236                StackTraceElement var7 = null;
    237
    238                if (var5 != null && var5.length - var4 < var5.length)
    239                {
    240                    var6 = var5[var5.length - var4];
    241
    242                    if (var5.length + 1 - var4 < var5.length)
    243                    {
    244                        var7 = var5[var5.length + 1 - var4];
    245                    }
    246                }
    247
    248                this.field_85059_f = var3.func_85069_a(var6, var7);
    249
    250                if (var4 > 0 && !this.crashReportSections.isEmpty())
    251                {
    252                    CrashReportCategory var8 = (CrashReportCategory)this.crashReportSections.get(this.crashReportSections.size() - 1);
    253                    var8.func_85070_b(var4);
    254                }
    255                else if (var5 != null && var5.length >= var4)
    256                {
    257                    this.field_85060_g = new StackTraceElement[var5.length - var4];
    258                    System.arraycopy(var5, 0, this.field_85060_g, 0, this.field_85060_g.length);
    259                }
    260                else
    261                {
    262                    this.field_85059_f = false;
    263                }
    264            }
    265
    266            this.crashReportSections.add(var3);
    267            return var3;
    268        }
    269
    270        /**
    271         * Gets a random witty comment for inclusion in this CrashReport
    272         */
    273        private static String getWittyComment()
    274        {
    275            String[] var0 = new String[] {"Who set us up the TNT?", "Everything\'s going to plan. No, really, that was supposed to happen.", "Uh... Did I do that?", "Oops.", "Why did you do that?", "I feel sad now :(", "My bad.", "I\'m sorry, Dave.", "I let you down. Sorry :(", "On the bright side, I bought you a teddy bear!", "Daisy, daisy...", "Oh - I know what I did wrong!", "Hey, that tickles! Hehehe!", "I blame Dinnerbone.", "You should try our sister game, Minceraft!", "Don\'t be sad. I\'ll do better next time, I promise!", "Don\'t be sad, have a hug! <3", "I just don\'t know what went wrong :(", "Shall we play a game?", "Quite honestly, I wouldn\'t worry myself about that.", "I bet Cylons wouldn\'t have this problem.", "Sorry :(", "Surprise! Haha. Well, this is awkward.", "Would you like a cupcake?", "Hi. I\'m Minecraft, and I\'m a crashaholic.", "Ooh. Shiny.", "This doesn\'t make any sense!", "Why is it breaking :(", "Don\'t do that.", "Ouch. That hurt :(", "You\'re mean.", "This is a token for 1 free hug. Redeem at your nearest Mojangsta: [~~HUG~~]", "There are four lights!"};
    276
    277            try
    278            {
    279                return var0[(int)(System.nanoTime() % (long)var0.length)];
    280            }
    281            catch (Throwable var2)
    282            {
    283                return "Witty comment unavailable :(";
    284            }
    285        }
    286
    287        public static CrashReport func_85055_a(Throwable par0Throwable, String par1Str)
    288        {
    289            CrashReport var2;
    290
    291            if (par0Throwable instanceof ReportedException)
    292            {
    293                var2 = ((ReportedException)par0Throwable).getTheReportedExceptionCrashReport();
    294            }
    295            else
    296            {
    297                var2 = new CrashReport(par1Str, par0Throwable);
    298            }
    299
    300            return var2;
    301        }
    302    }