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