Commit 5403adcb8967388e8e6704ec11d8c8f75fe0c12c

Authored by Mumfrey
1 parent 6e6559c6

LiteLoader for 1.4.7

+ Merged fixes for examining class path under FML 1.4.6 and later
 + Added additional post-render callbacks, useful for mods that want to render arbitrary things in the world transform
 + Added branding support, so that the particular mod pack distribution or repackage will be reported in crash reports
 + Added options file for choosing WHERE to look for mods
 + Added fix (?) for infinite recursion under Mac OS when using Magic Launcher
 + Added redirect to stdout via config file or JVM flag
 + 20% more awesome
java/com/mumfrey/liteloader/PostRenderListener.java 0 → 100644
  1 +package com.mumfrey.liteloader;
  2 +
  3 +/**
  4 + * Render callback that gets called AFTER entities are rendered
  5 + *
  6 + * @author Adam Mummery-Smith
  7 + */
  8 +public interface PostRenderListener extends LiteMod
  9 +{
  10 + /**
  11 + * Called after entities are rendered but before particles
  12 + *
  13 + * @param partialTicks
  14 + */
  15 + public abstract void onPostRenderEntities(float partialTicks);
  16 +
  17 + /**
  18 + * Called after all world rendering is completed
  19 + *
  20 + * @param partialTicks
  21 + */
  22 + public abstract void onPostRender(float partialTicks);
  23 +}
... ...
java/com/mumfrey/liteloader/core/CallableLiteLoaderBrand.java 0 → 100644
  1 +package com.mumfrey.liteloader.core;
  2 +
  3 +import java.util.concurrent.Callable;
  4 +
  5 +import net.minecraft.src.CrashReport;
  6 +
  7 +public class CallableLiteLoaderBrand implements Callable<String>
  8 +{
  9 + final CrashReport crashReport;
  10 +
  11 + public CallableLiteLoaderBrand(CrashReport report)
  12 + {
  13 + this.crashReport = report;
  14 + }
  15 +
  16 + /* (non-Javadoc)
  17 + * @see java.util.concurrent.Callable#call()
  18 + */
  19 + @Override
  20 + public String call() throws Exception
  21 + {
  22 + String brand = LiteLoader.getInstance().getBranding();
  23 + return brand == null ? "Unknown / None" : brand;
  24 + }
  25 +}
... ...
java/com/mumfrey/liteloader/core/HookProfiler.java
... ... @@ -135,16 +135,21 @@ public class HookProfiler extends Profiler
135 135 loader.onInit();
136 136 }
137 137  
138   - if ("gameRenderer".equalsIgnoreCase(sectionName) && "root".equalsIgnoreCase(sectionStack.getLast()))
  138 + if ("gameRenderer".equals(sectionName) && "root".equals(sectionStack.getLast()))
139 139 {
140 140 loader.onRender();
141 141 }
142 142  
143   - if ("frustrum".equalsIgnoreCase(sectionName) && "level".equalsIgnoreCase(sectionStack.getLast()))
  143 + if ("frustrum".equals(sectionName) && "level".equals(sectionStack.getLast()))
144 144 {
145 145 loader.onSetupCameraTransform();
146 146 }
147 147  
  148 + if ("litParticles".equals(sectionName))
  149 + {
  150 + loader.postRenderEntities();
  151 + }
  152 +
148 153 if ("animateTick".equals(sectionName)) tick = true;
149 154 sectionStack.add(sectionName);
150 155 super.startSection(sectionName);
... ... @@ -190,5 +195,9 @@ public class HookProfiler extends Profiler
190 195 {
191 196 loader.onBeforeGuiRender();
192 197 }
  198 + else if ("hand".equals(endingSection) && "level".equals(sectionStack.getLast()))
  199 + {
  200 + loader.postRender();
  201 + }
193 202 }
194 203 }
... ...
java/com/mumfrey/liteloader/core/LiteLoader.java
1 1 package com.mumfrey.liteloader.core;
2 2  
3   -import java.io.*;
  3 +import java.io.BufferedReader;
  4 +import java.io.ByteArrayOutputStream;
  5 +import java.io.File;
  6 +import java.io.FileInputStream;
  7 +import java.io.FileNotFoundException;
  8 +import java.io.FileWriter;
  9 +import java.io.FilenameFilter;
  10 +import java.io.IOException;
  11 +import java.io.InputStream;
  12 +import java.io.InputStreamReader;
  13 +import java.io.PrintStream;
4 14 import java.lang.reflect.Constructor;
5 15 import java.lang.reflect.Method;
6 16 import java.net.URL;
7 17 import java.net.URLClassLoader;
8 18 import java.net.URLDecoder;
9   -import java.nio.CharBuffer;
10 19 import java.nio.charset.Charset;
11   -import java.util.*;
12   -import java.util.concurrent.Callable;
13   -import java.util.logging.*;
  20 +import java.util.Arrays;
  21 +import java.util.HashMap;
  22 +import java.util.Iterator;
  23 +import java.util.LinkedList;
  24 +import java.util.List;
  25 +import java.util.Properties;
  26 +import java.util.logging.FileHandler;
14 27 import java.util.logging.Formatter;
  28 +import java.util.logging.Level;
  29 +import java.util.logging.Logger;
  30 +import java.util.logging.StreamHandler;
15 31 import java.util.zip.ZipEntry;
16 32 import java.util.zip.ZipFile;
17 33 import java.util.zip.ZipInputStream;
18 34  
19   -import com.mumfrey.liteloader.*;
20   -import com.mumfrey.liteloader.util.ModUtilities;
21   -import com.mumfrey.liteloader.util.PrivateFields;
22   -
23 35 import net.minecraft.client.Minecraft;
24   -import net.minecraft.src.*;
  36 +import net.minecraft.src.ConsoleLogManager;
  37 +import net.minecraft.src.NetHandler;
  38 +import net.minecraft.src.Packet1Login;
  39 +import net.minecraft.src.Packet3Chat;
  40 +import net.minecraft.src.Profiler;
25 41 import net.minecraft.src.Timer;
26 42  
  43 +import com.mumfrey.liteloader.ChatFilter;
  44 +import com.mumfrey.liteloader.ChatListener;
  45 +import com.mumfrey.liteloader.InitCompleteListener;
  46 +import com.mumfrey.liteloader.LiteMod;
  47 +import com.mumfrey.liteloader.LoginListener;
  48 +import com.mumfrey.liteloader.PluginChannelListener;
  49 +import com.mumfrey.liteloader.PostRenderListener;
  50 +import com.mumfrey.liteloader.PreLoginListener;
  51 +import com.mumfrey.liteloader.RenderListener;
  52 +import com.mumfrey.liteloader.Tickable;
  53 +import com.mumfrey.liteloader.util.ModUtilities;
  54 +import com.mumfrey.liteloader.util.PrivateFields;
  55 +
27 56 /**
28 57 * LiteLoader is a simple loader which provides tick events to loaded mods
29 58 *
30 59 * @author Adam Mummery-Smith
31   - * @version 1.4.6
  60 + * @version 1.4.7
32 61 */
33 62 @SuppressWarnings("rawtypes")
34 63 public final class LiteLoader implements FilenameFilter
... ... @@ -36,19 +65,24 @@ public final class LiteLoader implements FilenameFilter
36 65 /**
37 66 * Liteloader version
38 67 */
39   - private static final String LOADER_VERSION = "1.4.6";
  68 + private static final String LOADER_VERSION = "1.4.7";
40 69  
41 70 /**
42 71 * Loader revision, can be used by mods to determine whether the loader is sufficiently up-to-date
43 72 */
44   - private static final int LOADER_REVISION = 6;
  73 + private static final int LOADER_REVISION = 7;
45 74  
46 75 /**
47 76 * Minecraft versions that we will load mods for, this will be compared
48 77 * against the version.txt value in mod files to prevent outdated mods being
49 78 * loaded!!!
50 79 */
51   - private static final String[] SUPPORTED_VERSIONS = { "1.4.6" };
  80 + private static final String[] SUPPORTED_VERSIONS = { "1.4.6", "1.4.7" };
  81 +
  82 + /**
  83 + * Maximum recursion depth for mod discovery
  84 + */
  85 + private static final int MAX_DISCOVERY_DEPTH = 16;
52 86  
53 87 /**
54 88 * LiteLoader is a singleton, this is the singleton instance
... ... @@ -61,6 +95,11 @@ public final class LiteLoader implements FilenameFilter
61 95 public static Logger logger = Logger.getLogger("liteloader");
62 96  
63 97 /**
  98 + * Use stdout rather than stderr
  99 + */
  100 + private static boolean useStdOut = false;
  101 +
  102 + /**
64 103 * "mods" folder which contains mods and config files
65 104 */
66 105 private File modsFolder;
... ... @@ -71,6 +110,26 @@ public final class LiteLoader implements FilenameFilter
71 110 private Minecraft minecraft = Minecraft.getMinecraft();
72 111  
73 112 /**
  113 + * File containing the properties
  114 + */
  115 + private File propertiesFile = new File(Minecraft.getMinecraftDir(), "liteloader.properties");
  116 +
  117 + /**
  118 + * Internal properties loaded from inside the jar
  119 + */
  120 + private Properties internalProperties = new Properties();
  121 +
  122 + /**
  123 + * LiteLoader properties
  124 + */
  125 + private Properties localProperties = new Properties();
  126 +
  127 + /**
  128 + * Pack brand from properties, used to put the modpack/compilation name in crash reports
  129 + */
  130 + private String branding = null;
  131 +
  132 + /**
74 133 * Reference to the minecraft timer
75 134 */
76 135 private Timer minecraftTimer;
... ... @@ -103,6 +162,11 @@ public final class LiteLoader implements FilenameFilter
103 162 private LinkedList<RenderListener> renderListeners = new LinkedList<RenderListener>();
104 163  
105 164 /**
  165 + * List of mods which implement the PostRenderListener interface and want to render entities
  166 + */
  167 + private LinkedList<PostRenderListener> postRenderListeners = new LinkedList<PostRenderListener>();
  168 +
  169 + /**
106 170 * List of mods which implement ChatListener interface and will receive chat
107 171 * events
108 172 */
... ... @@ -144,6 +208,9 @@ public final class LiteLoader implements FilenameFilter
144 208 */
145 209 private boolean loaderStartupDone, loaderStartupComplete, lateInitDone;
146 210  
  211 + /**
  212 + * Flags which keep track of whether hooks have been applied
  213 + */
147 214 private boolean chatHooked, loginHooked, pluginChannelHooked, tickHooked;
148 215  
149 216 /**
... ... @@ -174,6 +241,11 @@ public final class LiteLoader implements FilenameFilter
174 241 return logger;
175 242 }
176 243  
  244 + public static final PrintStream getConsoleStream()
  245 + {
  246 + return useStdOut ? System.out : System.err;
  247 + }
  248 +
177 249 /**
178 250 * Get LiteLoader version
179 251 *
... ... @@ -203,28 +275,54 @@ public final class LiteLoader implements FilenameFilter
203 275  
204 276 private void initLoader()
205 277 {
206   - if (loaderStartupDone) return;
207   - loaderStartupDone = true;
  278 + if (this.loaderStartupDone) return;
  279 + this.loaderStartupDone = true;
208 280  
209 281 // Set up base class overrides
210   - prepareClassOverrides();
  282 + this.prepareClassOverrides();
211 283  
212 284 // Set up loader, initialises any reflection methods needed
213   - if (prepareLoader())
  285 + if (this.prepareLoader())
214 286 {
215   - logger.info("LiteLoader " + LOADER_VERSION + " starting up...");
  287 + logger.info(String.format("LiteLoader %s starting up...", LOADER_VERSION));
  288 +
  289 + // Print the branding version if any was provided
  290 + if (this.branding != null)
  291 + {
  292 + logger.info(String.format("Active Pack: %s", this.branding));
  293 + }
  294 +
216 295 logger.info(String.format("Java reports OS=\"%s\"", System.getProperty("os.name").toLowerCase()));
  296 +
  297 + boolean searchMods = this.localProperties.getProperty("search.mods", "true").equalsIgnoreCase("true");
  298 + boolean searchProtectionDomain = this.localProperties.getProperty("search.jar", "true").equalsIgnoreCase("true");
  299 + boolean searchClassPath = this.localProperties.getProperty("search.classpath", "true").equalsIgnoreCase("true");
  300 +
  301 + if (!searchMods && !searchProtectionDomain && !searchClassPath)
  302 + {
  303 + logger.warning("Invalid configuration, no search locations defined. Enabling all search locations.");
  304 +
  305 + this.localProperties.setProperty("search.mods", "true");
  306 + this.localProperties.setProperty("search.jar", "true");
  307 + this.localProperties.setProperty("search.classpath", "true");
  308 +
  309 + searchMods = true;
  310 + searchProtectionDomain = true;
  311 + searchClassPath = true;
  312 + }
217 313  
218 314 // Examines the class path and mods folder and locates loadable mods
219   - prepareMods();
  315 + this.prepareMods(searchMods, searchProtectionDomain, searchClassPath);
220 316  
221 317 // Initialises enumerated mods
222   - initMods();
  318 + this.initMods();
223 319  
224 320 // Initialises the required hooks for loaded mods
225   - initHooks();
  321 + this.initHooks();
226 322  
227   - loaderStartupComplete = true;
  323 + this.loaderStartupComplete = true;
  324 +
  325 + this.writeProperties();
228 326 }
229 327 }
230 328  
... ... @@ -233,7 +331,7 @@ public final class LiteLoader implements FilenameFilter
233 331 */
234 332 private void prepareClassOverrides()
235 333 {
236   - registerBaseClassOverride(ModUtilities.getObfuscatedFieldName("net.minecraft.src.CallableJVMFlags", "g"), "g");
  334 + this.registerBaseClassOverride(ModUtilities.getObfuscatedFieldName("net.minecraft.src.CallableJVMFlags", "g"), "g");
237 335 }
238 336  
239 337 /**
... ... @@ -282,39 +380,29 @@ public final class LiteLoader implements FilenameFilter
282 380 /**
283 381 * Set up reflection methods required by the loader
284 382 */
285   - @SuppressWarnings("unchecked")
286 383 private boolean prepareLoader()
287 384 {
288 385 try
289 386 {
290 387 // addURL method is used by the class loader to
291   - mAddUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
292   - mAddUrl.setAccessible(true);
  388 + this.mAddUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
  389 + this.mAddUrl.setAccessible(true);
293 390  
294   - Formatter minecraftLogFormatter = null;
  391 + // Prepare the properties
  392 + this.prepareProperties();
295 393  
296   - try
297   - {
298   - Class<? extends Formatter> formatterClass = (Class<? extends Formatter>)Minecraft.class.getClassLoader().loadClass(ModUtilities.getObfuscatedFieldName("net.minecraft.src.ConsoleLogFormatter", "em"));
299   - Constructor<? extends Formatter> defaultConstructor = formatterClass.getDeclaredConstructor();
300   - defaultConstructor.setAccessible(true);
301   - minecraftLogFormatter = defaultConstructor.newInstance();
302   - }
303   - catch (Exception ex)
304   - {
305   - ConsoleLogManager.init();
306   - minecraftLogFormatter = ConsoleLogManager.loggerLogManager.getHandlers()[0].getFormatter();
307   - }
  394 + // Prepare the log writer
  395 + this.prepareLogger();
308 396  
309   - logger.setUseParentHandlers(false);
  397 + this.branding = this.internalProperties.getProperty("brand", null);
  398 + if (this.branding != null && this.branding.length() < 1) this.branding = null;
310 399  
311   - StreamHandler consoleHandler = new ConsoleHandler();
312   - if (minecraftLogFormatter != null) consoleHandler.setFormatter(minecraftLogFormatter);
313   - logger.addHandler(consoleHandler);
  400 + // Save appropriate branding in the local properties file
  401 + if (this.branding != null)
  402 + this.localProperties.setProperty("brand", this.branding);
  403 + else
  404 + this.localProperties.remove("brand");
314 405  
315   - FileHandler logFileHandler = new FileHandler(new File(Minecraft.getMinecraftDir(), "LiteLoader.txt").getAbsolutePath());
316   - if (minecraftLogFormatter != null) logFileHandler.setFormatter(minecraftLogFormatter);
317   - logger.addHandler(logFileHandler);
318 406 }
319 407 catch (Throwable th)
320 408 {
... ... @@ -324,28 +412,131 @@ public final class LiteLoader implements FilenameFilter
324 412  
325 413 return true;
326 414 }
  415 +
  416 + /**
  417 + * @throws SecurityException
  418 + * @throws IOException
  419 + */
  420 + @SuppressWarnings("unchecked")
  421 + private void prepareLogger() throws SecurityException, IOException
  422 + {
  423 + Formatter minecraftLogFormatter = null;
  424 +
  425 + try
  426 + {
  427 + Class<? extends Formatter> formatterClass = (Class<? extends Formatter>)Minecraft.class.getClassLoader().loadClass(ModUtilities.getObfuscatedFieldName("net.minecraft.src.ConsoleLogFormatter", "em"));
  428 + Constructor<? extends Formatter> defaultConstructor = formatterClass.getDeclaredConstructor();
  429 + defaultConstructor.setAccessible(true);
  430 + minecraftLogFormatter = defaultConstructor.newInstance();
  431 + }
  432 + catch (Exception ex)
  433 + {
  434 + ConsoleLogManager.init();
  435 + minecraftLogFormatter = ConsoleLogManager.loggerLogManager.getHandlers()[0].getFormatter();
  436 + }
  437 +
  438 + logger.setUseParentHandlers(false);
  439 +
  440 + this.useStdOut = System.getProperty("liteloader.log", "stderr").equalsIgnoreCase("stdout") || this.localProperties.getProperty("log", "stderr").equalsIgnoreCase("stdout");
  441 +
  442 + StreamHandler consoleHandler = useStdOut ? new com.mumfrey.liteloader.util.log.ConsoleHandler() : new java.util.logging.ConsoleHandler();
  443 + if (minecraftLogFormatter != null) consoleHandler.setFormatter(minecraftLogFormatter);
  444 + logger.addHandler(consoleHandler);
  445 +
  446 + FileHandler logFileHandler = new FileHandler(new File(Minecraft.getMinecraftDir(), "LiteLoader.txt").getAbsolutePath());
  447 + if (minecraftLogFormatter != null) logFileHandler.setFormatter(minecraftLogFormatter);
  448 + logger.addHandler(logFileHandler);
  449 + }
  450 +
  451 + /**
  452 + * Prepare the loader properties
  453 + */
  454 + private void prepareProperties()
  455 + {
  456 + try
  457 + {
  458 + InputStream propertiesStream = LiteLoader.class.getResourceAsStream("/liteloader.properties");
  459 +
  460 + if (propertiesStream != null)
  461 + {
  462 + this.internalProperties.load(propertiesStream);
  463 + propertiesStream.close();
  464 + }
  465 + }
  466 + catch (Throwable th)
  467 + {
  468 + this.internalProperties = new Properties();
  469 + }
  470 +
  471 + try
  472 + {
  473 + InputStream localPropertiesStream = this.getLocalPropertiesStream();
  474 +
  475 + if (localPropertiesStream != null)
  476 + {
  477 + this.localProperties.load(localPropertiesStream);
  478 + localPropertiesStream.close();
  479 + }
  480 + }
  481 + catch (Throwable th)
  482 + {
  483 + this.localProperties = new Properties();
  484 + }
  485 + }
  486 +
  487 + /**
  488 + * Get the properties stream either from the jar or from the properties file in the minecraft folder
  489 + *
  490 + * @return
  491 + * @throws FileNotFoundException
  492 + */
  493 + private InputStream getLocalPropertiesStream() throws FileNotFoundException
  494 + {
  495 + if (this.propertiesFile.exists())
  496 + {
  497 + return new FileInputStream(this.propertiesFile);
  498 + }
  499 +
  500 + // Otherwise read settings from the config
  501 + return LiteLoader.class.getResourceAsStream("/liteloader.properties");
  502 + }
327 503  
328 504 /**
  505 + * Write current properties to the properties file
  506 + */
  507 + private void writeProperties()
  508 + {
  509 + try
  510 + {
  511 + this.localProperties.store(new FileWriter(this.propertiesFile), String.format("Properties for LiteLoader %s", LOADER_VERSION));
  512 + }
  513 + catch (Throwable th)
  514 + {
  515 + logger.log(Level.WARNING, "Error writing liteloader properties", th);
  516 + }
  517 + }
  518 +
  519 + /**
329 520 * Get the "mods" folder
330 521 */
331 522 public File getModsFolder()
332 523 {
333   - if (modsFolder == null)
  524 + if (this.modsFolder == null)
334 525 {
335   - modsFolder = new File(Minecraft.getMinecraftDir(), "mods");
  526 + this.modsFolder = new File(Minecraft.getMinecraftDir(), "mods");
336 527  
337   - if (!modsFolder.exists() || !modsFolder.isDirectory())
  528 + if (!this.modsFolder.exists() || !this.modsFolder.isDirectory())
338 529 {
339 530 try
340 531 {
341 532 // Attempt to create the "mods" folder if it does not already exist
342   - modsFolder.mkdirs();
  533 + this.modsFolder.mkdirs();
343 534 }
344 535 catch (Exception ex) {}
345 536 }
346 537 }
347 538  
348   - return modsFolder;
  539 + return this.modsFolder;
349 540 }
350 541  
351 542 /**
... ... @@ -355,24 +546,37 @@ public final class LiteLoader implements FilenameFilter
355 546 */
356 547 public String getLoadedModsList()
357 548 {
358   - return loadedModsList;
  549 + return this.loadedModsList;
  550 + }
  551 +
  552 + /**
  553 + * Used to get the name of the modpack being used
  554 + *
  555 + * @return name of the modpack in use or null if no pack
  556 + */
  557 + public String getBranding()
  558 + {
  559 + return this.branding;
359 560 }
360 561  
361 562 /**
362 563 * Enumerate the java class path and "mods" folder to find mod classes, then load the classes
363 564 */
364   - private void prepareMods()
  565 + private void prepareMods(boolean searchMods, boolean searchProtectionDomain, boolean searchClassPath)
365 566 {
366 567 // List of mod files in the "mods" folder
367 568 LinkedList<File> modFiles = new LinkedList<File>();
368 569  
369   - // Find and enumerate the "mods" folder
370   - File modFolder = getModsFolder();
371   - if (modFolder.exists() && modFolder.isDirectory())
  570 + if (searchMods)
372 571 {
373   - logger.info("Mods folder found, searching " + modFolder.getPath());
374   - findModFiles(modFolder, modFiles);
375   - logger.info("Found " + modFiles.size() + " mod file(s)");
  572 + // Find and enumerate the "mods" folder
  573 + File modFolder = this.getModsFolder();
  574 + if (modFolder.exists() && modFolder.isDirectory())
  575 + {
  576 + logger.info("Mods folder found, searching " + modFolder.getPath());
  577 + this.findModFiles(modFolder, modFiles);
  578 + logger.info("Found " + modFiles.size() + " mod file(s)");
  579 + }
376 580 }
377 581  
378 582 // Find and enumerate classes on the class path
... ... @@ -388,9 +592,8 @@ public final class LiteLoader implements FilenameFilter
388 592 logger.info(String.format("Class path separator=\"%s\"", classPathSeparator));
389 593 logger.info(String.format("Class path entries=(\n classpathEntry=%s\n)", classPath.replace(classPathSeparator, "\n classpathEntry=")));
390 594  
391   - logger.info("Loading mods from class path...");
392   -
393   - modsToLoad = findModClasses(classPathEntries, modFiles);
  595 + if (searchProtectionDomain || searchClassPath) logger.info("Discovering mods on class path...");
  596 + modsToLoad = this.findModClasses(classPathEntries, modFiles, searchProtectionDomain, searchClassPath);
394 597  
395 598 logger.info("Mod class discovery completed");
396 599 }
... ... @@ -400,7 +603,7 @@ public final class LiteLoader implements FilenameFilter
400 603 return;
401 604 }
402 605  
403   - loadMods(modsToLoad);
  606 + this.loadMods(modsToLoad);
404 607 }
405 608  
406 609 /**
... ... @@ -460,36 +663,68 @@ public final class LiteLoader implements FilenameFilter
460 663 * @param classPathEntries Java class path split into string entries
461 664 * @return map of classes to load
462 665 */
463   - private HashMap<String, Class> findModClasses(String[] classPathEntries, LinkedList<File> modFiles)
  666 + private HashMap<String, Class> findModClasses(String[] classPathEntries, LinkedList<File> modFiles, boolean searchProtectionDomain, boolean searchClassPath)
464 667 {
465 668 // To try to avoid loading the same mod multiple times if it appears in more than one entry in the class path, we index
466 669 // the mods by name and hopefully match only a single instance of a particular mod
467 670 HashMap<String, Class> modsToLoad = new HashMap<String, Class>();
468 671  
469   - try
  672 + if (searchProtectionDomain)
470 673 {
471   - logger.info("Searching protection domain code source...");
472   -
473   - File packagePath = null;
474   -
475   - if (LiteLoader.class.getProtectionDomain().getCodeSource().getLocation() != null)
476   - {
477   - packagePath = new File(LiteLoader.class.getProtectionDomain().getCodeSource().getLocation().toURI());
478   - }
479   - else
  674 + try
480 675 {
481   - // Fix (?) for forge and other mods which screw up the protection domain
482   - String reflectionClassPath = LiteLoader.class.getResource("/com/mumfrey/liteloader/core/LiteLoader.class").getPath();
  676 + logger.info("Searching protection domain code source...");
  677 +
  678 + File packagePath = null;
  679 +
  680 + URL protectionDomainLocation = LiteLoader.class.getProtectionDomain().getCodeSource().getLocation();
  681 + if (protectionDomainLocation != null)
  682 + {
  683 + if (protectionDomainLocation.toString().indexOf('!') > -1 && protectionDomainLocation.toString().startsWith("jar:"))
  684 + {
  685 + protectionDomainLocation = new URL(protectionDomainLocation.toString().substring(4, protectionDomainLocation.toString().indexOf('!')));
  686 + }
  687 +
  688 + packagePath = new File(protectionDomainLocation.toURI());
  689 + }
  690 + else
  691 + {
  692 + // Fix (?) for forge and other mods which screw up the protection domain
  693 + String reflectionClassPath = LiteLoader.class.getResource("/com/mumfrey/liteloader/core/LiteLoader.class").getPath();
  694 +
  695 + if (reflectionClassPath.indexOf('!') > -1)
  696 + {
  697 + reflectionClassPath = URLDecoder.decode(reflectionClassPath, "UTF-8");
  698 + packagePath = new File(reflectionClassPath.substring(5, reflectionClassPath.indexOf('!')));
  699 + }
  700 + }
483 701  
484   - if (reflectionClassPath.indexOf('!') > -1)
  702 + if (packagePath != null)
485 703 {
486   - reflectionClassPath = URLDecoder.decode(reflectionClassPath, "UTF-8");
487   - packagePath = new File(reflectionClassPath.substring(5, reflectionClassPath.indexOf('!')));
  704 + LinkedList<Class> modClasses = getSubclassesFor(packagePath, Minecraft.class.getClassLoader(), LiteMod.class, "LiteMod");
  705 +
  706 + for (Class mod : modClasses)
  707 + {
  708 + modsToLoad.put(mod.getSimpleName(), mod);
  709 + }
  710 +
  711 + if (modClasses.size() > 0) logger.info(String.format("Found %s potential matches", modClasses.size()));
488 712 }
489 713 }
490   -
491   - if (packagePath != null)
  714 + catch (Throwable th)
  715 + {
  716 + logger.warning("Error loading from local class path: " + th.getMessage());
  717 + }
  718 + }
  719 +
  720 + if (searchClassPath)
  721 + {
  722 + // Search through the class path and find mod classes
  723 + for (String classPathPart : classPathEntries)
492 724 {
  725 + logger.info(String.format("Searching %s...", classPathPart));
  726 +
  727 + File packagePath = new File(classPathPart);
493 728 LinkedList<Class> modClasses = getSubclassesFor(packagePath, Minecraft.class.getClassLoader(), LiteMod.class, "LiteMod");
494 729  
495 730 for (Class mod : modClasses)
... ... @@ -500,26 +735,6 @@ public final class LiteLoader implements FilenameFilter
500 735 if (modClasses.size() > 0) logger.info(String.format("Found %s potential matches", modClasses.size()));
501 736 }
502 737 }
503   - catch (Throwable th)
504   - {
505   - logger.warning("Error loading from local class path: " + th.getMessage());
506   - }
507   -
508   - // Search through the class path and find mod classes
509   - for (String classPathPart : classPathEntries)
510   - {
511   - logger.info(String.format("Searching %s...", classPathPart));
512   -
513   - File packagePath = new File(classPathPart);
514   - LinkedList<Class> modClasses = getSubclassesFor(packagePath, Minecraft.class.getClassLoader(), LiteMod.class, "LiteMod");
515   -
516   - for (Class mod : modClasses)
517   - {
518   - modsToLoad.put(mod.getSimpleName(), mod);
519   - }
520   -
521   - if (modClasses.size() > 0) logger.info(String.format("Found %s potential matches", modClasses.size()));
522   - }
523 738  
524 739 // Search through mod files and find mod classes
525 740 for (File modFile : modFiles)
... ... @@ -561,7 +776,7 @@ public final class LiteLoader implements FilenameFilter
561 776 logger.info("Loading mod from " + mod.getName());
562 777  
563 778 LiteMod newMod = (LiteMod)mod.newInstance();
564   - mods.add(newMod);
  779 + this.mods.add(newMod);
565 780  
566 781 logger.info("Successfully added mod " + newMod.getName() + " version " + newMod.getVersion());
567 782 }
... ... @@ -578,7 +793,7 @@ public final class LiteLoader implements FilenameFilter
578 793 */
579 794 private void initMods()
580 795 {
581   - loadedModsList = "";
  796 + this.loadedModsList = "";
582 797 int loadedModsCount = 0;
583 798  
584 799 for (Iterator<LiteMod> iter = mods.iterator(); iter.hasNext();)
... ... @@ -593,45 +808,50 @@ public final class LiteLoader implements FilenameFilter
593 808  
594 809 if (mod instanceof Tickable)
595 810 {
596   - addTickListener((Tickable)mod);
  811 + this.addTickListener((Tickable)mod);
597 812 }
598 813  
599 814 if (mod instanceof InitCompleteListener)
600 815 {
601   - addInitListener((InitCompleteListener)mod);
  816 + this.addInitListener((InitCompleteListener)mod);
602 817 }
603 818  
604 819 if (mod instanceof RenderListener)
605 820 {
606   - addRenderListener((RenderListener)mod);
  821 + this.addRenderListener((RenderListener)mod);
  822 + }
  823 +
  824 + if (mod instanceof PostRenderListener)
  825 + {
  826 + this.addPostRenderListener((PostRenderListener)mod);
607 827 }
608 828  
609 829 if (mod instanceof ChatFilter)
610 830 {
611   - addChatFilter((ChatFilter)mod);
  831 + this.addChatFilter((ChatFilter)mod);
612 832 }
613 833  
614 834 if (mod instanceof ChatListener && !(mod instanceof ChatFilter))
615 835 {
616   - addChatListener((ChatListener)mod);
  836 + this.addChatListener((ChatListener)mod);
617 837 }
618 838  
619 839 if (mod instanceof PreLoginListener)
620 840 {
621   - addPreLoginListener((PreLoginListener)mod);
  841 + this.addPreLoginListener((PreLoginListener)mod);
622 842 }
623 843  
624 844 if (mod instanceof LoginListener)
625 845 {
626   - addLoginListener((LoginListener)mod);
  846 + this.addLoginListener((LoginListener)mod);
627 847 }
628 848  
629 849 if (mod instanceof PluginChannelListener)
630 850 {
631   - addPluginChannelListener((PluginChannelListener)mod);
  851 + this.addPluginChannelListener((PluginChannelListener)mod);
632 852 }
633 853  
634   - loadedModsList += String.format("\n - %s version %s", mod.getName(), mod.getVersion());
  854 + this.loadedModsList += String.format("\n - %s version %s", mod.getName(), mod.getVersion());
635 855 loadedModsCount++;
636 856 }
637 857 catch (Throwable th)
... ... @@ -641,7 +861,7 @@ public final class LiteLoader implements FilenameFilter
641 861 }
642 862 }
643 863  
644   - loadedModsList = String.format("%s loaded mod(s)%s", loadedModsCount, loadedModsList);
  864 + this.loadedModsList = String.format("%s loaded mod(s)%s", loadedModsCount, this.loadedModsList);
645 865 }
646 866  
647 867 /**
... ... @@ -652,34 +872,34 @@ public final class LiteLoader implements FilenameFilter
652 872 try
653 873 {
654 874 // Chat hook
655   - if ((chatListeners.size() > 0 || chatFilters.size() > 0) && !chatHooked)
  875 + if ((this.chatListeners.size() > 0 || this.chatFilters.size() > 0) && !this.chatHooked)
656 876 {
657   - chatHooked = true;
  877 + this.chatHooked = true;
658 878 HookChat.Register();
659 879 HookChat.RegisterPacketHandler(this);
660 880 }
661 881  
662 882 // Login hook
663   - if ((preLoginListeners.size() > 0 || loginListeners.size() > 0) && !loginHooked)
  883 + if ((this.preLoginListeners.size() > 0 || this.loginListeners.size() > 0) && !this.loginHooked)
664 884 {
665   - loginHooked = true;
  885 + this.loginHooked = true;
666 886 ModUtilities.registerPacketOverride(1, HookLogin.class);
667 887 HookLogin.loader = this;
668 888 }
669 889  
670 890 // Plugin channels hook
671   - if (pluginChannelListeners.size() > 0 && !pluginChannelHooked)
  891 + if (this.pluginChannelListeners.size() > 0 && !this.pluginChannelHooked)
672 892 {
673   - pluginChannelHooked = true;
  893 + this.pluginChannelHooked = true;
674 894 HookPluginChannels.Register();
675 895 HookPluginChannels.RegisterPacketHandler(this);
676 896 }
677 897  
678 898 // Tick hook
679   - if (!tickHooked)
  899 + if (!this.tickHooked)
680 900 {
681   - tickHooked = true;
682   - PrivateFields.minecraftProfiler.SetFinal(minecraft, new HookProfiler(this, logger));
  901 + this.tickHooked = true;
  902 + PrivateFields.minecraftProfiler.SetFinal(this.minecraft, new HookProfiler(this, logger));
683 903 }
684 904 }
685 905 catch (Exception ex)
... ... @@ -694,10 +914,10 @@ public final class LiteLoader implements FilenameFilter
694 914 */
695 915 public void addTickListener(Tickable tickable)
696 916 {
697   - if (!tickListeners.contains(tickable))
  917 + if (!this.tickListeners.contains(tickable))
698 918 {
699   - tickListeners.add(tickable);
700   - if (loaderStartupComplete) initHooks();
  919 + this.tickListeners.add(tickable);
  920 + if (this.loaderStartupComplete) this.initHooks();
701 921 }
702 922 }
703 923  
... ... @@ -706,10 +926,10 @@ public final class LiteLoader implements FilenameFilter
706 926 */
707 927 public void addInitListener(InitCompleteListener initCompleteListener)
708 928 {
709   - if (!initListeners.contains(initCompleteListener))
  929 + if (!this.initListeners.contains(initCompleteListener))
710 930 {
711   - initListeners.add(initCompleteListener);
712   - if (loaderStartupComplete) initHooks();
  931 + this.initListeners.add(initCompleteListener);
  932 + if (this.loaderStartupComplete) this.initHooks();
713 933 }
714 934 }
715 935  
... ... @@ -718,10 +938,22 @@ public final class LiteLoader implements FilenameFilter
718 938 */
719 939 public void addRenderListener(RenderListener tickable)
720 940 {
721   - if (!renderListeners.contains(tickable))
  941 + if (!this.renderListeners.contains(tickable))
  942 + {
  943 + this.renderListeners.add(tickable);
  944 + if (this.loaderStartupComplete) this.initHooks();
  945 + }
  946 + }
  947 +
  948 + /**
  949 + * @param tickable
  950 + */
  951 + public void addPostRenderListener(PostRenderListener tickable)
  952 + {
  953 + if (!this.postRenderListeners.contains(tickable))
722 954 {
723   - renderListeners.add(tickable);
724   - if (loaderStartupComplete) initHooks();
  955 + this.postRenderListeners.add(tickable);
  956 + if (this.loaderStartupComplete) this.initHooks();
725 957 }
726 958 }
727 959  
... ... @@ -730,10 +962,10 @@ public final class LiteLoader implements FilenameFilter
730 962 */
731 963 public void addChatFilter(ChatFilter chatFilter)
732 964 {
733   - if (!chatFilters.contains(chatFilter))
  965 + if (!this.chatFilters.contains(chatFilter))
734 966 {
735   - chatFilters.add(chatFilter);
736   - if (loaderStartupComplete) initHooks();
  967 + this.chatFilters.add(chatFilter);
  968 + if (this.loaderStartupComplete) this.initHooks();
737 969 }
738 970 }
739 971  
... ... @@ -742,10 +974,10 @@ public final class LiteLoader implements FilenameFilter
742 974 */
743 975 public void addChatListener(ChatListener chatListener)
744 976 {
745   - if (!chatListeners.contains(chatListener))
  977 + if (!this.chatListeners.contains(chatListener))
746 978 {
747   - chatListeners.add(chatListener);
748   - if (loaderStartupComplete) initHooks();
  979 + this.chatListeners.add(chatListener);
  980 + if (this.loaderStartupComplete) this.initHooks();
749 981 }
750 982 }
751 983  
... ... @@ -754,10 +986,10 @@ public final class LiteLoader implements FilenameFilter
754 986 */
755 987 public void addPreLoginListener(PreLoginListener loginListener)
756 988 {
757   - if (!preLoginListeners.contains(loginListener))
  989 + if (!this.preLoginListeners.contains(loginListener))
758 990 {
759   - preLoginListeners.add(loginListener);
760   - if (loaderStartupComplete) initHooks();
  991 + this.preLoginListeners.add(loginListener);
  992 + if (this.loaderStartupComplete) this.initHooks();
761 993 }
762 994 }
763 995  
... ... @@ -766,10 +998,10 @@ public final class LiteLoader implements FilenameFilter
766 998 */
767 999 public void addLoginListener(LoginListener loginListener)
768 1000 {
769   - if (!loginListeners.contains(loginListener))
  1001 + if (!this.loginListeners.contains(loginListener))
770 1002 {
771   - loginListeners.add(loginListener);
772   - if (loaderStartupComplete) initHooks();
  1003 + this.loginListeners.add(loginListener);
  1004 + if (this.loaderStartupComplete) this.initHooks();
773 1005 }
774 1006 }
775 1007  
... ... @@ -778,10 +1010,10 @@ public final class LiteLoader implements FilenameFilter
778 1010 */
779 1011 public void addPluginChannelListener(PluginChannelListener pluginChannelListener)
780 1012 {
781   - if (!pluginChannelListeners.contains(pluginChannelListener))
  1013 + if (!this.pluginChannelListeners.contains(pluginChannelListener))
782 1014 {
783   - pluginChannelListeners.add(pluginChannelListener);
784   - if (loaderStartupComplete) initHooks();
  1015 + this.pluginChannelListeners.add(pluginChannelListener);
  1016 + if (this.loaderStartupComplete) this.initHooks();
785 1017 }
786 1018 }
787 1019  
... ... @@ -867,7 +1099,7 @@ public final class LiteLoader implements FilenameFilter
867 1099 */
868 1100 private static void enumerateDirectory(String prefix, Class superClass, ClassLoader classloader, LinkedList<Class> classes, File packagePath)
869 1101 {
870   - enumerateDirectory(prefix, superClass, classloader, classes, packagePath, "");
  1102 + enumerateDirectory(prefix, superClass, classloader, classes, packagePath, "", 0);
871 1103 }
872 1104  
873 1105 /**
... ... @@ -879,15 +1111,18 @@ public final class LiteLoader implements FilenameFilter
879 1111 * @param packagePath
880 1112 * @param packageName
881 1113 */
882   - private static void enumerateDirectory(String prefix, Class superClass, ClassLoader classloader, LinkedList<Class> classes, File packagePath, String packageName)
  1114 + private static void enumerateDirectory(String prefix, Class superClass, ClassLoader classloader, LinkedList<Class> classes, File packagePath, String packageName, int depth)
883 1115 {
  1116 + // Prevent crash due to broken recursion
  1117 + if (depth > MAX_DISCOVERY_DEPTH) return;
  1118 +
884 1119 File[] classFiles = packagePath.listFiles();
885 1120  
886 1121 for (File classFile : classFiles)
887 1122 {
888 1123 if (classFile.isDirectory())
889 1124 {
890   - enumerateDirectory(prefix, superClass, classloader, classes, classFile, packageName + classFile.getName() + ".");
  1125 + enumerateDirectory(prefix, superClass, classloader, classes, classFile, packageName + classFile.getName() + ".", depth + 1);
891 1126 }
892 1127 else
893 1128 {
... ... @@ -937,10 +1172,10 @@ public final class LiteLoader implements FilenameFilter
937 1172 {
938 1173 try
939 1174 {
940   - if (Minecraft.class.getClassLoader() instanceof URLClassLoader && mAddUrl != null && mAddUrl.isAccessible())
  1175 + if (Minecraft.class.getClassLoader() instanceof URLClassLoader && this.mAddUrl != null && this.mAddUrl.isAccessible())
941 1176 {
942 1177 URLClassLoader classLoader = (URLClassLoader)Minecraft.class.getClassLoader();
943   - mAddUrl.invoke(classLoader, classUrl);
  1178 + this.mAddUrl.invoke(classLoader, classUrl);
944 1179 return true;
945 1180 }
946 1181 }
... ... @@ -957,16 +1192,16 @@ public final class LiteLoader implements FilenameFilter
957 1192 */
958 1193 public void onInit()
959 1194 {
960   - if (!lateInitDone)
  1195 + if (!this.lateInitDone)
961 1196 {
962   - lateInitDone = true;
  1197 + this.lateInitDone = true;
963 1198  
964   - for (InitCompleteListener initMod : initListeners)
  1199 + for (InitCompleteListener initMod : this.initListeners)
965 1200 {
966 1201 try
967 1202 {
968 1203 logger.info("Calling late init for mod " + initMod.getName());
969   - initMod.onInitCompleted(minecraft, this);
  1204 + initMod.onInitCompleted(this.minecraft, this);
970 1205 }
971 1206 catch (Throwable th)
972 1207 {
... ... @@ -981,17 +1216,39 @@ public final class LiteLoader implements FilenameFilter
981 1216 */
982 1217 public void onRender()
983 1218 {
984   - for (RenderListener renderListener : renderListeners)
  1219 + for (RenderListener renderListener : this.renderListeners)
985 1220 renderListener.onRender();
986 1221 }
  1222 +
  1223 + /**
  1224 + * Callback from the tick hook, post render entities
  1225 + */
  1226 + public void postRenderEntities()
  1227 + {
  1228 + float partialTicks = (this.minecraftTimer != null) ? this.minecraftTimer.elapsedPartialTicks : 0.0F;
  1229 +
  1230 + for (PostRenderListener renderListener : this.postRenderListeners)
  1231 + renderListener.onPostRenderEntities(partialTicks);
  1232 + }
  1233 +
  1234 + /**
  1235 + * Callback from the tick hook, post render
  1236 + */
  1237 + public void postRender()
  1238 + {
  1239 + float partialTicks = (this.minecraftTimer != null) ? this.minecraftTimer.elapsedPartialTicks : 0.0F;
  1240 +
  1241 + for (PostRenderListener renderListener : this.postRenderListeners)
  1242 + renderListener.onPostRender(partialTicks);
  1243 + }
987 1244  
988 1245 /**
989 1246 * Called immediately before the current GUI is rendered
990 1247 */
991 1248 public void onBeforeGuiRender()
992 1249 {
993   - for (RenderListener renderListener : renderListeners)
994   - renderListener.onRenderGui(minecraft.currentScreen);
  1250 + for (RenderListener renderListener : this.renderListeners)
  1251 + renderListener.onRenderGui(this.minecraft.currentScreen);
995 1252 }
996 1253  
997 1254 /**
... ... @@ -999,7 +1256,7 @@ public final class LiteLoader implements FilenameFilter
999 1256 */
1000 1257 public void onSetupCameraTransform()
1001 1258 {
1002   - for (RenderListener renderListener : renderListeners)
  1259 + for (RenderListener renderListener : this.renderListeners)
1003 1260 renderListener.onSetupCameraTransform();
1004 1261 }
1005 1262  
... ... @@ -1013,26 +1270,26 @@ public final class LiteLoader implements FilenameFilter
1013 1270 float partialTicks = 0.0F;
1014 1271  
1015 1272 // Try to get the minecraft timer object and determine the value of the partialTicks
1016   - if (tick || minecraftTimer == null)
  1273 + if (tick || this.minecraftTimer == null)
1017 1274 {
1018   - minecraftTimer = PrivateFields.minecraftTimer.Get(minecraft);
  1275 + this.minecraftTimer = PrivateFields.minecraftTimer.Get(this.minecraft);
1019 1276 }
1020 1277  
1021 1278 // Hooray, we got the timer reference
1022   - if (minecraftTimer != null)
  1279 + if (this.minecraftTimer != null)
1023 1280 {
1024   - partialTicks = minecraftTimer.elapsedPartialTicks;
1025   - tick = minecraftTimer.elapsedTicks > 0;
  1281 + partialTicks = this.minecraftTimer.elapsedPartialTicks;
  1282 + tick = this.minecraftTimer.elapsedTicks > 0;
1026 1283 }
1027 1284  
1028 1285 // Flag indicates whether we are in game at the moment
1029   - boolean inGame = minecraft.renderViewEntity != null && minecraft.renderViewEntity.worldObj != null;
  1286 + boolean inGame = this.minecraft.renderViewEntity != null && this.minecraft.renderViewEntity.worldObj != null;
1030 1287  
1031 1288 // Iterate tickable mods
1032   - for (Tickable tickable : tickListeners)
  1289 + for (Tickable tickable : this.tickListeners)
1033 1290 {
1034 1291 profiler.startSection(tickable.getClass().getSimpleName());
1035   - tickable.onTick(minecraft, partialTicks, inGame, tick);
  1292 + tickable.onTick(this.minecraft, partialTicks, inGame, tick);
1036 1293 profiler.endSection();
1037 1294 }
1038 1295 }
... ... @@ -1046,12 +1303,12 @@ public final class LiteLoader implements FilenameFilter
1046 1303 public boolean onChat(Packet3Chat chatPacket)
1047 1304 {
1048 1305 // Chat filters get a stab at the chat first, if any filter returns false the chat is discarded
1049   - for (ChatFilter chatFilter : chatFilters)
  1306 + for (ChatFilter chatFilter : this.chatFilters)
1050 1307 if (!chatFilter.onChat(chatPacket))
1051 1308 return false;
1052 1309  
1053 1310 // Chat listeners get the chat if no filter removed it
1054   - for (ChatListener chatListener : chatListeners)
  1311 + for (ChatListener chatListener : this.chatListeners)
1055 1312 chatListener.onChat(chatPacket.message);
1056 1313  
1057 1314 return true;
... ... @@ -1068,7 +1325,7 @@ public final class LiteLoader implements FilenameFilter
1068 1325 {
1069 1326 boolean cancelled = false;
1070 1327  
1071   - for (PreLoginListener loginListener : preLoginListeners)
  1328 + for (PreLoginListener loginListener : this.preLoginListeners)
1072 1329 {
1073 1330 cancelled |= !loginListener.onPreLogin(netHandler, loginPacket);
1074 1331 }
... ... @@ -1084,7 +1341,7 @@ public final class LiteLoader implements FilenameFilter
1084 1341 */
1085 1342 public void onConnectToServer(NetHandler netHandler, Packet1Login loginPacket)
1086 1343 {
1087   - for (LoginListener loginListener : loginListeners)
  1344 + for (LoginListener loginListener : this.loginListeners)
1088 1345 loginListener.onLogin(netHandler, loginPacket);
1089 1346  
1090 1347 setupPluginChannels();
... ... @@ -1097,9 +1354,9 @@ public final class LiteLoader implements FilenameFilter
1097 1354 */
1098 1355 public void onPluginChannelMessage(HookPluginChannels hookPluginChannels)
1099 1356 {
1100   - if (hookPluginChannels != null && hookPluginChannels.channel != null && pluginChannels.containsKey(hookPluginChannels.channel))
  1357 + if (hookPluginChannels != null && hookPluginChannels.channel != null && this.pluginChannels.containsKey(hookPluginChannels.channel))
1101 1358 {
1102   - for (PluginChannelListener pluginChannelListener : pluginChannels.get(hookPluginChannels.channel))
  1359 + for (PluginChannelListener pluginChannelListener : this.pluginChannels.get(hookPluginChannels.channel))
1103 1360 {
1104 1361 try
1105 1362 {
... ... @@ -1127,10 +1384,10 @@ public final class LiteLoader implements FilenameFilter
1127 1384 protected void setupPluginChannels()
1128 1385 {
1129 1386 // Clear any channels from before
1130   - pluginChannels.clear();
  1387 + this.pluginChannels.clear();
1131 1388  
1132 1389 // Enumerate mods for plugin channels
1133   - for (PluginChannelListener pluginChannelListener : pluginChannelListeners)
  1390 + for (PluginChannelListener pluginChannelListener : this.pluginChannelListeners)
1134 1391 {
1135 1392 List<String> channels = pluginChannelListener.getChannels();
1136 1393  
... ... @@ -1141,23 +1398,23 @@ public final class LiteLoader implements FilenameFilter
1141 1398 if (channel.length() > 16 || channel.toUpperCase().equals("REGISTER") || channel.toUpperCase().equals("UNREGISTER"))
1142 1399 continue;
1143 1400  
1144   - if (!pluginChannels.containsKey(channel))
  1401 + if (!this.pluginChannels.containsKey(channel))
1145 1402 {
1146   - pluginChannels.put(channel, new LinkedList<PluginChannelListener>());
  1403 + this.pluginChannels.put(channel, new LinkedList<PluginChannelListener>());
1147 1404 }
1148 1405  
1149   - pluginChannels.get(channel).add(pluginChannelListener);
  1406 + this.pluginChannels.get(channel).add(pluginChannelListener);
1150 1407 }
1151 1408 }
1152 1409 }
1153 1410  
1154 1411 // If any mods have registered channels, send the REGISTER packet
1155   - if (pluginChannels.keySet().size() > 0)
  1412 + if (this.pluginChannels.keySet().size() > 0)
1156 1413 {
1157 1414 StringBuilder channelList = new StringBuilder();
1158 1415 boolean separator = false;
1159 1416  
1160   - for (String channel : pluginChannels.keySet())
  1417 + for (String channel : this.pluginChannels.keySet())
1161 1418 {
1162 1419 if (separator) channelList.append("\u0000");
1163 1420 channelList.append(channel);
... ...
java/com/mumfrey/liteloader/util/log/ConsoleHandler.java 0 → 100644
  1 +package com.mumfrey.liteloader.util.log;
  2 +
  3 +import java.util.logging.LogRecord;
  4 +import java.util.logging.StreamHandler;
  5 +
  6 +public class ConsoleHandler extends StreamHandler
  7 +{
  8 + /**
  9 + * Create a <tt>ConsoleHandler</tt> for <tt>System.err</tt>.
  10 + * <p>
  11 + * The <tt>ConsoleHandler</tt> is configured based on <tt>LogManager</tt>
  12 + * properties (or their default values).
  13 + *
  14 + */
  15 + public ConsoleHandler()
  16 + {
  17 + setOutputStream(System.out);
  18 + }
  19 +
  20 + /**
  21 + * Publish a <tt>LogRecord</tt>.
  22 + * <p>
  23 + * The logging request was made initially to a <tt>Logger</tt> object, which
  24 + * initialized the <tt>LogRecord</tt> and forwarded it here.
  25 + * <p>
  26 + *
  27 + * @param record
  28 + * description of the log event. A null record is silently
  29 + * ignored and is not published
  30 + */
  31 + @Override
  32 + public synchronized void publish(LogRecord record)
  33 + {
  34 + super.publish(record);
  35 + flush();
  36 + }
  37 +
  38 + /**
  39 + * Override <tt>StreamHandler.close</tt> to do a flush but not to close the
  40 + * output stream. That is, we do <b>not</b> close <tt>System.err</tt>.
  41 + */
  42 + @Override
  43 + public synchronized void close()
  44 + {
  45 + flush();
  46 + }
  47 +}
... ...
java/net/minecraft/src/CallableJVMFlags.java
... ... @@ -6,6 +6,7 @@ import java.util.Iterator;
6 6 import java.util.List;
7 7 import java.util.concurrent.Callable;
8 8  
  9 +import com.mumfrey.liteloader.core.CallableLiteLoaderBrand;
9 10 import com.mumfrey.liteloader.core.CallableLiteLoaderMods;
10 11  
11 12 class CallableJVMFlags implements Callable
... ... @@ -16,10 +17,14 @@ class CallableJVMFlags implements Callable
16 17 CallableJVMFlags(CrashReport par1CrashReport)
17 18 {
18 19 this.crashReportJVMFlags = par1CrashReport;
  20 + par1CrashReport.func_85056_g().addCrashSectionCallable("Mod Pack", new CallableLiteLoaderBrand(par1CrashReport));
19 21 par1CrashReport.func_85056_g().addCrashSectionCallable("LiteLoader Mods", new CallableLiteLoaderMods(par1CrashReport));
20 22 }
21 23  
22   - public String func_71487_a()
  24 + /**
  25 + * Returns the number of JVM Flags along with the passed JVM Flags.
  26 + */
  27 + public String getJVMFlagsAsString()
23 28 {
24 29 RuntimeMXBean var1 = ManagementFactory.getRuntimeMXBean();
25 30 List var2 = var1.getInputArguments();
... ... @@ -48,6 +53,6 @@ class CallableJVMFlags implements Callable
48 53 @Override
49 54 public Object call()
50 55 {
51   - return this.func_71487_a();
  56 + return this.getJVMFlagsAsString();
52 57 }
53 58 }
... ...
res/liteloader.properties 0 → 100644
  1 +search.mods=true
  2 +search.jar=true
  3 +search.classpath=true
  4 +log=stderr
  5 +
  6 +
... ...