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