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