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 }