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