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 }