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