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