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