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 }