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 }