    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.Date;
    013    import java.util.Iterator;
    014    import java.util.LinkedHashMap;
    015    import java.util.Map;
    016    import java.util.Map.Entry;
    017    import java.util.concurrent.Callable;
    018    import java.util.logging.Level;
    019    import java.util.logging.Logger;
    020
    021    public class CrashReport
    022    {
    023        /** Description of the crash report. */
    024        private final String description;
    025
    026        /** The Throwable that is the "cause" for this crash and Crash Report. */
    027        private final Throwable cause;
    028
    029        /** Holds the keys and values of all crash report sections. */
    030        private final Map crashReportSections = new LinkedHashMap();
    031
    032        /** File of crash report. */
    033        private File crashReportFile = null;
    034
    035        public CrashReport(String par1Str, Throwable par2Throwable)
    036        {
    037            this.description = par1Str;
    038            this.cause = par2Throwable;
    039            this.func_71504_g();
    040        }
    041
    042        private void func_71504_g()
    043        {
    044            this.addCrashSectionCallable("Minecraft Version", new CallableMinecraftVersion(this));
    045            this.addCrashSectionCallable("Operating System", new CallableOSInfo(this));
    046            this.addCrashSectionCallable("Java Version", new CallableJavaInfo(this));
    047            this.addCrashSectionCallable("Java VM Version", new CallableJavaInfo2(this));
    048            this.addCrashSectionCallable("Memory", new CallableMemoryInfo(this));
    049            this.addCrashSectionCallable("JVM Flags", new CallableJVMFlags(this));
    050            this.addCrashSectionCallable("AABB Pool Size", new CallableCrashMemoryReport(this));
    051            FMLCommonHandler.instance().enhanceCrashReport(this);
    052        }
    053
    054        /**
    055         * Adds a Crashreport section with the given name with the value set to the result of the given Callable;
    056         */
    057        public void addCrashSectionCallable(String par1Str, Callable par2Callable)
    058        {
    059            try
    060            {
    061                this.addCrashSection(par1Str, par2Callable.call());
    062            }
    063            catch (Throwable var4)
    064            {
    065                this.addCrashSectionThrowable(par1Str, var4);
    066            }
    067        }
    068
    069        /**
    070         * Adds a Crashreport section with the given name with the given value (convered .toString())
    071         */
    072        public void addCrashSection(String par1Str, Object par2Obj)
    073        {
    074            this.crashReportSections.put(par1Str, par2Obj == null ? "null" : par2Obj.toString());
    075        }
    076
    077        /**
    078         * Adds a Crashreport section with the given name with the given Throwable
    079         */
    080        public void addCrashSectionThrowable(String par1Str, Throwable par2Throwable)
    081        {
    082            this.addCrashSection(par1Str, "~ERROR~ " + par2Throwable.getClass().getSimpleName() + ": " + par2Throwable.getMessage());
    083        }
    084
    085        /**
    086         * Returns the description of the Crash Report.
    087         */
    088        public String getDescription()
    089        {
    090            return this.description;
    091        }
    092
    093        /**
    094         * Returns the Throwable object that is the cause for the crash and Crash Report.
    095         */
    096        public Throwable getCrashCause()
    097        {
    098            return this.cause;
    099        }
    100
    101        @SideOnly(Side.CLIENT)
    102
    103        /**
    104         * Gets a string representation of all sections in the crash report.
    105         */
    106        public String getSections()
    107        {
    108            StringBuilder var1 = new StringBuilder();
    109            this.getSectionsInStringBuilder(var1);
    110            return var1.toString();
    111        }
    112
    113        /**
    114         * Gets the various sections of the crash report into the given StringBuilder
    115         */
    116        public void getSectionsInStringBuilder(StringBuilder par1StringBuilder)
    117        {
    118            boolean var2 = true;
    119
    120            for (Iterator var3 = this.crashReportSections.entrySet().iterator(); var3.hasNext(); var2 = false)
    121            {
    122                Entry var4 = (Entry)var3.next();
    123
    124                if (!var2)
    125                {
    126                    par1StringBuilder.append("\n");
    127                }
    128
    129                par1StringBuilder.append("- ");
    130                par1StringBuilder.append((String)var4.getKey());
    131                par1StringBuilder.append(": ");
    132                par1StringBuilder.append((String)var4.getValue());
    133            }
    134        }
    135
    136        /**
    137         * Gets the stack trace of the Throwable that caused this crash report, or if that fails, the cause .toString().
    138         */
    139        public String getCauseStackTraceOrString()
    140        {
    141            StringWriter var1 = null;
    142            PrintWriter var2 = null;
    143            String var3 = this.cause.toString();
    144
    145            try
    146            {
    147                var1 = new StringWriter();
    148                var2 = new PrintWriter(var1);
    149                this.cause.printStackTrace(var2);
    150                var3 = var1.toString();
    151            }
    152            finally
    153            {
    154                try
    155                {
    156                    if (var1 != null)
    157                    {
    158                        var1.close();
    159                    }
    160
    161                    if (var2 != null)
    162                    {
    163                        var2.close();
    164                    }
    165                }
    166                catch (IOException var10)
    167                {
    168                    ;
    169                }
    170            }
    171
    172            return var3;
    173        }
    174
    175        /**
    176         * Gets the complete report with headers, stack trace, and different sections as a string.
    177         */
    178        public String getCompleteReport()
    179        {
    180            StringBuilder var1 = new StringBuilder();
    181            var1.append("---- Minecraft Crash Report ----\n");
    182            var1.append("// ");
    183            var1.append(getWittyComment());
    184            var1.append("\n\n");
    185            var1.append("Time: ");
    186            var1.append((new SimpleDateFormat()).format(new Date()));
    187            var1.append("\n");
    188            var1.append("Description: ");
    189            var1.append(this.description);
    190            var1.append("\n\n");
    191            var1.append(this.getCauseStackTraceOrString());
    192            var1.append("\n");
    193            var1.append("Relevant Details:");
    194            var1.append("\n");
    195            this.getSectionsInStringBuilder(var1);
    196            return var1.toString();
    197        }
    198
    199        @SideOnly(Side.CLIENT)
    200
    201        /**
    202         * Gets the file this crash report is saved into.
    203         */
    204        public File getFile()
    205        {
    206            return this.crashReportFile;
    207        }
    208
    209        /**
    210         * Saves the complete crash report to the given File.
    211         */
    212        public boolean saveToFile(File par1File)
    213        {
    214            if (this.crashReportFile != null)
    215            {
    216                return false;
    217            }
    218            else
    219            {
    220                if (par1File.getParentFile() != null)
    221                {
    222                    par1File.getParentFile().mkdirs();
    223                }
    224
    225                try
    226                {
    227                    FileWriter var2 = new FileWriter(par1File);
    228                    var2.write(this.getCompleteReport());
    229                    var2.close();
    230                    this.crashReportFile = par1File;
    231                    return true;
    232                }
    233                catch (Throwable var3)
    234                {
    235                    Logger.getLogger("Minecraft").log(Level.SEVERE, "Could not save crash report to " + par1File, var3);
    236                    return false;
    237                }
    238            }
    239        }
    240
    241        /**
    242         * Gets a random witty comment for inclusion in this CrashReport
    243         */
    244        private static String getWittyComment()
    245        {
    246            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 :("};
    247
    248            try
    249            {
    250                return var0[(int)(System.nanoTime() % (long)var0.length)];
    251            }
    252            catch (Throwable var2)
    253            {
    254                return "Witty comment unavailable :(";
    255            }
    256        }
    257    }