Commit 6f0192d282bb262fc13d747a9ab2bb1962c21eaf

Authored by Mumfrey
1 parent 07ffd14f

LiteLoader 1.6.4_02 - experimental - multi-stage startup process to support twea…

…k injection and loading mods from jars, added meta to allow FML to load LL
ant/build_liteloader.xml
... ... @@ -13,6 +13,7 @@
13 13 <property name="project" value="LiteLoader" />
14 14 <property name="md5set" value="mcp" />
15 15 <property name="outmd5set" value="liteloader" />
  16 + <property name="tweakclass" value="com.mumfrey.liteloader.launch.LiteLoaderTweaker" />
16 17  
17 18 <property name="mcp.dir" location="../../.." />
18 19 <property name="build" location="${mcp.dir}/build" />
... ... @@ -202,12 +203,14 @@
202 203 <echo level="info" message="Building final output" />
203 204  
204 205 <mkdir dir="${dist.dir}" />
  206 +
205 207 <jar destfile="${dist.dir}/${ant.project.name}-${mcversion}.${filetype}" duplicate="preserve" index="true" manifestencoding="UTF-8">
206 208 <manifest>
207 209 <attribute name="Built-By" value="MCP (http://mcp.ocean-labs.de)" />
208 210 <attribute name="Implementation-Vendor" value="${author}" />
209 211 <attribute name="Implementation-Title" value="${ant.project.name}" />
210 212 <attribute name="Implementation-Version" value="${version}" />
  213 + <attribute name="TweakClass" value="${tweakclass}" />
211 214 </manifest>
212 215 <fileset dir="${stage.dir}" />
213 216 </jar>
... ...
java/com/mumfrey/liteloader/core/ClassPathMod.java
1 1 package com.mumfrey.liteloader.core;
2 2  
3 3 import java.io.File;
  4 +import java.util.logging.Logger;
4 5  
5 6 import com.mumfrey.liteloader.resources.ModResourcePack;
6 7 import com.mumfrey.liteloader.resources.ModResourcePackDir;
... ... @@ -13,8 +14,10 @@ import com.mumfrey.liteloader.resources.ModResourcePackDir;
13 14 public class ClassPathMod extends ModFile
14 15 {
15 16 private static final long serialVersionUID = -4759310661966590773L;
  17 +
  18 + private static final Logger logger = Logger.getLogger("liteloader");
16 19  
17   - public ClassPathMod(File file, String name, String version)
  20 + ClassPathMod(File file, String name, String version)
18 21 {
19 22 super(file, "");
20 23  
... ... @@ -29,22 +32,22 @@ public class ClassPathMod extends ModFile
29 32 }
30 33  
31 34 @Override
32   - public boolean registerAsResourcePack(String name)
  35 + public boolean canRegisterAsResourcePack(String name)
33 36 {
34 37 if (this.resourcePack == null)
35 38 {
36 39 if (this.isDirectory())
37 40 {
38   - LiteLoader.getLogger().info(String.format("Registering \"%s/%s\" as mod resource pack with identifier \"%s\"", this.getParentFile().getName(), this.getName(), name));
  41 + ClassPathMod.logger.info(String.format("Registering \"%s/%s\" as mod resource pack with identifier \"%s\"", this.getParentFile().getName(), this.getName(), name));
39 42 this.resourcePack = new ModResourcePackDir(name, this);
40 43 }
41 44 else
42 45 {
43   - LiteLoader.getLogger().info(String.format("Registering \"%s\" as mod resource pack with identifier \"%s\"", this.getName(), name));
  46 + ClassPathMod.logger.info(String.format("Registering \"%s\" as mod resource pack with identifier \"%s\"", this.getName(), name));
44 47 this.resourcePack = new ModResourcePack(name, this);
45 48 }
46 49  
47   - return LiteLoader.getInstance().registerModResourcePack(this.resourcePack);
  50 + return true;
48 51 }
49 52  
50 53 return false;
... ...
java/com/mumfrey/liteloader/core/Events.java
... ... @@ -129,7 +129,14 @@ public class Events implements IPlayerUsage
129 129 */
130 130 private LinkedList<PreLoginListener> preLoginListeners = new LinkedList<PreLoginListener>();
131 131  
132   - public Events(LiteLoader loader, Minecraft minecraft, PluginChannels pluginChannels)
  132 + /**
  133 + * Package private ctor
  134 + *
  135 + * @param loader
  136 + * @param minecraft
  137 + * @param pluginChannels
  138 + */
  139 + Events(LiteLoader loader, Minecraft minecraft, PluginChannels pluginChannels)
133 140 {
134 141 this.loader = loader;
135 142 this.minecraft = minecraft;
... ... @@ -405,9 +412,9 @@ public class Events implements IPlayerUsage
405 412 /**
406 413 * Late initialisation callback
407 414 */
408   - public void onInit()
  415 + public void preBeginGame()
409 416 {
410   - this.loader.refreshResources();
  417 + this.loader.preInitMods();
411 418  
412 419 if (!this.lateInitDone)
413 420 {
... ... @@ -427,7 +434,7 @@ public class Events implements IPlayerUsage
427 434 }
428 435 }
429 436  
430   - this.loader.onInit();
  437 + this.loader.preBeginGame();
431 438 }
432 439  
433 440 /**
... ...
java/com/mumfrey/liteloader/core/LiteLoader.java
1 1 package com.mumfrey.liteloader.core;
2 2  
3   -import java.io.*;
4   -import java.lang.reflect.Field;
5   -import java.net.MalformedURLException;
6   -import java.net.URISyntaxException;
7   -import java.net.URL;
8   -import java.net.URLDecoder;
  3 +import java.io.File;
  4 +import java.io.FileReader;
  5 +import java.io.FileWriter;
  6 +import java.io.IOException;
  7 +import java.io.PrintStream;
9 8 import java.util.ArrayList;
10 9 import java.util.Arrays;
11 10 import java.util.Collections;
... ... @@ -14,23 +13,12 @@ import java.util.Iterator;
14 13 import java.util.LinkedList;
15 14 import java.util.List;
16 15 import java.util.Map;
17   -import java.util.Map.Entry;
18 16 import java.util.Properties;
19   -import java.util.TreeSet;
20   -import java.util.jar.Attributes;
21   -import java.util.jar.JarFile;
22   -import java.util.logging.FileHandler;
23   -import java.util.logging.Formatter;
24 17 import java.util.logging.Level;
25 18 import java.util.logging.Logger;
26   -import java.util.logging.StreamHandler;
27   -import java.util.zip.ZipEntry;
28   -import java.util.zip.ZipFile;
29   -import java.util.zip.ZipInputStream;
30 19  
31 20 import javax.activity.InvalidActivityException;
32 21  
33   -import net.minecraft.client.ClientBrandRetriever;
34 22 import net.minecraft.launchwrapper.LaunchClassLoader;
35 23 import net.minecraft.src.CrashReport;
36 24 import net.minecraft.src.GuiControls;
... ... @@ -43,9 +31,9 @@ import net.minecraft.src.ResourcePack;
43 31 import net.minecraft.src.SimpleReloadableResourceManager;
44 32  
45 33 import com.mumfrey.liteloader.*;
  34 +import com.mumfrey.liteloader.crashreport.CallableLiteLoaderBrand;
  35 +import com.mumfrey.liteloader.crashreport.CallableLiteLoaderMods;
46 36 import com.mumfrey.liteloader.gui.GuiControlsPaginated;
47   -import com.mumfrey.liteloader.launch.LiteLoaderTweaker;
48   -import com.mumfrey.liteloader.log.LiteLoaderLogFormatter;
49 37 import com.mumfrey.liteloader.permissions.PermissionsManagerClient;
50 38 import com.mumfrey.liteloader.util.PrivateFields;
51 39  
... ... @@ -54,21 +42,11 @@ import com.mumfrey.liteloader.util.PrivateFields;
54 42 * lightweight mods
55 43 *
56 44 * @author Adam Mummery-Smith
57   - * @version 1.6.4_01
  45 + * @version 1.6.4_02
58 46 */
59   -public final class LiteLoader implements FilenameFilter
  47 +public final class LiteLoader
60 48 {
61 49 /**
62   - * Liteloader version
63   - */
64   - private static final LiteLoaderVersion VERSION = LiteLoaderVersion.MC_1_6_4_R1;
65   -
66   - /**
67   - * Maximum recursion depth for mod discovery
68   - */
69   - private static final int MAX_DISCOVERY_DEPTH = 16;
70   -
71   - /**
72 50 * LiteLoader is a singleton, this is the singleton instance
73 51 */
74 52 private static LiteLoader instance;
... ... @@ -79,26 +57,6 @@ public final class LiteLoader implements FilenameFilter
79 57 private static final Logger logger = Logger.getLogger("liteloader");
80 58  
81 59 /**
82   - * Use stdout rather than stderr
83   - */
84   - private static boolean useStdOut = false;
85   -
86   - /**
87   - * Game dir from launcher
88   - */
89   - private static File gameDirectory;
90   -
91   - /**
92   - * Assets dir from launcher
93   - */
94   - private static File assetsDirectory;
95   -
96   - /**
97   - * Profile name from launcher
98   - */
99   - private static String profile = "";
100   -
101   - /**
102 60 * Tweak system class loader
103 61 */
104 62 private static LaunchClassLoader classLoader;
... ... @@ -135,51 +93,25 @@ public final class LiteLoader implements FilenameFilter
135 93 private File enabledModsFile;
136 94  
137 95 /**
138   - * File to write log entries to
139   - */
140   - private File logFile;
141   -
142   - /**
143 96 * Reference to the Minecraft game instance
144 97 */
145 98 private Minecraft minecraft;
146 99  
147 100 /**
148   - * File containing the properties
149   - */
150   - private File propertiesFile;
151   -
152   - /**
153   - * Internal properties loaded from inside the jar
154   - */
155   - private Properties internalProperties = new Properties();
156   -
157   - /**
158   - * LiteLoader properties
159   - */
160   - private Properties localProperties = new Properties();
161   -
162   - /**
163   - * Pack brand from properties, used to put the modpack/compilation name in
164   - * crash reports
165   - */
166   - private String branding = null;
167   -
168   - /**
169 101 * Setting value, if true we will swap out the MC "Controls" GUI for our
170 102 * custom, paginated one
171 103 */
172 104 private boolean paginateControls = true;
173 105  
174 106 /**
175   - * Classes to load, mapped by class name
  107 + * Loader Bootstrap instance
176 108 */
177   - private final Map<String, Class<? extends LiteMod>> modsToLoad = new HashMap<String, Class<? extends LiteMod>>();
  109 + private final LiteLoaderBootstrap bootstrap;
178 110  
179 111 /**
180   - * Mod metadata from version file
  112 + * Mod enumerator instance
181 113 */
182   - private final Map<String, ModFile> modFiles = new HashMap<String, ModFile>();
  114 + private final LiteLoaderEnumerator enumerator;
183 115  
184 116 /**
185 117 * Registered resource packs
... ... @@ -224,7 +156,7 @@ public final class LiteLoader implements FilenameFilter
224 156 /**
225 157 * Flag which keeps track of whether late initialisation has been done
226 158 */
227   - private boolean preInitStarted, preInitCompleted, postInitStarted, startupComplete;
  159 + private boolean postInitStarted, startupComplete;
228 160  
229 161 /**
230 162 * True while initialising mods if we need to do a resource manager reload once the process is completed
... ... @@ -263,20 +195,6 @@ public final class LiteLoader implements FilenameFilter
263 195 private Map<KeyBinding, Integer> storedModKeyBindings = new HashMap<KeyBinding, Integer>();
264 196  
265 197 /**
266   - * True if liteloader should also search files ending with .zip
267   - */
268   - private boolean readZipFiles = false;
269   -
270   - /**
271   - * True if the loader is allowed to load tweak classes from mod files
272   - */
273   - private final boolean loadTweaks;
274   -
275   - private boolean searchModsFolder = true;
276   - private boolean searchProtectionDomain = true;
277   - private boolean searchClassPath = true;
278   -
279   - /**
280 198 * Pre-init routine, called using reflection by the tweaker
281 199 *
282 200 * @param gameDirectory Game directory passed to the tweaker
... ... @@ -285,26 +203,21 @@ public final class LiteLoader implements FilenameFilter
285 203 * @param modNameFilter List of mod names parsed from the command line
286 204 * @param classLoader LaunchClassLoader
287 205 */
288   - @SuppressWarnings("unused")
289   - private static final void preInit(File gameDirectory, File assetsDirectory, String profile, List<String> modNameFilter, LaunchClassLoader classLoader, boolean loadTweaks)
  206 + static final void init(LiteLoaderBootstrap bootstrap, LiteLoaderEnumerator enumerator, List<String> modNameFilter, LaunchClassLoader classLoader)
290 207 {
291 208 if (LiteLoader.instance == null)
292 209 {
293   - LiteLoader.gameDirectory = gameDirectory;
294   - LiteLoader.assetsDirectory = assetsDirectory;
295   - LiteLoader.profile = profile;
296 210 LiteLoader.classLoader = classLoader;
297 211  
298   - LiteLoader.instance = new LiteLoader(profile, modNameFilter, loadTweaks);
299   - LiteLoader.instance.onPreInit();
  212 + LiteLoader.instance = new LiteLoader(bootstrap, enumerator, modNameFilter);
  213 + LiteLoader.instance.onInit();
300 214 }
301 215 }
302 216  
303 217 /**
304 218 * Post-init routine, initialises and loads mods enumerated in preInit
305 219 */
306   - @SuppressWarnings("unused")
307   - private static final void postInit()
  220 + static final void postInit()
308 221 {
309 222 if (LiteLoader.instance != null)
310 223 {
... ... @@ -318,39 +231,34 @@ public final class LiteLoader implements FilenameFilter
318 231 * @param profile
319 232 * @param modNameFilter
320 233 */
321   - private LiteLoader(String profile, List<String> modNameFilter, boolean loadTweaks)
  234 + private LiteLoader(LiteLoaderBootstrap bootstrap, LiteLoaderEnumerator enumerator, List<String> modNameFilter)
322 235 {
323   - // This valus is passed through from the tweaker, if we are being called pre-startup then this will be true
324   - // since we are starting up early enough to load tweaks. At the moment we can't do this because if we start
325   - // before a name transformer then all hell breaks loose later on. Need to split the mod enumeration into a separate
326   - // class before this is likely to work as intended.
327   - this.loadTweaks = loadTweaks;
328   -
329   - this.initPaths();
  236 + this.bootstrap = bootstrap;
  237 + this.enumerator = enumerator;
  238 +
  239 + this.setupPaths(bootstrap);
330 240  
331 241 this.enabledModsList = EnabledModsList.createFrom(this.enabledModsFile);
332   - this.enabledModsList.processModsList(profile, modNameFilter);
  242 + this.enabledModsList.processModsList(bootstrap.getProfile(), modNameFilter);
333 243 }
334 244  
335 245 /**
336 246 * Set up paths used by the loader
337 247 */
338   - private void initPaths()
  248 + private void setupPaths(LiteLoaderBootstrap bootstrap)
339 249 {
340   - this.modsFolder = new File(LiteLoader.gameDirectory, "mods");
341   - this.configBaseFolder = new File(LiteLoader.gameDirectory, "liteconfig");
  250 + this.modsFolder = bootstrap.getModsFolder();
  251 + this.configBaseFolder = bootstrap.getConfigBaseFolder();
342 252  
343 253 this.commonConfigFolder = new File(this.configBaseFolder, "common");
344   - this.versionConfigFolder = this.inflectVersionedConfigPath(LiteLoader.VERSION);
  254 + this.versionConfigFolder = this.inflectVersionedConfigPath(LiteLoaderBootstrap.VERSION);
345 255  
346 256 if (!this.modsFolder.exists()) this.modsFolder.mkdirs();
347 257 if (!this.configBaseFolder.exists()) this.configBaseFolder.mkdirs();
348 258 if (!this.commonConfigFolder.exists()) this.commonConfigFolder.mkdirs();
349 259 if (!this.versionConfigFolder.exists()) this.versionConfigFolder.mkdirs();
350 260  
351   - this.propertiesFile = new File(this.configBaseFolder, "liteloader.properties");
352 261 this.enabledModsFile = new File(this.configBaseFolder, "liteloader.profiles.json");
353   - this.logFile = new File(this.configBaseFolder, "liteloader.log");
354 262 this.keyMapSettingsFile = new File(this.configBaseFolder, "liteloader.keys.properties");
355 263 }
356 264  
... ... @@ -358,7 +266,7 @@ public final class LiteLoader implements FilenameFilter
358 266 * @param version
359 267 * @return
360 268 */
361   - protected File inflectVersionedConfigPath(LiteLoaderVersion version)
  269 + private File inflectVersionedConfigPath(LiteLoaderVersion version)
362 270 {
363 271 if (version.equals(LiteLoaderVersion.LEGACY))
364 272 {
... ... @@ -367,45 +275,40 @@ public final class LiteLoader implements FilenameFilter
367 275  
368 276 return new File(this.configBaseFolder, String.format("config.%s", version.getMinecraftVersion()));
369 277 }
370   -
  278 +
371 279 /**
372   - * Loader initialisation
  280 + * Set up reflection methods required by the loader
373 281 */
374   - private void onPreInit()
  282 + private boolean onInit()
375 283 {
376   - if (this.preInitStarted) return;
377   - this.preInitStarted = true;
378   -
379   - // Set up loader, initialises any reflection methods needed
380   - if (this.prepareLoader())
  284 + try
381 285 {
382   - LiteLoader.logInfo("LiteLoader %s starting up...", VERSION.getLoaderVersion());
383   -
384   - // Print the branding version if any was provided
385   - if (this.branding != null)
  286 + if (this.keyMapSettingsFile.exists())
386 287 {
387   - LiteLoader.logInfo("Active Pack: %s", this.branding);
  288 + try
  289 + {
  290 + this.keyMapSettings.load(new FileReader(this.keyMapSettingsFile));
  291 + }
  292 + catch (Exception ex) {}
388 293 }
389 294  
390   - LiteLoader.logInfo("Java reports OS=\"%s\"", System.getProperty("os.name").toLowerCase());
391   -
392   - // Read the discovery settings from the properties
393   - this.prepareDiscoverySettings();
  295 + this.paginateControls = this.bootstrap.getAndStoreBooleanProperty("controls.pages", true);
  296 + this.inhibitSoundManagerReload = this.bootstrap.getAndStoreBooleanProperty("soundManagerFix", true);
394 297  
395   - // Examines the class path and mods folder and locates loadable mods
396   - this.discoverMods();
397   -
398   - // Set the loader branding in ClientBrandRetriever using reflection
399   - this.setBranding("LiteLoader");
400   -
401   - LiteLoader.logInfo("LiteLoader PreInit completed");
402   - this.preInitCompleted = true;
  298 + this.enumerator.discoverModClasses();
  299 + }
  300 + catch (Throwable th)
  301 + {
  302 + LiteLoader.getLogger().log(Level.SEVERE, "Error initialising LiteLoader", th);
  303 + return false;
403 304 }
  305 +
  306 + return true;
404 307 }
405 308  
406 309 private void onPostInit(Minecraft minecraft)
407 310 {
408   - if (!this.preInitCompleted || this.postInitStarted) return;
  311 + if (this.postInitStarted) return;
409 312 this.postInitStarted = true;
410 313  
411 314 // Cache local minecraft reference
... ... @@ -425,178 +328,11 @@ public final class LiteLoader implements FilenameFilter
425 328 this.startupComplete = true;
426 329  
427 330 this.enabledModsList.saveTo(this.enabledModsFile);
428   - this.writeProperties();
429   - }
430   -
431   - /**
432   - * Set up reflection methods required by the loader
433   - */
434   - private boolean prepareLoader()
435   - {
436   - try
437   - {
438   - // Prepare the properties
439   - this.prepareProperties();
440   -
441   - // Prepare the log writer
442   - this.prepareLogger();
443   -
444   - this.paginateControls = this.localProperties.getProperty("controls.pages", "true").equalsIgnoreCase("true");
445   - this.localProperties.setProperty("controls.pages", String.valueOf(this.paginateControls));
446   -
447   - this.inhibitSoundManagerReload = this.localProperties.getProperty("soundManagerFix", "true").equalsIgnoreCase("true");
448   - this.localProperties.setProperty("soundManagerFix", String.valueOf(this.inhibitSoundManagerReload));
449   -
450   - this.branding = this.internalProperties.getProperty("brand", null);
451   - if (this.branding != null && this.branding.length() < 1)
452   - this.branding = null;
453   -
454   - // Save appropriate branding in the local properties file
455   - if (this.branding != null)
456   - this.localProperties.setProperty("brand", this.branding);
457   - else
458   - this.localProperties.remove("brand");
459   -
460   - }
461   - catch (Throwable th)
462   - {
463   - LiteLoader.getLogger().log(Level.SEVERE, "Error initialising LiteLoader", th);
464   - return false;
465   - }
466   -
467   - return true;
468   - }
469   -
470   - /**
471   - * @throws SecurityException
472   - * @throws IOException
473   - */
474   - private void prepareLogger() throws SecurityException, IOException
475   - {
476   - Formatter logFormatter = new LiteLoaderLogFormatter();
477   -
478   - LiteLoader.logger.setUseParentHandlers(false);
479   - LiteLoader.useStdOut = System.getProperty("liteloader.log", "stderr").equalsIgnoreCase("stdout") || this.localProperties.getProperty("log", "stderr").equalsIgnoreCase("stdout");
480   -
481   - StreamHandler consoleHandler = useStdOut ? new com.mumfrey.liteloader.util.log.ConsoleHandler() : new java.util.logging.ConsoleHandler();
482   - consoleHandler.setFormatter(logFormatter);
483   - LiteLoader.logger.addHandler(consoleHandler);
484   -
485   - FileHandler logFileHandler = new FileHandler(this.logFile.getAbsolutePath());
486   - logFileHandler.setFormatter(logFormatter);
487   - LiteLoader.logger.addHandler(logFileHandler);
488   - }
489   -
490   - /**
491   - * Prepare the loader properties
492   - */
493   - private void prepareProperties()
494   - {
495   - try
496   - {
497   - InputStream propertiesStream = LiteLoader.class.getResourceAsStream("/liteloader.properties");
498   -
499   - if (propertiesStream != null)
500   - {
501   - this.internalProperties.load(propertiesStream);
502   - propertiesStream.close();
503   - }
504   - }
505   - catch (Throwable th)
506   - {
507   - this.internalProperties = new Properties();
508   - }
509   -
510   - try
511   - {
512   - this.localProperties = new Properties(this.internalProperties);
513   - InputStream localPropertiesStream = this.getLocalPropertiesStream();
514   -
515   - if (localPropertiesStream != null)
516   - {
517   - this.localProperties.load(localPropertiesStream);
518   - localPropertiesStream.close();
519   - }
520   - }
521   - catch (Throwable th)
522   - {
523   - this.localProperties = new Properties(this.internalProperties);
524   - }
525   -
526   - if (this.keyMapSettingsFile.exists())
527   - {
528   - try
529   - {
530   - this.keyMapSettings.load(new FileReader(this.keyMapSettingsFile));
531   - }
532   - catch (Exception ex) {}
533   - }
534   - }
535   -
536   - /**
537   - *
538   - */
539   - public void prepareDiscoverySettings()
540   - {
541   - this.readZipFiles = this.localProperties.getProperty("search.zips", "false").equalsIgnoreCase("true");
542   - this.searchModsFolder = this.localProperties.getProperty("search.mods", "true").equalsIgnoreCase("true");
543   - this.searchProtectionDomain = this.localProperties.getProperty("search.jar", "true").equalsIgnoreCase("true");
544   - this.searchClassPath = this.localProperties.getProperty("search.classpath", "true").equalsIgnoreCase("true");
545   -
546   - if (!this.searchModsFolder && !this.searchProtectionDomain && !this.searchClassPath)
547   - {
548   - LiteLoader.logWarning("Invalid configuration, no search locations defined. Enabling all search locations.");
549   -
550   - this.searchModsFolder = true;
551   - this.searchProtectionDomain = true;
552   - this.searchClassPath = true;
553   - }
554   -
555   - this.localProperties.setProperty("search.zips", String.valueOf(this.readZipFiles));
556   - this.localProperties.setProperty("search.mods", String.valueOf(this.searchModsFolder));
557   - this.localProperties.setProperty("search.jar", String.valueOf(this.searchProtectionDomain));
558   - this.localProperties.setProperty("search.classpath", String.valueOf(this.searchClassPath));
559   - }
560   -
561   - /**
562   - * Get the properties stream either from the jar or from the properties file
563   - * in the minecraft folder
564   - *
565   - * @return
566   - * @throws FileNotFoundException
567   - */
568   - private InputStream getLocalPropertiesStream() throws FileNotFoundException
569   - {
570   - if (this.propertiesFile.exists())
571   - {
572   - return new FileInputStream(this.propertiesFile);
573   - }
574   -
575   - // Otherwise read settings from the config
576   - return LiteLoader.class.getResourceAsStream("/liteloader.properties");
577   - }
578   -
579   - /**
580   - * Write current properties to the properties file
581   - */
582   - private void writeProperties()
583   - {
584   - try
585   - {
586   - this.localProperties.store(new FileWriter(this.propertiesFile), String.format("Properties for LiteLoader %s", VERSION));
587   - }
588   - catch (Throwable th)
589   - {
590   - LiteLoader.getLogger().log(Level.WARNING, "Error writing liteloader properties", th);
591   - }
  331 + this.bootstrap.writeProperties();
592 332 }
593 333  
594   - /**
595   - * Register a
596   - *
597   - * @param name
598   - * @param resourcePack
599   - * @return
  334 + /* (non-Javadoc)
  335 + * @see com.mumfrey.liteloader.core.ICustomResourcePackManager#registerModResourcePack(net.minecraft.src.ResourcePack)
600 336 */
601 337 public boolean registerModResourcePack(ResourcePack resourcePack)
602 338 {
... ... @@ -616,9 +352,8 @@ public final class LiteLoader implements FilenameFilter
616 352 return false;
617 353 }
618 354  
619   - /**
620   - * @param name
621   - * @return
  355 + /* (non-Javadoc)
  356 + * @see com.mumfrey.liteloader.core.ICustomResourcePackManager#unRegisterModResourcePack(net.minecraft.src.ResourcePack)
622 357 */
623 358 public boolean unRegisterModResourcePack(ResourcePack resourcePack)
624 359 {
... ... @@ -674,7 +409,7 @@ public final class LiteLoader implements FilenameFilter
674 409 */
675 410 public static final PrintStream getConsoleStream()
676 411 {
677   - return LiteLoader.useStdOut ? System.out : System.err;
  412 + return LiteLoaderBootstrap.getConsoleStream();
678 413 }
679 414  
680 415 /**
... ... @@ -684,7 +419,7 @@ public final class LiteLoader implements FilenameFilter
684 419 */
685 420 public static final String getVersion()
686 421 {
687   - return LiteLoader.VERSION.getLoaderVersion();
  422 + return LiteLoaderBootstrap.VERSION.getLoaderVersion();
688 423 }
689 424  
690 425 /**
... ... @@ -694,7 +429,7 @@ public final class LiteLoader implements FilenameFilter
694 429 */
695 430 public static final int getRevision()
696 431 {
697   - return LiteLoader.VERSION.getLoaderRevision();
  432 + return LiteLoaderBootstrap.VERSION.getLoaderRevision();
698 433 }
699 434  
700 435 /**
... ... @@ -754,7 +489,7 @@ public final class LiteLoader implements FilenameFilter
754 489 */
755 490 public static File getGameDirectory()
756 491 {
757   - return LiteLoader.gameDirectory;
  492 + return LiteLoader.getInstance().bootstrap.getGameDirectory();
758 493 }
759 494  
760 495 /**
... ... @@ -762,7 +497,7 @@ public final class LiteLoader implements FilenameFilter
762 497 */
763 498 public static File getAssetsDirectory()
764 499 {
765   - return LiteLoader.assetsDirectory;
  500 + return LiteLoader.getInstance().bootstrap.getAssetsDirectory();
766 501 }
767 502  
768 503 /**
... ... @@ -770,7 +505,7 @@ public final class LiteLoader implements FilenameFilter
770 505 */
771 506 public static String getProfile()
772 507 {
773   - return LiteLoader.profile;
  508 + return LiteLoader.getInstance().bootstrap.getProfile();
774 509 }
775 510  
776 511 /**
... ... @@ -806,7 +541,7 @@ public final class LiteLoader implements FilenameFilter
806 541 */
807 542 public String getBranding()
808 543 {
809   - return this.branding;
  544 + return this.bootstrap.getBranding();
810 545 }
811 546  
812 547 /**
... ... @@ -827,37 +562,6 @@ public final class LiteLoader implements FilenameFilter
827 562 }
828 563  
829 564 /**
830   - * Store current revision for mod in the config file
831   - *
832   - * @param modKey
833   - */
834   - private void storeLastKnownModRevision(String modKey)
835   - {
836   - if (this.localProperties != null)
837   - {
838   - this.localProperties.setProperty(modKey, String.valueOf(LiteLoader.VERSION.getLoaderRevision()));
839   - this.writeProperties();
840   - }
841   - }
842   -
843   - /**
844   - * Get last know revision for mod from the config file
845   - *
846   - * @param modKey
847   - * @return
848   - */
849   - private int getLastKnownModRevision(String modKey)
850   - {
851   - if (this.localProperties != null)
852   - {
853   - String storedRevision = this.localProperties.getProperty(modKey, "0");
854   - return Integer.parseInt(storedRevision);
855   - }
856   -
857   - return 0;
858   - }
859   -
860   - /**
861 565 * Get a reference to a loaded mod, if the mod exists
862 566 *
863 567 * @param modName Mod's name or class name
... ... @@ -954,7 +658,7 @@ public final class LiteLoader implements FilenameFilter
954 658 public String getModMetaData(LiteMod mod, String metaDataKey, String defaultValue)
955 659 {
956 660 if (mod == null || metaDataKey == null) return defaultValue;
957   - return this.getModMetaData(mod.getClass(), metaDataKey, defaultValue);
  661 + return this.enumerator.getModMetaData(mod.getClass(), metaDataKey, defaultValue);
958 662 }
959 663  
960 664 /**
... ... @@ -967,17 +671,7 @@ public final class LiteLoader implements FilenameFilter
967 671 */
968 672 public String getModMetaData(Class<? extends LiteMod> modClass, String metaDataKey, String defaultValue)
969 673 {
970   - ModFile modFile = this.getModFile(modClass);
971   - return modFile != null ? modFile.getMetaValue(metaDataKey, defaultValue) : defaultValue;
972   - }
973   -
974   - /**
975   - * @param mod
976   - * @return
977   - */
978   - private ModFile getModFile(Class<? extends LiteMod> modClass)
979   - {
980   - return this.modFiles.get(modClass.getSimpleName());
  674 + return this.enumerator.getModMetaData(modClass, metaDataKey, defaultValue);
981 675 }
982 676  
983 677 /**
... ... @@ -988,466 +682,83 @@ public final class LiteLoader implements FilenameFilter
988 682 */
989 683 public String getModMetaName(Class<? extends LiteMod> modClass)
990 684 {
991   - String modClassName = modClass.getSimpleName();
992   - if (!this.modFiles.containsKey(modClassName)) return null;
993   - return this.modFiles.get(modClassName).getModName().toLowerCase();
  685 + return this.enumerator.getModMetaName(modClass);
994 686 }
995 687  
996 688 /**
997   - * Enumerate the java class path and "mods" folder to find mod classes, then
998   - * load the classes
  689 + * Create mod instances from the enumerated classes
  690 + *
  691 + * @param modsToLoad List of mods to load
999 692 */
1000   - private void discoverMods()
  693 + private void loadMods()
1001 694 {
1002   - // List of mod files in the "mods" folder
1003   - List<ModFile> modFiles = new LinkedList<ModFile>();
1004   -
1005   - if (this.searchModsFolder)
1006   - {
1007   - // Find and enumerate the "mods" folder
1008   - File modFolder = LiteLoader.getModsFolder();
1009   - if (modFolder.exists() && modFolder.isDirectory())
1010   - {
1011   - LiteLoader.logInfo("Mods folder found, searching %s", modFolder.getPath());
1012   - this.findModFiles(modFolder, modFiles);
1013   - LiteLoader.logInfo("Found %d mod file(s)", modFiles.size());
1014   - }
1015   - }
1016   -
1017   - try
1018   - {
1019   - LiteLoader.logInfo("Enumerating class path...");
1020   -
1021   - String classPath = System.getProperty("java.class.path");
1022   - String classPathSeparator = System.getProperty("path.separator");
1023   - String[] classPathEntries = classPath.split(classPathSeparator);
1024   -
1025   - LiteLoader.logInfo("Class path separator=\"%s\"", classPathSeparator);
1026   - LiteLoader.logInfo("Class path entries=(\n classpathEntry=%s\n)", classPath.replace(classPathSeparator, "\n classpathEntry="));
1027   -
1028   - if (this.searchProtectionDomain || this.searchClassPath)
1029   - LiteLoader.logInfo("Discovering mods on class path...");
1030   -
1031   - this.findModClasses(modFiles, classPathEntries);
1032   -
1033   - LiteLoader.logInfo("Mod class discovery completed");
1034   - }
1035   - catch (Throwable th)
  695 + if (!this.enumerator.hasModsToLoad())
1036 696 {
1037   - LiteLoader.getLogger().log(Level.WARNING, "Mod class discovery failed", th);
  697 + LiteLoader.logInfo("Mod class discovery failed or no mod classes were found. Not loading any mods.");
1038 698 return;
1039 699 }
1040   - }
1041   -
1042   - /**
1043   - * Find mod files in the "mods" folder
1044   - *
1045   - * @param modFolder Folder to search
1046   - * @param modFiles List of mod files to load
1047   - */
1048   - protected void findModFiles(File modFolder, List<ModFile> modFiles)
1049   - {
1050   - Map<String, TreeSet<ModFile>> versionOrderingSets = new HashMap<String, TreeSet<ModFile>>();
1051 700  
1052   - for (File modFile : modFolder.listFiles(this))
  701 + LiteLoader.logInfo("Discovered %d total mod(s)", this.enumerator.modsToLoadCount());
  702 +
  703 + this.pendingResourceReload = false;
  704 + this.soundManagerReloadInhibitor = new SoundManagerReloadInhibitor((SimpleReloadableResourceManager)this.minecraft.getResourceManager(), this.minecraft.sndManager);
  705 + if (this.inhibitSoundManagerReload) this.soundManagerReloadInhibitor.inhibit();
  706 +
  707 + for (Class<? extends LiteMod> mod : this.enumerator.getModsToLoad())
1053 708 {
1054 709 try
1055 710 {
1056   - String strVersion = null;
1057   -
1058   - // Check for a version file
1059   - ZipFile modZip = new ZipFile(modFile);
1060   - ZipEntry version = modZip.getEntry("litemod.json");
1061   -
1062   - // Not supporting this past 1.6.2
1063   -// if (version == null)
1064   -// {
1065   -// version = modZip.getEntry("version.txt");
1066   -// }
1067   -
1068   - if (version != null)
  711 + String metaName = this.getModMetaName(mod);
  712 + if (metaName == null || this.enabledModsList.isEnabled(this.bootstrap.getProfile(), metaName))
1069 713 {
1070   - BufferedReader versionReader = null;
1071   - StringBuilder versionBuilder = new StringBuilder();
  714 + LiteLoader.logInfo("Loading mod from %s", mod.getName());
1072 715  
1073   - try
1074   - {
1075   - // Read the version string
1076   - InputStream versionStream = modZip.getInputStream(version);
1077   - versionReader = new BufferedReader(new InputStreamReader(versionStream));
1078   -
1079   - String versionFileLine;
1080   - while ((versionFileLine = versionReader.readLine()) != null)
1081   - versionBuilder.append(versionFileLine);
1082   -
1083   - strVersion = versionBuilder.toString();
1084   - }
1085   - catch (Exception ex)
1086   - {
1087   - LiteLoader.logWarning("Error reading version data from %s", modFile.getName());
1088   - }
1089   - finally
1090   - {
1091   - if (versionReader != null) versionReader.close();
1092   - }
  716 + LiteMod newMod = mod.newInstance();
  717 +
  718 + this.mods.add(newMod);
  719 + String modName = newMod.getName();
  720 + if (modName == null && metaName != null) modName = metaName;
  721 + LiteLoader.logInfo("Successfully added mod %s version %s", modName, newMod.getVersion());
1093 722  
1094   - if (strVersion != null)
  723 + // Get the mod file and register it as a resource pack if it exists
  724 + ModFile modFile = this.enumerator.getModFile(mod);
  725 + if (modFile != null)
1095 726 {
1096   - ModFile modFileInfo = new ModFile(modFile, strVersion);
  727 + this.disabledMods.remove(modFile);
1097 728  
1098   - if (modFileInfo.isValid())
  729 + LiteLoader.logInfo("Adding \"%s\" to active resource pack set", modFile.getAbsolutePath());
  730 + if (modName != null && modFile.canRegisterAsResourcePack(modName))
1099 731 {
1100   - // Only add the mod if the version matches and we were able
1101   - // to successfully add it to the class path
1102   - if (LiteLoader.VERSION.isVersionSupported(modFileInfo.getVersion()))
1103   - {
1104   -// if (!modFileInfo.isJson())
1105   -// {
1106   -// LiteLoader.logWarning("Missing or invalid litemod.json reading mod file: %s", modFile.getAbsolutePath());
1107   -// }
1108   -
1109   - if (!versionOrderingSets.containsKey(modFileInfo.getName()))
1110   - {
1111   - versionOrderingSets.put(modFileInfo.getModName(), new TreeSet<ModFile>());
1112   - }
1113   -
1114   - LiteLoader.logInfo("Considering valid mod file: %s", modFileInfo.getAbsolutePath());
1115   - versionOrderingSets.get(modFileInfo.getModName()).add(modFileInfo);
1116   - }
1117   - else
  732 + if (this.registerModResourcePack((ResourcePack)modFile.getResourcePack()))
1118 733 {
1119   - LiteLoader.logInfo("Not adding invalid or outdated mod file: %s", modFile.getAbsolutePath());
  734 + LiteLoader.logInfo("Successfully added \"%s\" to active resource pack set", modFile.getAbsolutePath());
1120 735 }
1121 736 }
1122 737 }
1123 738 }
1124 739 else
1125 740 {
1126   - ZipEntry legacyVersion = modZip.getEntry("version.txt");
1127   - if (legacyVersion != null)
1128   - {
1129   - LiteLoader.logWarning("version.txt is no longer supported, ignoring outdated mod file: %s", modFile.getAbsolutePath());
1130   - }
  741 + LiteLoader.logInfo("Not loading mod %s, excluded by filter", metaName);
  742 + this.disabledMods.add(this.enumerator.getModFile(mod));
1131 743 }
1132   -
1133   - modZip.close();
1134 744 }
1135   - catch (Exception ex)
  745 + catch (Throwable th)
1136 746 {
1137   - ex.printStackTrace(System.err);
1138   - LiteLoader.logInfo("Error enumerating '%s': Invalid zip file or error reading file", modFile.getAbsolutePath());
  747 + th.printStackTrace(System.out);
  748 + LiteLoader.getLogger().log(Level.WARNING, String.format("Error loading mod from %s", mod.getName()), th);
1139 749 }
1140 750 }
  751 + }
1141 752  
1142   - // Copy the first entry in every version set into the modfiles list
1143   - for (Entry<String, TreeSet<ModFile>> modFileEntry : versionOrderingSets.entrySet())
1144   - {
1145   - ModFile newestVersion = modFileEntry.getValue().iterator().next();
1146   -
1147   - try
1148   - {
1149   - LiteLoader.logInfo("Adding newest valid mod file '%s' at revision %.4f: ", newestVersion.getAbsolutePath(), newestVersion.getRevision());
1150   -
1151   - LiteLoader.classLoader.addURL(newestVersion.toURI().toURL());
1152   - modFiles.add(newestVersion);
1153   - }
1154   - catch (Exception ex)
1155   - {
1156   - LiteLoader.logWarning("Error injecting '%s' into classPath. The mod will not be loaded", newestVersion.getAbsolutePath());
1157   - }
1158   -
1159   - // Tweak load functionality, currently not used
1160   - if (this.loadTweaks)
1161   - {
1162   - try
1163   - {
1164   - this.addTweaksFrom(newestVersion);
1165   - }
1166   - catch (Throwable th)
1167   - {
1168   - LiteLoader.logWarning("Error adding tweaks from '%s'", newestVersion.getAbsolutePath());
1169   - }
1170   - }
1171   - }
1172   - }
1173   -
1174   - /*
1175   - * (non-Javadoc)
1176   - *
1177   - * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
1178   - */
1179   - @Override
1180   - public boolean accept(File dir, String fileName)
1181   - {
1182   - fileName = fileName.toLowerCase();
1183   - return fileName.endsWith(".litemod") || (this.readZipFiles && (fileName.endsWith(".zip") || fileName.endsWith(".jar")));
1184   - }
1185   -
1186   - /**
1187   - * @param modFile
1188   - * @throws IOException
1189   - */
1190   - private void addTweaksFrom(ModFile modFile)
1191   - {
1192   - JarFile jar = null;
1193   -
1194   - LiteLoader.logInfo("Adding tweaks from file '%s'", modFile.getName());
1195   - try
1196   - {
1197   - jar = new JarFile(modFile);
1198   - Attributes manifestAttributes = jar.getManifest().getMainAttributes();
1199   -
1200   - String tweakClass = manifestAttributes.getValue("TweakClass");
1201   - if (tweakClass != null)
1202   - {
1203   - LiteLoader.logInfo("Mod file '%s' provides tweakClass '%s', adding to Launch queue", modFile.getName(), tweakClass);
1204   -
1205   - if (LiteLoaderTweaker.addTweaker(modFile.toURI().toURL(), tweakClass))
1206   - {
1207   - LiteLoader.logInfo("tweakClass '%s' was successfully added", tweakClass);
1208   - }
1209   - }
1210   -
1211   - String classPath = manifestAttributes.getValue("Class-Path");
1212   - if (classPath != null)
1213   - {
1214   - String[] classPathEntries = classPath.split(" ");
1215   - for (String classPathEntry : classPathEntries)
1216   - {
1217   - File classPathJar = new File(LiteLoader.gameDirectory, classPathEntry);
1218   - URL jarUrl = classPathJar.toURI().toURL();
1219   -
1220   - LiteLoader.logInfo("Adding Class-Path entry: %s", classPathEntry);
1221   - LiteLoaderTweaker.addURLToParentClassLoader(jarUrl);
1222   - LiteLoader.classLoader.addURL(jarUrl);
1223   - }
1224   - }
1225   - }
1226   - catch (Exception ex)
1227   - {
1228   - LiteLoader.logWarning("Error parsing tweak class manifest entry in '%s'", modFile.getAbsolutePath());
1229   - }
1230   - finally
1231   - {
1232   - try
1233   - {
1234   - if (jar != null) jar.close();
1235   - }
1236   - catch (IOException ex) {}
1237   - }
1238   - }
1239   -
1240   - /**
1241   - * Find mod classes in the class path and enumerated mod files list
1242   - * @param classPathEntries Java class path split into string entries
1243   - */
1244   - private void findModClasses(List<ModFile> modFiles, String[] classPathEntries)
1245   - {
1246   - if (this.searchProtectionDomain)
1247   - {
1248   - try
1249   - {
1250   - this.searchProtectionDomain();
1251   - }
1252   - catch (Throwable th)
1253   - {
1254   - LiteLoader.logWarning("Error loading from local class path: %s", th.getMessage());
1255   - }
1256   - }
1257   -
1258   - if (this.searchClassPath)
1259   - {
1260   - // Search through the class path and find mod classes
1261   - this.searchClassPath(classPathEntries);
1262   - }
1263   -
1264   - // Search through mod files and find mod classes
1265   - this.searchModFiles(modFiles);
1266   - }
1267   -
1268   - /**
1269   - * @param modsToLoad
1270   - * @throws MalformedURLException
1271   - * @throws URISyntaxException
1272   - * @throws UnsupportedEncodingException
1273   - */
1274   - @SuppressWarnings("unchecked")
1275   - private void searchProtectionDomain() throws MalformedURLException, URISyntaxException, UnsupportedEncodingException
1276   - {
1277   - LiteLoader.logInfo("Searching protection domain code source...");
1278   -
1279   - File packagePath = null;
1280   -
1281   - URL protectionDomainLocation = LiteLoader.class.getProtectionDomain().getCodeSource().getLocation();
1282   - if (protectionDomainLocation != null)
1283   - {
1284   - if (protectionDomainLocation.toString().indexOf('!') > -1 && protectionDomainLocation.toString().startsWith("jar:"))
1285   - {
1286   - protectionDomainLocation = new URL(protectionDomainLocation.toString().substring(4, protectionDomainLocation.toString().indexOf('!')));
1287   - }
1288   -
1289   - packagePath = new File(protectionDomainLocation.toURI());
1290   - }
1291   - else
1292   - {
1293   - // Fix (?) for forge and other mods which screw up the
1294   - // protection domain
1295   - String reflectionClassPath = LiteLoader.class.getResource("/com/mumfrey/liteloader/core/LiteLoader.class").getPath();
1296   -
1297   - if (reflectionClassPath.indexOf('!') > -1)
1298   - {
1299   - reflectionClassPath = URLDecoder.decode(reflectionClassPath, "UTF-8");
1300   - packagePath = new File(reflectionClassPath.substring(5, reflectionClassPath.indexOf('!')));
1301   - }
1302   - }
1303   -
1304   - if (packagePath != null)
1305   - {
1306   - LinkedList<Class<?>> modClasses = getSubclassesFor(packagePath, LiteLoader.classLoader, LiteMod.class, "LiteMod");
1307   -
1308   - for (Class<?> mod : modClasses)
1309   - {
1310   - if (this.modsToLoad.containsKey(mod.getSimpleName()))
1311   - {
1312   - LiteLoader.logWarning("Mod name collision for mod with class '%s', maybe you have more than one copy?", mod.getSimpleName());
1313   - }
1314   -
1315   - this.modsToLoad.put(mod.getSimpleName(), (Class<? extends LiteMod>)mod);
1316   - }
1317   -
1318   - if (modClasses.size() > 0)
1319   - LiteLoader.logInfo("Found %s potential matches", modClasses.size());
1320   - }
1321   - }
1322   -
1323   - /**
1324   - * @param classPathEntries
1325   - * @param modsToLoad
1326   - */
1327   - @SuppressWarnings("unchecked")
1328   - private void searchClassPath(String[] classPathEntries)
1329   - {
1330   - for (String classPathPart : classPathEntries)
1331   - {
1332   - LiteLoader.logInfo("Searching %s...", classPathPart);
1333   -
1334   - File packagePath = new File(classPathPart);
1335   - LinkedList<Class<?>> modClasses = getSubclassesFor(packagePath, LiteLoader.classLoader, LiteMod.class, "LiteMod");
1336   -
1337   - for (Class<?> mod : modClasses)
1338   - {
1339   - if (this.modsToLoad.containsKey(mod.getSimpleName()))
1340   - {
1341   - LiteLoader.logWarning("Mod name collision for mod with class '%s', maybe you have more than one copy?", mod.getSimpleName());
1342   - }
1343   -
1344   - this.modsToLoad.put(mod.getSimpleName(), (Class<? extends LiteMod>)mod);
1345   - this.modFiles.put(mod.getSimpleName(), new ClassPathMod(packagePath, mod.getSimpleName().substring(7), LiteLoader.getVersion()));
1346   - }
1347   -
1348   - if (modClasses.size() > 0)
1349   - LiteLoader.logInfo("Found %s potential matches", modClasses.size());
1350   - }
1351   - }
1352   -
1353   - /**
1354   - * @param modFiles
1355   - * @param modsToLoad
1356   - */
1357   - @SuppressWarnings("unchecked")
1358   - private void searchModFiles(List<ModFile> modFiles)
1359   - {
1360   - for (ModFile modFile : modFiles)
1361   - {
1362   - LiteLoader.logInfo("Searching %s...", modFile.getAbsolutePath());
1363   -
1364   - LinkedList<Class<?>> modClasses = LiteLoader.getSubclassesFor(modFile, LiteLoader.classLoader, LiteMod.class, "LiteMod");
1365   -
1366   - for (Class<?> mod : modClasses)
1367   - {
1368   - if (this.modsToLoad.containsKey(mod.getSimpleName()))
1369   - {
1370   - LiteLoader.logWarning("Mod name collision for mod with class '%s', maybe you have more than one copy?", mod.getSimpleName());
1371   - }
1372   -
1373   - this.modsToLoad.put(mod.getSimpleName(), (Class<? extends LiteMod>)mod);
1374   - this.modFiles.put(mod.getSimpleName(), modFile);
1375   - }
1376   -
1377   - if (modClasses.size() > 0)
1378   - LiteLoader.logInfo("Found %s potential matches", modClasses.size());
1379   - }
1380   - }
1381   -
1382   - /**
1383   - * Create mod instances from the enumerated classes
1384   - *
1385   - * @param modsToLoad List of mods to load
1386   - */
1387   - private void loadMods()
1388   - {
1389   - if (this.modsToLoad == null)
1390   - {
1391   - LiteLoader.logInfo("Mod class discovery failed. Not loading any mods!");
1392   - return;
1393   - }
1394   -
1395   - LiteLoader.logInfo("Discovered %d total mod(s)", this.modsToLoad.size());
1396   -
1397   - this.pendingResourceReload = false;
1398   - this.soundManagerReloadInhibitor = new SoundManagerReloadInhibitor((SimpleReloadableResourceManager)this.minecraft.getResourceManager(), this.minecraft.sndManager);
1399   - if (this.inhibitSoundManagerReload) this.soundManagerReloadInhibitor.inhibit();
1400   -
1401   - for (Class<? extends LiteMod> mod : this.modsToLoad.values())
1402   - {
1403   - try
1404   - {
1405   - String metaName = this.getModMetaName(mod);
1406   - if (metaName == null || this.enabledModsList.isEnabled(LiteLoader.profile, metaName))
1407   - {
1408   - LiteLoader.logInfo("Loading mod from %s", mod.getName());
1409   -
1410   - LiteMod newMod = mod.newInstance();
1411   -
1412   - this.mods.add(newMod);
1413   - String modName = newMod.getName();
1414   - if (modName == null && metaName != null) modName = metaName;
1415   - LiteLoader.logInfo("Successfully added mod %s version %s", modName, newMod.getVersion());
1416   -
1417   - // Get the mod file and register it as a resource pack if it exists
1418   - ModFile modFile = this.getModFile(mod);
1419   - if (modFile != null)
1420   - {
1421   - this.disabledMods.remove(modFile);
1422   -
1423   - if (modName != null && modFile.registerAsResourcePack(modName))
1424   - {
1425   - LiteLoader.logInfo("Successfully added \"%s\" to active resource pack set", modFile.getAbsolutePath());
1426   - }
1427   - }
1428   - }
1429   - else
1430   - {
1431   - LiteLoader.logInfo("Not loading mod %s, excluded by filter", metaName);
1432   - this.disabledMods.add(this.getModFile(mod));
1433   - }
1434   - }
1435   - catch (Throwable th)
1436   - {
1437   - LiteLoader.getLogger().log(Level.WARNING, String.format("Error loading mod from %s", mod.getName()), th);
1438   - }
1439   - }
1440   - }
1441   -
1442   - /**
1443   - * Initialise the mods which were loaded
1444   - */
1445   - private void initMods()
1446   - {
1447   - this.loadedModsList = "";
1448   - int loadedModsCount = 0;
1449   -
1450   - for (Iterator<LiteMod> iter = this.mods.iterator(); iter.hasNext();)
  753 + /**
  754 + * Initialise the mods which were loaded
  755 + */
  756 + private void initMods()
  757 + {
  758 + this.loadedModsList = "";
  759 + int loadedModsCount = 0;
  760 +
  761 + for (Iterator<LiteMod> iter = this.mods.iterator(); iter.hasNext();)
1451 762 {
1452 763 LiteMod mod = iter.next();
1453 764 String modName = mod.getName();
... ... @@ -1459,14 +770,14 @@ public final class LiteLoader implements FilenameFilter
1459 770 try
1460 771 {
1461 772 String modKey = this.getModNameForConfig(mod.getClass(), modName);
1462   - LiteLoaderVersion lastModVersion = LiteLoaderVersion.getVersionFromRevision(this.getLastKnownModRevision(modKey));
  773 + LiteLoaderVersion lastModVersion = LiteLoaderVersion.getVersionFromRevision(this.bootstrap.getLastKnownModRevision(modKey));
1463 774  
1464   - if (LiteLoader.VERSION.getLoaderRevision() > lastModVersion.getLoaderRevision())
  775 + if (LiteLoaderBootstrap.VERSION.getLoaderRevision() > lastModVersion.getLoaderRevision())
1465 776 {
1466   - LiteLoader.logInfo("Performing config upgrade for mod %s. Upgrading %s to %s...", modName, lastModVersion, LiteLoader.VERSION);
1467   - mod.upgradeSettings(VERSION.getMinecraftVersion(), this.versionConfigFolder, this.inflectVersionedConfigPath(lastModVersion));
  777 + LiteLoader.logInfo("Performing config upgrade for mod %s. Upgrading %s to %s...", modName, lastModVersion, LiteLoaderBootstrap.VERSION);
  778 + mod.upgradeSettings(LiteLoaderBootstrap.VERSION.getMinecraftVersion(), this.versionConfigFolder, this.inflectVersionedConfigPath(lastModVersion));
1468 779  
1469   - this.storeLastKnownModRevision(modKey);
  780 + this.bootstrap.storeLastKnownModRevision(modKey);
1470 781 LiteLoader.logInfo("Config upgrade succeeded for mod %s", modName);
1471 782 }
1472 783 }
... ... @@ -1500,152 +811,9 @@ public final class LiteLoader implements FilenameFilter
1500 811 }
1501 812  
1502 813 /**
1503   - * Enumerate classes on the classpath which are subclasses of the specified
1504   - * class
1505   - *
1506   - * @param superClass
1507   - * @return
1508   - */
1509   - private static LinkedList<Class<?>> getSubclassesFor(File packagePath, ClassLoader classloader, Class<?> superClass, String prefix)
1510   - {
1511   - LinkedList<Class<?>> classes = new LinkedList<Class<?>>();
1512   -
1513   - try
1514   - {
1515   - if (packagePath.isDirectory())
1516   - {
1517   - enumerateDirectory(prefix, superClass, classloader, classes, packagePath);
1518   - }
1519   - else if (packagePath.isFile() && (packagePath.getName().endsWith(".jar") || packagePath.getName().endsWith(".zip") || packagePath.getName().endsWith(".litemod")))
1520   - {
1521   - enumerateCompressedPackage(prefix, superClass, classloader, classes, packagePath);
1522   - }
1523   - }
1524   - catch (Throwable th)
1525   - {
1526   - LiteLoader.getLogger().log(Level.WARNING, "Enumeration error", th);
1527   - }
1528   -
1529   - return classes;
1530   - }
1531   -
1532   - /**
1533   - * @param superClass
1534   - * @param classloader
1535   - * @param classes
1536   - * @param packagePath
1537   - * @throws FileNotFoundException
1538   - * @throws IOException
1539   - */
1540   - private static void enumerateCompressedPackage(String prefix, Class<?> superClass, ClassLoader classloader, LinkedList<Class<?>> classes, File packagePath) throws FileNotFoundException, IOException
1541   - {
1542   - FileInputStream fileinputstream = new FileInputStream(packagePath);
1543   - ZipInputStream zipinputstream = new ZipInputStream(fileinputstream);
1544   -
1545   - ZipEntry zipentry = null;
1546   -
1547   - do
1548   - {
1549   - zipentry = zipinputstream.getNextEntry();
1550   -
1551   - if (zipentry != null && zipentry.getName().endsWith(".class"))
1552   - {
1553   - String classFileName = zipentry.getName();
1554   - String className = classFileName.lastIndexOf('/') > -1 ? classFileName.substring(classFileName.lastIndexOf('/') + 1) : classFileName;
1555   -
1556   - if (prefix == null || className.startsWith(prefix))
1557   - {
1558   - try
1559   - {
1560   - String fullClassName = classFileName.substring(0, classFileName.length() - 6).replaceAll("/", ".");
1561   - checkAndAddClass(classloader, superClass, classes, fullClassName);
1562   - }
1563   - catch (Exception ex)
1564   - {
1565   - }
1566   - }
1567   - }
1568   - } while (zipentry != null);
1569   -
1570   - fileinputstream.close();
1571   - }
1572   -
1573   - /**
1574   - * Recursive function to enumerate classes inside a classpath folder
1575   - *
1576   - * @param superClass
1577   - * @param classloader
1578   - * @param classes
1579   - * @param packagePath
1580   - * @param packageName
1581   - */
1582   - private static void enumerateDirectory(String prefix, Class<?> superClass, ClassLoader classloader, LinkedList<Class<?>> classes, File packagePath)
1583   - {
1584   - enumerateDirectory(prefix, superClass, classloader, classes, packagePath, "", 0);
1585   - }
1586   -
1587   - /**
1588   - * Recursive function to enumerate classes inside a classpath folder
1589   - *
1590   - * @param superClass
1591   - * @param classloader
1592   - * @param classes
1593   - * @param packagePath
1594   - * @param packageName
1595   - */
1596   - private static void enumerateDirectory(String prefix, Class<?> superClass, ClassLoader classloader, LinkedList<Class<?>> classes, File packagePath, String packageName, int depth)
1597   - {
1598   - // Prevent crash due to broken recursion
1599   - if (depth > MAX_DISCOVERY_DEPTH)
1600   - return;
1601   -
1602   - File[] classFiles = packagePath.listFiles();
1603   -
1604   - for (File classFile : classFiles)
1605   - {
1606   - if (classFile.isDirectory())
1607   - {
1608   - enumerateDirectory(prefix, superClass, classloader, classes, classFile, packageName + classFile.getName() + ".", depth + 1);
1609   - }
1610   - else
1611   - {
1612   - if (classFile.getName().endsWith(".class") && (prefix == null || classFile.getName().startsWith(prefix)))
1613   - {
1614   - String classFileName = classFile.getName();
1615   - String className = packageName + classFileName.substring(0, classFileName.length() - 6);
1616   - checkAndAddClass(classloader, superClass, classes, className);
1617   - }
1618   - }
1619   - }
1620   - }
1621   -
1622   - /**
1623   - * @param classloader
1624   - * @param superClass
1625   - * @param classes
1626   - * @param className
  814 + * Called before mod late initialisation, refresh the resources that have been added so that mods can use them
1627 815 */
1628   - private static void checkAndAddClass(ClassLoader classloader, Class<?> superClass, LinkedList<Class<?>> classes, String className)
1629   - {
1630   - if (className.indexOf('$') > -1)
1631   - return;
1632   -
1633   - try
1634   - {
1635   - Class<?> subClass = classloader.loadClass(className);
1636   -
1637   - if (subClass != null && !superClass.equals(subClass) && superClass.isAssignableFrom(subClass) && !subClass.isInterface() && !classes.contains(subClass))
1638   - {
1639   - classes.add(subClass);
1640   - }
1641   - }
1642   - catch (Throwable th)
1643   - {
1644   - LiteLoader.getLogger().log(Level.WARNING, "checkAndAddClass error", th);
1645   - }
1646   - }
1647   -
1648   - public void refreshResources()
  816 + void preInitMods()
1649 817 {
1650 818 if (this.pendingResourceReload)
1651 819 {
... ... @@ -1654,20 +822,32 @@ public final class LiteLoader implements FilenameFilter
1654 822 }
1655 823 }
1656 824  
1657   - public void onInit()
  825 + /**
  826 + * Called after mod late init
  827 + */
  828 + void preBeginGame()
1658 829 {
  830 + // Set the loader branding in ClientBrandRetriever using reflection
  831 + LiteLoaderBootstrap.setBranding("LiteLoader");
  832 +
1659 833 if (this.soundManagerReloadInhibitor != null && this.soundManagerReloadInhibitor.isInhibited())
1660 834 {
1661 835 this.soundManagerReloadInhibitor.unInhibit(true);
1662 836 }
1663 837 }
1664 838  
1665   - public void onLogin(NetHandler netHandler, Packet1Login loginPacket)
  839 + /**
  840 + * Called on login
  841 + *
  842 + * @param netHandler
  843 + * @param loginPacket
  844 + */
  845 + void onLogin(NetHandler netHandler, Packet1Login loginPacket)
1666 846 {
1667 847 this.permissionsManager.onLogin(netHandler, loginPacket);
1668 848 }
1669 849  
1670   - public void onRender()
  850 + void onRender()
1671 851 {
1672 852 if (this.paginateControls && this.minecraft.currentScreen != null && this.minecraft.currentScreen.getClass().equals(GuiControls.class))
1673 853 {
... ... @@ -1683,7 +863,7 @@ public final class LiteLoader implements FilenameFilter
1683 863 }
1684 864 }
1685 865  
1686   - public void onTick(float partialTicks, boolean inGame)
  866 + void onTick(float partialTicks, boolean inGame)
1687 867 {
1688 868 // Tick the permissions manager
1689 869 this.permissionsManager.onTick(this.minecraft, partialTicks, inGame);
... ... @@ -1748,7 +928,7 @@ public final class LiteLoader implements FilenameFilter
1748 928 /**
1749 929 * Writes mod bindings to disk
1750 930 */
1751   - protected void storeBindings()
  931 + private void storeBindings()
1752 932 {
1753 933 try
1754 934 {
... ... @@ -1756,132 +936,22 @@ public final class LiteLoader implements FilenameFilter
1756 936 }
1757 937 catch (IOException ex) {}
1758 938 }
1759   -
1760   - /**
1761   - * Set the brand in ClientBrandRetriever to the specified brand
1762   - *
1763   - * @param brand
1764   - */
1765   - private void setBranding(String brand)
1766   - {
1767   - try
1768   - {
1769   - String oldBrand = ClientBrandRetriever.getClientModName();
1770   -
1771   - if (oldBrand.equals("vanilla"))
1772   - {
1773   - char[] newValue = brand.toCharArray();
1774   -
1775   - Field stringValue = String.class.getDeclaredField("value");
1776   - stringValue.setAccessible(true);
1777   - stringValue.set(oldBrand, newValue);
1778   -
1779   - try
1780   - {
1781   - Field stringCount = String.class.getDeclaredField("count");
1782   - stringCount.setAccessible(true);
1783   - stringCount.set(oldBrand, newValue.length);
1784   - }
1785   - catch (NoSuchFieldException ex) {} // java 1.7 doesn't have this member
1786   - }
1787   - }
1788   - catch (Exception ex)
1789   - {
1790   - LiteLoader.getLogger().log(Level.WARNING, "Setting branding failed", ex);
1791   - }
1792   - }
1793 939  
1794 940 private static void logInfo(String string, Object... args)
1795 941 {
1796   - LiteLoader.getLogger().info(String.format(string, args));
1797   - }
1798   -
1799   - private static void logWarning(String string, Object... args)
1800   - {
1801   - LiteLoader.getLogger().warning(String.format(string, args));
  942 +// System.out.println("<INFO> " + String.format(string, args));
  943 + LiteLoader.logger.info(String.format(string, args));
1802 944 }
1803 945  
1804   - public static void populateCrashReport(CrashReport par1CrashReport)
1805   - {
1806   - par1CrashReport.getCategory().addCrashSectionCallable("Mod Pack", new CallableLiteLoaderBrand(par1CrashReport));
1807   - par1CrashReport.getCategory().addCrashSectionCallable("LiteLoader Mods", new CallableLiteLoaderMods(par1CrashReport));
1808   - }
1809   -
1810   - // -----------------------------------------------------------------------------------------------------------
1811   - // TODO Remove delegates below after 1.6.4
1812   - // -----------------------------------------------------------------------------------------------------------
1813   -
1814   - /**
1815   - * Delegate to PluginChannels.sendMessage. Deprecated and will be removed
1816   - *
1817   - * @param channel Channel to send data to
1818   - * @param data Data to send
1819   - *
1820   - * @deprecated User PluginChannels.sendMessage(channel, data) instead.
1821   - */
1822   - @Deprecated
1823   - public void sendPluginChannelMessage(String channel, byte[] data)
1824   - {
1825   - PluginChannels.sendMessage(channel, data);
1826   - }
1827   -
1828   - @Deprecated
1829   - public void addTickListener(Tickable tickable)
1830   - {
1831   - this.events.addTickListener(tickable);
1832   - }
1833   -
1834   - @Deprecated
1835   - public void addLoopListener(GameLoopListener loopListener)
1836   - {
1837   - this.events.addLoopListener(loopListener);
1838   - }
1839   -
1840   - @Deprecated
1841   - public void addInitListener(InitCompleteListener initCompleteListener)
1842   - {
1843   - this.events.addInitListener(initCompleteListener);
1844   - }
1845   -
1846   - @Deprecated
1847   - public void addRenderListener(RenderListener renderListener)
1848   - {
1849   - this.events.addRenderListener(renderListener);
1850   - }
1851   -
1852   - @Deprecated
1853   - public void addPostRenderListener(PostRenderListener postRenderListener)
1854   - {
1855   - this.events.addPostRenderListener(postRenderListener);
1856   - }
1857   -
1858   - @Deprecated
1859   - public void addChatFilter(ChatFilter chatFilter)
1860   - {
1861   - this.events.addChatFilter(chatFilter);
1862   - }
1863   -
1864   - @Deprecated
1865   - public void addChatListener(ChatListener chatListener)
1866   - {
1867   - this.events.addChatListener(chatListener);
1868   - }
1869   -
1870   - @Deprecated
1871   - public void addChatRenderListener(ChatRenderListener chatRenderListener)
1872   - {
1873   - this.events.addChatRenderListener(chatRenderListener);
1874   - }
1875   -
1876   - @Deprecated
1877   - public void addPreLoginListener(PreLoginListener loginListener)
  946 + private static void logWarning(String string, Object... args)
1878 947 {
1879   - this.events.addPreLoginListener(loginListener);
  948 +// System.out.println("<WARN> " + String.format(string, args));
  949 + LiteLoader.logger.warning(String.format(string, args));
1880 950 }
1881 951  
1882   - @Deprecated
1883   - public void addLoginListener(LoginListener loginListener)
  952 + public static void populateCrashReport(CrashReport crashReport)
1884 953 {
1885   - this.events.addLoginListener(loginListener);
  954 + crashReport.getCategory().addCrashSectionCallable("Mod Pack", new CallableLiteLoaderBrand(crashReport));
  955 + crashReport.getCategory().addCrashSectionCallable("LiteLoader Mods", new CallableLiteLoaderMods(crashReport));
1886 956 }
1887 957 }
1888 958 \ No newline at end of file
... ...
java/com/mumfrey/liteloader/core/LiteLoaderBootstrap.java 0 → 100644
  1 +package com.mumfrey.liteloader.core;
  2 +
  3 +import java.io.File;
  4 +import java.io.FileInputStream;
  5 +import java.io.FileNotFoundException;
  6 +import java.io.FileWriter;
  7 +import java.io.IOException;
  8 +import java.io.InputStream;
  9 +import java.io.PrintStream;
  10 +import java.lang.reflect.Field;
  11 +import java.util.List;
  12 +import java.util.Properties;
  13 +import java.util.logging.FileHandler;
  14 +import java.util.logging.Formatter;
  15 +import java.util.logging.Level;
  16 +import java.util.logging.Logger;
  17 +import java.util.logging.StreamHandler;
  18 +
  19 +import net.minecraft.client.ClientBrandRetriever;
  20 +import net.minecraft.launchwrapper.LaunchClassLoader;
  21 +
  22 +import com.mumfrey.liteloader.launch.ILoaderBootstrap;
  23 +import com.mumfrey.liteloader.log.LiteLoaderLogFormatter;
  24 +
  25 +/**
  26 + * LiteLoaderBootstrap is a proxy class which handles the early part of the LiteLoader startup process which
  27 + * used to be handled by the loader itself, this is to ensure that NONE of the Minecraft classes which by
  28 + * necessity the Loader references get loaded before the pre-init stage has completed. This allows us to load
  29 + * transforming tweakers in the pre-init stage without all hell breaking loose because class names have changed
  30 + * between initialisation stages!
  31 + *
  32 + * This class handles setting up requisite resources like the logger and the enumerator and passes init calls
  33 + * through to the LiteLoader instance at the appropriate points during startup. Because this class is the first
  34 + * part of the loader to get loaded, we also keep central references like the paths and version in here.
  35 + *
  36 + * @author Adam Mummery-Smith
  37 + */
  38 +class LiteLoaderBootstrap implements ILoaderBootstrap
  39 +{
  40 + /**
  41 + * Liteloader version
  42 + */
  43 + public static final LiteLoaderVersion VERSION = LiteLoaderVersion.MC_1_6_4_R1;
  44 +
  45 + /**
  46 + * Local logger reference
  47 + */
  48 + private static final Logger logger = Logger.getLogger("liteloader");
  49 +
  50 + /**
  51 + * True to use stdout instead of stderr
  52 + */
  53 + private static boolean useStdOut;
  54 +
  55 + /**
  56 + * Base game directory, passed in from the tweaker
  57 + */
  58 + private final File gameDirectory;
  59 +
  60 + /**
  61 + * Assets directory, passed in from the tweaker
  62 + */
  63 + private final File assetsDirectory;
  64 +
  65 + /**
  66 + * Active profile, passed in from the tweaker
  67 + */
  68 + private final String profile;
  69 +
  70 + /**
  71 + * "Mods" folder to use
  72 + */
  73 + private final File modsFolder;
  74 +
  75 + /**
  76 + * Base "liteconfig" folder under which all other lite mod configs and liteloader configs are placed
  77 + */
  78 + private final File configBaseFolder;
  79 +
  80 + /**
  81 + * File to write log entries to
  82 + */
  83 + private File logFile;
  84 +
  85 + /**
  86 + * File containing the properties
  87 + */
  88 + private File propertiesFile;
  89 +
  90 + /**
  91 + * Internal properties loaded from inside the jar
  92 + */
  93 + private Properties internalProperties = new Properties();
  94 +
  95 + /**
  96 + * LiteLoader properties
  97 + */
  98 + private Properties localProperties = new Properties();
  99 +
  100 + /**
  101 + * Pack brand from properties, used to put the modpack/compilation name in
  102 + * crash reports
  103 + */
  104 + private String branding = null;
  105 +
  106 + /**
  107 + * The mod enumerator instance
  108 + */
  109 + private LiteLoaderEnumerator enumerator;
  110 +
  111 + /**
  112 + * @param gameDirectory
  113 + * @param assetsDirectory
  114 + * @param profile
  115 + */
  116 + public LiteLoaderBootstrap(File gameDirectory, File assetsDirectory, String profile)
  117 + {
  118 + this.gameDirectory = gameDirectory;
  119 + this.assetsDirectory = assetsDirectory;
  120 + this.profile = profile;
  121 +
  122 + this.modsFolder = new File(this.gameDirectory, "mods");
  123 + this.configBaseFolder = new File(this.gameDirectory, "liteconfig");
  124 + this.logFile = new File(this.configBaseFolder, "liteloader.log");
  125 + this.propertiesFile = new File(this.configBaseFolder, "liteloader.properties");
  126 + }
  127 +
  128 + /* (non-Javadoc)
  129 + * @see com.mumfrey.liteloader.launch.ILoaderBootstrap#preInit(net.minecraft.launchwrapper.LaunchClassLoader, boolean)
  130 + */
  131 + @Override
  132 + public void preInit(LaunchClassLoader classLoader, boolean loadTweaks)
  133 + {
  134 + // Set up the bootstrap
  135 + if (!this.prepare()) return;
  136 +
  137 + LiteLoaderBootstrap.logInfo("LiteLoader %s starting up...", LiteLoaderBootstrap.VERSION.getLoaderVersion());
  138 +
  139 + // Print the branding version if any was provided
  140 + if (this.branding != null)
  141 + {
  142 + LiteLoaderBootstrap.logInfo("Active Pack: %s", this.branding);
  143 + }
  144 +
  145 + LiteLoaderBootstrap.logInfo("Java reports OS=\"%s\"", System.getProperty("os.name").toLowerCase());
  146 +
  147 + this.enumerator = new LiteLoaderEnumerator(this, classLoader, loadTweaks);
  148 + this.enumerator.discoverModFiles();
  149 +
  150 + LiteLoaderBootstrap.logInfo("LiteLoader PreInit completed");
  151 + }
  152 +
  153 + /* (non-Javadoc)
  154 + * @see com.mumfrey.liteloader.launch.ILoaderBootstrap#init(java.util.List, net.minecraft.launchwrapper.LaunchClassLoader)
  155 + */
  156 + @Override
  157 + public void init(List<String> modsToLoad, LaunchClassLoader classLoader)
  158 + {
  159 + try
  160 + {
  161 + if (LiteLoaderBootstrap.logger.getHandlers().length < 1)
  162 + this.prepareLogger();
  163 + }
  164 + catch (Exception ex) {}
  165 +
  166 + LiteLoaderBootstrap.logger.info("Beginning LiteLoader Init...");
  167 + LiteLoader.init(this, this.enumerator, modsToLoad, classLoader);
  168 + }
  169 +
  170 + /* (non-Javadoc)
  171 + * @see com.mumfrey.liteloader.launch.ILoaderBootstrap#postInit()
  172 + */
  173 + @Override
  174 + public void postInit()
  175 + {
  176 + try
  177 + {
  178 + if (LiteLoaderBootstrap.logger.getHandlers().length < 1)
  179 + this.prepareLogger();
  180 + }
  181 + catch (Exception ex) {}
  182 +
  183 + LiteLoaderBootstrap.logger.info("Beginning LiteLoader PostInit...");
  184 + LiteLoader.postInit();
  185 + }
  186 +
  187 + /**
  188 + * Set up reflection methods required by the loader
  189 + */
  190 + private boolean prepare()
  191 + {
  192 + try
  193 + {
  194 + // Prepare the properties
  195 + this.prepareProperties();
  196 +
  197 + // Prepare the log writer
  198 + this.prepareLogger();
  199 +
  200 + this.branding = this.internalProperties.getProperty("brand", null);
  201 + if (this.branding != null && this.branding.length() < 1)
  202 + this.branding = null;
  203 +
  204 + // Save appropriate branding in the local properties file
  205 + if (this.branding != null)
  206 + this.localProperties.setProperty("brand", this.branding);
  207 + else
  208 + this.localProperties.remove("brand");
  209 + }
  210 + catch (Throwable th)
  211 + {
  212 + LiteLoaderBootstrap.logger.log(Level.SEVERE, "Error initialising LiteLoader Bootstrap", th);
  213 + return false;
  214 + }
  215 +
  216 + return true;
  217 + }
  218 +
  219 + /**
  220 + * @throws SecurityException
  221 + * @throws IOException
  222 + */
  223 + private void prepareLogger() throws SecurityException, IOException
  224 + {
  225 + Formatter logFormatter = new LiteLoaderLogFormatter();
  226 +
  227 + LiteLoaderBootstrap.logger.setUseParentHandlers(false);
  228 + LiteLoaderBootstrap.useStdOut = System.getProperty("liteloader.log", "stderr").equalsIgnoreCase("stdout") || this.localProperties.getProperty("log", "stderr").equalsIgnoreCase("stdout");
  229 +
  230 + StreamHandler consoleHandler = useStdOut ? new com.mumfrey.liteloader.util.log.ConsoleHandler() : new java.util.logging.ConsoleHandler();
  231 + consoleHandler.setFormatter(logFormatter);
  232 + LiteLoaderBootstrap.logger.addHandler(consoleHandler);
  233 +
  234 + FileHandler logFileHandler = new FileHandler(this.logFile.getAbsolutePath());
  235 + logFileHandler.setFormatter(logFormatter);
  236 + LiteLoaderBootstrap.logger.addHandler(logFileHandler);
  237 + }
  238 +
  239 + /**
  240 + * Get the output stream which we are using for console output
  241 + *
  242 + * @return
  243 + */
  244 + public static final PrintStream getConsoleStream()
  245 + {
  246 + return LiteLoaderBootstrap.useStdOut ? System.out : System.err;
  247 + }
  248 +
  249 + /**
  250 + * Prepare the loader properties
  251 + */
  252 + private void prepareProperties()
  253 + {
  254 + try
  255 + {
  256 + InputStream propertiesStream = LiteLoaderBootstrap.class.getResourceAsStream("/liteloader.properties");
  257 +
  258 + if (propertiesStream != null)
  259 + {
  260 + this.internalProperties.load(propertiesStream);
  261 + propertiesStream.close();
  262 + }
  263 + }
  264 + catch (Throwable th)
  265 + {
  266 + this.internalProperties = new Properties();
  267 + }
  268 +
  269 + try
  270 + {
  271 + this.localProperties = new Properties(this.internalProperties);
  272 + InputStream localPropertiesStream = this.getLocalPropertiesStream();
  273 +
  274 + if (localPropertiesStream != null)
  275 + {
  276 + this.localProperties.load(localPropertiesStream);
  277 + localPropertiesStream.close();
  278 + }
  279 + }
  280 + catch (Throwable th)
  281 + {
  282 + this.localProperties = new Properties(this.internalProperties);
  283 + }
  284 + }
  285 +
  286 + /**
  287 + * Get the properties stream either from the jar or from the properties file
  288 + * in the minecraft folder
  289 + *
  290 + * @return
  291 + * @throws FileNotFoundException
  292 + */
  293 + private InputStream getLocalPropertiesStream() throws FileNotFoundException
  294 + {
  295 + if (this.propertiesFile.exists())
  296 + {
  297 + return new FileInputStream(this.propertiesFile);
  298 + }
  299 +
  300 + // Otherwise read settings from the config
  301 + return LiteLoaderBootstrap.class.getResourceAsStream("/liteloader.properties");
  302 + }
  303 +
  304 + /**
  305 + * Write current properties to the properties file
  306 + */
  307 + public void writeProperties()
  308 + {
  309 + try
  310 + {
  311 + this.localProperties.store(new FileWriter(this.propertiesFile), String.format("Properties for LiteLoader %s", LiteLoaderBootstrap.VERSION));
  312 + }
  313 + catch (Throwable th)
  314 + {
  315 + LiteLoaderBootstrap.logger.log(Level.WARNING, "Error writing liteloader properties", th);
  316 + }
  317 + }
  318 +
  319 + /**
  320 + * Get the game directory
  321 + */
  322 + public File getGameDirectory()
  323 + {
  324 + return this.gameDirectory;
  325 + }
  326 +
  327 + /**
  328 + * Get the assets directory
  329 + */
  330 + public File getAssetsDirectory()
  331 + {
  332 + return this.assetsDirectory;
  333 + }
  334 +
  335 + /**
  336 + * Get the profile directory
  337 + */
  338 + public String getProfile()
  339 + {
  340 + return this.profile;
  341 + }
  342 +
  343 + /**
  344 + * Get the mods folder
  345 + */
  346 + public File getModsFolder()
  347 + {
  348 + return this.modsFolder;
  349 + }
  350 +
  351 + /**
  352 + * Get the base "liteconfig" folder
  353 + */
  354 + public File getConfigBaseFolder()
  355 + {
  356 + return this.configBaseFolder;
  357 + }
  358 +
  359 + /**
  360 + * Get a boolean propery from the properties file and also write the new value back to the properties file
  361 + *
  362 + * @param propertyName
  363 + * @param defaultValue
  364 + * @return
  365 + */
  366 + public boolean getAndStoreBooleanProperty(String propertyName, boolean defaultValue)
  367 + {
  368 + boolean result = this.localProperties.getProperty(propertyName, String.valueOf(defaultValue)).equalsIgnoreCase("true");
  369 + this.localProperties.setProperty(propertyName, String.valueOf(result));
  370 + return result;
  371 + }
  372 +
  373 + /**
  374 + * Set a boolean property
  375 + *
  376 + * @param propertyName
  377 + * @param value
  378 + */
  379 + public void setBooleanProperty(String propertyName, boolean value)
  380 + {
  381 + this.localProperties.setProperty(propertyName, String.valueOf(value));
  382 + }
  383 +
  384 + /**
  385 + * Store current revision for mod in the config file
  386 + *
  387 + * @param modKey
  388 + */
  389 + public void storeLastKnownModRevision(String modKey)
  390 + {
  391 + if (this.localProperties != null)
  392 + {
  393 + this.localProperties.setProperty(modKey, String.valueOf(LiteLoaderBootstrap.VERSION.getLoaderRevision()));
  394 + this.writeProperties();
  395 + }
  396 + }
  397 +
  398 + /**
  399 + * Get last know revision for mod from the config file
  400 + *
  401 + * @param modKey
  402 + * @return
  403 + */
  404 + public int getLastKnownModRevision(String modKey)
  405 + {
  406 + if (this.localProperties != null)
  407 + {
  408 + String storedRevision = this.localProperties.getProperty(modKey, "0");
  409 + return Integer.parseInt(storedRevision);
  410 + }
  411 +
  412 + return 0;
  413 + }
  414 +
  415 + /**
  416 + * Used to get the name of the modpack being used
  417 + *
  418 + * @return name of the modpack in use or null if no pack
  419 + */
  420 + public String getBranding()
  421 + {
  422 + return this.branding;
  423 + }
  424 +
  425 + /**
  426 + * Set the brand in ClientBrandRetriever to the specified brand
  427 + *
  428 + * @param brand
  429 + */
  430 + static void setBranding(String brand)
  431 + {
  432 + try
  433 + {
  434 + String oldBrand = ClientBrandRetriever.getClientModName();
  435 +
  436 + if (oldBrand.equals("vanilla"))
  437 + {
  438 + char[] newValue = brand.toCharArray();
  439 +
  440 + Field stringValue = String.class.getDeclaredField("value");
  441 + stringValue.setAccessible(true);
  442 + stringValue.set(oldBrand, newValue);
  443 +
  444 + try
  445 + {
  446 + Field stringCount = String.class.getDeclaredField("count");
  447 + stringCount.setAccessible(true);
  448 + stringCount.set(oldBrand, newValue.length);
  449 + }
  450 + catch (NoSuchFieldException ex) {} // java 1.7 doesn't have this member
  451 + }
  452 + }
  453 + catch (Throwable th)
  454 + {
  455 + LiteLoaderBootstrap.logger.log(Level.WARNING, "Setting branding failed", th);
  456 + }
  457 + }
  458 +
  459 + /**
  460 + * @param string
  461 + * @param args
  462 + */
  463 + private static void logInfo(String string, Object... args)
  464 + {
  465 + LiteLoaderBootstrap.logger.info(String.format(string, args));
  466 + }
  467 +}
... ...
java/com/mumfrey/liteloader/core/LiteLoaderEnumerator.java 0 → 100644
  1 +package com.mumfrey.liteloader.core;
  2 +
  3 +import java.io.BufferedReader;
  4 +import java.io.File;
  5 +import java.io.FileInputStream;
  6 +import java.io.FileNotFoundException;
  7 +import java.io.FilenameFilter;
  8 +import java.io.IOException;
  9 +import java.io.InputStream;
  10 +import java.io.InputStreamReader;
  11 +import java.io.UnsupportedEncodingException;
  12 +import java.net.MalformedURLException;
  13 +import java.net.URISyntaxException;
  14 +import java.net.URL;
  15 +import java.net.URLDecoder;
  16 +import java.util.ArrayList;
  17 +import java.util.Collection;
  18 +import java.util.HashMap;
  19 +import java.util.LinkedList;
  20 +import java.util.List;
  21 +import java.util.Map;
  22 +import java.util.Map.Entry;
  23 +import java.util.TreeSet;
  24 +import java.util.jar.Attributes;
  25 +import java.util.jar.JarFile;
  26 +import java.util.logging.Level;
  27 +import java.util.logging.Logger;
  28 +import java.util.zip.ZipEntry;
  29 +import java.util.zip.ZipFile;
  30 +import java.util.zip.ZipInputStream;
  31 +
  32 +import net.minecraft.launchwrapper.LaunchClassLoader;
  33 +
  34 +import com.mumfrey.liteloader.LiteMod;
  35 +import com.mumfrey.liteloader.launch.LiteLoaderTweaker;
  36 +
  37 +/**
  38 + * The enumerator performs all mod discovery functions for LiteLoader, this includes locating mod files to load
  39 + * as well as searching for mod classes within the class path and discovered mod files.
  40 + *
  41 + * @author Adam Mummery-Smith
  42 + */
  43 +class LiteLoaderEnumerator implements FilenameFilter
  44 +{
  45 + /**
  46 + * Maximum recursion depth for mod discovery
  47 + */
  48 + private static final int MAX_DISCOVERY_DEPTH = 16;
  49 +
  50 + /**
  51 + * Local logger reference
  52 + */
  53 + private static Logger logger = Logger.getLogger("liteloader");
  54 +
  55 + /**
  56 + * Reference to the bootstrap agent
  57 + */
  58 + private final LiteLoaderBootstrap bootstrap;
  59 +
  60 + /**
  61 + * Reference to the launch classloader
  62 + */
  63 + private final LaunchClassLoader classLoader;
  64 +
  65 + /**
  66 + * Classes to load, mapped by class name
  67 + */
  68 + private final Map<String, Class<? extends LiteMod>> modsToLoad = new HashMap<String, Class<? extends LiteMod>>();
  69 +
  70 + /**
  71 + * URLs to add once init is completed
  72 + */
  73 + private final List<ModFile> allModFiles = new ArrayList<ModFile>();
  74 +
  75 + /**
  76 + * Mod metadata from version file
  77 + */
  78 + private final Map<String, ModFile> modFiles = new HashMap<String, ModFile>();
  79 +
  80 + /**
  81 + * True if the loader is allowed to load tweak classes from mod files
  82 + */
  83 + private final boolean loadTweaks;
  84 +
  85 + /**
  86 + * True if liteloader should also search files ending with .zip
  87 + */
  88 + private boolean readZipFiles = false;
  89 +
  90 + /**
  91 + * True if liteloader should also search files ending with .jar
  92 + */
  93 + private boolean readJarFiles = true;
  94 +
  95 + private boolean searchModsFolder = true;
  96 + private boolean searchProtectionDomain = true;
  97 + private boolean searchClassPath = true;
  98 +
  99 + /**
  100 + * @param properties
  101 + * @param gameFolder
  102 + * @param classLoader
  103 + * @param loadTweaks
  104 + */
  105 + public LiteLoaderEnumerator(LiteLoaderBootstrap bootstrap, LaunchClassLoader classLoader, boolean loadTweaks)
  106 + {
  107 + this.bootstrap = bootstrap;
  108 + this.classLoader = classLoader;
  109 + this.loadTweaks = loadTweaks;
  110 +
  111 + // Read the discovery settings from the properties
  112 + this.readSettings();
  113 + }
  114 +
  115 + /**
  116 + * Get the list of all enumerated mod classes to load
  117 + */
  118 + public Collection<Class<? extends LiteMod>> getModsToLoad()
  119 + {
  120 + return this.modsToLoad.values();
  121 + }
  122 +
  123 + /**
  124 + * Get the number of mods to load
  125 + */
  126 + public int modsToLoadCount()
  127 + {
  128 + return this.modsToLoad.size();
  129 + }
  130 +
  131 + /**
  132 + * @return
  133 + */
  134 + public boolean hasModsToLoad()
  135 + {
  136 + return this.modsToLoad.size() > 0;
  137 + }
  138 +
  139 + /**
  140 + * Get a metadata value for the specified mod
  141 + *
  142 + * @param modClassName
  143 + * @param metaDataKey
  144 + * @param defaultValue
  145 + * @return
  146 + */
  147 + public String getModMetaData(Class<? extends LiteMod> modClass, String metaDataKey, String defaultValue)
  148 + {
  149 + ModFile modFile = this.getModFile(modClass);
  150 + return modFile != null ? modFile.getMetaValue(metaDataKey, defaultValue) : defaultValue;
  151 + }
  152 +
  153 + /**
  154 + * @param mod
  155 + * @return
  156 + */
  157 + public ModFile getModFile(Class<? extends LiteMod> modClass)
  158 + {
  159 + return this.modFiles.get(modClass.getSimpleName());
  160 + }
  161 +
  162 + /**
  163 + * Get the mod "name" metadata key, this is used for versioning, exclusivity, and enablement checks
  164 + *
  165 + * @param modClass
  166 + * @return
  167 + */
  168 + public String getModMetaName(Class<? extends LiteMod> modClass)
  169 + {
  170 + String modClassName = modClass.getSimpleName();
  171 + if (!this.modFiles.containsKey(modClassName)) return null;
  172 + return this.modFiles.get(modClassName).getModName().toLowerCase();
  173 + }
  174 +
  175 + /**
  176 + * Get the discovery settings from the properties file
  177 + */
  178 + public void readSettings()
  179 + {
  180 + this.readZipFiles = this.bootstrap.getAndStoreBooleanProperty("search.zips", false);
  181 + this.readZipFiles = this.bootstrap.getAndStoreBooleanProperty("search.jars", true);
  182 + this.searchModsFolder = this.bootstrap.getAndStoreBooleanProperty("search.mods", true);
  183 + this.searchProtectionDomain = this.bootstrap.getAndStoreBooleanProperty("search.jar", true);
  184 + this.searchClassPath = this.bootstrap.getAndStoreBooleanProperty("search.classpath", true);
  185 +
  186 + if (!this.searchModsFolder && !this.searchProtectionDomain && !this.searchClassPath)
  187 + {
  188 + LiteLoaderEnumerator.logWarning("Invalid configuration, no search locations defined. Enabling all search locations.");
  189 +
  190 + this.searchModsFolder = true;
  191 + this.searchProtectionDomain = true;
  192 + this.searchClassPath = true;
  193 + }
  194 +
  195 + this.bootstrap.setBooleanProperty("search.zips", this.readZipFiles);
  196 + this.bootstrap.setBooleanProperty("search.jars", this.readJarFiles);
  197 + this.bootstrap.setBooleanProperty("search.mods", this.searchModsFolder);
  198 + this.bootstrap.setBooleanProperty("search.jar", this.searchProtectionDomain);
  199 + this.bootstrap.setBooleanProperty("search.classpath", this.searchClassPath);
  200 + }
  201 +
  202 + /**
  203 + * Enumerate the "mods" folder to find mod files
  204 + */
  205 + protected void discoverModFiles()
  206 + {
  207 + if (this.searchModsFolder)
  208 + {
  209 + // Find and enumerate the "mods" folder
  210 + File modsFolder = this.bootstrap.getModsFolder();
  211 + if (modsFolder.exists() && modsFolder.isDirectory())
  212 + {
  213 + LiteLoaderEnumerator.logInfo("Mods folder found, searching %s", modsFolder.getPath());
  214 + this.findModFiles(modsFolder, false);
  215 + LiteLoaderEnumerator.logInfo("Found %d mod file(s)", this.allModFiles.size());
  216 +
  217 + File versionedModsFolder = new File(modsFolder, LiteLoaderBootstrap.VERSION.getMinecraftVersion());
  218 + if (versionedModsFolder.exists() && versionedModsFolder.isDirectory())
  219 + {
  220 + LiteLoaderEnumerator.logInfo("Versioned mods folder found, searching %s", versionedModsFolder.getPath());
  221 + this.findModFiles(versionedModsFolder, true);
  222 + LiteLoaderEnumerator.logInfo("Found %d mod file(s)", this.allModFiles.size());
  223 + }
  224 + }
  225 + }
  226 + }
  227 +
  228 + /**
  229 + * Enumerate class path and discovered mod files to find mod classes
  230 + */
  231 + protected void discoverModClasses()
  232 + {
  233 + try
  234 + {
  235 + // Inject mod files discovered earlier into the class loader
  236 + this.injectIntoClassPath();
  237 +
  238 + // Split the environment classpath into entries
  239 + String[] classPathEntries = this.readClassPath();
  240 +
  241 + // then search through all sources to find mod classes
  242 + this.findModClasses(classPathEntries);
  243 + }
  244 + catch (Throwable th)
  245 + {
  246 + LiteLoaderEnumerator.logger.log(Level.WARNING, "Mod class discovery failed", th);
  247 + return;
  248 + }
  249 + }
  250 +
  251 + /**
  252 + * Injects all external mod files into the launch classloader's class path
  253 + */
  254 + private void injectIntoClassPath()
  255 + {
  256 + LiteLoaderEnumerator.logInfo("Injecting external mods into class path...");
  257 +
  258 + for (ModFile file : this.allModFiles)
  259 + {
  260 + try
  261 + {
  262 + LiteLoaderEnumerator.logInfo("Injecting mod file '%s' into classpath", file.getAbsolutePath());
  263 + this.classLoader.addURL(file.toURI().toURL());
  264 + }
  265 + catch (Exception ex)
  266 + {
  267 + LiteLoaderEnumerator.logWarning("Error injecting '%s' into classPath. The mod will not be loaded", file.getAbsolutePath());
  268 + }
  269 + }
  270 + }
  271 +
  272 + /**
  273 + * Reads the class path entries that were supplied to the JVM and returns them as an array
  274 + */
  275 + private String[] readClassPath()
  276 + {
  277 + LiteLoaderEnumerator.logInfo("Enumerating class path...");
  278 +
  279 + String classPath = System.getProperty("java.class.path");
  280 + String classPathSeparator = System.getProperty("path.separator");
  281 + String[] classPathEntries = classPath.split(classPathSeparator);
  282 +
  283 + LiteLoaderEnumerator.logInfo("Class path separator=\"%s\"", classPathSeparator);
  284 + LiteLoaderEnumerator.logInfo("Class path entries=(\n classpathEntry=%s\n)", classPath.replace(classPathSeparator, "\n classpathEntry="));
  285 + return classPathEntries;
  286 + }
  287 +
  288 + /**
  289 + * For FilenameFilter interface
  290 + *
  291 + * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
  292 + */
  293 + @Override
  294 + public boolean accept(File dir, String fileName)
  295 + {
  296 + fileName = fileName.toLowerCase();
  297 + return fileName.endsWith(".litemod")
  298 + || (this.readZipFiles && fileName.endsWith(".zip"))
  299 + || (this.readJarFiles && fileName.endsWith(".jar"));
  300 + }
  301 +
  302 + /**
  303 + * Find mod files in the "mods" folder
  304 + *
  305 + * @param modFolder Folder to search
  306 + * @param isVersionedModFolder This is true if we will also allow non-metadata-containing jars to be examined for tweaks
  307 + */
  308 + protected void findModFiles(File modFolder, boolean isVersionedModFolder)
  309 + {
  310 + Map<String, TreeSet<ModFile>> versionOrderingSets = new HashMap<String, TreeSet<ModFile>>();
  311 +
  312 + for (File modFile : modFolder.listFiles(this))
  313 + {
  314 + try
  315 + {
  316 + ZipFile modZip = new ZipFile(modFile);
  317 + ZipEntry versionEntry = modZip.getEntry("litemod.json");
  318 + ZipEntry legacyVersionEntry = modZip.getEntry("version.txt");
  319 +
  320 + // Check for a version file
  321 + if (versionEntry != null)
  322 + {
  323 + String strVersion = this.readVersion(modZip, versionEntry);
  324 +
  325 + if (strVersion != null)
  326 + {
  327 + ModFile modFileInfo = new ModFile(modFile, strVersion);
  328 +
  329 + if (modFileInfo.isValid())
  330 + {
  331 + // Only add the mod if the version matches, we add candidates to the versionOrderingSets in
  332 + // order to determine the most recent version available.
  333 + if (LiteLoaderBootstrap.VERSION.isVersionSupported(modFileInfo.getVersion()))
  334 + {
  335 + if (!versionOrderingSets.containsKey(modFileInfo.getName()))
  336 + {
  337 + versionOrderingSets.put(modFileInfo.getModName(), new TreeSet<ModFile>());
  338 + }
  339 +
  340 + LiteLoaderEnumerator.logInfo("Considering valid mod file: %s", modFileInfo.getAbsolutePath());
  341 + versionOrderingSets.get(modFileInfo.getModName()).add(modFileInfo);
  342 + }
  343 + else
  344 + {
  345 + LiteLoaderEnumerator.logInfo("Not adding invalid or outdated mod file: %s", modFile.getAbsolutePath());
  346 + }
  347 + }
  348 + }
  349 + }
  350 + else if (legacyVersionEntry != null)
  351 + {
  352 + LiteLoaderEnumerator.logWarning("version.txt is no longer supported, ignoring outdated mod file: %s", modFile.getAbsolutePath());
  353 + }
  354 + else if (isVersionedModFolder && this.loadTweaks && this.readJarFiles && modFile.getName().toLowerCase().endsWith(".jar"))
  355 + {
  356 + this.addTweaksFrom(modFile);
  357 + }
  358 +
  359 + modZip.close();
  360 + }
  361 + catch (Exception ex)
  362 + {
  363 + ex.printStackTrace(System.err);
  364 + LiteLoaderEnumerator.logInfo("Error enumerating '%s': Invalid zip file or error reading file", modFile.getAbsolutePath());
  365 + }
  366 + }
  367 +
  368 + // Copy the first entry in every version set into the modfiles list
  369 + for (Entry<String, TreeSet<ModFile>> modFileEntry : versionOrderingSets.entrySet())
  370 + {
  371 + ModFile newestVersion = modFileEntry.getValue().iterator().next();
  372 +
  373 + LiteLoaderEnumerator.logInfo("Adding newest valid mod file '%s' at revision %.4f: ", newestVersion.getAbsolutePath(), newestVersion.getRevision());
  374 + this.allModFiles.add(newestVersion);
  375 +
  376 + if (this.loadTweaks)
  377 + {
  378 + try
  379 + {
  380 + this.addTweaksFrom(newestVersion);
  381 +
  382 + }
  383 + catch (Throwable th)
  384 + {
  385 + LiteLoaderEnumerator.logWarning("Error adding tweaks from '%s'", newestVersion.getAbsolutePath());
  386 + }
  387 + }
  388 + }
  389 + }
  390 +
  391 + /**
  392 + * @param strVersion
  393 + * @param modZip
  394 + * @param versionEntry
  395 + * @return
  396 + * @throws IOException
  397 + */
  398 + public String readVersion(ZipFile modZip, ZipEntry versionEntry) throws IOException
  399 + {
  400 + String strVersion = null;
  401 + BufferedReader versionReader = null;
  402 + StringBuilder versionBuilder = new StringBuilder();
  403 +
  404 + try
  405 + {
  406 + // Read the version string
  407 + InputStream versionStream = modZip.getInputStream(versionEntry);
  408 + versionReader = new BufferedReader(new InputStreamReader(versionStream));
  409 +
  410 + String versionFileLine;
  411 + while ((versionFileLine = versionReader.readLine()) != null)
  412 + versionBuilder.append(versionFileLine);
  413 +
  414 + strVersion = versionBuilder.toString();
  415 + }
  416 + catch (Exception ex)
  417 + {
  418 + LiteLoaderEnumerator.logWarning("Error reading version data from %s", modZip.getName());
  419 + }
  420 + finally
  421 + {
  422 + if (versionReader != null) versionReader.close();
  423 + }
  424 + return strVersion;
  425 + }
  426 +
  427 + /**
  428 + * @param jarFile
  429 + * @throws IOException
  430 + */
  431 + private void addTweaksFrom(File jarFile)
  432 + {
  433 + JarFile jar = null;
  434 +
  435 + LiteLoaderEnumerator.logInfo("Searching for tweaks in '%s'", jarFile.getName());
  436 + try
  437 + {
  438 + jar = new JarFile(jarFile);
  439 + Attributes manifestAttributes = jar.getManifest().getMainAttributes();
  440 +
  441 + String tweakClass = manifestAttributes.getValue("TweakClass");
  442 + if (tweakClass != null)
  443 + {
  444 + LiteLoaderEnumerator.logInfo("Mod file '%s' provides tweakClass '%s', adding to Launch queue", jarFile.getName(), tweakClass);
  445 +
  446 + if (LiteLoaderTweaker.addTweaker(jarFile.toURI().toURL(), tweakClass))
  447 + {
  448 + LiteLoaderEnumerator.logInfo("tweakClass '%s' was successfully added", tweakClass);
  449 + this.classLoader.addURL(jarFile.toURI().toURL());
  450 + }
  451 + }
  452 +
  453 + String classPath = manifestAttributes.getValue("Class-Path");
  454 + if (classPath != null)
  455 + {
  456 + String[] classPathEntries = classPath.split(" ");
  457 + for (String classPathEntry : classPathEntries)
  458 + {
  459 + File classPathJar = new File(this.bootstrap.getGameDirectory(), classPathEntry);
  460 + URL jarUrl = classPathJar.toURI().toURL();
  461 +
  462 + LiteLoaderEnumerator.logInfo("Adding Class-Path entry: %s", classPathEntry);
  463 + LiteLoaderTweaker.addURLToParentClassLoader(jarUrl);
  464 + this.classLoader.addURL(jarUrl);
  465 + }
  466 + }
  467 + }
  468 + catch (Exception ex)
  469 + {
  470 + LiteLoaderEnumerator.logWarning("Error parsing tweak class manifest entry in '%s'", jarFile.getAbsolutePath());
  471 + }
  472 + finally
  473 + {
  474 + try
  475 + {
  476 + if (jar != null) jar.close();
  477 + }
  478 + catch (IOException ex) {}
  479 + }
  480 + }
  481 +
  482 + /**
  483 + * Find mod classes in the class path and enumerated mod files list
  484 + * @param classPathEntries Java class path split into string entries
  485 + */
  486 + private void findModClasses(String[] classPathEntries)
  487 + {
  488 + if (this.searchProtectionDomain || this.searchClassPath)
  489 + LiteLoaderEnumerator.logInfo("Discovering mods on class path...");
  490 +
  491 + if (this.searchProtectionDomain)
  492 + {
  493 + try
  494 + {
  495 + this.findModsInProtectionDomain();
  496 + }
  497 + catch (Throwable th)
  498 + {
  499 + LiteLoaderEnumerator.logWarning("Error loading from local class path: %s", th.getMessage());
  500 + }
  501 + }
  502 +
  503 + if (this.searchClassPath)
  504 + {
  505 + // Search through the class path and find mod classes
  506 + this.findModsInClassPath(classPathEntries);
  507 + }
  508 +
  509 + // Search through mod files and find mod classes
  510 + this.findModsInFiles();
  511 +
  512 + LiteLoaderEnumerator.logInfo("Mod class discovery completed");
  513 + }
  514 +
  515 + /**
  516 + * @param modsToLoad
  517 + * @throws MalformedURLException
  518 + * @throws URISyntaxException
  519 + * @throws UnsupportedEncodingException
  520 + */
  521 + @SuppressWarnings("unchecked")
  522 + private void findModsInProtectionDomain() throws MalformedURLException, URISyntaxException, UnsupportedEncodingException
  523 + {
  524 + LiteLoaderEnumerator.logInfo("Searching protection domain code source...");
  525 +
  526 + File packagePath = null;
  527 +
  528 + URL protectionDomainLocation = LiteLoaderEnumerator.class.getProtectionDomain().getCodeSource().getLocation();
  529 + if (protectionDomainLocation != null)
  530 + {
  531 + if (protectionDomainLocation.toString().indexOf('!') > -1 && protectionDomainLocation.toString().startsWith("jar:"))
  532 + {
  533 + protectionDomainLocation = new URL(protectionDomainLocation.toString().substring(4, protectionDomainLocation.toString().indexOf('!')));
  534 + }
  535 +
  536 + packagePath = new File(protectionDomainLocation.toURI());
  537 + }
  538 + else
  539 + {
  540 + // Fix (?) for forge and other mods which mangle the protection domain
  541 + String reflectionClassPath = LiteLoaderEnumerator.class.getResource("/com/mumfrey/liteloader/core/LiteLoader.class").getPath();
  542 +
  543 + if (reflectionClassPath.indexOf('!') > -1)
  544 + {
  545 + reflectionClassPath = URLDecoder.decode(reflectionClassPath, "UTF-8");
  546 + packagePath = new File(reflectionClassPath.substring(5, reflectionClassPath.indexOf('!')));
  547 + }
  548 + }
  549 +
  550 + if (packagePath != null)
  551 + {
  552 + LinkedList<Class<?>> modClasses = LiteLoaderEnumerator.getSubclassesFor(packagePath, this.classLoader, LiteMod.class, "LiteMod");
  553 +
  554 + for (Class<?> mod : modClasses)
  555 + {
  556 + if (this.modsToLoad.containsKey(mod.getSimpleName()))
  557 + {
  558 + LiteLoaderEnumerator.logWarning("Mod name collision for mod with class '%s', maybe you have more than one copy?", mod.getSimpleName());
  559 + }
  560 +
  561 + this.modsToLoad.put(mod.getSimpleName(), (Class<? extends LiteMod>)mod);
  562 + }
  563 +
  564 + if (modClasses.size() > 0)
  565 + LiteLoaderEnumerator.logInfo("Found %s potential matches", modClasses.size());
  566 + }
  567 + }
  568 +
  569 + /**
  570 + * @param classPathEntries
  571 + * @param modsToLoad
  572 + */
  573 + @SuppressWarnings("unchecked")
  574 + private void findModsInClassPath(String[] classPathEntries)
  575 + {
  576 + for (String classPathPart : classPathEntries)
  577 + {
  578 + LiteLoaderEnumerator.logInfo("Searching %s...", classPathPart);
  579 +
  580 + File packagePath = new File(classPathPart);
  581 + LinkedList<Class<?>> modClasses = LiteLoaderEnumerator.getSubclassesFor(packagePath, this.classLoader, LiteMod.class, "LiteMod");
  582 +
  583 + for (Class<?> mod : modClasses)
  584 + {
  585 + if (this.modsToLoad.containsKey(mod.getSimpleName()))
  586 + {
  587 + LiteLoaderEnumerator.logWarning("Mod name collision for mod with class '%s', maybe you have more than one copy?", mod.getSimpleName());
  588 + }
  589 +
  590 + this.modsToLoad.put(mod.getSimpleName(), (Class<? extends LiteMod>)mod);
  591 + this.modFiles.put(mod.getSimpleName(), new ClassPathMod(packagePath, mod.getSimpleName().substring(7), LiteLoaderBootstrap.VERSION.getLoaderVersion()));
  592 + }
  593 +
  594 + if (modClasses.size() > 0)
  595 + LiteLoaderEnumerator.logInfo("Found %s potential matches", modClasses.size());
  596 + }
  597 + }
  598 +
  599 + /**
  600 + */
  601 + @SuppressWarnings("unchecked")
  602 + private void findModsInFiles()
  603 + {
  604 + for (ModFile modFile : this.allModFiles)
  605 + {
  606 + LiteLoaderEnumerator.logInfo("Searching %s...", modFile.getAbsolutePath());
  607 +
  608 + LinkedList<Class<?>> modClasses = LiteLoaderEnumerator.getSubclassesFor(modFile, this.classLoader, LiteMod.class, "LiteMod");
  609 +
  610 + for (Class<?> mod : modClasses)
  611 + {
  612 + if (this.modsToLoad.containsKey(mod.getSimpleName()))
  613 + {
  614 + LiteLoaderEnumerator.logWarning("Mod name collision for mod with class '%s', maybe you have more than one copy?", mod.getSimpleName());
  615 + }
  616 +
  617 + this.modsToLoad.put(mod.getSimpleName(), (Class<? extends LiteMod>)mod);
  618 + this.modFiles.put(mod.getSimpleName(), modFile);
  619 + }
  620 +
  621 + if (modClasses.size() > 0)
  622 + LiteLoaderEnumerator.logInfo("Found %s potential matches", modClasses.size());
  623 + }
  624 + }
  625 +
  626 + /**
  627 + * Enumerate classes on the classpath which are subclasses of the specified
  628 + * class
  629 + *
  630 + * @param superClass
  631 + * @return
  632 + */
  633 + private static LinkedList<Class<?>> getSubclassesFor(File packagePath, ClassLoader classloader, Class<?> superClass, String prefix)
  634 + {
  635 + LinkedList<Class<?>> classes = new LinkedList<Class<?>>();
  636 +
  637 + try
  638 + {
  639 + if (packagePath.isDirectory())
  640 + {
  641 + LiteLoaderEnumerator.enumerateDirectory(prefix, superClass, classloader, classes, packagePath);
  642 + }
  643 + else if (packagePath.isFile() && (packagePath.getName().endsWith(".jar") || packagePath.getName().endsWith(".zip") || packagePath.getName().endsWith(".litemod")))
  644 + {
  645 + LiteLoaderEnumerator.enumerateCompressedPackage(prefix, superClass, classloader, classes, packagePath);
  646 + }
  647 + }
  648 + catch (Throwable th)
  649 + {
  650 + LiteLoaderEnumerator.logger.log(Level.WARNING, "Enumeration error", th);
  651 + }
  652 +
  653 + return classes;
  654 + }
  655 +
  656 + /**
  657 + * @param superClass
  658 + * @param classloader
  659 + * @param classes
  660 + * @param packagePath
  661 + * @throws FileNotFoundException
  662 + * @throws IOException
  663 + */
  664 + private static void enumerateCompressedPackage(String prefix, Class<?> superClass, ClassLoader classloader, LinkedList<Class<?>> classes, File packagePath) throws FileNotFoundException, IOException
  665 + {
  666 + FileInputStream fileinputstream = new FileInputStream(packagePath);
  667 + ZipInputStream zipinputstream = new ZipInputStream(fileinputstream);
  668 +
  669 + ZipEntry zipentry = null;
  670 +
  671 + do
  672 + {
  673 + zipentry = zipinputstream.getNextEntry();
  674 +
  675 + if (zipentry != null && zipentry.getName().endsWith(".class"))
  676 + {
  677 + String classFileName = zipentry.getName();
  678 + String className = classFileName.lastIndexOf('/') > -1 ? classFileName.substring(classFileName.lastIndexOf('/') + 1) : classFileName;
  679 +
  680 + if (prefix == null || className.startsWith(prefix))
  681 + {
  682 + try
  683 + {
  684 + String fullClassName = classFileName.substring(0, classFileName.length() - 6).replaceAll("/", ".");
  685 + LiteLoaderEnumerator.checkAndAddClass(classloader, superClass, classes, fullClassName);
  686 + }
  687 + catch (Exception ex) {}
  688 + }
  689 + }
  690 + } while (zipentry != null);
  691 +
  692 + fileinputstream.close();
  693 + }
  694 +
  695 + /**
  696 + * Recursive function to enumerate classes inside a classpath folder
  697 + *
  698 + * @param superClass
  699 + * @param classloader
  700 + * @param classes
  701 + * @param packagePath
  702 + * @param packageName
  703 + */
  704 + private static void enumerateDirectory(String prefix, Class<?> superClass, ClassLoader classloader, LinkedList<Class<?>> classes, File packagePath)
  705 + {
  706 + LiteLoaderEnumerator.enumerateDirectory(prefix, superClass, classloader, classes, packagePath, "", 0);
  707 + }
  708 +
  709 + /**
  710 + * Recursive function to enumerate classes inside a classpath folder
  711 + *
  712 + * @param superClass
  713 + * @param classloader
  714 + * @param classes
  715 + * @param packagePath
  716 + * @param packageName
  717 + */
  718 + private static void enumerateDirectory(String prefix, Class<?> superClass, ClassLoader classloader, LinkedList<Class<?>> classes, File packagePath, String packageName, int depth)
  719 + {
  720 + // Prevent crash due to broken recursion
  721 + if (depth > MAX_DISCOVERY_DEPTH)
  722 + return;
  723 +
  724 + File[] classFiles = packagePath.listFiles();
  725 +
  726 + for (File classFile : classFiles)
  727 + {
  728 + if (classFile.isDirectory())
  729 + {
  730 + LiteLoaderEnumerator.enumerateDirectory(prefix, superClass, classloader, classes, classFile, packageName + classFile.getName() + ".", depth + 1);
  731 + }
  732 + else
  733 + {
  734 + if (classFile.getName().endsWith(".class") && (prefix == null || classFile.getName().startsWith(prefix)))
  735 + {
  736 + String classFileName = classFile.getName();
  737 + String className = packageName + classFileName.substring(0, classFileName.length() - 6);
  738 + LiteLoaderEnumerator.checkAndAddClass(classloader, superClass, classes, className);
  739 + }
  740 + }
  741 + }
  742 + }
  743 +
  744 + /**
  745 + * @param classloader
  746 + * @param superClass
  747 + * @param classes
  748 + * @param className
  749 + */
  750 + private static void checkAndAddClass(ClassLoader classloader, Class<?> superClass, LinkedList<Class<?>> classes, String className)
  751 + {
  752 + if (className.indexOf('$') > -1)
  753 + return;
  754 +
  755 + try
  756 + {
  757 + Class<?> subClass = classloader.loadClass(className);
  758 +
  759 + if (subClass != null && !superClass.equals(subClass) && superClass.isAssignableFrom(subClass) && !subClass.isInterface() && !classes.contains(subClass))
  760 + {
  761 + classes.add(subClass);
  762 + }
  763 + }
  764 + catch (Throwable th)
  765 + {
  766 + LiteLoaderEnumerator.logger.log(Level.WARNING, "checkAndAddClass error", th);
  767 + }
  768 + }
  769 +
  770 + private static void logInfo(String string, Object... args)
  771 + {
  772 + LiteLoaderEnumerator.logger.info(String.format(string, args));
  773 + }
  774 +
  775 + private static void logWarning(String string, Object... args)
  776 + {
  777 + LiteLoaderEnumerator.logger.warning(String.format(string, args));
  778 + }
  779 +}
... ...
java/com/mumfrey/liteloader/core/LiteLoaderVersion.java
... ... @@ -7,7 +7,7 @@ import java.util.Set;
7 7 * LiteLoader version table
8 8 *
9 9 * @author Adam Mummery-Smith
10   - * @version 1.6.4_01
  10 + * @version 1.6.4_02
11 11 */
12 12 public enum LiteLoaderVersion
13 13 {
... ... @@ -23,7 +23,8 @@ public enum LiteLoaderVersion
23 23 MC_1_6_2_R4(15, "1.6.2", "1.6.2_04", "1.6.2", "1.6.r2"),
24 24 MC_1_6_3_R0(16, "1.6.3", "1.6.3", "1.6.3", "1.6.r3"),
25 25 MC_1_6_4_R0(17, "1.6.4", "1.6.4", "1.6.4", "1.6.r4"),
26   - MC_1_6_4_R1(18, "1.6.4", "1.6.4_01", "1.6.4", "1.6.r4");
  26 + MC_1_6_4_R1(18, "1.6.4", "1.6.4_01", "1.6.4", "1.6.r4"),
  27 + MC_1_6_4_R2(19, "1.6.4", "1.6.4_02", "1.6.4", "1.6.r4");
27 28  
28 29 private int revision;
29 30  
... ...
java/com/mumfrey/liteloader/core/ModFile.java
... ... @@ -3,8 +3,7 @@ package com.mumfrey.liteloader.core;
3 3 import java.io.File;
4 4 import java.util.HashMap;
5 5 import java.util.Map;
6   -
7   -import net.minecraft.src.ResourcePack;
  6 +import java.util.logging.Logger;
8 7  
9 8 import com.google.gson.Gson;
10 9 import com.google.gson.JsonSyntaxException;
... ... @@ -21,6 +20,8 @@ public class ModFile extends File
21 20 {
22 21 private static final long serialVersionUID = -7952147161905688459L;
23 22  
  23 + private static final Logger logger = Logger.getLogger("liteloader");
  24 +
24 25 /**
25 26 * Gson parser for JSON
26 27 */
... ... @@ -64,7 +65,7 @@ public class ModFile extends File
64 65 /**
65 66 * Resource pack we have registered with minecraft
66 67 */
67   - protected ResourcePack resourcePack = null;
  68 + protected Object resourcePack = null;
68 69  
69 70 /**
70 71 * ALL of the parsed metadata from the file, associated with the mod later on for retrieval via the loader
... ... @@ -75,7 +76,7 @@ public class ModFile extends File
75 76 * @param file
76 77 * @param strVersion
77 78 */
78   - public ModFile(File file, String strVersion)
  79 + ModFile(File file, String strVersion)
79 80 {
80 81 super(file.getAbsolutePath());
81 82  
... ... @@ -87,47 +88,36 @@ public class ModFile extends File
87 88 @SuppressWarnings("unchecked")
88 89 protected void parseVersionFile(String strVersionData)
89 90 {
90   - // Assume that it's json if the file starts with a brace
91   -// if (strVersionData.trim().startsWith("{"))
92   -// {
93   - try
94   - {
95   - this.metaData = ModFile.gson.fromJson(strVersionData, HashMap.class);
96   - }
97   - catch (JsonSyntaxException jsx)
98   - {
99   - LiteLoader.getLogger().warning("Error reading litemod.json in " + this.getName() + ", JSON syntax exception: " + jsx.getMessage());
100   - return;
101   - }
102   -
103   - this.modName = this.metaData.get("name");
104   -
105   - this.version = this.metaData.get("mcversion");
106   - if (this.version == null)
107   - {
108   - LiteLoader.getLogger().warning("Mod in " + this.getName() + " has no loader version number reading litemod.json");
109   - return;
110   - }
111   -
112   - try
113   - {
114   - this.revision = Float.parseFloat(this.metaData.get("revision"));
115   - this.hasRevision = true;
116   - }
117   - catch (Exception ex)
118   - {
119   - LiteLoader.getLogger().warning("Mod in " + this.getName() + " has an invalid revision number reading litemod.json");
120   - }
  91 + try
  92 + {
  93 + this.metaData = ModFile.gson.fromJson(strVersionData, HashMap.class);
  94 + }
  95 + catch (JsonSyntaxException jsx)
  96 + {
  97 + ModFile.logger.warning("Error reading litemod.json in " + this.getName() + ", JSON syntax exception: " + jsx.getMessage());
  98 + return;
  99 + }
  100 +
  101 + this.modName = this.metaData.get("name");
  102 +
  103 + this.version = this.metaData.get("mcversion");
  104 + if (this.version == null)
  105 + {
  106 + ModFile.logger.warning("Mod in " + this.getName() + " has no loader version number reading litemod.json");
  107 + return;
  108 + }
  109 +
  110 + try
  111 + {
  112 + this.revision = Float.parseFloat(this.metaData.get("revision"));
  113 + this.hasRevision = true;
  114 + }
  115 + catch (Exception ex)
  116 + {
  117 + ModFile.logger.warning("Mod in " + this.getName() + " has an invalid revision number reading litemod.json");
  118 + }
121 119  
122   - this.valid = true;
123   -// this.json = true;
124   -// }
125   -// else
126   -// {
127   -// // Legacy version.txt file
128   -// this.version = strVersionData;
129   -// this.valid = true;
130   -// }
  120 + this.valid = true;
131 121  
132 122 if (this.modName == null)
133 123 {
... ... @@ -145,11 +135,6 @@ public class ModFile extends File
145 135 return this.valid;
146 136 }
147 137  
148   -// public boolean isJson()
149   -// {
150   -// return this.json;
151   -// }
152   -
153 138 public String getVersion()
154 139 {
155 140 return this.version;
... ... @@ -170,19 +155,25 @@ public class ModFile extends File
170 155 return this.metaData;
171 156 }
172 157  
  158 + @SuppressWarnings("unchecked")
  159 + public <T> T getResourcePack()
  160 + {
  161 + return (T)this.resourcePack;
  162 + }
  163 +
173 164 /**
174 165 * Registers this file as a minecraft resource pack
175 166 *
176 167 * @param name
177 168 * @return true if the pack was added
178 169 */
179   - public boolean registerAsResourcePack(String name)
  170 + public boolean canRegisterAsResourcePack(String name)
180 171 {
181 172 if (this.resourcePack == null)
182 173 {
183   - LiteLoader.getLogger().info(String.format("Registering \"%s\" as mod resource pack with identifier \"%s\"", this.getName(), name));
  174 + ModFile.logger.info(String.format("Registering \"%s\" as mod resource pack with identifier \"%s\"", this.getName(), name));
184 175 this.resourcePack = new ModResourcePack(name, this);
185   - return LiteLoader.getInstance().registerModResourcePack(this.resourcePack);
  176 + return true;
186 177 }
187 178  
188 179 return false;
... ...
java/com/mumfrey/liteloader/core/PluginChannels.java
... ... @@ -41,11 +41,9 @@ public class PluginChannels
41 41 private LinkedList<PluginChannelListener> pluginChannelListeners = new LinkedList<PluginChannelListener>();
42 42  
43 43 /**
44   - * @param loader
  44 + * Package private
45 45 */
46   - public PluginChannels()
47   - {
48   - }
  46 + PluginChannels() {}
49 47  
50 48 /**
51 49 *
... ... @@ -145,7 +143,7 @@ public class PluginChannels
145 143 }
146 144  
147 145 byte[] registrationData = channelList.toString().getBytes(Charset.forName("UTF8"));
148   - PluginChannels.sendMessage(CHANNEL_REGISTER, registrationData);
  146 + PluginChannels.dispatch(new Packet250CustomPayload(CHANNEL_REGISTER, registrationData));
149 147 }
150 148 }
151 149  
... ... @@ -176,20 +174,33 @@ public class PluginChannels
176 174 }
177 175 }
178 176  
  177 + /**
  178 + * Send a message on a plugin channel
  179 + *
  180 + * @param channel Channel to send, must not be a reserved channel name
  181 + * @param data
  182 + */
179 183 public static void sendMessage(String channel, byte[] data)
180 184 {
181   - if (channel == null || channel.length() > 16)
  185 + if (channel == null || channel.length() > 16 || CHANNEL_REGISTER.equals(channel) || CHANNEL_UNREGISTER.equals(channel))
182 186 throw new RuntimeException("Invalid channel name specified");
183 187  
  188 + Packet250CustomPayload payload = new Packet250CustomPayload(channel, data);
  189 + PluginChannels.dispatch(payload);
  190 + }
  191 +
  192 + /**
  193 + * @param channel
  194 + * @param data
  195 + */
  196 + private static void dispatch(Packet250CustomPayload payload)
  197 + {
184 198 try
185 199 {
186 200 Minecraft minecraft = Minecraft.getMinecraft();
187 201  
188 202 if (minecraft.thePlayer != null && minecraft.thePlayer.sendQueue != null)
189   - {
190   - Packet250CustomPayload payload = new Packet250CustomPayload(channel, data);
191 203 minecraft.thePlayer.sendQueue.addToSendQueue(payload);
192   - }
193 204 }
194 205 catch (Exception ex) {}
195 206 }
... ...
java/com/mumfrey/liteloader/core/SoundManagerReloadInhibitor.java
... ... @@ -35,7 +35,7 @@ public class SoundManagerReloadInhibitor
35 35 */
36 36 private int storedIndex;
37 37  
38   - public SoundManagerReloadInhibitor(SimpleReloadableResourceManager resourceManager, SoundManager soundManager)
  38 + SoundManagerReloadInhibitor(SimpleReloadableResourceManager resourceManager, SoundManager soundManager)
39 39 {
40 40 this.resourceManager = resourceManager;
41 41 this.soundManager = soundManager;
... ...
java/com/mumfrey/liteloader/core/hooks/HookProfiler.java
... ... @@ -146,7 +146,7 @@ public class HookProfiler extends Profiler
146 146 if (!this.initDone)
147 147 {
148 148 this.initDone = true;
149   - this.events.onInit();
  149 + this.events.preBeginGame();
150 150 }
151 151  
152 152 if ("gameRenderer".equals(sectionName) && "root".equals(this.sectionStack.getLast()))
... ... @@ -249,14 +249,4 @@ public class HookProfiler extends Profiler
249 249 throw new ProfilerStackCorruptionException("Corrupted Profiler stack detected");
250 250 }
251 251 }
252   -//
253   -// @Override
254   -// public void dumpState()
255   -// {
256   -// String endingSection = this.sectionStack.size() > 0 ? this.sectionStack.getLast() : null;
257   -// String nextSection = this.sectionStack.size() > 1 ? this.sectionStack.get(sectionStack.size() - 2) : null;
258   -//
259   -// System.out.println("endingSection=" + endingSection + " nextSection=" + nextSection);
260   -// }
261   -
262   -}
  252 +}
263 253 \ No newline at end of file
... ...
java/com/mumfrey/liteloader/core/CallableLiteLoaderBrand.java renamed to java/com/mumfrey/liteloader/crashreport/CallableLiteLoaderBrand.java
1   -package com.mumfrey.liteloader.core;
  1 +package com.mumfrey.liteloader.crashreport;
2 2  
3 3 import java.util.concurrent.Callable;
4 4  
  5 +import com.mumfrey.liteloader.core.LiteLoader;
  6 +
5 7 import net.minecraft.src.CrashReport;
6 8  
7 9 public class CallableLiteLoaderBrand implements Callable<String>
... ...
java/com/mumfrey/liteloader/core/CallableLiteLoaderMods.java renamed to java/com/mumfrey/liteloader/crashreport/CallableLiteLoaderMods.java
1   -package com.mumfrey.liteloader.core;
  1 +package com.mumfrey.liteloader.crashreport;
2 2  
3 3 import java.util.concurrent.Callable;
4 4  
  5 +import com.mumfrey.liteloader.core.LiteLoader;
  6 +
5 7 import net.minecraft.src.CrashReport;
6 8  
7 9 public class CallableLiteLoaderMods implements Callable<String>
... ...
java/com/mumfrey/liteloader/launch/ILoaderBootstrap.java 0 → 100644
  1 +package com.mumfrey.liteloader.launch;
  2 +
  3 +import java.util.List;
  4 +
  5 +import net.minecraft.launchwrapper.LaunchClassLoader;
  6 +
  7 +/**
  8 + * Interface for the loader bootstrap, this is loaded in the parent classloader for convenience
  9 + * otherwise it would be necessary to call the initialisation functions using reflection which
  10 + * just gets boring very quickly.
  11 + *
  12 + * @author Adam Mummery-Smith
  13 + */
  14 +public interface ILoaderBootstrap
  15 +{
  16 + /**
  17 + * Pre-init, perform mod file discovery and initial setup (eg. logger, properties)
  18 + *
  19 + * @param classLoader
  20 + * @param loadTweaks
  21 + */
  22 + public abstract void preInit(LaunchClassLoader classLoader, boolean loadTweaks);
  23 +
  24 + /**
  25 + * Init, create the loader instance and load mods
  26 + *
  27 + * @param modsToLoad
  28 + * @param classLoader
  29 + */
  30 + public abstract void init(List<String> modsToLoad, LaunchClassLoader classLoader);
  31 +
  32 + /**
  33 + * Post-init, initialise loaded mods
  34 + */
  35 + public abstract void postInit();
  36 +}
... ...
java/com/mumfrey/liteloader/launch/LiteLoaderTransformer.java
... ... @@ -17,8 +17,8 @@ public class LiteLoaderTransformer implements IClassTransformer
17 17 if ((classMappingRenderLightningBolt.equals(name) || classMappingRenderLightningBoltObf.equals(name)) && !LiteLoaderTransformer.postInit)
18 18 {
19 19 LiteLoaderTransformer.postInit = true;
20   - LiteLoaderTweaker.preInitLoader(); // This is here at the moment, it will move later
21   - LiteLoaderTweaker.postInitLoader();
  20 + LiteLoaderTweaker.init();
  21 + LiteLoaderTweaker.postInit();
22 22 }
23 23  
24 24 return basicClass;
... ...
java/com/mumfrey/liteloader/launch/LiteLoaderTweaker.java
1 1 package com.mumfrey.liteloader.launch;
2 2  
3 3 import java.io.File;
  4 +import java.lang.reflect.Constructor;
  5 +import java.lang.reflect.InvocationTargetException;
4 6 import java.lang.reflect.Method;
5 7 import java.net.URL;
6 8 import java.net.URLClassLoader;
... ... @@ -16,6 +18,8 @@ import joptsimple.ArgumentAcceptingOptionSpec;
16 18 import joptsimple.NonOptionArgumentSpec;
17 19 import joptsimple.OptionParser;
18 20 import joptsimple.OptionSet;
  21 +import net.minecraft.client.ClientBrandRetriever;
  22 +import net.minecraft.launchwrapper.IClassTransformer;
19 23 import net.minecraft.launchwrapper.ITweaker;
20 24 import net.minecraft.launchwrapper.Launch;
21 25 import net.minecraft.launchwrapper.LaunchClassLoader;
... ... @@ -32,6 +36,8 @@ public class LiteLoaderTweaker implements ITweaker
32 36  
33 37 private static boolean preInit = true;
34 38  
  39 + private static boolean init = true;
  40 +
35 41 private static File gameDirectory;
36 42  
37 43 private static File assetsDirectory;
... ... @@ -40,6 +46,8 @@ public class LiteLoaderTweaker implements ITweaker
40 46  
41 47 private static List<String> modsToLoad;
42 48  
  49 + private static ILoaderBootstrap bootstrap;
  50 +
43 51 private List<String> singularLaunchArgs = new ArrayList<String>();
44 52  
45 53 private Map<String, String> launchArgs;
... ... @@ -84,7 +92,7 @@ public class LiteLoaderTweaker implements ITweaker
84 92 LiteLoaderTweaker.modsToLoad = this.modsOption.values(this.parsedOptions);
85 93 }
86 94  
87   -// LiteLoaderTweaker.preInitLoader(); // for future version with tweak support
  95 + this.preInit();
88 96 }
89 97  
90 98 /**
... ... @@ -166,21 +174,6 @@ public class LiteLoaderTweaker implements ITweaker
166 174  
167 175 return args.toArray(new String[args.size()]);
168 176 }
169   -
170   - public File getGameDirectory()
171   - {
172   - return LiteLoaderTweaker.gameDirectory;
173   - }
174   -
175   - public File getAssetsDirectory()
176   - {
177   - return LiteLoaderTweaker.assetsDirectory;
178   - }
179   -
180   - public String getProfile()
181   - {
182   - return LiteLoaderTweaker.profile;
183   - }
184 177  
185 178 public static boolean addTweaker(URL tweakSource, String tweakClass)
186 179 {
... ... @@ -204,22 +197,58 @@ public class LiteLoaderTweaker implements ITweaker
204 197  
205 198 return false;
206 199 }
207   -
  200 +
  201 + /**
  202 + * @param url URL to add
  203 + */
  204 + public static boolean addURLToParentClassLoader(URL url)
  205 + {
  206 + if (LiteLoaderTweaker.preInit)
  207 + {
  208 + try
  209 + {
  210 + URLClassLoader classLoader = (URLClassLoader)Launch.class.getClassLoader();
  211 + Method mAddUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
  212 + mAddUrl.setAccessible(true);
  213 + mAddUrl.invoke(classLoader, url);
  214 +
  215 + return true;
  216 + }
  217 + catch (Exception ex)
  218 + {
  219 + LiteLoaderTweaker.logger.log(Level.WARNING, String.format("addURLToParentClassLoader failed: %s", ex.getMessage()), ex);
  220 + }
  221 + }
  222 +
  223 + return false;
  224 + }
  225 +
  226 + @SuppressWarnings("unchecked")
  227 + private static void spawnBootstrap() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
  228 + {
  229 + Class<? extends ILoaderBootstrap> bootstrapClass = (Class<? extends ILoaderBootstrap>)Class.forName("com.mumfrey.liteloader.core.LiteLoaderBootstrap", false, Launch.classLoader);
  230 + Constructor<? extends ILoaderBootstrap> bootstrapCtor = bootstrapClass.getDeclaredConstructor(File.class, File.class, String.class);
  231 + bootstrapCtor.setAccessible(true);
  232 +
  233 + LiteLoaderTweaker.bootstrap = bootstrapCtor.newInstance(LiteLoaderTweaker.gameDirectory, LiteLoaderTweaker.assetsDirectory, LiteLoaderTweaker.profile);
  234 + }
  235 +
208 236 /**
209 237 * Do the first stage of loader startup, which enumerates mod sources and finds tweakers
210 238 */
211   - protected static void preInitLoader()
  239 + private void preInit()
212 240 {
213 241 if (!LiteLoaderTweaker.preInit) throw new IllegalStateException("Attempt to perform LiteLoader PreInit but PreInit was already completed");
214   - LiteLoaderTweaker.logger.info("Beginning LiteLoader PreInit...");
215 242  
216 243 try
217 244 {
218   - Class<?> loaderClass = Class.forName("com.mumfrey.liteloader.core.LiteLoader", false, Launch.classLoader);
219   - Method mPreInit = loaderClass.getDeclaredMethod("preInit", File.class, File.class, String.class, List.class, LaunchClassLoader.class, Boolean.TYPE);
220   - mPreInit.setAccessible(true);
221   - mPreInit.invoke(null, LiteLoaderTweaker.gameDirectory, LiteLoaderTweaker.assetsDirectory, LiteLoaderTweaker.profile, LiteLoaderTweaker.modsToLoad, Launch.classLoader, false);
222   -
  245 + LiteLoaderTweaker.logger.info("Bootstrapping LiteLoader " + LiteLoaderTweaker.VERSION);
  246 +
  247 + LiteLoaderTweaker.spawnBootstrap();
  248 +
  249 + LiteLoaderTweaker.logger.info("Beginning LiteLoader PreInit...");
  250 +
  251 + LiteLoaderTweaker.bootstrap.preInit(Launch.classLoader, true);
223 252 LiteLoaderTweaker.preInit = false;
224 253 }
225 254 catch (Throwable th)
... ... @@ -227,51 +256,53 @@ public class LiteLoaderTweaker implements ITweaker
227 256 LiteLoaderTweaker.logger.log(Level.SEVERE, String.format("Error during LiteLoader PreInit: %s", th.getMessage()), th);
228 257 }
229 258 }
230   -
  259 +
231 260 /**
232 261 * Do the second stage of loader startup
233 262 */
234   - protected static void postInitLoader()
  263 + protected static void init()
235 264 {
236   - if (LiteLoaderTweaker.preInit) throw new IllegalStateException("Attempt to perform LiteLoader PostInit but PreInit was not completed");
237   - LiteLoaderTweaker.logger.info("Beginning LiteLoader PostInit...");
  265 + if (LiteLoaderTweaker.preInit) throw new IllegalStateException("Attempt to perform LiteLoader Init but PreInit was not completed");
  266 + LiteLoaderTweaker.init = true;
238 267  
239 268 try
240 269 {
241   - Class<?> loaderClass = Class.forName("com.mumfrey.liteloader.core.LiteLoader", false, Launch.classLoader);
242   - Method mPostInit = loaderClass.getDeclaredMethod("postInit");
243   - mPostInit.setAccessible(true);
244   - mPostInit.invoke(null);
  270 + LiteLoaderTweaker.bootstrap.init(LiteLoaderTweaker.modsToLoad, Launch.classLoader);
  271 + LiteLoaderTweaker.init = false;
  272 + }
  273 + catch (Throwable th)
  274 + {
  275 + LiteLoaderTweaker.logger.log(Level.SEVERE, String.format("Error during LiteLoader Init: %s", th.getMessage()), th);
  276 + }
  277 + }
  278 +
  279 + /**
  280 + * Do the second stage of loader startup
  281 + */
  282 + protected static void postInit()
  283 + {
  284 + if (LiteLoaderTweaker.init) throw new IllegalStateException("Attempt to perform LiteLoader PostInit but Init was not completed");
  285 +
  286 + try
  287 + {
  288 + LiteLoaderTweaker.bootstrap.postInit();
245 289 }
246 290 catch (Throwable th)
247 291 {
248   - th.printStackTrace(System.out);
249 292 LiteLoaderTweaker.logger.log(Level.SEVERE, String.format("Error during LiteLoader PostInit: %s", th.getMessage()), th);
250 293 }
251 294 }
252 295  
253 296 /**
254   - * @param url URL to add
  297 + * Naive implementation to check whether Forge ModLoader (FML) is loaded
255 298 */
256   - public static boolean addURLToParentClassLoader(URL url)
  299 + public static boolean fmlIsPresent()
257 300 {
258   - if (LiteLoaderTweaker.preInit)
259   - {
260   - try
261   - {
262   - URLClassLoader classLoader = (URLClassLoader)Launch.class.getClassLoader();
263   - Method mAddUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
264   - mAddUrl.setAccessible(true);
265   - mAddUrl.invoke(classLoader, url);
  301 + if (ClientBrandRetriever.getClientModName().contains("fml")) return true;
266 302  
267   - return true;
268   - }
269   - catch (Exception ex)
270   - {
271   - LiteLoaderTweaker.logger.log(Level.WARNING, String.format("addURLToParentClassLoader failed: %s", ex.getMessage()), ex);
272   - }
273   - }
274   -
  303 + for (IClassTransformer transformer : Launch.classLoader.getTransformers())
  304 + if (transformer.getClass().getName().contains("fml")) return true;
  305 +
275 306 return false;
276 307 }
277 308 }
278 309 \ No newline at end of file
... ...
java/com/mumfrey/liteloader/log/LiteLoaderLogFormatter.java
... ... @@ -16,12 +16,12 @@ public class LiteLoaderLogFormatter extends Formatter
16 16 {
17 17 StringBuilder sb = new StringBuilder();
18 18 sb.append(this.simpleDateFormatLogFormatter.format(Long.valueOf(logRecord.getMillis())));
19   - Level var3 = logRecord.getLevel();
  19 + Level level = logRecord.getLevel();
20 20  
21   - if (var3 == Level.SEVERE)
22   - sb.append(" [").append(var3.getLocalizedName()).append("] ");
  21 + if (level == Level.SEVERE)
  22 + sb.append(" [").append(level.getLocalizedName()).append("] ");
23 23 else
24   - sb.append(" [").append(var3.toString().toUpperCase()).append("] ");
  24 + sb.append(" [").append(level.toString().toUpperCase()).append("] ");
25 25  
26 26 sb.append(logRecord.getMessage());
27 27 sb.append('\n');
... ...
java/com/mumfrey/liteloader/util/ModUtilities.java
... ... @@ -8,8 +8,8 @@ import java.util.Set;
8 8  
9 9 import com.mumfrey.liteloader.core.LiteLoader;
10 10 import com.mumfrey.liteloader.core.PluginChannels;
  11 +import com.mumfrey.liteloader.launch.LiteLoaderTweaker;
11 12  
12   -import net.minecraft.client.ClientBrandRetriever;
13 13 import net.minecraft.src.*;
14 14  
15 15 public abstract class ModUtilities
... ... @@ -27,7 +27,7 @@ public abstract class ModUtilities
27 27 static
28 28 {
29 29 // Check for FML
30   - ModUtilities.forgeModLoader = ClientBrandRetriever.getClientModName().contains("fml");
  30 + ModUtilities.forgeModLoader = LiteLoaderTweaker.fmlIsPresent();
31 31 }
32 32  
33 33 /**
... ...