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,6 +13,7 @@
13 <property name="project" value="LiteLoader" /> 13 <property name="project" value="LiteLoader" />
14 <property name="md5set" value="mcp" /> 14 <property name="md5set" value="mcp" />
15 <property name="outmd5set" value="liteloader" /> 15 <property name="outmd5set" value="liteloader" />
  16 + <property name="tweakclass" value="com.mumfrey.liteloader.launch.LiteLoaderTweaker" />
16 17
17 <property name="mcp.dir" location="../../.." /> 18 <property name="mcp.dir" location="../../.." />
18 <property name="build" location="${mcp.dir}/build" /> 19 <property name="build" location="${mcp.dir}/build" />
@@ -202,12 +203,14 @@ @@ -202,12 +203,14 @@
202 <echo level="info" message="Building final output" /> 203 <echo level="info" message="Building final output" />
203 204
204 <mkdir dir="${dist.dir}" /> 205 <mkdir dir="${dist.dir}" />
  206 +
205 <jar destfile="${dist.dir}/${ant.project.name}-${mcversion}.${filetype}" duplicate="preserve" index="true" manifestencoding="UTF-8"> 207 <jar destfile="${dist.dir}/${ant.project.name}-${mcversion}.${filetype}" duplicate="preserve" index="true" manifestencoding="UTF-8">
206 <manifest> 208 <manifest>
207 <attribute name="Built-By" value="MCP (http://mcp.ocean-labs.de)" /> 209 <attribute name="Built-By" value="MCP (http://mcp.ocean-labs.de)" />
208 <attribute name="Implementation-Vendor" value="${author}" /> 210 <attribute name="Implementation-Vendor" value="${author}" />
209 <attribute name="Implementation-Title" value="${ant.project.name}" /> 211 <attribute name="Implementation-Title" value="${ant.project.name}" />
210 <attribute name="Implementation-Version" value="${version}" /> 212 <attribute name="Implementation-Version" value="${version}" />
  213 + <attribute name="TweakClass" value="${tweakclass}" />
211 </manifest> 214 </manifest>
212 <fileset dir="${stage.dir}" /> 215 <fileset dir="${stage.dir}" />
213 </jar> 216 </jar>
java/com/mumfrey/liteloader/core/ClassPathMod.java
1 package com.mumfrey.liteloader.core; 1 package com.mumfrey.liteloader.core;
2 2
3 import java.io.File; 3 import java.io.File;
  4 +import java.util.logging.Logger;
4 5
5 import com.mumfrey.liteloader.resources.ModResourcePack; 6 import com.mumfrey.liteloader.resources.ModResourcePack;
6 import com.mumfrey.liteloader.resources.ModResourcePackDir; 7 import com.mumfrey.liteloader.resources.ModResourcePackDir;
@@ -13,8 +14,10 @@ import com.mumfrey.liteloader.resources.ModResourcePackDir; @@ -13,8 +14,10 @@ import com.mumfrey.liteloader.resources.ModResourcePackDir;
13 public class ClassPathMod extends ModFile 14 public class ClassPathMod extends ModFile
14 { 15 {
15 private static final long serialVersionUID = -4759310661966590773L; 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 super(file, ""); 22 super(file, "");
20 23
@@ -29,22 +32,22 @@ public class ClassPathMod extends ModFile @@ -29,22 +32,22 @@ public class ClassPathMod extends ModFile
29 } 32 }
30 33
31 @Override 34 @Override
32 - public boolean registerAsResourcePack(String name) 35 + public boolean canRegisterAsResourcePack(String name)
33 { 36 {
34 if (this.resourcePack == null) 37 if (this.resourcePack == null)
35 { 38 {
36 if (this.isDirectory()) 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 this.resourcePack = new ModResourcePackDir(name, this); 42 this.resourcePack = new ModResourcePackDir(name, this);
40 } 43 }
41 else 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 this.resourcePack = new ModResourcePack(name, this); 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 return false; 53 return false;
java/com/mumfrey/liteloader/core/Events.java
@@ -129,7 +129,14 @@ public class Events implements IPlayerUsage @@ -129,7 +129,14 @@ public class Events implements IPlayerUsage
129 */ 129 */
130 private LinkedList<PreLoginListener> preLoginListeners = new LinkedList<PreLoginListener>(); 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 this.loader = loader; 141 this.loader = loader;
135 this.minecraft = minecraft; 142 this.minecraft = minecraft;
@@ -405,9 +412,9 @@ public class Events implements IPlayerUsage @@ -405,9 +412,9 @@ public class Events implements IPlayerUsage
405 /** 412 /**
406 * Late initialisation callback 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 if (!this.lateInitDone) 419 if (!this.lateInitDone)
413 { 420 {
@@ -427,7 +434,7 @@ public class Events implements IPlayerUsage @@ -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 package com.mumfrey.liteloader.core; 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 import java.util.ArrayList; 8 import java.util.ArrayList;
10 import java.util.Arrays; 9 import java.util.Arrays;
11 import java.util.Collections; 10 import java.util.Collections;
@@ -14,23 +13,12 @@ import java.util.Iterator; @@ -14,23 +13,12 @@ import java.util.Iterator;
14 import java.util.LinkedList; 13 import java.util.LinkedList;
15 import java.util.List; 14 import java.util.List;
16 import java.util.Map; 15 import java.util.Map;
17 -import java.util.Map.Entry;  
18 import java.util.Properties; 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 import java.util.logging.Level; 17 import java.util.logging.Level;
25 import java.util.logging.Logger; 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 import javax.activity.InvalidActivityException; 20 import javax.activity.InvalidActivityException;
32 21
33 -import net.minecraft.client.ClientBrandRetriever;  
34 import net.minecraft.launchwrapper.LaunchClassLoader; 22 import net.minecraft.launchwrapper.LaunchClassLoader;
35 import net.minecraft.src.CrashReport; 23 import net.minecraft.src.CrashReport;
36 import net.minecraft.src.GuiControls; 24 import net.minecraft.src.GuiControls;
@@ -43,9 +31,9 @@ import net.minecraft.src.ResourcePack; @@ -43,9 +31,9 @@ import net.minecraft.src.ResourcePack;
43 import net.minecraft.src.SimpleReloadableResourceManager; 31 import net.minecraft.src.SimpleReloadableResourceManager;
44 32
45 import com.mumfrey.liteloader.*; 33 import com.mumfrey.liteloader.*;
  34 +import com.mumfrey.liteloader.crashreport.CallableLiteLoaderBrand;
  35 +import com.mumfrey.liteloader.crashreport.CallableLiteLoaderMods;
46 import com.mumfrey.liteloader.gui.GuiControlsPaginated; 36 import com.mumfrey.liteloader.gui.GuiControlsPaginated;
47 -import com.mumfrey.liteloader.launch.LiteLoaderTweaker;  
48 -import com.mumfrey.liteloader.log.LiteLoaderLogFormatter;  
49 import com.mumfrey.liteloader.permissions.PermissionsManagerClient; 37 import com.mumfrey.liteloader.permissions.PermissionsManagerClient;
50 import com.mumfrey.liteloader.util.PrivateFields; 38 import com.mumfrey.liteloader.util.PrivateFields;
51 39
@@ -54,21 +42,11 @@ import com.mumfrey.liteloader.util.PrivateFields; @@ -54,21 +42,11 @@ import com.mumfrey.liteloader.util.PrivateFields;
54 * lightweight mods 42 * lightweight mods
55 * 43 *
56 * @author Adam Mummery-Smith 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 * LiteLoader is a singleton, this is the singleton instance 50 * LiteLoader is a singleton, this is the singleton instance
73 */ 51 */
74 private static LiteLoader instance; 52 private static LiteLoader instance;
@@ -79,26 +57,6 @@ public final class LiteLoader implements FilenameFilter @@ -79,26 +57,6 @@ public final class LiteLoader implements FilenameFilter
79 private static final Logger logger = Logger.getLogger("liteloader"); 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 * Tweak system class loader 60 * Tweak system class loader
103 */ 61 */
104 private static LaunchClassLoader classLoader; 62 private static LaunchClassLoader classLoader;
@@ -135,51 +93,25 @@ public final class LiteLoader implements FilenameFilter @@ -135,51 +93,25 @@ public final class LiteLoader implements FilenameFilter
135 private File enabledModsFile; 93 private File enabledModsFile;
136 94
137 /** 95 /**
138 - * File to write log entries to  
139 - */  
140 - private File logFile;  
141 -  
142 - /**  
143 * Reference to the Minecraft game instance 96 * Reference to the Minecraft game instance
144 */ 97 */
145 private Minecraft minecraft; 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 * Setting value, if true we will swap out the MC "Controls" GUI for our 101 * Setting value, if true we will swap out the MC "Controls" GUI for our
170 * custom, paginated one 102 * custom, paginated one
171 */ 103 */
172 private boolean paginateControls = true; 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 * Registered resource packs 117 * Registered resource packs
@@ -224,7 +156,7 @@ public final class LiteLoader implements FilenameFilter @@ -224,7 +156,7 @@ public final class LiteLoader implements FilenameFilter
224 /** 156 /**
225 * Flag which keeps track of whether late initialisation has been done 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 * True while initialising mods if we need to do a resource manager reload once the process is completed 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,20 +195,6 @@ public final class LiteLoader implements FilenameFilter
263 private Map<KeyBinding, Integer> storedModKeyBindings = new HashMap<KeyBinding, Integer>(); 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 * Pre-init routine, called using reflection by the tweaker 198 * Pre-init routine, called using reflection by the tweaker
281 * 199 *
282 * @param gameDirectory Game directory passed to the tweaker 200 * @param gameDirectory Game directory passed to the tweaker
@@ -285,26 +203,21 @@ public final class LiteLoader implements FilenameFilter @@ -285,26 +203,21 @@ public final class LiteLoader implements FilenameFilter
285 * @param modNameFilter List of mod names parsed from the command line 203 * @param modNameFilter List of mod names parsed from the command line
286 * @param classLoader LaunchClassLoader 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 if (LiteLoader.instance == null) 208 if (LiteLoader.instance == null)
292 { 209 {
293 - LiteLoader.gameDirectory = gameDirectory;  
294 - LiteLoader.assetsDirectory = assetsDirectory;  
295 - LiteLoader.profile = profile;  
296 LiteLoader.classLoader = classLoader; 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 * Post-init routine, initialises and loads mods enumerated in preInit 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 if (LiteLoader.instance != null) 222 if (LiteLoader.instance != null)
310 { 223 {
@@ -318,39 +231,34 @@ public final class LiteLoader implements FilenameFilter @@ -318,39 +231,34 @@ public final class LiteLoader implements FilenameFilter
318 * @param profile 231 * @param profile
319 * @param modNameFilter 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 this.enabledModsList = EnabledModsList.createFrom(this.enabledModsFile); 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 * Set up paths used by the loader 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 this.commonConfigFolder = new File(this.configBaseFolder, "common"); 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 if (!this.modsFolder.exists()) this.modsFolder.mkdirs(); 256 if (!this.modsFolder.exists()) this.modsFolder.mkdirs();
347 if (!this.configBaseFolder.exists()) this.configBaseFolder.mkdirs(); 257 if (!this.configBaseFolder.exists()) this.configBaseFolder.mkdirs();
348 if (!this.commonConfigFolder.exists()) this.commonConfigFolder.mkdirs(); 258 if (!this.commonConfigFolder.exists()) this.commonConfigFolder.mkdirs();
349 if (!this.versionConfigFolder.exists()) this.versionConfigFolder.mkdirs(); 259 if (!this.versionConfigFolder.exists()) this.versionConfigFolder.mkdirs();
350 260
351 - this.propertiesFile = new File(this.configBaseFolder, "liteloader.properties");  
352 this.enabledModsFile = new File(this.configBaseFolder, "liteloader.profiles.json"); 261 this.enabledModsFile = new File(this.configBaseFolder, "liteloader.profiles.json");
353 - this.logFile = new File(this.configBaseFolder, "liteloader.log");  
354 this.keyMapSettingsFile = new File(this.configBaseFolder, "liteloader.keys.properties"); 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,7 +266,7 @@ public final class LiteLoader implements FilenameFilter
358 * @param version 266 * @param version
359 * @return 267 * @return
360 */ 268 */
361 - protected File inflectVersionedConfigPath(LiteLoaderVersion version) 269 + private File inflectVersionedConfigPath(LiteLoaderVersion version)
362 { 270 {
363 if (version.equals(LiteLoaderVersion.LEGACY)) 271 if (version.equals(LiteLoaderVersion.LEGACY))
364 { 272 {
@@ -367,45 +275,40 @@ public final class LiteLoader implements FilenameFilter @@ -367,45 +275,40 @@ public final class LiteLoader implements FilenameFilter
367 275
368 return new File(this.configBaseFolder, String.format("config.%s", version.getMinecraftVersion())); 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 private void onPostInit(Minecraft minecraft) 309 private void onPostInit(Minecraft minecraft)
407 { 310 {
408 - if (!this.preInitCompleted || this.postInitStarted) return; 311 + if (this.postInitStarted) return;
409 this.postInitStarted = true; 312 this.postInitStarted = true;
410 313
411 // Cache local minecraft reference 314 // Cache local minecraft reference
@@ -425,178 +328,11 @@ public final class LiteLoader implements FilenameFilter @@ -425,178 +328,11 @@ public final class LiteLoader implements FilenameFilter
425 this.startupComplete = true; 328 this.startupComplete = true;
426 329
427 this.enabledModsList.saveTo(this.enabledModsFile); 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 public boolean registerModResourcePack(ResourcePack resourcePack) 337 public boolean registerModResourcePack(ResourcePack resourcePack)
602 { 338 {
@@ -616,9 +352,8 @@ public final class LiteLoader implements FilenameFilter @@ -616,9 +352,8 @@ public final class LiteLoader implements FilenameFilter
616 return false; 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 public boolean unRegisterModResourcePack(ResourcePack resourcePack) 358 public boolean unRegisterModResourcePack(ResourcePack resourcePack)
624 { 359 {
@@ -674,7 +409,7 @@ public final class LiteLoader implements FilenameFilter @@ -674,7 +409,7 @@ public final class LiteLoader implements FilenameFilter
674 */ 409 */
675 public static final PrintStream getConsoleStream() 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,7 +419,7 @@ public final class LiteLoader implements FilenameFilter
684 */ 419 */
685 public static final String getVersion() 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,7 +429,7 @@ public final class LiteLoader implements FilenameFilter
694 */ 429 */
695 public static final int getRevision() 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,7 +489,7 @@ public final class LiteLoader implements FilenameFilter
754 */ 489 */
755 public static File getGameDirectory() 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,7 +497,7 @@ public final class LiteLoader implements FilenameFilter
762 */ 497 */
763 public static File getAssetsDirectory() 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,7 +505,7 @@ public final class LiteLoader implements FilenameFilter
770 */ 505 */
771 public static String getProfile() 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,7 +541,7 @@ public final class LiteLoader implements FilenameFilter
806 */ 541 */
807 public String getBranding() 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,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 * Get a reference to a loaded mod, if the mod exists 565 * Get a reference to a loaded mod, if the mod exists
862 * 566 *
863 * @param modName Mod's name or class name 567 * @param modName Mod's name or class name
@@ -954,7 +658,7 @@ public final class LiteLoader implements FilenameFilter @@ -954,7 +658,7 @@ public final class LiteLoader implements FilenameFilter
954 public String getModMetaData(LiteMod mod, String metaDataKey, String defaultValue) 658 public String getModMetaData(LiteMod mod, String metaDataKey, String defaultValue)
955 { 659 {
956 if (mod == null || metaDataKey == null) return defaultValue; 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,17 +671,7 @@ public final class LiteLoader implements FilenameFilter
967 */ 671 */
968 public String getModMetaData(Class<? extends LiteMod> modClass, String metaDataKey, String defaultValue) 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,466 +682,83 @@ public final class LiteLoader implements FilenameFilter
988 */ 682 */
989 public String getModMetaName(Class<? extends LiteMod> modClass) 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 return; 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 try 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 else 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 LiteMod mod = iter.next(); 763 LiteMod mod = iter.next();
1453 String modName = mod.getName(); 764 String modName = mod.getName();
@@ -1459,14 +770,14 @@ public final class LiteLoader implements FilenameFilter @@ -1459,14 +770,14 @@ public final class LiteLoader implements FilenameFilter
1459 try 770 try
1460 { 771 {
1461 String modKey = this.getModNameForConfig(mod.getClass(), modName); 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 LiteLoader.logInfo("Config upgrade succeeded for mod %s", modName); 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,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 if (this.pendingResourceReload) 818 if (this.pendingResourceReload)
1651 { 819 {
@@ -1654,20 +822,32 @@ public final class LiteLoader implements FilenameFilter @@ -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 if (this.soundManagerReloadInhibitor != null && this.soundManagerReloadInhibitor.isInhibited()) 833 if (this.soundManagerReloadInhibitor != null && this.soundManagerReloadInhibitor.isInhibited())
1660 { 834 {
1661 this.soundManagerReloadInhibitor.unInhibit(true); 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 this.permissionsManager.onLogin(netHandler, loginPacket); 847 this.permissionsManager.onLogin(netHandler, loginPacket);
1668 } 848 }
1669 849
1670 - public void onRender() 850 + void onRender()
1671 { 851 {
1672 if (this.paginateControls && this.minecraft.currentScreen != null && this.minecraft.currentScreen.getClass().equals(GuiControls.class)) 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,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 // Tick the permissions manager 868 // Tick the permissions manager
1689 this.permissionsManager.onTick(this.minecraft, partialTicks, inGame); 869 this.permissionsManager.onTick(this.minecraft, partialTicks, inGame);
@@ -1748,7 +928,7 @@ public final class LiteLoader implements FilenameFilter @@ -1748,7 +928,7 @@ public final class LiteLoader implements FilenameFilter
1748 /** 928 /**
1749 * Writes mod bindings to disk 929 * Writes mod bindings to disk
1750 */ 930 */
1751 - protected void storeBindings() 931 + private void storeBindings()
1752 { 932 {
1753 try 933 try
1754 { 934 {
@@ -1756,132 +936,22 @@ public final class LiteLoader implements FilenameFilter @@ -1756,132 +936,22 @@ public final class LiteLoader implements FilenameFilter
1756 } 936 }
1757 catch (IOException ex) {} 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 private static void logInfo(String string, Object... args) 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 \ No newline at end of file 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 +7,7 @@ import java.util.Set;
7 * LiteLoader version table 7 * LiteLoader version table
8 * 8 *
9 * @author Adam Mummery-Smith 9 * @author Adam Mummery-Smith
10 - * @version 1.6.4_01 10 + * @version 1.6.4_02
11 */ 11 */
12 public enum LiteLoaderVersion 12 public enum LiteLoaderVersion
13 { 13 {
@@ -23,7 +23,8 @@ public enum LiteLoaderVersion @@ -23,7 +23,8 @@ public enum LiteLoaderVersion
23 MC_1_6_2_R4(15, "1.6.2", "1.6.2_04", "1.6.2", "1.6.r2"), 23 MC_1_6_2_R4(15, "1.6.2", "1.6.2_04", "1.6.2", "1.6.r2"),
24 MC_1_6_3_R0(16, "1.6.3", "1.6.3", "1.6.3", "1.6.r3"), 24 MC_1_6_3_R0(16, "1.6.3", "1.6.3", "1.6.3", "1.6.r3"),
25 MC_1_6_4_R0(17, "1.6.4", "1.6.4", "1.6.4", "1.6.r4"), 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 private int revision; 29 private int revision;
29 30
java/com/mumfrey/liteloader/core/ModFile.java
@@ -3,8 +3,7 @@ package com.mumfrey.liteloader.core; @@ -3,8 +3,7 @@ package com.mumfrey.liteloader.core;
3 import java.io.File; 3 import java.io.File;
4 import java.util.HashMap; 4 import java.util.HashMap;
5 import java.util.Map; 5 import java.util.Map;
6 -  
7 -import net.minecraft.src.ResourcePack; 6 +import java.util.logging.Logger;
8 7
9 import com.google.gson.Gson; 8 import com.google.gson.Gson;
10 import com.google.gson.JsonSyntaxException; 9 import com.google.gson.JsonSyntaxException;
@@ -21,6 +20,8 @@ public class ModFile extends File @@ -21,6 +20,8 @@ public class ModFile extends File
21 { 20 {
22 private static final long serialVersionUID = -7952147161905688459L; 21 private static final long serialVersionUID = -7952147161905688459L;
23 22
  23 + private static final Logger logger = Logger.getLogger("liteloader");
  24 +
24 /** 25 /**
25 * Gson parser for JSON 26 * Gson parser for JSON
26 */ 27 */
@@ -64,7 +65,7 @@ public class ModFile extends File @@ -64,7 +65,7 @@ public class ModFile extends File
64 /** 65 /**
65 * Resource pack we have registered with minecraft 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 * ALL of the parsed metadata from the file, associated with the mod later on for retrieval via the loader 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,7 +76,7 @@ public class ModFile extends File
75 * @param file 76 * @param file
76 * @param strVersion 77 * @param strVersion
77 */ 78 */
78 - public ModFile(File file, String strVersion) 79 + ModFile(File file, String strVersion)
79 { 80 {
80 super(file.getAbsolutePath()); 81 super(file.getAbsolutePath());
81 82
@@ -87,47 +88,36 @@ public class ModFile extends File @@ -87,47 +88,36 @@ public class ModFile extends File
87 @SuppressWarnings("unchecked") 88 @SuppressWarnings("unchecked")
88 protected void parseVersionFile(String strVersionData) 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 if (this.modName == null) 122 if (this.modName == null)
133 { 123 {
@@ -145,11 +135,6 @@ public class ModFile extends File @@ -145,11 +135,6 @@ public class ModFile extends File
145 return this.valid; 135 return this.valid;
146 } 136 }
147 137
148 -// public boolean isJson()  
149 -// {  
150 -// return this.json;  
151 -// }  
152 -  
153 public String getVersion() 138 public String getVersion()
154 { 139 {
155 return this.version; 140 return this.version;
@@ -170,19 +155,25 @@ public class ModFile extends File @@ -170,19 +155,25 @@ public class ModFile extends File
170 return this.metaData; 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 * Registers this file as a minecraft resource pack 165 * Registers this file as a minecraft resource pack
175 * 166 *
176 * @param name 167 * @param name
177 * @return true if the pack was added 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 if (this.resourcePack == null) 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 this.resourcePack = new ModResourcePack(name, this); 175 this.resourcePack = new ModResourcePack(name, this);
185 - return LiteLoader.getInstance().registerModResourcePack(this.resourcePack); 176 + return true;
186 } 177 }
187 178
188 return false; 179 return false;
java/com/mumfrey/liteloader/core/PluginChannels.java
@@ -41,11 +41,9 @@ public class PluginChannels @@ -41,11 +41,9 @@ public class PluginChannels
41 private LinkedList<PluginChannelListener> pluginChannelListeners = new LinkedList<PluginChannelListener>(); 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,7 +143,7 @@ public class PluginChannels
145 } 143 }
146 144
147 byte[] registrationData = channelList.toString().getBytes(Charset.forName("UTF8")); 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,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 public static void sendMessage(String channel, byte[] data) 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 throw new RuntimeException("Invalid channel name specified"); 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 try 198 try
185 { 199 {
186 Minecraft minecraft = Minecraft.getMinecraft(); 200 Minecraft minecraft = Minecraft.getMinecraft();
187 201
188 if (minecraft.thePlayer != null && minecraft.thePlayer.sendQueue != null) 202 if (minecraft.thePlayer != null && minecraft.thePlayer.sendQueue != null)
189 - {  
190 - Packet250CustomPayload payload = new Packet250CustomPayload(channel, data);  
191 minecraft.thePlayer.sendQueue.addToSendQueue(payload); 203 minecraft.thePlayer.sendQueue.addToSendQueue(payload);
192 - }  
193 } 204 }
194 catch (Exception ex) {} 205 catch (Exception ex) {}
195 } 206 }
java/com/mumfrey/liteloader/core/SoundManagerReloadInhibitor.java
@@ -35,7 +35,7 @@ public class SoundManagerReloadInhibitor @@ -35,7 +35,7 @@ public class SoundManagerReloadInhibitor
35 */ 35 */
36 private int storedIndex; 36 private int storedIndex;
37 37
38 - public SoundManagerReloadInhibitor(SimpleReloadableResourceManager resourceManager, SoundManager soundManager) 38 + SoundManagerReloadInhibitor(SimpleReloadableResourceManager resourceManager, SoundManager soundManager)
39 { 39 {
40 this.resourceManager = resourceManager; 40 this.resourceManager = resourceManager;
41 this.soundManager = soundManager; 41 this.soundManager = soundManager;
java/com/mumfrey/liteloader/core/hooks/HookProfiler.java
@@ -146,7 +146,7 @@ public class HookProfiler extends Profiler @@ -146,7 +146,7 @@ public class HookProfiler extends Profiler
146 if (!this.initDone) 146 if (!this.initDone)
147 { 147 {
148 this.initDone = true; 148 this.initDone = true;
149 - this.events.onInit(); 149 + this.events.preBeginGame();
150 } 150 }
151 151
152 if ("gameRenderer".equals(sectionName) && "root".equals(this.sectionStack.getLast())) 152 if ("gameRenderer".equals(sectionName) && "root".equals(this.sectionStack.getLast()))
@@ -249,14 +249,4 @@ public class HookProfiler extends Profiler @@ -249,14 +249,4 @@ public class HookProfiler extends Profiler
249 throw new ProfilerStackCorruptionException("Corrupted Profiler stack detected"); 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 \ No newline at end of file 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 import java.util.concurrent.Callable; 3 import java.util.concurrent.Callable;
4 4
  5 +import com.mumfrey.liteloader.core.LiteLoader;
  6 +
5 import net.minecraft.src.CrashReport; 7 import net.minecraft.src.CrashReport;
6 8
7 public class CallableLiteLoaderBrand implements Callable<String> 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 import java.util.concurrent.Callable; 3 import java.util.concurrent.Callable;
4 4
  5 +import com.mumfrey.liteloader.core.LiteLoader;
  6 +
5 import net.minecraft.src.CrashReport; 7 import net.minecraft.src.CrashReport;
6 8
7 public class CallableLiteLoaderMods implements Callable<String> 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,8 +17,8 @@ public class LiteLoaderTransformer implements IClassTransformer
17 if ((classMappingRenderLightningBolt.equals(name) || classMappingRenderLightningBoltObf.equals(name)) && !LiteLoaderTransformer.postInit) 17 if ((classMappingRenderLightningBolt.equals(name) || classMappingRenderLightningBoltObf.equals(name)) && !LiteLoaderTransformer.postInit)
18 { 18 {
19 LiteLoaderTransformer.postInit = true; 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 return basicClass; 24 return basicClass;
java/com/mumfrey/liteloader/launch/LiteLoaderTweaker.java
1 package com.mumfrey.liteloader.launch; 1 package com.mumfrey.liteloader.launch;
2 2
3 import java.io.File; 3 import java.io.File;
  4 +import java.lang.reflect.Constructor;
  5 +import java.lang.reflect.InvocationTargetException;
4 import java.lang.reflect.Method; 6 import java.lang.reflect.Method;
5 import java.net.URL; 7 import java.net.URL;
6 import java.net.URLClassLoader; 8 import java.net.URLClassLoader;
@@ -16,6 +18,8 @@ import joptsimple.ArgumentAcceptingOptionSpec; @@ -16,6 +18,8 @@ import joptsimple.ArgumentAcceptingOptionSpec;
16 import joptsimple.NonOptionArgumentSpec; 18 import joptsimple.NonOptionArgumentSpec;
17 import joptsimple.OptionParser; 19 import joptsimple.OptionParser;
18 import joptsimple.OptionSet; 20 import joptsimple.OptionSet;
  21 +import net.minecraft.client.ClientBrandRetriever;
  22 +import net.minecraft.launchwrapper.IClassTransformer;
19 import net.minecraft.launchwrapper.ITweaker; 23 import net.minecraft.launchwrapper.ITweaker;
20 import net.minecraft.launchwrapper.Launch; 24 import net.minecraft.launchwrapper.Launch;
21 import net.minecraft.launchwrapper.LaunchClassLoader; 25 import net.minecraft.launchwrapper.LaunchClassLoader;
@@ -32,6 +36,8 @@ public class LiteLoaderTweaker implements ITweaker @@ -32,6 +36,8 @@ public class LiteLoaderTweaker implements ITweaker
32 36
33 private static boolean preInit = true; 37 private static boolean preInit = true;
34 38
  39 + private static boolean init = true;
  40 +
35 private static File gameDirectory; 41 private static File gameDirectory;
36 42
37 private static File assetsDirectory; 43 private static File assetsDirectory;
@@ -40,6 +46,8 @@ public class LiteLoaderTweaker implements ITweaker @@ -40,6 +46,8 @@ public class LiteLoaderTweaker implements ITweaker
40 46
41 private static List<String> modsToLoad; 47 private static List<String> modsToLoad;
42 48
  49 + private static ILoaderBootstrap bootstrap;
  50 +
43 private List<String> singularLaunchArgs = new ArrayList<String>(); 51 private List<String> singularLaunchArgs = new ArrayList<String>();
44 52
45 private Map<String, String> launchArgs; 53 private Map<String, String> launchArgs;
@@ -84,7 +92,7 @@ public class LiteLoaderTweaker implements ITweaker @@ -84,7 +92,7 @@ public class LiteLoaderTweaker implements ITweaker
84 LiteLoaderTweaker.modsToLoad = this.modsOption.values(this.parsedOptions); 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,21 +174,6 @@ public class LiteLoaderTweaker implements ITweaker
166 174
167 return args.toArray(new String[args.size()]); 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 public static boolean addTweaker(URL tweakSource, String tweakClass) 178 public static boolean addTweaker(URL tweakSource, String tweakClass)
186 { 179 {
@@ -204,22 +197,58 @@ public class LiteLoaderTweaker implements ITweaker @@ -204,22 +197,58 @@ public class LiteLoaderTweaker implements ITweaker
204 197
205 return false; 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 * Do the first stage of loader startup, which enumerates mod sources and finds tweakers 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 if (!LiteLoaderTweaker.preInit) throw new IllegalStateException("Attempt to perform LiteLoader PreInit but PreInit was already completed"); 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 try 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 LiteLoaderTweaker.preInit = false; 252 LiteLoaderTweaker.preInit = false;
224 } 253 }
225 catch (Throwable th) 254 catch (Throwable th)
@@ -227,51 +256,53 @@ public class LiteLoaderTweaker implements ITweaker @@ -227,51 +256,53 @@ public class LiteLoaderTweaker implements ITweaker
227 LiteLoaderTweaker.logger.log(Level.SEVERE, String.format("Error during LiteLoader PreInit: %s", th.getMessage()), th); 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 * Do the second stage of loader startup 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 try 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 catch (Throwable th) 290 catch (Throwable th)
247 { 291 {
248 - th.printStackTrace(System.out);  
249 LiteLoaderTweaker.logger.log(Level.SEVERE, String.format("Error during LiteLoader PostInit: %s", th.getMessage()), th); 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 return false; 306 return false;
276 } 307 }
277 } 308 }
278 \ No newline at end of file 309 \ No newline at end of file
java/com/mumfrey/liteloader/log/LiteLoaderLogFormatter.java
@@ -16,12 +16,12 @@ public class LiteLoaderLogFormatter extends Formatter @@ -16,12 +16,12 @@ public class LiteLoaderLogFormatter extends Formatter
16 { 16 {
17 StringBuilder sb = new StringBuilder(); 17 StringBuilder sb = new StringBuilder();
18 sb.append(this.simpleDateFormatLogFormatter.format(Long.valueOf(logRecord.getMillis()))); 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 else 23 else
24 - sb.append(" [").append(var3.toString().toUpperCase()).append("] "); 24 + sb.append(" [").append(level.toString().toUpperCase()).append("] ");
25 25
26 sb.append(logRecord.getMessage()); 26 sb.append(logRecord.getMessage());
27 sb.append('\n'); 27 sb.append('\n');
java/com/mumfrey/liteloader/util/ModUtilities.java
@@ -8,8 +8,8 @@ import java.util.Set; @@ -8,8 +8,8 @@ import java.util.Set;
8 8
9 import com.mumfrey.liteloader.core.LiteLoader; 9 import com.mumfrey.liteloader.core.LiteLoader;
10 import com.mumfrey.liteloader.core.PluginChannels; 10 import com.mumfrey.liteloader.core.PluginChannels;
  11 +import com.mumfrey.liteloader.launch.LiteLoaderTweaker;
11 12
12 -import net.minecraft.client.ClientBrandRetriever;  
13 import net.minecraft.src.*; 13 import net.minecraft.src.*;
14 14
15 public abstract class ModUtilities 15 public abstract class ModUtilities
@@ -27,7 +27,7 @@ public abstract class ModUtilities @@ -27,7 +27,7 @@ public abstract class ModUtilities
27 static 27 static
28 { 28 {
29 // Check for FML 29 // Check for FML
30 - ModUtilities.forgeModLoader = ClientBrandRetriever.getClientModName().contains("fml"); 30 + ModUtilities.forgeModLoader = LiteLoaderTweaker.fmlIsPresent();
31 } 31 }
32 32
33 /** 33 /**