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 public Throwable func_71505_b() 093 { 094 return this.cause; 095 } 096 097 @SideOnly(Side.CLIENT) 098 099 /** 100 * Gets a string representation of all sections in the crash report. 101 */ 102 public String getSections() 103 { 104 StringBuilder var1 = new StringBuilder(); 105 this.getSectionsInStringBuilder(var1); 106 return var1.toString(); 107 } 108 109 /** 110 * Gets the various sections of the crash report into the given StringBuilder 111 */ 112 public void getSectionsInStringBuilder(StringBuilder par1StringBuilder) 113 { 114 boolean var2 = true; 115 116 for (Iterator var3 = this.crashReportSections.entrySet().iterator(); var3.hasNext(); var2 = false) 117 { 118 Entry var4 = (Entry)var3.next(); 119 120 if (!var2) 121 { 122 par1StringBuilder.append("\n"); 123 } 124 125 par1StringBuilder.append("- "); 126 par1StringBuilder.append((String)var4.getKey()); 127 par1StringBuilder.append(": "); 128 par1StringBuilder.append((String)var4.getValue()); 129 } 130 } 131 132 /** 133 * Gets the stack trace of the Throwable that caused this crash report, or if that fails, the cause .toString(). 134 */ 135 public String getCauseStackTraceOrString() 136 { 137 StringWriter var1 = null; 138 PrintWriter var2 = null; 139 String var3 = this.cause.toString(); 140 141 try 142 { 143 var1 = new StringWriter(); 144 var2 = new PrintWriter(var1); 145 this.cause.printStackTrace(var2); 146 var3 = var1.toString(); 147 } 148 finally 149 { 150 try 151 { 152 if (var1 != null) 153 { 154 var1.close(); 155 } 156 157 if (var2 != null) 158 { 159 var2.close(); 160 } 161 } 162 catch (IOException var10) 163 { 164 ; 165 } 166 } 167 168 return var3; 169 } 170 171 /** 172 * Gets the complete report with headers, stack trace, and different sections as a string. 173 */ 174 public String getCompleteReport() 175 { 176 StringBuilder var1 = new StringBuilder(); 177 var1.append("---- Minecraft Crash Report ----\n"); 178 var1.append("// "); 179 var1.append(getWittyComment()); 180 var1.append("\n\n"); 181 var1.append("Time: "); 182 var1.append((new SimpleDateFormat()).format(new Date())); 183 var1.append("\n"); 184 var1.append("Description: "); 185 var1.append(this.description); 186 var1.append("\n\n"); 187 var1.append(this.getCauseStackTraceOrString()); 188 var1.append("\n"); 189 var1.append("Relevant Details:"); 190 var1.append("\n"); 191 this.getSectionsInStringBuilder(var1); 192 return var1.toString(); 193 } 194 195 @SideOnly(Side.CLIENT) 196 197 /** 198 * Gets the file this crash report is saved into. 199 */ 200 public File getFile() 201 { 202 return this.crashReportFile; 203 } 204 205 /** 206 * Saves the complete crash report to the given File. 207 */ 208 public boolean saveToFile(File par1File) 209 { 210 if (this.crashReportFile != null) 211 { 212 return false; 213 } 214 else 215 { 216 if (par1File.getParentFile() != null) 217 { 218 par1File.getParentFile().mkdirs(); 219 } 220 221 try 222 { 223 FileWriter var2 = new FileWriter(par1File); 224 var2.write(this.getCompleteReport()); 225 var2.close(); 226 this.crashReportFile = par1File; 227 return true; 228 } 229 catch (Throwable var3) 230 { 231 Logger.getLogger("Minecraft").log(Level.SEVERE, "Could not save crash report to " + par1File, var3); 232 return false; 233 } 234 } 235 } 236 237 /** 238 * Gets a random witty comment for inclusion in this CrashReport 239 */ 240 private static String getWittyComment() 241 { 242 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 :("}; 243 244 try 245 { 246 return var0[(int)(System.nanoTime() % (long)var0.length)]; 247 } 248 catch (Throwable var2) 249 { 250 return "Witty comment unavailable :("; 251 } 252 } 253 }