    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        @SideOnly(Side.CLIENT)
    074        public String func_90021_c()
    075        {
    076            StringBuilder var1 = new StringBuilder();
    077            this.getSectionsInStringBuilder(var1);
    078            return var1.toString();
    079        }
    080
    081        /**
    082         * Gets the various sections of the crash report into the given StringBuilder
    083         */
    084        public void getSectionsInStringBuilder(StringBuilder par1StringBuilder)
    085        {
    086            if (this.field_85060_g != null && this.field_85060_g.length > 0)
    087            {
    088                par1StringBuilder.append("-- Head --\n");
    089                par1StringBuilder.append("Stacktrace:\n");
    090                StackTraceElement[] var2 = this.field_85060_g;
    091                int var3 = var2.length;
    092
    093                for (int var4 = 0; var4 < var3; ++var4)
    094                {
    095                    StackTraceElement var5 = var2[var4];
    096                    par1StringBuilder.append("\t").append("at ").append(var5.toString());
    097                    par1StringBuilder.append("\n");
    098                }
    099
    100                par1StringBuilder.append("\n");
    101            }
    102
    103            Iterator var6 = this.crashReportSections.iterator();
    104
    105            while (var6.hasNext())
    106            {
    107                CrashReportCategory var7 = (CrashReportCategory)var6.next();
    108                var7.func_85072_a(par1StringBuilder);
    109                par1StringBuilder.append("\n\n");
    110            }
    111
    112            this.field_85061_c.func_85072_a(par1StringBuilder);
    113        }
    114
    115        /**
    116         * Gets the stack trace of the Throwable that caused this crash report, or if that fails, the cause .toString().
    117         */
    118        public String getCauseStackTraceOrString()
    119        {
    120            StringWriter var1 = null;
    121            PrintWriter var2 = null;
    122            String var3 = this.cause.toString();
    123
    124            try
    125            {
    126                var1 = new StringWriter();
    127                var2 = new PrintWriter(var1);
    128                this.cause.printStackTrace(var2);
    129                var3 = var1.toString();
    130            }
    131            finally
    132            {
    133                try
    134                {
    135                    if (var1 != null)
    136                    {
    137                        var1.close();
    138                    }
    139
    140                    if (var2 != null)
    141                    {
    142                        var2.close();
    143                    }
    144                }
    145                catch (IOException var10)
    146                {
    147                    ;
    148                }
    149            }
    150
    151            return var3;
    152        }
    153
    154        /**
    155         * Gets the complete report with headers, stack trace, and different sections as a string.
    156         */
    157        public String getCompleteReport()
    158        {
    159            StringBuilder var1 = new StringBuilder();
    160            var1.append("---- Minecraft Crash Report ----\n");
    161            var1.append("// ");
    162            var1.append(getWittyComment());
    163            var1.append("\n\n");
    164            var1.append("Time: ");
    165            var1.append((new SimpleDateFormat()).format(new Date()));
    166            var1.append("\n");
    167            var1.append("Description: ");
    168            var1.append(this.description);
    169            var1.append("\n\n");
    170            var1.append(this.getCauseStackTraceOrString());
    171            var1.append("\n\nA detailed walkthrough of the error, its code path and all known details is as follows:\n");
    172
    173            for (int var2 = 0; var2 < 87; ++var2)
    174            {
    175                var1.append("-");
    176            }
    177
    178            var1.append("\n\n");
    179            this.getSectionsInStringBuilder(var1);
    180            return var1.toString();
    181        }
    182
    183        @SideOnly(Side.CLIENT)
    184
    185        /**
    186         * Gets the file this crash report is saved into.
    187         */
    188        public File getFile()
    189        {
    190            return this.crashReportFile;
    191        }
    192
    193        /**
    194         * Saves the complete crash report to the given File.
    195         */
    196        public boolean saveToFile(File par1File)
    197        {
    198            if (this.crashReportFile != null)
    199            {
    200                return false;
    201            }
    202            else
    203            {
    204                if (par1File.getParentFile() != null)
    205                {
    206                    par1File.getParentFile().mkdirs();
    207                }
    208
    209                try
    210                {
    211                    FileWriter var2 = new FileWriter(par1File);
    212                    var2.write(this.getCompleteReport());
    213                    var2.close();
    214                    this.crashReportFile = par1File;
    215                    return true;
    216                }
    217                catch (Throwable var3)
    218                {
    219                    Logger.getLogger("Minecraft").log(Level.SEVERE, "Could not save crash report to " + par1File, var3);
    220                    return false;
    221                }
    222            }
    223        }
    224
    225        public CrashReportCategory func_85056_g()
    226        {
    227            return this.field_85061_c;
    228        }
    229
    230        public CrashReportCategory func_85058_a(String par1Str)
    231        {
    232            return this.func_85057_a(par1Str, 1);
    233        }
    234
    235        public CrashReportCategory func_85057_a(String par1Str, int par2)
    236        {
    237            CrashReportCategory var3 = new CrashReportCategory(this, par1Str);
    238
    239            if (this.field_85059_f)
    240            {
    241                int var4 = var3.func_85073_a(par2);
    242                StackTraceElement[] var5 = this.cause.getStackTrace();
    243                StackTraceElement var6 = null;
    244                StackTraceElement var7 = null;
    245
    246                if (var5 != null && var5.length - var4 < var5.length)
    247                {
    248                    var6 = var5[var5.length - var4];
    249
    250                    if (var5.length + 1 - var4 < var5.length)
    251                    {
    252                        var7 = var5[var5.length + 1 - var4];
    253                    }
    254                }
    255
    256                this.field_85059_f = var3.func_85069_a(var6, var7);
    257
    258                if (var4 > 0 && !this.crashReportSections.isEmpty())
    259                {
    260                    CrashReportCategory var8 = (CrashReportCategory)this.crashReportSections.get(this.crashReportSections.size() - 1);
    261                    var8.func_85070_b(var4);
    262                }
    263                else if (var5 != null && var5.length >= var4)
    264                {
    265                    this.field_85060_g = new StackTraceElement[var5.length - var4];
    266                    System.arraycopy(var5, 0, this.field_85060_g, 0, this.field_85060_g.length);
    267                }
    268                else
    269                {
    270                    this.field_85059_f = false;
    271                }
    272            }
    273
    274            this.crashReportSections.add(var3);
    275            return var3;
    276        }
    277
    278        /**
    279         * Gets a random witty comment for inclusion in this CrashReport
    280         */
    281        private static String getWittyComment()
    282        {
    283            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!"};
    284
    285            try
    286            {
    287                return var0[(int)(System.nanoTime() % (long)var0.length)];
    288            }
    289            catch (Throwable var2)
    290            {
    291                return "Witty comment unavailable :(";
    292            }
    293        }
    294
    295        public static CrashReport func_85055_a(Throwable par0Throwable, String par1Str)
    296        {
    297            CrashReport var2;
    298
    299            if (par0Throwable instanceof ReportedException)
    300            {
    301                var2 = ((ReportedException)par0Throwable).getTheReportedExceptionCrashReport();
    302            }
    303            else
    304            {
    305                var2 = new CrashReport(par1Str, par0Throwable);
    306            }
    307
    308            return var2;
    309        }
    310    }