Commit 09ab166d80d1cd803a1ff7454f3ac2975af0d25b
Merge branch '1.11.2-backport' into 1.11.2
Showing
28 changed files
with
1433 additions
and
440 deletions
build.gradle
| ... | ... | @@ -72,7 +72,7 @@ repositories { |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | 74 | dependencies { |
| 75 | - compile('org.spongepowered:mixin:0.7.1-SNAPSHOT') { | |
| 75 | + compile('org.spongepowered:mixin:0.7.3-SNAPSHOT') { | |
| 76 | 76 | exclude module: 'asm-commons' |
| 77 | 77 | exclude module: 'asm-tree' |
| 78 | 78 | exclude module: 'launchwrapper' | ... | ... |
src/client/java/com/mumfrey/liteloader/client/gui/GuiPanelLiteLoaderLog.java
| ... | ... | @@ -290,6 +290,9 @@ class GuiPanelLiteLoaderLog extends GuiPanel implements ScrollPanelContent |
| 290 | 290 | if (logLine.startsWith("tweakClass '")) return 0x5555FF; |
| 291 | 291 | if (logLine.startsWith("baking listener list")) return 0x00AAAA; |
| 292 | 292 | if (logLine.startsWith("generating new event handler")) return 0xFFFF55; |
| 293 | + if (logLine.startsWith("resolving mods")) return 0xFFAA00; | |
| 294 | + if (logLine.startsWith("resolved artefact")) return 0x00AA00; | |
| 295 | + if (logLine.startsWith("evicting")) return 0xFFAA00; | |
| 293 | 296 | |
| 294 | 297 | return 0xCCCCCC; |
| 295 | 298 | } | ... | ... |
src/client/java/com/mumfrey/liteloader/modconfig/AbstractConfigPanel.java
| ... | ... | @@ -105,7 +105,7 @@ public abstract class AbstractConfigPanel implements ConfigPanel |
| 105 | 105 | /** |
| 106 | 106 | * Base for config option handle structs |
| 107 | 107 | */ |
| 108 | - static abstract class ConfigOption | |
| 108 | + abstract static class ConfigOption | |
| 109 | 109 | { |
| 110 | 110 | void onTick() |
| 111 | 111 | { |
| ... | ... | @@ -303,7 +303,7 @@ public abstract class AbstractConfigPanel implements ConfigPanel |
| 303 | 303 | @Override |
| 304 | 304 | public ConfigTextField setRegex(String regex, boolean force) |
| 305 | 305 | { |
| 306 | - this.textField.setRegex(Pattern.compile(regex), force);; | |
| 306 | + this.textField.setRegex(Pattern.compile(regex), force); | |
| 307 | 307 | return this; |
| 308 | 308 | } |
| 309 | 309 | |
| ... | ... | @@ -343,7 +343,8 @@ public abstract class AbstractConfigPanel implements ConfigPanel |
| 343 | 343 | } |
| 344 | 344 | else |
| 345 | 345 | { |
| 346 | - this.setValidator((text) -> { | |
| 346 | + this.setValidator((text) -> | |
| 347 | + { | |
| 347 | 348 | this.validate(text); |
| 348 | 349 | return true; |
| 349 | 350 | }); | ... | ... |
src/main/java/com/mumfrey/liteloader/api/EnumeratorModule.java
| ... | ... | @@ -36,10 +36,7 @@ public interface EnumeratorModule |
| 36 | 36 | public abstract void writeSettings(LoaderEnvironment environment, LoaderProperties properties); |
| 37 | 37 | |
| 38 | 38 | /** |
| 39 | - * Find loadable mods in this enumerator's domain, the enumerator module | |
| 40 | - * should call back against the enumerator itself to register containers it | |
| 41 | - * discovers using the registerModContainer() and registerTweakContainer() | |
| 42 | - * callbacks. | |
| 39 | + * Find loadable mods in this enumerator's domain. | |
| 43 | 40 | * |
| 44 | 41 | * <p>This method is called during loader PREINIT phase so <b>do not use any |
| 45 | 42 | * game classes here</b>!</p> |
| ... | ... | @@ -48,6 +45,20 @@ public interface EnumeratorModule |
| 48 | 45 | * @param profile |
| 49 | 46 | */ |
| 50 | 47 | public abstract void enumerate(ModularEnumerator enumerator, String profile); |
| 48 | + | |
| 49 | + /** | |
| 50 | + * Register loadable mods discovered in this enumerator's domain during the | |
| 51 | + * call to {@link #enumerate}, the enumerator module should call back | |
| 52 | + * against the enumerator itself to register containers it discovers using | |
| 53 | + * the registerModContainer() and registerTweakContainer() callbacks. | |
| 54 | + * | |
| 55 | + * <p>This method is called during loader PREINIT phase so <b>do not use any | |
| 56 | + * game classes here</b>!</p> | |
| 57 | + * | |
| 58 | + * @param enumerator | |
| 59 | + * @param profile | |
| 60 | + */ | |
| 61 | + public abstract void register(ModularEnumerator enumerator, String profile); | |
| 51 | 62 | |
| 52 | 63 | /** |
| 53 | 64 | * The enumerator module should inject (as required) any discovered | ... | ... |
src/main/java/com/mumfrey/liteloader/core/EnabledModsList.java
| ... | ... | @@ -8,7 +8,6 @@ package com.mumfrey.liteloader.core; |
| 8 | 8 | import java.io.File; |
| 9 | 9 | import java.io.FileReader; |
| 10 | 10 | import java.io.FileWriter; |
| 11 | -import java.io.IOException; | |
| 12 | 11 | import java.util.List; |
| 13 | 12 | import java.util.Map; |
| 14 | 13 | import java.util.TreeMap; |
| ... | ... | @@ -186,12 +185,9 @@ public final class EnabledModsList |
| 186 | 185 | { |
| 187 | 186 | if (file.exists()) |
| 188 | 187 | { |
| 189 | - FileReader reader = null; | |
| 190 | - | |
| 191 | - try | |
| 188 | + try (FileReader reader = new FileReader(file)) | |
| 192 | 189 | { |
| 193 | - reader = new FileReader(file); | |
| 194 | - EnabledModsList instance = gson.fromJson(reader, EnabledModsList.class); | |
| 190 | + EnabledModsList instance = EnabledModsList.gson.fromJson(reader, EnabledModsList.class); | |
| 195 | 191 | instance.setEnabledModsFile(file); |
| 196 | 192 | return instance; |
| 197 | 193 | } |
| ... | ... | @@ -199,20 +195,6 @@ public final class EnabledModsList |
| 199 | 195 | { |
| 200 | 196 | ex.printStackTrace(); |
| 201 | 197 | } |
| 202 | - finally | |
| 203 | - { | |
| 204 | - try | |
| 205 | - { | |
| 206 | - if (reader != null) | |
| 207 | - { | |
| 208 | - reader.close(); | |
| 209 | - } | |
| 210 | - } | |
| 211 | - catch (IOException ex) | |
| 212 | - { | |
| 213 | - ex.printStackTrace(); | |
| 214 | - } | |
| 215 | - } | |
| 216 | 198 | } |
| 217 | 199 | |
| 218 | 200 | EnabledModsList instance = new EnabledModsList(); |
| ... | ... | @@ -229,31 +211,14 @@ public final class EnabledModsList |
| 229 | 211 | { |
| 230 | 212 | if (!this.allowSave) return; |
| 231 | 213 | |
| 232 | - FileWriter writer = null; | |
| 233 | - | |
| 234 | - try | |
| 214 | + try (FileWriter writer = new FileWriter(file)) | |
| 235 | 215 | { |
| 236 | - writer = new FileWriter(file); | |
| 237 | - gson.toJson(this, writer); | |
| 216 | + EnabledModsList.gson.toJson(this, writer); | |
| 238 | 217 | } |
| 239 | 218 | catch (Exception ex) |
| 240 | 219 | { |
| 241 | 220 | ex.printStackTrace(); |
| 242 | 221 | } |
| 243 | - finally | |
| 244 | - { | |
| 245 | - try | |
| 246 | - { | |
| 247 | - if (writer != null) | |
| 248 | - { | |
| 249 | - writer.close(); | |
| 250 | - } | |
| 251 | - } | |
| 252 | - catch (IOException ex) | |
| 253 | - { | |
| 254 | - ex.printStackTrace(); | |
| 255 | - } | |
| 256 | - } | |
| 257 | 222 | } |
| 258 | 223 | |
| 259 | 224 | /** | ... | ... |
src/main/java/com/mumfrey/liteloader/core/LiteLoaderBootstrap.java
| ... | ... | @@ -29,6 +29,7 @@ import com.mumfrey.liteloader.api.manager.APIProvider; |
| 29 | 29 | import com.mumfrey.liteloader.api.manager.APIRegistry; |
| 30 | 30 | import com.mumfrey.liteloader.common.LoadingProgress; |
| 31 | 31 | import com.mumfrey.liteloader.core.api.LiteLoaderCoreAPI; |
| 32 | +import com.mumfrey.liteloader.core.api.repository.Repository; | |
| 32 | 33 | import com.mumfrey.liteloader.interfaces.LoaderEnumerator; |
| 33 | 34 | import com.mumfrey.liteloader.launch.ClassTransformerManager; |
| 34 | 35 | import com.mumfrey.liteloader.launch.LiteLoaderTweaker; |
| ... | ... | @@ -102,6 +103,16 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP |
| 102 | 103 | * Folder containing version-specific configuration |
| 103 | 104 | */ |
| 104 | 105 | private final File versionConfigFolder; |
| 106 | + | |
| 107 | + /** | |
| 108 | + * Mods repo file | |
| 109 | + */ | |
| 110 | + private final String repositoryFile; | |
| 111 | + | |
| 112 | + /** | |
| 113 | + * Mod repository defined in JSON | |
| 114 | + */ | |
| 115 | + private final Repository repository; | |
| 105 | 116 | |
| 106 | 117 | /** |
| 107 | 118 | * File to write log entries to |
| ... | ... | @@ -138,6 +149,8 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP |
| 138 | 149 | |
| 139 | 150 | private LaunchClassLoader classLoader; |
| 140 | 151 | |
| 152 | + private final StartupEnvironment env; | |
| 153 | + | |
| 141 | 154 | private final ITweaker tweaker; |
| 142 | 155 | |
| 143 | 156 | private final APIRegistry apiRegistry; |
| ... | ... | @@ -157,7 +170,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP |
| 157 | 170 | * List of mods passed into the command line |
| 158 | 171 | */ |
| 159 | 172 | private EnabledModsList enabledModsList; |
| 160 | - | |
| 173 | + | |
| 161 | 174 | /** |
| 162 | 175 | * @param env |
| 163 | 176 | * @param tweaker |
| ... | ... | @@ -165,6 +178,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP |
| 165 | 178 | public LiteLoaderBootstrap(StartupEnvironment env, ITweaker tweaker) |
| 166 | 179 | { |
| 167 | 180 | this.environmentType = EnvironmentType.values()[env.getEnvironmentTypeId()]; |
| 181 | + this.env = env; | |
| 168 | 182 | this.tweaker = tweaker; |
| 169 | 183 | |
| 170 | 184 | this.apiRegistry = new APIRegistry(this.getEnvironment(), this.getProperties()); |
| ... | ... | @@ -173,6 +187,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP |
| 173 | 187 | this.assetsDirectory = env.getAssetsDirectory(); |
| 174 | 188 | this.profile = env.getProfile(); |
| 175 | 189 | this.modsFolder = env.getModsFolder(); |
| 190 | + this.repositoryFile = env.getModsRepoFile(); | |
| 176 | 191 | |
| 177 | 192 | this.versionedModsFolder = new File(this.modsFolder, LiteLoaderVersion.CURRENT.getMinecraftVersion()); |
| 178 | 193 | this.configBaseFolder = new File(this.gameDirectory, "liteconfig"); |
| ... | ... | @@ -183,17 +198,27 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP |
| 183 | 198 | this.commonConfigFolder = new File(this.configBaseFolder, "common"); |
| 184 | 199 | this.versionConfigFolder = this.inflectVersionedConfigPath(LiteLoaderVersion.CURRENT); |
| 185 | 200 | |
| 186 | - if (!this.modsFolder.exists()) this.modsFolder.mkdirs(); | |
| 187 | - if (!this.versionedModsFolder.exists()) this.versionedModsFolder.mkdirs(); | |
| 188 | - if (!this.configBaseFolder.exists()) this.configBaseFolder.mkdirs(); | |
| 189 | - if (!this.commonConfigFolder.exists()) this.commonConfigFolder.mkdirs(); | |
| 190 | - if (!this.versionConfigFolder.exists()) this.versionConfigFolder.mkdirs(); | |
| 201 | + this.repository = new Repository(this.gameDirectory, this.versionedModsFolder); | |
| 202 | + | |
| 203 | + this.mkdir(this.modsFolder); | |
| 204 | + this.mkdir(this.versionedModsFolder); | |
| 205 | + this.mkdir(this.configBaseFolder); | |
| 206 | + this.mkdir(this.commonConfigFolder); | |
| 207 | + this.mkdir(this.versionConfigFolder); | |
| 191 | 208 | |
| 192 | 209 | this.initAPIs(env.getAPIsToLoad()); |
| 193 | 210 | this.apiProvider = this.apiRegistry.getProvider(); |
| 194 | 211 | this.apiAdapter = this.apiRegistry.getAdapter(); |
| 195 | 212 | } |
| 196 | 213 | |
| 214 | + private void mkdir(File dir) | |
| 215 | + { | |
| 216 | + if (!dir.isDirectory()) | |
| 217 | + { | |
| 218 | + dir.mkdirs(); | |
| 219 | + } | |
| 220 | + } | |
| 221 | + | |
| 197 | 222 | /** |
| 198 | 223 | * @param version |
| 199 | 224 | */ |
| ... | ... | @@ -249,6 +274,12 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP |
| 249 | 274 | { |
| 250 | 275 | return this.enabledModsList; |
| 251 | 276 | } |
| 277 | + | |
| 278 | + @Override | |
| 279 | + public Repository getModRepository() | |
| 280 | + { | |
| 281 | + return this.repository; | |
| 282 | + } | |
| 252 | 283 | |
| 253 | 284 | @Override |
| 254 | 285 | public LoaderEnumerator getEnumerator() |
| ... | ... | @@ -301,15 +332,20 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP |
| 301 | 332 | * #preInit(net.minecraft.launchwrapper.LaunchClassLoader, boolean) |
| 302 | 333 | */ |
| 303 | 334 | @Override |
| 304 | - public void preInit(LaunchClassLoader classLoader, boolean loadTweaks, List<String> modsToLoad) | |
| 335 | + public void preInit(LaunchClassLoader classLoader, boolean loadTweaks) | |
| 305 | 336 | { |
| 337 | + List<String> modsToLoad = this.env.getModFilterList(); | |
| 338 | + | |
| 306 | 339 | this.classLoader = classLoader; |
| 307 | 340 | this.loadTweaks = loadTweaks; |
| 308 | 341 | |
| 309 | 342 | LiteLoaderLogger.info(Verbosity.REDUCED, "LiteLoader begin PREINIT..."); |
| 310 | 343 | |
| 311 | 344 | // Set up the bootstrap |
| 312 | - if (!this.prepare()) return; | |
| 345 | + if (!this.prepare()) | |
| 346 | + { | |
| 347 | + return; | |
| 348 | + } | |
| 313 | 349 | |
| 314 | 350 | LiteLoaderLogger.info(Verbosity.REDUCED, "LiteLoader %s starting up...", LiteLoaderVersion.CURRENT.getLoaderVersion()); |
| 315 | 351 | |
| ... | ... | @@ -323,7 +359,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP |
| 323 | 359 | |
| 324 | 360 | this.enabledModsList = EnabledModsList.createFrom(this.enabledModsFile); |
| 325 | 361 | this.enabledModsList.processModsList(this.profile, modsToLoad); |
| 326 | - | |
| 362 | + | |
| 327 | 363 | this.enumerator = this.spawnEnumerator(classLoader); |
| 328 | 364 | this.enumerator.onPreInit(); |
| 329 | 365 | |
| ... | ... | @@ -599,6 +635,16 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP |
| 599 | 635 | { |
| 600 | 636 | return this.versionConfigFolder; |
| 601 | 637 | } |
| 638 | + | |
| 639 | + /** | |
| 640 | + * Get the path to a JSON file describing a mod repository layout, can be | |
| 641 | + * null if not defined | |
| 642 | + */ | |
| 643 | + @Override | |
| 644 | + public String getModsRepoFile() | |
| 645 | + { | |
| 646 | + return this.repositoryFile; | |
| 647 | + } | |
| 602 | 648 | |
| 603 | 649 | /** |
| 604 | 650 | * Get a boolean propery from the properties file and also write the new | ... | ... |
src/main/java/com/mumfrey/liteloader/core/LiteLoaderEnumerator.java
| ... | ... | @@ -122,7 +122,7 @@ public class LiteLoaderEnumerator implements LoaderEnumerator |
| 122 | 122 | private final FastIterableDeque<EnumerationObserver> observers = new HandlerList<EnumerationObserver>(EnumerationObserver.class); |
| 123 | 123 | |
| 124 | 124 | protected EnumeratorState state = EnumeratorState.INIT; |
| 125 | - | |
| 125 | + | |
| 126 | 126 | /** |
| 127 | 127 | * @param environment |
| 128 | 128 | * @param properties |
| ... | ... | @@ -144,7 +144,7 @@ public class LiteLoaderEnumerator implements LoaderEnumerator |
| 144 | 144 | // Initialise the shared mod list if we haven't already |
| 145 | 145 | this.getSharedModList(); |
| 146 | 146 | } |
| 147 | - | |
| 147 | + | |
| 148 | 148 | /** |
| 149 | 149 | * @param environment |
| 150 | 150 | */ |
| ... | ... | @@ -397,11 +397,13 @@ public class LiteLoaderEnumerator implements LoaderEnumerator |
| 397 | 397 | { |
| 398 | 398 | this.gotoState(EnumeratorState.DISCOVER); |
| 399 | 399 | |
| 400 | + String profile = this.environment.getProfile(); | |
| 401 | + | |
| 400 | 402 | for (EnumeratorModule module : this.modules) |
| 401 | 403 | { |
| 402 | 404 | try |
| 403 | 405 | { |
| 404 | - module.enumerate(this, this.environment.getProfile()); | |
| 406 | + module.enumerate(this, profile); | |
| 405 | 407 | } |
| 406 | 408 | catch (Throwable th) |
| 407 | 409 | { |
| ... | ... | @@ -409,6 +411,18 @@ public class LiteLoaderEnumerator implements LoaderEnumerator |
| 409 | 411 | } |
| 410 | 412 | } |
| 411 | 413 | |
| 414 | + for (EnumeratorModule module : this.modules) | |
| 415 | + { | |
| 416 | + try | |
| 417 | + { | |
| 418 | + module.register(this, profile); | |
| 419 | + } | |
| 420 | + catch (Throwable th) | |
| 421 | + { | |
| 422 | + LiteLoaderLogger.warning(th, "Enumerator Module %s encountered an error whilst enumerating", module.getClass().getName()); | |
| 423 | + } | |
| 424 | + } | |
| 425 | + | |
| 412 | 426 | this.checkDependencies(); |
| 413 | 427 | } |
| 414 | 428 | |
| ... | ... | @@ -651,7 +665,15 @@ public class LiteLoaderEnumerator implements LoaderEnumerator |
| 651 | 665 | if (config.endsWith(".json")) |
| 652 | 666 | { |
| 653 | 667 | LiteLoaderLogger.info(Verbosity.REDUCED, "Registering mixin config %s for %s", config, container.getName()); |
| 654 | - Mixins.addConfiguration(config); | |
| 668 | + try | |
| 669 | + { | |
| 670 | + Mixins.addConfiguration(config); | |
| 671 | + } | |
| 672 | + catch (Throwable th) | |
| 673 | + { | |
| 674 | + LiteLoaderLogger.severe(th, "Error registering mixin config %s for %s", config, container); | |
| 675 | + container.registerMixinError(th); | |
| 676 | + } | |
| 655 | 677 | } |
| 656 | 678 | else if (config.contains(".json@")) |
| 657 | 679 | { | ... | ... |
src/main/java/com/mumfrey/liteloader/core/LiteLoaderMods.java
| ... | ... | @@ -24,6 +24,7 @@ import com.mumfrey.liteloader.interfaces.FastIterableDeque; |
| 24 | 24 | import com.mumfrey.liteloader.interfaces.Loadable; |
| 25 | 25 | import com.mumfrey.liteloader.interfaces.LoadableMod; |
| 26 | 26 | import com.mumfrey.liteloader.interfaces.LoaderEnumerator; |
| 27 | +import com.mumfrey.liteloader.interfaces.MixinContainer; | |
| 27 | 28 | import com.mumfrey.liteloader.interfaces.TweakContainer; |
| 28 | 29 | import com.mumfrey.liteloader.launch.ClassTransformerManager; |
| 29 | 30 | import com.mumfrey.liteloader.launch.LoaderEnvironment; |
| ... | ... | @@ -444,6 +445,12 @@ public class LiteLoaderMods |
| 444 | 445 | String identifier = mod.getIdentifier(); |
| 445 | 446 | if (identifier == null || this.environment.getEnabledModsList().isEnabled(this.environment.getProfile(), identifier)) |
| 446 | 447 | { |
| 448 | + if (!this.validateMixins(mod, container)) | |
| 449 | + { | |
| 450 | + this.onModLoadFailed(container, identifier, "mixins for the specified mod encountered a startup error", null); | |
| 451 | + continue; | |
| 452 | + } | |
| 453 | + | |
| 447 | 454 | if (!this.enumerator.checkDependencies(container)) |
| 448 | 455 | { |
| 449 | 456 | this.onModLoadFailed(container, identifier, "the mod was missing a required dependency", null); |
| ... | ... | @@ -474,6 +481,23 @@ public class LiteLoaderMods |
| 474 | 481 | this.observers.all().onPostModLoaded(mod); |
| 475 | 482 | } |
| 476 | 483 | } |
| 484 | + | |
| 485 | + private boolean validateMixins(ModInfo<?> mod, LoadableMod<?> container) | |
| 486 | + { | |
| 487 | + if (container instanceof MixinContainer) | |
| 488 | + { | |
| 489 | + @SuppressWarnings("unchecked") | |
| 490 | + Collection<Throwable> errors = ((MixinContainer<File>)container).getMixinErrors(); | |
| 491 | + for (Throwable error : errors) | |
| 492 | + { | |
| 493 | + this.registerModStartupError(mod, error, true); | |
| 494 | + } | |
| 495 | + | |
| 496 | + return errors.size() == 0; | |
| 497 | + } | |
| 498 | + | |
| 499 | + return true; | |
| 500 | + } | |
| 477 | 501 | |
| 478 | 502 | /** |
| 479 | 503 | * @param identifier |
| ... | ... | @@ -697,26 +721,28 @@ public class LiteLoaderMods |
| 697 | 721 | |
| 698 | 722 | for (Mod mod : this.loadedMods) |
| 699 | 723 | { |
| 700 | - if (mod.hasClassTransformers()) | |
| 724 | + if (!mod.hasClassTransformers()) | |
| 701 | 725 | { |
| 702 | - List<String> modTransformers = ((TweakContainer<?>)mod.getContainer()).getClassTransformerClassNames(); | |
| 703 | - for (String modTransformer : modTransformers) | |
| 726 | + continue; | |
| 727 | + } | |
| 728 | + | |
| 729 | + List<String> modTransformers = ((TweakContainer<?>)mod.getContainer()).getClassTransformerClassNames(); | |
| 730 | + for (String modTransformer : modTransformers) | |
| 731 | + { | |
| 732 | + if (!injectedTransformers.contains(modTransformer)) | |
| 704 | 733 | { |
| 705 | - if (!injectedTransformers.contains(modTransformer)) | |
| 734 | + List<Throwable> throwables = transformerManager.getTransformerStartupErrors(modTransformer); | |
| 735 | + if (throwables != null) | |
| 706 | 736 | { |
| 707 | - List<Throwable> throwables = transformerManager.getTransformerStartupErrors(modTransformer); | |
| 708 | - if (throwables != null) | |
| 737 | + for (Throwable th : throwables) | |
| 709 | 738 | { |
| 710 | - for (Throwable th : throwables) | |
| 711 | - { | |
| 712 | - this.registerModStartupError(mod, th, true); | |
| 713 | - } | |
| 714 | - } | |
| 715 | - else | |
| 716 | - { | |
| 717 | - this.registerModStartupError(mod, new RuntimeException("Missing class transformer " + modTransformer), true); | |
| 739 | + this.registerModStartupError(mod, th, true); | |
| 718 | 740 | } |
| 719 | 741 | } |
| 742 | + else | |
| 743 | + { | |
| 744 | + this.registerModStartupError(mod, new RuntimeException("Missing class transformer " + modTransformer), true); | |
| 745 | + } | |
| 720 | 746 | } |
| 721 | 747 | } |
| 722 | 748 | } |
| ... | ... | @@ -765,7 +791,11 @@ public class LiteLoaderMods |
| 765 | 791 | private void registerModStartupError(ModInfo<?> mod, Throwable th, boolean critical) |
| 766 | 792 | { |
| 767 | 793 | this.startupErrorCount++; |
| 768 | - if (critical) this.criticalErrorCount++; | |
| 794 | + if (critical) | |
| 795 | + { | |
| 796 | + this.criticalErrorCount++; | |
| 797 | + } | |
| 798 | + | |
| 769 | 799 | mod.registerStartupError(th); |
| 770 | 800 | |
| 771 | 801 | if (!this.loadedMods.contains(mod) && !this.disabledMods.contains(mod)) | ... | ... |
src/main/java/com/mumfrey/liteloader/core/api/EnumeratorModuleClassPath.java
| ... | ... | @@ -82,37 +82,43 @@ public class EnumeratorModuleClassPath implements EnumeratorModule |
| 82 | 82 | @Override |
| 83 | 83 | public void enumerate(ModularEnumerator enumerator, String profile) |
| 84 | 84 | { |
| 85 | - if (this.loadTweaks) | |
| 85 | + } | |
| 86 | + | |
| 87 | + @Override | |
| 88 | + public void register(ModularEnumerator enumerator, String profile) | |
| 89 | + { | |
| 90 | + if (!this.loadTweaks) | |
| 86 | 91 | { |
| 87 | - LiteLoaderLogger.info("Discovering tweaks on class path..."); | |
| 88 | - | |
| 89 | - for (String classPathPart : this.classPathEntries) | |
| 92 | + return; | |
| 93 | + } | |
| 94 | + | |
| 95 | + LiteLoaderLogger.info("Discovering tweaks on class path..."); | |
| 96 | + for (String classPathPart : this.classPathEntries) | |
| 97 | + { | |
| 98 | + try | |
| 90 | 99 | { |
| 91 | - try | |
| 100 | + File packagePath = new File(classPathPart); | |
| 101 | + if (packagePath.exists()) | |
| 92 | 102 | { |
| 93 | - File packagePath = new File(classPathPart); | |
| 94 | - if (packagePath.exists()) | |
| 103 | + LoadableModClassPath classPathMod = new LoadableModClassPath(packagePath); | |
| 104 | + if (enumerator.registerModContainer(classPathMod)) | |
| 95 | 105 | { |
| 96 | - LoadableModClassPath classPathMod = new LoadableModClassPath(packagePath); | |
| 97 | - if (enumerator.registerModContainer(classPathMod)) | |
| 106 | + this.loadableMods.add(classPathMod); | |
| 107 | + if (classPathMod.requiresPreInitInjection()) | |
| 98 | 108 | { |
| 99 | - this.loadableMods.add(classPathMod); | |
| 100 | - if (classPathMod.requiresPreInitInjection()) | |
| 101 | - { | |
| 102 | - enumerator.registerTweakContainer(classPathMod); | |
| 103 | - } | |
| 104 | - } | |
| 105 | - else | |
| 106 | - { | |
| 107 | - LiteLoaderLogger.info(Verbosity.REDUCED, "Mod %s is disabled or missing a required dependency, not injecting tranformers", | |
| 108 | - classPathMod.getIdentifier()); | |
| 109 | + enumerator.registerTweakContainer(classPathMod); | |
| 109 | 110 | } |
| 110 | 111 | } |
| 112 | + else | |
| 113 | + { | |
| 114 | + LiteLoaderLogger.info(Verbosity.REDUCED, "Mod %s is disabled or missing a required dependency, not injecting tranformers", | |
| 115 | + classPathMod.getIdentifier()); | |
| 116 | + } | |
| 111 | 117 | } |
| 112 | - catch (Throwable th) | |
| 113 | - { | |
| 114 | - LiteLoaderLogger.warning(th, "Error encountered whilst inspecting %s", classPathPart); | |
| 115 | - } | |
| 118 | + } | |
| 119 | + catch (Throwable th) | |
| 120 | + { | |
| 121 | + LiteLoaderLogger.warning(th, "Error encountered whilst inspecting %s", classPathPart); | |
| 116 | 122 | } |
| 117 | 123 | } |
| 118 | 124 | } | ... | ... |
src/main/java/com/mumfrey/liteloader/core/api/EnumeratorModuleFiles.java
0 โ 100644
| 1 | +/* | |
| 2 | + * This file is part of LiteLoader. | |
| 3 | + * Copyright (C) 2012-16 Adam Mummery-Smith | |
| 4 | + * All Rights Reserved. | |
| 5 | + */ | |
| 6 | +package com.mumfrey.liteloader.core.api; | |
| 7 | + | |
| 8 | +import java.io.File; | |
| 9 | +import java.io.FilenameFilter; | |
| 10 | +import java.net.MalformedURLException; | |
| 11 | +import java.util.ArrayList; | |
| 12 | +import java.util.Iterator; | |
| 13 | +import java.util.LinkedHashMap; | |
| 14 | +import java.util.List; | |
| 15 | +import java.util.Map; | |
| 16 | +import java.util.Set; | |
| 17 | +import java.util.TreeSet; | |
| 18 | + | |
| 19 | +import com.google.common.base.Charsets; | |
| 20 | +import com.mumfrey.liteloader.api.EnumeratorModule; | |
| 21 | +import com.mumfrey.liteloader.common.LoadingProgress; | |
| 22 | +import com.mumfrey.liteloader.core.LiteLoaderVersion; | |
| 23 | +import com.mumfrey.liteloader.core.api.EnumeratorModuleFiles.ContainerEnvironment.Candidate; | |
| 24 | +import com.mumfrey.liteloader.interfaces.LoadableFile; | |
| 25 | +import com.mumfrey.liteloader.interfaces.LoadableMod; | |
| 26 | +import com.mumfrey.liteloader.interfaces.ModularEnumerator; | |
| 27 | +import com.mumfrey.liteloader.interfaces.TweakContainer; | |
| 28 | +import com.mumfrey.liteloader.launch.LoaderEnvironment; | |
| 29 | +import com.mumfrey.liteloader.launch.LoaderProperties; | |
| 30 | +import com.mumfrey.liteloader.util.log.LiteLoaderLogger; | |
| 31 | +import com.mumfrey.liteloader.util.log.LiteLoaderLogger.Verbosity; | |
| 32 | + | |
| 33 | +import net.minecraft.launchwrapper.LaunchClassLoader; | |
| 34 | + | |
| 35 | +public abstract class EnumeratorModuleFiles implements FilenameFilter, EnumeratorModule | |
| 36 | +{ | |
| 37 | + public static class ContainerEnvironment implements Iterable<ContainerEnvironment.Candidate> | |
| 38 | + { | |
| 39 | + static class Candidate | |
| 40 | + { | |
| 41 | + private final Set<LoadableMod<File>> availableFiles = new TreeSet<LoadableMod<File>>(); | |
| 42 | + | |
| 43 | + private boolean isRegistered; | |
| 44 | + | |
| 45 | + public void add(LoadableMod<File> modFile) | |
| 46 | + { | |
| 47 | + if (!this.isRegistered) | |
| 48 | + { | |
| 49 | + this.availableFiles.add(modFile); | |
| 50 | + } | |
| 51 | + } | |
| 52 | + | |
| 53 | + public LoadableMod<File> getNewestVersion() | |
| 54 | + { | |
| 55 | + return this.availableFiles.iterator().next(); | |
| 56 | + } | |
| 57 | + | |
| 58 | + public boolean isRegistered() | |
| 59 | + { | |
| 60 | + return this.isRegistered; | |
| 61 | + } | |
| 62 | + | |
| 63 | + public void register() | |
| 64 | + { | |
| 65 | + this.isRegistered = true; | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * Ordered sets used to sort mods by version/revision | |
| 71 | + */ | |
| 72 | + private final Map<String, Candidate> orderedCandidates = new LinkedHashMap<String, Candidate>(); | |
| 73 | + | |
| 74 | + public void addCandidate(LoadableMod<File> modFile) | |
| 75 | + { | |
| 76 | + if (!this.orderedCandidates.containsKey(modFile.getModName())) | |
| 77 | + { | |
| 78 | + this.orderedCandidates.put(modFile.getModName(), new Candidate()); | |
| 79 | + } | |
| 80 | + | |
| 81 | + LiteLoaderLogger.info("Considering valid mod file: %s", modFile); | |
| 82 | + this.orderedCandidates.get(modFile.getModName()).add(modFile); | |
| 83 | + } | |
| 84 | + | |
| 85 | + @Override | |
| 86 | + public Iterator<Candidate> iterator() | |
| 87 | + { | |
| 88 | + return this.orderedCandidates.values().iterator(); | |
| 89 | + } | |
| 90 | + } | |
| 91 | + | |
| 92 | + /** | |
| 93 | + * Ordered sets used to sort mods by version/revision | |
| 94 | + */ | |
| 95 | + private final ContainerEnvironment containers; | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * Mods to add once init is completed | |
| 99 | + */ | |
| 100 | + private final List<LoadableMod<File>> loadableMods = new ArrayList<LoadableMod<File>>(); | |
| 101 | + | |
| 102 | + protected final LiteLoaderCoreAPI api; | |
| 103 | + | |
| 104 | + public EnumeratorModuleFiles(LiteLoaderCoreAPI api, ContainerEnvironment containers) | |
| 105 | + { | |
| 106 | + this.api = api; | |
| 107 | + this.containers = containers; | |
| 108 | + } | |
| 109 | + | |
| 110 | + protected abstract boolean readJarFiles(); | |
| 111 | + | |
| 112 | + protected abstract boolean loadTweakJars(); | |
| 113 | + | |
| 114 | + protected abstract boolean loadTweaks(); | |
| 115 | + | |
| 116 | + protected abstract boolean forceInjection(); | |
| 117 | + | |
| 118 | + protected abstract File[] getFiles(); | |
| 119 | + | |
| 120 | + @Override | |
| 121 | + public void init(LoaderEnvironment environment, LoaderProperties properties) | |
| 122 | + { | |
| 123 | + } | |
| 124 | + | |
| 125 | + /** | |
| 126 | + * Write settings | |
| 127 | + */ | |
| 128 | + @Override | |
| 129 | + public void writeSettings(LoaderEnvironment environment, LoaderProperties properties) | |
| 130 | + { | |
| 131 | + } | |
| 132 | + | |
| 133 | + /* (non-Javadoc) | |
| 134 | + * @see com.mumfrey.liteloader.core.Enumerator#getLoadableMods() | |
| 135 | + */ | |
| 136 | + public List<LoadableMod<File>> getLoadableMods() | |
| 137 | + { | |
| 138 | + return this.loadableMods; | |
| 139 | + } | |
| 140 | + | |
| 141 | + /** | |
| 142 | + * For FilenameFilter interface | |
| 143 | + * | |
| 144 | + * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String) | |
| 145 | + */ | |
| 146 | + @Override | |
| 147 | + public boolean accept(File dir, String fileName) | |
| 148 | + { | |
| 149 | + fileName = fileName.toLowerCase(); | |
| 150 | + | |
| 151 | + if (fileName.endsWith(".litemod.zip")) | |
| 152 | + { | |
| 153 | + LiteLoaderLogger.warning("Found %s with unsupported extension .litemod.zip." | |
| 154 | + + " Please change file extension to .litemod to allow this file to be loaded!", fileName); | |
| 155 | + return true; | |
| 156 | + } | |
| 157 | + | |
| 158 | + return fileName.endsWith(".litemod") || fileName.endsWith(".jar"); | |
| 159 | + } | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * Search the folder for (potentially) valid files | |
| 163 | + */ | |
| 164 | + protected void findValidFiles(ModularEnumerator enumerator) | |
| 165 | + { | |
| 166 | + for (File file : this.getFiles()) | |
| 167 | + { | |
| 168 | + LoadableFile candidateFile = new LoadableFile(file); | |
| 169 | + candidateFile.setForceInjection(this.forceInjection()); | |
| 170 | + try | |
| 171 | + { | |
| 172 | + this.inspectFile(enumerator, candidateFile); | |
| 173 | + } | |
| 174 | + catch (Exception ex) | |
| 175 | + { | |
| 176 | + LiteLoaderLogger.warning(ex, "An error occurred whilst inspecting %s", candidateFile); | |
| 177 | + } | |
| 178 | + } | |
| 179 | + } | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * Check whether a particular file is valid, and add it to the candiates | |
| 183 | + * list if it appears to be acceptable. | |
| 184 | + * | |
| 185 | + * @param enumerator | |
| 186 | + * @param candidateFile | |
| 187 | + */ | |
| 188 | + protected void inspectFile(ModularEnumerator enumerator, LoadableFile candidateFile) | |
| 189 | + { | |
| 190 | + if (this.isValidFile(enumerator, candidateFile)) | |
| 191 | + { | |
| 192 | + String metaData = candidateFile.getFileContents(LoadableMod.METADATA_FILENAME, Charsets.UTF_8); | |
| 193 | + if (metaData != null) | |
| 194 | + { | |
| 195 | + LoadableMod<File> modFile = this.getModFile(candidateFile, metaData); | |
| 196 | + this.addModFile(enumerator, modFile); | |
| 197 | + return; | |
| 198 | + } | |
| 199 | + else if (this.isValidTweakContainer(candidateFile)) | |
| 200 | + { | |
| 201 | + TweakContainer<File> container = this.getTweakFile(candidateFile); | |
| 202 | + this.addTweakFile(enumerator, container); | |
| 203 | + return; | |
| 204 | + } | |
| 205 | + else | |
| 206 | + { | |
| 207 | + LiteLoaderLogger.info("Ignoring %s", candidateFile); | |
| 208 | +// enumerator.registerBadContainer(candidateFile, "No metadata"); | |
| 209 | + } | |
| 210 | + } | |
| 211 | +// else | |
| 212 | +// { | |
| 213 | +// enumerator.registerBadContainer(candidateFile, "Not a valid file"); | |
| 214 | +// } | |
| 215 | + } | |
| 216 | + | |
| 217 | + /** | |
| 218 | + * Check whether the specified file is a valid mod container | |
| 219 | + * | |
| 220 | + * @param enumerator | |
| 221 | + * @param candidateFile | |
| 222 | + */ | |
| 223 | + protected boolean isValidFile(ModularEnumerator enumerator, LoadableFile candidateFile) | |
| 224 | + { | |
| 225 | + String filename = candidateFile.getName().toLowerCase(); | |
| 226 | + if (filename.endsWith(".litemod.zip")) | |
| 227 | + { | |
| 228 | + enumerator.registerBadContainer(candidateFile, "Invalid file extension .litemod.zip"); | |
| 229 | + return false; | |
| 230 | + } | |
| 231 | + else if (filename.endsWith(".litemod")) | |
| 232 | + { | |
| 233 | + return true; | |
| 234 | + } | |
| 235 | + else if (filename.endsWith(".jar")) | |
| 236 | + { | |
| 237 | + Set<String> modSystems = candidateFile.getModSystems(); | |
| 238 | + boolean hasLiteLoader = modSystems.contains("LiteLoader"); | |
| 239 | + if (modSystems.size() > 0) | |
| 240 | + { | |
| 241 | + LiteLoaderLogger.info("%s supports mod systems %s", candidateFile, modSystems); | |
| 242 | + if (!hasLiteLoader) return false; | |
| 243 | + } | |
| 244 | + | |
| 245 | + return this.loadTweakJars() || this.readJarFiles() || hasLiteLoader; | |
| 246 | + } | |
| 247 | + | |
| 248 | + return false; | |
| 249 | + } | |
| 250 | + | |
| 251 | + /** | |
| 252 | + * Called only if the file is not a valid mod container (has no mod | |
| 253 | + * metadata) to check whether it could instead be a potential tweak | |
| 254 | + * container. | |
| 255 | + * | |
| 256 | + * @param candidateFile | |
| 257 | + */ | |
| 258 | + protected boolean isValidTweakContainer(LoadableFile candidateFile) | |
| 259 | + { | |
| 260 | + return this.loadTweakJars() && this.loadTweaks() && candidateFile.getName().toLowerCase().endsWith(".jar"); | |
| 261 | + } | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * Get the {@link FilenameFilter} to use to filter candidate files | |
| 265 | + */ | |
| 266 | + protected FilenameFilter getFilenameFilter() | |
| 267 | + { | |
| 268 | + return this; | |
| 269 | + } | |
| 270 | + | |
| 271 | + /** | |
| 272 | + * @param modFile | |
| 273 | + */ | |
| 274 | + protected boolean isFileSupported(LoadableMod<File> modFile) | |
| 275 | + { | |
| 276 | + return LiteLoaderVersion.CURRENT.isVersionSupported(modFile.getTargetVersion()); | |
| 277 | + } | |
| 278 | + | |
| 279 | + /** | |
| 280 | + * @param candidateFile | |
| 281 | + * @param metaData | |
| 282 | + */ | |
| 283 | + protected LoadableMod<File> getModFile(LoadableFile candidateFile, String metaData) | |
| 284 | + { | |
| 285 | + return new LoadableModFile(candidateFile, metaData); | |
| 286 | + } | |
| 287 | + | |
| 288 | + /** | |
| 289 | + * @param candidateFile | |
| 290 | + */ | |
| 291 | + protected TweakContainer<File> getTweakFile(LoadableFile candidateFile) | |
| 292 | + { | |
| 293 | + return candidateFile; | |
| 294 | + } | |
| 295 | + | |
| 296 | + /** | |
| 297 | + * @param enumerator | |
| 298 | + * @param modFile | |
| 299 | + */ | |
| 300 | + protected void addModFile(ModularEnumerator enumerator, LoadableMod<File> modFile) | |
| 301 | + { | |
| 302 | + if (modFile.hasValidMetaData()) | |
| 303 | + { | |
| 304 | + // Only add the mod if the version matches, we add candidates to the versionOrderingSets in | |
| 305 | + // order to determine the most recent version available. | |
| 306 | + if (this.isFileSupported(modFile)) | |
| 307 | + { | |
| 308 | + this.containers.addCandidate(modFile); | |
| 309 | + } | |
| 310 | + else | |
| 311 | + { | |
| 312 | + LiteLoaderLogger.info(Verbosity.REDUCED, "Not adding invalid or version-mismatched mod file: %s", modFile); | |
| 313 | + enumerator.registerBadContainer(modFile, "Version not supported"); | |
| 314 | + } | |
| 315 | + } | |
| 316 | + } | |
| 317 | + | |
| 318 | + /** | |
| 319 | + * @param enumerator | |
| 320 | + * @param container | |
| 321 | + */ | |
| 322 | + protected void addTweakFile(ModularEnumerator enumerator, TweakContainer<File> container) | |
| 323 | + { | |
| 324 | + enumerator.registerTweakContainer(container); | |
| 325 | + } | |
| 326 | + | |
| 327 | + /** | |
| 328 | + * @param enumerator | |
| 329 | + */ | |
| 330 | + protected void sortAndRegisterFiles(ModularEnumerator enumerator) | |
| 331 | + { | |
| 332 | + // Copy the first entry in every version set into the modfiles list | |
| 333 | + for (Candidate candidate : this.containers) | |
| 334 | + { | |
| 335 | + if (candidate.isRegistered()) | |
| 336 | + { | |
| 337 | + continue; | |
| 338 | + } | |
| 339 | + | |
| 340 | + LoadableMod<File> newestVersion = candidate.getNewestVersion(); | |
| 341 | + this.registerFile(enumerator, newestVersion); | |
| 342 | + candidate.register(); | |
| 343 | + } | |
| 344 | + } | |
| 345 | + | |
| 346 | + /** | |
| 347 | + * @param enumerator | |
| 348 | + * @param modFile | |
| 349 | + */ | |
| 350 | + @SuppressWarnings("unchecked") | |
| 351 | + protected void registerFile(ModularEnumerator enumerator, LoadableMod<File> modFile) | |
| 352 | + { | |
| 353 | + if (enumerator.registerModContainer(modFile)) | |
| 354 | + { | |
| 355 | + LiteLoaderLogger.info(Verbosity.REDUCED, "Adding newest valid mod file '%s' at revision %.4f", modFile, modFile.getRevision()); | |
| 356 | + this.loadableMods.add(modFile); | |
| 357 | + } | |
| 358 | + else | |
| 359 | + { | |
| 360 | + LiteLoaderLogger.info(Verbosity.REDUCED, "Not adding valid mod file '%s', the specified mod is disabled or missing a required dependency", | |
| 361 | + modFile); | |
| 362 | + } | |
| 363 | + | |
| 364 | + if (this.loadTweaks()) | |
| 365 | + { | |
| 366 | + try | |
| 367 | + { | |
| 368 | + if (modFile instanceof TweakContainer) | |
| 369 | + { | |
| 370 | + this.addTweakFile(enumerator, (TweakContainer<File>)modFile); | |
| 371 | + } | |
| 372 | + } | |
| 373 | + catch (Throwable th) | |
| 374 | + { | |
| 375 | + LiteLoaderLogger.warning("Error adding tweaks from '%s'", modFile); | |
| 376 | + } | |
| 377 | + } | |
| 378 | + } | |
| 379 | + | |
| 380 | + @Override | |
| 381 | + public void injectIntoClassLoader(ModularEnumerator enumerator, LaunchClassLoader classLoader) | |
| 382 | + { | |
| 383 | + LiteLoaderLogger.info("Injecting external mods into class path..."); | |
| 384 | + | |
| 385 | + for (LoadableMod<?> loadableMod : this.loadableMods) | |
| 386 | + { | |
| 387 | + try | |
| 388 | + { | |
| 389 | + if (loadableMod.injectIntoClassPath(classLoader, false)) | |
| 390 | + { | |
| 391 | + LiteLoaderLogger.info("Successfully injected mod file '%s' into classpath", loadableMod); | |
| 392 | + } | |
| 393 | + } | |
| 394 | + catch (MalformedURLException ex) | |
| 395 | + { | |
| 396 | + LiteLoaderLogger.warning("Error injecting '%s' into classPath. The mod will not be loaded", loadableMod); | |
| 397 | + } | |
| 398 | + } | |
| 399 | + } | |
| 400 | + | |
| 401 | + @Override | |
| 402 | + public void registerMods(ModularEnumerator enumerator, LaunchClassLoader classLoader) | |
| 403 | + { | |
| 404 | + LiteLoaderLogger.info(Verbosity.REDUCED, "Discovering mods in valid mod files..."); | |
| 405 | + LoadingProgress.incTotalLiteLoaderProgress(this.loadableMods.size()); | |
| 406 | + | |
| 407 | + for (LoadableMod<?> modFile : this.loadableMods) | |
| 408 | + { | |
| 409 | + LoadingProgress.incLiteLoaderProgress("Searching for mods in " + modFile.getModName() + "..."); | |
| 410 | + LiteLoaderLogger.info("Searching %s...", modFile); | |
| 411 | + try | |
| 412 | + { | |
| 413 | + enumerator.registerModsFrom(modFile, true); | |
| 414 | + } | |
| 415 | + catch (Exception ex) | |
| 416 | + { | |
| 417 | + LiteLoaderLogger.warning("Error encountered whilst searching in %s...", modFile); | |
| 418 | + } | |
| 419 | + } | |
| 420 | + } | |
| 421 | +} | ... | ... |
src/main/java/com/mumfrey/liteloader/core/api/EnumeratorModuleFolder.java
| ... | ... | @@ -6,50 +6,19 @@ |
| 6 | 6 | package com.mumfrey.liteloader.core.api; |
| 7 | 7 | |
| 8 | 8 | import java.io.File; |
| 9 | -import java.io.FilenameFilter; | |
| 10 | -import java.net.MalformedURLException; | |
| 11 | -import java.util.ArrayList; | |
| 12 | -import java.util.HashMap; | |
| 13 | -import java.util.List; | |
| 14 | -import java.util.Map; | |
| 15 | -import java.util.Map.Entry; | |
| 16 | -import java.util.Set; | |
| 17 | -import java.util.TreeSet; | |
| 18 | 9 | |
| 19 | -import com.google.common.base.Charsets; | |
| 20 | -import com.mumfrey.liteloader.api.EnumeratorModule; | |
| 21 | -import com.mumfrey.liteloader.common.LoadingProgress; | |
| 22 | -import com.mumfrey.liteloader.core.LiteLoaderVersion; | |
| 23 | -import com.mumfrey.liteloader.interfaces.LoadableFile; | |
| 24 | -import com.mumfrey.liteloader.interfaces.LoadableMod; | |
| 25 | 10 | import com.mumfrey.liteloader.interfaces.ModularEnumerator; |
| 26 | -import com.mumfrey.liteloader.interfaces.TweakContainer; | |
| 27 | 11 | import com.mumfrey.liteloader.launch.LoaderEnvironment; |
| 28 | 12 | import com.mumfrey.liteloader.launch.LoaderProperties; |
| 29 | 13 | import com.mumfrey.liteloader.util.log.LiteLoaderLogger; |
| 30 | -import com.mumfrey.liteloader.util.log.LiteLoaderLogger.Verbosity; | |
| 31 | - | |
| 32 | -import net.minecraft.launchwrapper.LaunchClassLoader; | |
| 33 | 14 | |
| 34 | 15 | /** |
| 35 | 16 | * Enumerator module which searches for mods and tweaks in a folder |
| 36 | 17 | * |
| 37 | 18 | * @author Adam Mummery-Smith |
| 38 | 19 | */ |
| 39 | -public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule | |
| 20 | +public class EnumeratorModuleFolder extends EnumeratorModuleFiles | |
| 40 | 21 | { |
| 41 | - /** | |
| 42 | - * Ordered sets used to sort mods by version/revision | |
| 43 | - */ | |
| 44 | - protected final Map<String, TreeSet<LoadableMod<File>>> versionOrderingSets = new HashMap<String, TreeSet<LoadableMod<File>>>(); | |
| 45 | - | |
| 46 | - /** | |
| 47 | - * Mods to add once init is completed | |
| 48 | - */ | |
| 49 | - protected final List<LoadableMod<File>> loadableMods = new ArrayList<LoadableMod<File>>(); | |
| 50 | - | |
| 51 | - protected LiteLoaderCoreAPI coreAPI; | |
| 52 | - | |
| 53 | 22 | protected File directory; |
| 54 | 23 | |
| 55 | 24 | protected boolean readJarFiles; |
| ... | ... | @@ -62,13 +31,13 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule |
| 62 | 31 | */ |
| 63 | 32 | protected final boolean loadTweakJars; |
| 64 | 33 | |
| 65 | - public EnumeratorModuleFolder(LiteLoaderCoreAPI coreAPI, File directory, boolean loadTweakJars) | |
| 34 | + public EnumeratorModuleFolder(LiteLoaderCoreAPI api, ContainerEnvironment containers, File directory, boolean loadTweakJars) | |
| 66 | 35 | { |
| 67 | - this.coreAPI = coreAPI; | |
| 68 | - this.directory = directory; | |
| 69 | - this.loadTweakJars = loadTweakJars; | |
| 36 | + super(api, containers); | |
| 37 | + this.directory = directory; | |
| 38 | + this.loadTweakJars = loadTweakJars; | |
| 70 | 39 | } |
| 71 | - | |
| 40 | + | |
| 72 | 41 | @Override |
| 73 | 42 | public void init(LoaderEnvironment environment, LoaderProperties properties) |
| 74 | 43 | { |
| ... | ... | @@ -76,7 +45,7 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule |
| 76 | 45 | this.readJarFiles = properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_SEARCH_JARFILES, true); |
| 77 | 46 | this.forceInjection = properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_FORCE_INJECTION, false); |
| 78 | 47 | |
| 79 | - this.coreAPI.writeDiscoverySettings(); | |
| 48 | + this.api.writeDiscoverySettings(); | |
| 80 | 49 | } |
| 81 | 50 | |
| 82 | 51 | /** |
| ... | ... | @@ -88,6 +57,36 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule |
| 88 | 57 | properties.setBooleanProperty(LoaderProperties.OPTION_SEARCH_JARFILES, this.readJarFiles); |
| 89 | 58 | properties.setBooleanProperty(LoaderProperties.OPTION_FORCE_INJECTION, this.forceInjection); |
| 90 | 59 | } |
| 60 | + | |
| 61 | + @Override | |
| 62 | + protected boolean forceInjection() | |
| 63 | + { | |
| 64 | + return this.forceInjection; | |
| 65 | + } | |
| 66 | + | |
| 67 | + @Override | |
| 68 | + protected boolean loadTweakJars() | |
| 69 | + { | |
| 70 | + return this.loadTweakJars; | |
| 71 | + } | |
| 72 | + | |
| 73 | + @Override | |
| 74 | + protected boolean loadTweaks() | |
| 75 | + { | |
| 76 | + return this.loadTweaks; | |
| 77 | + } | |
| 78 | + | |
| 79 | + @Override | |
| 80 | + protected boolean readJarFiles() | |
| 81 | + { | |
| 82 | + return this.readJarFiles; | |
| 83 | + } | |
| 84 | + | |
| 85 | + @Override | |
| 86 | + protected File[] getFiles() | |
| 87 | + { | |
| 88 | + return this.directory.listFiles(this.getFilenameFilter()); | |
| 89 | + } | |
| 91 | 90 | |
| 92 | 91 | /* (non-Javadoc) |
| 93 | 92 | * @see java.lang.Object#toString() |
| ... | ... | @@ -107,34 +106,6 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule |
| 107 | 106 | } |
| 108 | 107 | |
| 109 | 108 | /* (non-Javadoc) |
| 110 | - * @see com.mumfrey.liteloader.core.Enumerator#getLoadableMods() | |
| 111 | - */ | |
| 112 | - public List<LoadableMod<File>> getLoadableMods() | |
| 113 | - { | |
| 114 | - return this.loadableMods; | |
| 115 | - } | |
| 116 | - | |
| 117 | - /** | |
| 118 | - * For FilenameFilter interface | |
| 119 | - * | |
| 120 | - * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String) | |
| 121 | - */ | |
| 122 | - @Override | |
| 123 | - public boolean accept(File dir, String fileName) | |
| 124 | - { | |
| 125 | - fileName = fileName.toLowerCase(); | |
| 126 | - | |
| 127 | - if (fileName.endsWith(".litemod.zip")) | |
| 128 | - { | |
| 129 | - LiteLoaderLogger.warning("Found %s with unsupported extension .litemod.zip." | |
| 130 | - + " Please change file extension to .litemod to allow this file to be loaded!", fileName); | |
| 131 | - return true; | |
| 132 | - } | |
| 133 | - | |
| 134 | - return fileName.endsWith(".litemod") || fileName.endsWith(".jar"); | |
| 135 | - } | |
| 136 | - | |
| 137 | - /* (non-Javadoc) | |
| 138 | 109 | * @see com.mumfrey.liteloader.core.Enumerator |
| 139 | 110 | * #enumerate(com.mumfrey.liteloader.core.EnabledModsList, |
| 140 | 111 | * java.lang.String) |
| ... | ... | @@ -145,272 +116,22 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule |
| 145 | 116 | if (this.directory.exists() && this.directory.isDirectory()) |
| 146 | 117 | { |
| 147 | 118 | LiteLoaderLogger.info("Discovering valid mod files in folder %s", this.directory.getPath()); |
| 148 | - | |
| 149 | 119 | this.findValidFiles(enumerator); |
| 150 | - this.sortAndRegisterFiles(enumerator); | |
| 151 | - } | |
| 152 | - } | |
| 153 | - | |
| 154 | - /** | |
| 155 | - * Search the folder for (potentially) valid files | |
| 156 | - */ | |
| 157 | - private void findValidFiles(ModularEnumerator enumerator) | |
| 158 | - { | |
| 159 | - for (File file : this.directory.listFiles(this.getFilenameFilter())) | |
| 160 | - { | |
| 161 | - LoadableFile candidateFile = new LoadableFile(file); | |
| 162 | - candidateFile.setForceInjection(this.forceInjection); | |
| 163 | - try | |
| 164 | - { | |
| 165 | - this.inspectFile(enumerator, candidateFile); | |
| 166 | - } | |
| 167 | - catch (Exception ex) | |
| 168 | - { | |
| 169 | - LiteLoaderLogger.warning(ex, "An error occurred whilst inspecting %s", candidateFile); | |
| 170 | - } | |
| 171 | 120 | } |
| 172 | 121 | } |
| 173 | - | |
| 174 | - /** | |
| 175 | - * Check whether a particular file is valid, and add it to the candiates | |
| 176 | - * list if it appears to be acceptable. | |
| 177 | - * | |
| 178 | - * @param enumerator | |
| 179 | - * @param candidateFile | |
| 180 | - */ | |
| 181 | - protected void inspectFile(ModularEnumerator enumerator, LoadableFile candidateFile) | |
| 182 | - { | |
| 183 | - if (this.isValidFile(enumerator, candidateFile)) | |
| 184 | - { | |
| 185 | - String metaData = candidateFile.getFileContents(LoadableMod.METADATA_FILENAME, Charsets.UTF_8); | |
| 186 | - if (metaData != null) | |
| 187 | - { | |
| 188 | - LoadableMod<File> modFile = this.getModFile(candidateFile, metaData); | |
| 189 | - this.addModFile(enumerator, modFile); | |
| 190 | - return; | |
| 191 | - } | |
| 192 | - else if (this.isValidTweakContainer(candidateFile)) | |
| 193 | - { | |
| 194 | - TweakContainer<File> container = this.getTweakFile(candidateFile); | |
| 195 | - this.addTweakFile(enumerator, container); | |
| 196 | - return; | |
| 197 | - } | |
| 198 | - else | |
| 199 | - { | |
| 200 | - LiteLoaderLogger.info("Ignoring %s", candidateFile); | |
| 201 | -// enumerator.registerBadContainer(candidateFile, "No metadata"); | |
| 202 | - } | |
| 203 | - } | |
| 204 | -// else | |
| 205 | -// { | |
| 206 | -// enumerator.registerBadContainer(candidateFile, "Not a valid file"); | |
| 207 | -// } | |
| 208 | - } | |
| 209 | - | |
| 210 | - /** | |
| 211 | - * Check whether the specified file is a valid mod container | |
| 212 | - * | |
| 213 | - * @param enumerator | |
| 214 | - * @param candidateFile | |
| 215 | - */ | |
| 216 | - protected boolean isValidFile(ModularEnumerator enumerator, LoadableFile candidateFile) | |
| 217 | - { | |
| 218 | - String filename = candidateFile.getName().toLowerCase(); | |
| 219 | - if (filename.endsWith(".litemod.zip")) | |
| 220 | - { | |
| 221 | - enumerator.registerBadContainer(candidateFile, "Invalid file extension .litemod.zip"); | |
| 222 | - return false; | |
| 223 | - } | |
| 224 | - else if (filename.endsWith(".litemod")) | |
| 225 | - { | |
| 226 | - return true; | |
| 227 | - } | |
| 228 | - else if (filename.endsWith(".jar")) | |
| 229 | - { | |
| 230 | - Set<String> modSystems = candidateFile.getModSystems(); | |
| 231 | - boolean hasLiteLoader = modSystems.contains("LiteLoader"); | |
| 232 | - if (modSystems.size() > 0) | |
| 233 | - { | |
| 234 | - LiteLoaderLogger.info("%s supports mod systems %s", candidateFile, modSystems); | |
| 235 | - if (!hasLiteLoader) return false; | |
| 236 | - } | |
| 237 | - | |
| 238 | - return this.loadTweakJars || this.readJarFiles || hasLiteLoader; | |
| 239 | - } | |
| 240 | - | |
| 241 | - return false; | |
| 242 | - } | |
| 243 | - | |
| 244 | - /** | |
| 245 | - * Called only if the file is not a valid mod container (has no mod | |
| 246 | - * metadata) to check whether it could instead be a potential tweak | |
| 247 | - * container. | |
| 248 | - * | |
| 249 | - * @param candidateFile | |
| 250 | - */ | |
| 251 | - protected boolean isValidTweakContainer(LoadableFile candidateFile) | |
| 252 | - { | |
| 253 | - return this.loadTweakJars && this.loadTweaks && candidateFile.getName().toLowerCase().endsWith(".jar"); | |
| 254 | - } | |
| 255 | - | |
| 256 | - /** | |
| 257 | - * Get the {@link FilenameFilter} to use to filter candidate files | |
| 258 | - */ | |
| 259 | - protected FilenameFilter getFilenameFilter() | |
| 260 | - { | |
| 261 | - return this; | |
| 262 | - } | |
| 263 | - | |
| 264 | - /** | |
| 265 | - * @param modFile | |
| 266 | - */ | |
| 267 | - protected boolean isFileSupported(LoadableMod<File> modFile) | |
| 268 | - { | |
| 269 | - return LiteLoaderVersion.CURRENT.isVersionSupported(modFile.getTargetVersion()); | |
| 270 | - } | |
| 271 | - | |
| 272 | - /** | |
| 273 | - * @param candidateFile | |
| 274 | - * @param metaData | |
| 275 | - */ | |
| 276 | - protected LoadableMod<File> getModFile(LoadableFile candidateFile, String metaData) | |
| 277 | - { | |
| 278 | - return new LoadableModFile(candidateFile, metaData); | |
| 279 | - } | |
| 280 | - | |
| 281 | - /** | |
| 282 | - * @param candidateFile | |
| 283 | - */ | |
| 284 | - protected TweakContainer<File> getTweakFile(LoadableFile candidateFile) | |
| 285 | - { | |
| 286 | - return candidateFile; | |
| 287 | - } | |
| 288 | - | |
| 289 | - /** | |
| 290 | - * @param enumerator | |
| 291 | - * @param modFile | |
| 292 | - */ | |
| 293 | - protected void addModFile(ModularEnumerator enumerator, LoadableMod<File> modFile) | |
| 294 | - { | |
| 295 | - if (modFile.hasValidMetaData()) | |
| 296 | - { | |
| 297 | - // Only add the mod if the version matches, we add candidates to the versionOrderingSets in | |
| 298 | - // order to determine the most recent version available. | |
| 299 | - if (this.isFileSupported(modFile)) | |
| 300 | - { | |
| 301 | - if (!this.versionOrderingSets.containsKey(modFile.getName())) | |
| 302 | - { | |
| 303 | - this.versionOrderingSets.put(modFile.getModName(), new TreeSet<LoadableMod<File>>()); | |
| 304 | - } | |
| 305 | - | |
| 306 | - LiteLoaderLogger.info("Considering valid mod file: %s", modFile); | |
| 307 | - this.versionOrderingSets.get(modFile.getModName()).add(modFile); | |
| 308 | - } | |
| 309 | - else | |
| 310 | - { | |
| 311 | - LiteLoaderLogger.info(Verbosity.REDUCED, "Not adding invalid or version-mismatched mod file: %s", modFile); | |
| 312 | - enumerator.registerBadContainer(modFile, "Version not supported"); | |
| 313 | - } | |
| 314 | - } | |
| 315 | - } | |
| 316 | - | |
| 317 | - /** | |
| 318 | - * @param enumerator | |
| 319 | - * @param container | |
| 320 | - */ | |
| 321 | - protected void addTweakFile(ModularEnumerator enumerator, TweakContainer<File> container) | |
| 322 | - { | |
| 323 | - enumerator.registerTweakContainer(container); | |
| 324 | - } | |
| 325 | - | |
| 326 | - /** | |
| 327 | - * @param enumerator | |
| 328 | - */ | |
| 329 | - protected void sortAndRegisterFiles(ModularEnumerator enumerator) | |
| 330 | - { | |
| 331 | - // Copy the first entry in every version set into the modfiles list | |
| 332 | - for (Entry<String, TreeSet<LoadableMod<File>>> modFileEntry : this.versionOrderingSets.entrySet()) | |
| 333 | - { | |
| 334 | - LoadableMod<File> newestVersion = modFileEntry.getValue().iterator().next(); | |
| 335 | - this.registerFile(enumerator, newestVersion); | |
| 336 | - } | |
| 337 | - | |
| 338 | - this.versionOrderingSets.clear(); | |
| 339 | - } | |
| 340 | - | |
| 341 | - /** | |
| 342 | - * @param enumerator | |
| 343 | - * @param modFile | |
| 122 | + | |
| 123 | + /* (non-Javadoc) | |
| 124 | + * @see com.mumfrey.liteloader.api.EnumeratorModule#register( | |
| 125 | + * com.mumfrey.liteloader.interfaces.ModularEnumerator, | |
| 126 | + * java.lang.String) | |
| 344 | 127 | */ |
| 345 | - @SuppressWarnings("unchecked") | |
| 346 | - protected void registerFile(ModularEnumerator enumerator, LoadableMod<File> modFile) | |
| 347 | - { | |
| 348 | - if (enumerator.registerModContainer(modFile)) | |
| 349 | - { | |
| 350 | - LiteLoaderLogger.info(Verbosity.REDUCED, "Adding newest valid mod file '%s' at revision %.4f", modFile, modFile.getRevision()); | |
| 351 | - this.loadableMods.add(modFile); | |
| 352 | - } | |
| 353 | - else | |
| 354 | - { | |
| 355 | - LiteLoaderLogger.info(Verbosity.REDUCED, "Not adding valid mod file '%s', the specified mod is disabled or missing a required dependency", | |
| 356 | - modFile); | |
| 357 | - } | |
| 358 | - | |
| 359 | - if (this.loadTweaks) | |
| 360 | - { | |
| 361 | - try | |
| 362 | - { | |
| 363 | - if (modFile instanceof TweakContainer) | |
| 364 | - { | |
| 365 | - this.addTweakFile(enumerator, (TweakContainer<File>)modFile); | |
| 366 | - } | |
| 367 | - } | |
| 368 | - catch (Throwable th) | |
| 369 | - { | |
| 370 | - LiteLoaderLogger.warning("Error adding tweaks from '%s'", modFile); | |
| 371 | - } | |
| 372 | - } | |
| 373 | - } | |
| 374 | - | |
| 375 | 128 | @Override |
| 376 | - public void injectIntoClassLoader(ModularEnumerator enumerator, LaunchClassLoader classLoader) | |
| 129 | + public void register(ModularEnumerator enumerator, String profile) | |
| 377 | 130 | { |
| 378 | - LiteLoaderLogger.info("Injecting external mods into class path..."); | |
| 379 | - | |
| 380 | - for (LoadableMod<?> loadableMod : this.loadableMods) | |
| 381 | - { | |
| 382 | - try | |
| 383 | - { | |
| 384 | - if (loadableMod.injectIntoClassPath(classLoader, false)) | |
| 385 | - { | |
| 386 | - LiteLoaderLogger.info("Successfully injected mod file '%s' into classpath", loadableMod); | |
| 387 | - } | |
| 388 | - } | |
| 389 | - catch (MalformedURLException ex) | |
| 390 | - { | |
| 391 | - LiteLoaderLogger.warning("Error injecting '%s' into classPath. The mod will not be loaded", loadableMod); | |
| 392 | - } | |
| 393 | - } | |
| 394 | - } | |
| 395 | - | |
| 396 | - @Override | |
| 397 | - public void registerMods(ModularEnumerator enumerator, LaunchClassLoader classLoader) | |
| 398 | - { | |
| 399 | - LiteLoaderLogger.info(Verbosity.REDUCED, "Discovering mods in valid mod files..."); | |
| 400 | - LoadingProgress.incTotalLiteLoaderProgress(this.loadableMods.size()); | |
| 401 | - | |
| 402 | - for (LoadableMod<?> modFile : this.loadableMods) | |
| 131 | + if (this.directory.exists() && this.directory.isDirectory()) | |
| 403 | 132 | { |
| 404 | - LoadingProgress.incLiteLoaderProgress("Searching for mods in " + modFile.getModName() + "..."); | |
| 405 | - LiteLoaderLogger.info("Searching %s...", modFile); | |
| 406 | - try | |
| 407 | - { | |
| 408 | - enumerator.registerModsFrom(modFile, true); | |
| 409 | - } | |
| 410 | - catch (Exception ex) | |
| 411 | - { | |
| 412 | - LiteLoaderLogger.warning("Error encountered whilst searching in %s...", modFile); | |
| 413 | - } | |
| 133 | + LiteLoaderLogger.info("Registering discovered mod files in folder %s", this.directory.getPath()); | |
| 134 | + this.sortAndRegisterFiles(enumerator); | |
| 414 | 135 | } |
| 415 | 136 | } |
| 416 | 137 | } | ... | ... |
src/main/java/com/mumfrey/liteloader/core/api/EnumeratorModuleRepository.java
0 โ 100644
| 1 | +/* | |
| 2 | + * This file is part of LiteLoader. | |
| 3 | + * Copyright (C) 2012-16 Adam Mummery-Smith | |
| 4 | + * All Rights Reserved. | |
| 5 | + */ | |
| 6 | +package com.mumfrey.liteloader.core.api; | |
| 7 | + | |
| 8 | +import java.io.File; | |
| 9 | +import java.util.ArrayList; | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +import com.mumfrey.liteloader.core.api.repository.Repository; | |
| 13 | +import com.mumfrey.liteloader.interfaces.ModularEnumerator; | |
| 14 | +import com.mumfrey.liteloader.util.log.LiteLoaderLogger; | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * Enumerator module which searches for mods and tweaks in a folder | |
| 18 | + * | |
| 19 | + * @author Adam Mummery-Smith | |
| 20 | + */ | |
| 21 | +public class EnumeratorModuleRepository extends EnumeratorModuleFiles | |
| 22 | +{ | |
| 23 | + private final File modList; | |
| 24 | + | |
| 25 | + private final Repository repo; | |
| 26 | + | |
| 27 | + private File[] files = new File[0]; | |
| 28 | + | |
| 29 | + public EnumeratorModuleRepository(LiteLoaderCoreAPI api, ContainerEnvironment containers, Repository repo, File modList) | |
| 30 | + { | |
| 31 | + super(api, containers); | |
| 32 | + this.repo = repo; | |
| 33 | + this.modList = modList; | |
| 34 | + } | |
| 35 | + | |
| 36 | + /* (non-Javadoc) | |
| 37 | + * @see java.lang.Object#toString() | |
| 38 | + */ | |
| 39 | + @Override | |
| 40 | + public String toString() | |
| 41 | + { | |
| 42 | + return this.modList.getAbsolutePath(); | |
| 43 | + } | |
| 44 | + | |
| 45 | + public File getModList() | |
| 46 | + { | |
| 47 | + return this.modList; | |
| 48 | + } | |
| 49 | + | |
| 50 | + @Override | |
| 51 | + protected boolean readJarFiles() | |
| 52 | + { | |
| 53 | + return true; | |
| 54 | + } | |
| 55 | + | |
| 56 | + @Override | |
| 57 | + protected boolean loadTweakJars() | |
| 58 | + { | |
| 59 | + return true; | |
| 60 | + } | |
| 61 | + | |
| 62 | + @Override | |
| 63 | + protected boolean loadTweaks() | |
| 64 | + { | |
| 65 | + return true; | |
| 66 | + } | |
| 67 | + | |
| 68 | + @Override | |
| 69 | + protected boolean forceInjection() | |
| 70 | + { | |
| 71 | + return false; | |
| 72 | + } | |
| 73 | + | |
| 74 | + @Override | |
| 75 | + protected File[] getFiles() | |
| 76 | + { | |
| 77 | + return this.files; | |
| 78 | + } | |
| 79 | + | |
| 80 | + /* (non-Javadoc) | |
| 81 | + * @see com.mumfrey.liteloader.core.Enumerator | |
| 82 | + * #enumerate(com.mumfrey.liteloader.core.EnabledModsList, | |
| 83 | + * java.lang.String) | |
| 84 | + */ | |
| 85 | + @Override | |
| 86 | + public void enumerate(ModularEnumerator enumerator, String profile) | |
| 87 | + { | |
| 88 | + if (this.modList.isFile()) | |
| 89 | + { | |
| 90 | + LiteLoaderLogger.info("Discovering mod files defined in repository %s", this.modList.getPath()); | |
| 91 | + this.resolve(); | |
| 92 | + | |
| 93 | + this.findValidFiles(enumerator); | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + @Override | |
| 98 | + public void register(ModularEnumerator enumerator, String profile) | |
| 99 | + { | |
| 100 | + if (this.modList.isFile()) | |
| 101 | + { | |
| 102 | + LiteLoaderLogger.info("Discovering mod files defined in repository %s", this.modList.getPath()); | |
| 103 | + this.resolve(); | |
| 104 | + | |
| 105 | + this.findValidFiles(enumerator); | |
| 106 | + this.sortAndRegisterFiles(enumerator); | |
| 107 | + } | |
| 108 | + } | |
| 109 | + | |
| 110 | + private void resolve() | |
| 111 | + { | |
| 112 | + this.repo.resolve(this.modList); | |
| 113 | + | |
| 114 | + List<File> files = new ArrayList<File>(); | |
| 115 | + files.addAll(this.repo.getFiles()); | |
| 116 | + this.files = files.toArray(this.files); | |
| 117 | + } | |
| 118 | +} | ... | ... |
src/main/java/com/mumfrey/liteloader/core/api/LiteLoaderCoreAPI.java
| ... | ... | @@ -14,6 +14,7 @@ import com.mumfrey.liteloader.api.EnumeratorModule; |
| 14 | 14 | import com.mumfrey.liteloader.api.LiteAPI; |
| 15 | 15 | import com.mumfrey.liteloader.api.MixinConfigProvider; |
| 16 | 16 | import com.mumfrey.liteloader.core.LiteLoaderVersion; |
| 17 | +import com.mumfrey.liteloader.core.api.EnumeratorModuleFiles.ContainerEnvironment; | |
| 17 | 18 | import com.mumfrey.liteloader.interfaces.ObjectFactory; |
| 18 | 19 | import com.mumfrey.liteloader.launch.LoaderEnvironment; |
| 19 | 20 | import com.mumfrey.liteloader.launch.LoaderProperties; |
| ... | ... | @@ -133,17 +134,26 @@ public abstract class LiteLoaderCoreAPI implements LiteAPI, MixinConfigProvider |
| 133 | 134 | { |
| 134 | 135 | enumeratorModules.add(new EnumeratorModuleClassPath()); |
| 135 | 136 | } |
| 137 | + | |
| 138 | + ContainerEnvironment containers = new ContainerEnvironment(); | |
| 136 | 139 | |
| 137 | 140 | if (this.searchModsFolder) |
| 138 | 141 | { |
| 139 | 142 | File modsFolder = this.environment.getModsFolder(); |
| 140 | - enumeratorModules.add(new EnumeratorModuleFolder(this, modsFolder, false)); | |
| 143 | + enumeratorModules.add(new EnumeratorModuleFolder(this, containers, modsFolder, false)); | |
| 141 | 144 | |
| 142 | 145 | File versionedModsFolder = this.environment.getVersionedModsFolder(); |
| 143 | - enumeratorModules.add(new EnumeratorModuleFolder(this, versionedModsFolder, true)); | |
| 146 | + enumeratorModules.add(new EnumeratorModuleFolder(this, containers, versionedModsFolder, true)); | |
| 147 | + } | |
| 148 | + | |
| 149 | + String modsRepoFile = this.environment.getModsRepoFile(); | |
| 150 | + if (modsRepoFile != null) | |
| 151 | + { | |
| 152 | + File modList = new File(modsRepoFile); | |
| 153 | + enumeratorModules.add(new EnumeratorModuleRepository(this, containers, this.environment.getModRepository(), modList)); | |
| 144 | 154 | } |
| 145 | 155 | |
| 146 | - return Collections.unmodifiableList(enumeratorModules); | |
| 156 | + return Collections.<EnumeratorModule>unmodifiableList(enumeratorModules); | |
| 147 | 157 | } |
| 148 | 158 | |
| 149 | 159 | /** | ... | ... |
src/main/java/com/mumfrey/liteloader/core/api/repository/Artefact.java
0 โ 100644
| 1 | +/* | |
| 2 | + * This file is part of LiteLoader. | |
| 3 | + * Copyright (C) 2012-16 Adam Mummery-Smith | |
| 4 | + * All Rights Reserved. | |
| 5 | + */ | |
| 6 | +package com.mumfrey.liteloader.core.api.repository; | |
| 7 | + | |
| 8 | +import java.io.File; | |
| 9 | +import java.util.regex.Matcher; | |
| 10 | +import java.util.regex.Pattern; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * Specifier for a mod in the ivy repo shorthand notation | |
| 14 | + */ | |
| 15 | +public final class Artefact | |
| 16 | +{ | |
| 17 | + /** | |
| 18 | + * Regex for matching valid specifiers | |
| 19 | + */ | |
| 20 | + private static final Pattern PATTERN = Pattern.compile("^([^:]+):([^:]+):([^:@]+?)(:([^:@]+?))?(@(zip|jar|litemod))?$"); | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * Artefact group id | |
| 24 | + */ | |
| 25 | + private final String group; | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * Artefact name | |
| 29 | + */ | |
| 30 | + private final String name; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * Artefact version | |
| 34 | + */ | |
| 35 | + private final String version; | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * Artefact classifier (can be null) | |
| 39 | + */ | |
| 40 | + private final String classifier; | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * Artefact type (can be null) | |
| 44 | + */ | |
| 45 | + private final String type; | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Resolved file | |
| 49 | + */ | |
| 50 | + private File file; | |
| 51 | + | |
| 52 | + public Artefact(String specifier) | |
| 53 | + { | |
| 54 | + if (specifier == null) | |
| 55 | + { | |
| 56 | + throw new IllegalArgumentException("Invalid artefact specifier: null"); | |
| 57 | + } | |
| 58 | + | |
| 59 | + Matcher matcher = Artefact.PATTERN.matcher(specifier); | |
| 60 | + if (!matcher.matches()) | |
| 61 | + { | |
| 62 | + throw new IllegalArgumentException("Invalid artefact specifier: " + specifier); | |
| 63 | + } | |
| 64 | + | |
| 65 | + this.group = matcher.group(1); | |
| 66 | + this.name = matcher.group(2); | |
| 67 | + this.version = matcher.group(3); | |
| 68 | + this.classifier = matcher.group(5); | |
| 69 | + this.type = matcher.group(7); | |
| 70 | + } | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * Get the artefact id consisting of the group and name | |
| 74 | + * | |
| 75 | + * @return | |
| 76 | + */ | |
| 77 | + public String getArtefactId() | |
| 78 | + { | |
| 79 | + return String.format("%s:%s", this.getGroup(), this.getName()); | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * Get the path portion of this artefact's resolved location | |
| 84 | + * | |
| 85 | + * @return artefact path | |
| 86 | + */ | |
| 87 | + public String getPath() | |
| 88 | + { | |
| 89 | + return String.format("%s/%s/%s", this.getGroup().replace('.', '/'), this.getName(), this.getVersion()); | |
| 90 | + } | |
| 91 | + | |
| 92 | + /** | |
| 93 | + * Get the file name portion of this artefact's resolved location | |
| 94 | + * | |
| 95 | + * @return arefact file name | |
| 96 | + */ | |
| 97 | + public String getFileName() | |
| 98 | + { | |
| 99 | + return String.format("%s-%s%s.%s", this.getName(), this.getVersion(), this.getClassifier("-"), this.getType()); | |
| 100 | + } | |
| 101 | + | |
| 102 | + /** | |
| 103 | + * Get the artefact group | |
| 104 | + */ | |
| 105 | + public String getGroup() | |
| 106 | + { | |
| 107 | + return this.group; | |
| 108 | + } | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * Get the artefact name | |
| 112 | + */ | |
| 113 | + public String getName() | |
| 114 | + { | |
| 115 | + return this.name; | |
| 116 | + } | |
| 117 | + | |
| 118 | + /** | |
| 119 | + * Get the artefact version | |
| 120 | + */ | |
| 121 | + public String getVersion() | |
| 122 | + { | |
| 123 | + return this.version; | |
| 124 | + } | |
| 125 | + | |
| 126 | + /** | |
| 127 | + * Get the artefact classifier, returns an empty string if no classifier is | |
| 128 | + * set | |
| 129 | + */ | |
| 130 | + public String getClassifier() | |
| 131 | + { | |
| 132 | + return this.getClassifier(""); | |
| 133 | + } | |
| 134 | + | |
| 135 | + private String getClassifier(String prefix) | |
| 136 | + { | |
| 137 | + return this.classifier != null ? prefix + this.classifier : ""; | |
| 138 | + } | |
| 139 | + | |
| 140 | + /** | |
| 141 | + * Get the artefact type, defaults to "jar" if no type was specified | |
| 142 | + */ | |
| 143 | + public String getType() | |
| 144 | + { | |
| 145 | + return this.type != null ? this.type : "jar"; | |
| 146 | + } | |
| 147 | + | |
| 148 | + /** | |
| 149 | + * Resolve this artefact beneath the specified repository root | |
| 150 | + * | |
| 151 | + * @param repositoryRoot repository root | |
| 152 | + * @return resolved file | |
| 153 | + */ | |
| 154 | + void resolve(File repositoryRoot) | |
| 155 | + { | |
| 156 | + this.file = new File(new File(repositoryRoot, this.getPath()), this.getFileName()); | |
| 157 | + } | |
| 158 | + | |
| 159 | + /** | |
| 160 | + * Get whether the resolved artefact actually exists | |
| 161 | + */ | |
| 162 | + public boolean exists() | |
| 163 | + { | |
| 164 | + return this.file != null && this.file.isFile(); | |
| 165 | + } | |
| 166 | + | |
| 167 | + /** | |
| 168 | + * After resolution, return the resolved file location | |
| 169 | + * | |
| 170 | + * @return resolved location | |
| 171 | + */ | |
| 172 | + public File getFile() | |
| 173 | + { | |
| 174 | + return this.file; | |
| 175 | + } | |
| 176 | + | |
| 177 | + /* (non-Javadoc) | |
| 178 | + * @see java.lang.Object#toString() | |
| 179 | + */ | |
| 180 | + @Override | |
| 181 | + public String toString() | |
| 182 | + { | |
| 183 | + String type = this.type != null && !"jar".equals(this.type) ? "@" + this.type : ""; | |
| 184 | + return String.format("%s:%s:%s%s%s", this.getGroup(), this.getName(), this.getVersion(), this.getClassifier(":"), type); | |
| 185 | + } | |
| 186 | +} | |
| 0 | 187 | \ No newline at end of file | ... | ... |
src/main/java/com/mumfrey/liteloader/core/api/repository/JsonResolver.java
0 โ 100644
| 1 | +/* | |
| 2 | + * This file is part of LiteLoader. | |
| 3 | + * Copyright (C) 2012-16 Adam Mummery-Smith | |
| 4 | + * All Rights Reserved. | |
| 5 | + */ | |
| 6 | +package com.mumfrey.liteloader.core.api.repository; | |
| 7 | + | |
| 8 | +import java.io.File; | |
| 9 | +import java.io.FileReader; | |
| 10 | +import java.util.Collections; | |
| 11 | +import java.util.List; | |
| 12 | +import java.util.Map; | |
| 13 | +import java.util.TreeMap; | |
| 14 | + | |
| 15 | +import com.google.common.base.Strings; | |
| 16 | +import com.google.gson.Gson; | |
| 17 | +import com.google.gson.GsonBuilder; | |
| 18 | +import com.google.gson.annotations.SerializedName; | |
| 19 | +import com.mumfrey.liteloader.util.log.LiteLoaderLogger; | |
| 20 | +import com.mumfrey.liteloader.util.log.LiteLoaderLogger.Verbosity; | |
| 21 | + | |
| 22 | +/** | |
| 23 | + * Modlist JSON resolver | |
| 24 | + */ | |
| 25 | +public final class JsonResolver | |
| 26 | +{ | |
| 27 | + /** | |
| 28 | + * Gson object for deserialisation | |
| 29 | + */ | |
| 30 | + private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * Root resolver, used as parent for resolvers with no parent | |
| 34 | + */ | |
| 35 | + private static final JsonResolver rootResolver = new JsonResolver().setRoot(); | |
| 36 | + | |
| 37 | + @SerializedName("repositoryRoot") | |
| 38 | + private String repositoryRoot; | |
| 39 | + | |
| 40 | + @SerializedName("modRef") | |
| 41 | + private List<String> modRefs; | |
| 42 | + | |
| 43 | + @SerializedName("parentList") | |
| 44 | + private String parentList; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * True when resolving, used to prevent accidental re-entrance if a config | |
| 48 | + * is defined as its own parent! | |
| 49 | + */ | |
| 50 | + private transient boolean resolving = false; | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * JSON file in the file system | |
| 54 | + */ | |
| 55 | + private transient File file; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * Resolved repository root | |
| 59 | + */ | |
| 60 | + private transient File root; | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Resolved parent | |
| 64 | + */ | |
| 65 | + private transient JsonResolver parent; | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * Resolved artefacts | |
| 69 | + */ | |
| 70 | + private final transient Map<String, Artefact> artefacts = new TreeMap<String, Artefact>(); | |
| 71 | + | |
| 72 | + private JsonResolver() | |
| 73 | + { | |
| 74 | + } | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * Configure this resolver as the root resolver | |
| 78 | + */ | |
| 79 | + private JsonResolver setRoot() | |
| 80 | + { | |
| 81 | + this.parent = this; | |
| 82 | + return this; | |
| 83 | + } | |
| 84 | + | |
| 85 | + /** | |
| 86 | + * Set the source file, called by the deserialisation routine | |
| 87 | + * | |
| 88 | + * @param file JSON file | |
| 89 | + * @return fluent | |
| 90 | + */ | |
| 91 | + JsonResolver setFile(File file) | |
| 92 | + { | |
| 93 | + this.file = file; | |
| 94 | + return this; | |
| 95 | + } | |
| 96 | + | |
| 97 | + boolean isResolved() | |
| 98 | + { | |
| 99 | + return this.parent != null; | |
| 100 | + } | |
| 101 | + | |
| 102 | + boolean isResolving() | |
| 103 | + { | |
| 104 | + return this.resolving; | |
| 105 | + } | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * Get resolved artefacts from this resolver | |
| 109 | + */ | |
| 110 | + public Map<String, Artefact> getArtefacts() | |
| 111 | + { | |
| 112 | + return Collections.<String, Artefact>unmodifiableMap(this.artefacts); | |
| 113 | + } | |
| 114 | + | |
| 115 | + /** | |
| 116 | + * Resolve this modlist, resolves parents recursively as required | |
| 117 | + * | |
| 118 | + * @param repository owning repository | |
| 119 | + * @return fluent | |
| 120 | + */ | |
| 121 | + JsonResolver resolve(Repository repository) | |
| 122 | + { | |
| 123 | + if (!this.isResolved() && !this.isResolving()) | |
| 124 | + { | |
| 125 | + LiteLoaderLogger.info(Verbosity.REDUCED, "Resolving mods in repository %s", this); | |
| 126 | + this.doResolve(repository); | |
| 127 | + } | |
| 128 | + | |
| 129 | + return this; | |
| 130 | + } | |
| 131 | + | |
| 132 | + private void doResolve(Repository repository) | |
| 133 | + { | |
| 134 | + this.resolving = true; | |
| 135 | + this.root = this.resolveRoot(repository); | |
| 136 | + | |
| 137 | + JsonResolver parent = this.resolveParent(repository); | |
| 138 | + if (parent.isResolving()) | |
| 139 | + { | |
| 140 | + throw new IllegalStateException("Unexpected circular dependency in mod lists: " + this + " <-> " + parent); | |
| 141 | + } | |
| 142 | + | |
| 143 | + this.artefacts.clear(); | |
| 144 | + this.artefacts.putAll(parent.artefacts); | |
| 145 | + | |
| 146 | + this.resolveArtefacts(repository); | |
| 147 | + this.resolving = false; | |
| 148 | + this.parent = parent; | |
| 149 | + } | |
| 150 | + | |
| 151 | + private File resolveRoot(Repository repository) | |
| 152 | + { | |
| 153 | + if (this.repositoryRoot == null) | |
| 154 | + { | |
| 155 | + if (this.file != null) | |
| 156 | + { | |
| 157 | + return this.file.getParentFile(); | |
| 158 | + } | |
| 159 | + | |
| 160 | + return repository.getDefaultRepositoryRoot(); | |
| 161 | + } | |
| 162 | + | |
| 163 | + // Absolute path | |
| 164 | + if (Repository.isAbsolutePath(this.repositoryRoot)) | |
| 165 | + { | |
| 166 | + return new File(this.repositoryRoot); | |
| 167 | + } | |
| 168 | + | |
| 169 | + // Relative path, relative to | |
| 170 | + return new File(repository.getRoot(), this.repositoryRoot); | |
| 171 | + } | |
| 172 | + | |
| 173 | + private JsonResolver resolveParent(Repository repository) | |
| 174 | + { | |
| 175 | + if (this.parentList == null) | |
| 176 | + { | |
| 177 | + return JsonResolver.rootResolver; | |
| 178 | + } | |
| 179 | + | |
| 180 | + if (Repository.isAbsolutePath(this.parentList)) | |
| 181 | + { | |
| 182 | + File path = new File(this.parentList); | |
| 183 | + return repository.getResolver(path).resolve(repository); | |
| 184 | + } | |
| 185 | + | |
| 186 | + File path = new File(repository.getRoot(), this.parentList); | |
| 187 | + return repository.getResolver(path).resolve(repository); | |
| 188 | + } | |
| 189 | + | |
| 190 | + private void resolveArtefacts(Repository repository) | |
| 191 | + { | |
| 192 | + if (this.modRefs == null) | |
| 193 | + { | |
| 194 | + return; | |
| 195 | + } | |
| 196 | + | |
| 197 | + for (String ref : this.modRefs) | |
| 198 | + { | |
| 199 | + if (Strings.isNullOrEmpty(ref)) | |
| 200 | + { | |
| 201 | + continue; | |
| 202 | + } | |
| 203 | + | |
| 204 | + try | |
| 205 | + { | |
| 206 | + Artefact artefact = new Artefact(ref); | |
| 207 | + artefact.resolve(this.root); | |
| 208 | + | |
| 209 | + LiteLoaderLogger.info(Verbosity.VERBOSE, "Resolved artefact '%s' at %s", artefact.getArtefactId(), artefact.getFile()); | |
| 210 | + | |
| 211 | + String artefactId = artefact.getArtefactId(); | |
| 212 | + Artefact existing = this.artefacts.get(artefactId); | |
| 213 | + if (existing != null) | |
| 214 | + { | |
| 215 | + LiteLoaderLogger.info(Verbosity.VERBOSE, "Evicting artefact '%s' -> '%s'", existing, artefact.getVersion()); | |
| 216 | + } | |
| 217 | + | |
| 218 | + this.artefacts.put(artefactId, artefact); | |
| 219 | + } | |
| 220 | + catch (IllegalArgumentException ex) | |
| 221 | + { | |
| 222 | + ex.printStackTrace(); | |
| 223 | + } | |
| 224 | + } | |
| 225 | + } | |
| 226 | + | |
| 227 | + /** | |
| 228 | + * Deserialise a resolver from a JSON source using Gson | |
| 229 | + * | |
| 230 | + * @param file file to read | |
| 231 | + * @return deserialised resolver or new resolver if could not be read | |
| 232 | + */ | |
| 233 | + static JsonResolver createFrom(File file) | |
| 234 | + { | |
| 235 | + if (file.isFile()) | |
| 236 | + { | |
| 237 | + try (FileReader reader = new FileReader(file)) | |
| 238 | + { | |
| 239 | + return JsonResolver.gson.fromJson(reader, JsonResolver.class).setFile(file); | |
| 240 | + } | |
| 241 | + catch (Exception ex) | |
| 242 | + { | |
| 243 | + ex.printStackTrace(); | |
| 244 | + } | |
| 245 | + } | |
| 246 | + | |
| 247 | + return new JsonResolver().setFile(file); | |
| 248 | + } | |
| 249 | + | |
| 250 | + @Override | |
| 251 | + public String toString() | |
| 252 | + { | |
| 253 | + return this.file.getPath(); | |
| 254 | + } | |
| 255 | +} | ... | ... |
src/main/java/com/mumfrey/liteloader/core/api/repository/Repository.java
0 โ 100644
| 1 | +/* | |
| 2 | + * This file is part of LiteLoader. | |
| 3 | + * Copyright (C) 2012-16 Adam Mummery-Smith | |
| 4 | + * All Rights Reserved. | |
| 5 | + */ | |
| 6 | +package com.mumfrey.liteloader.core.api.repository; | |
| 7 | + | |
| 8 | +import java.io.File; | |
| 9 | +import java.util.ArrayList; | |
| 10 | +import java.util.Collection; | |
| 11 | +import java.util.Collections; | |
| 12 | +import java.util.List; | |
| 13 | +import java.util.Map; | |
| 14 | +import java.util.TreeMap; | |
| 15 | + | |
| 16 | +import com.google.common.collect.ImmutableList; | |
| 17 | +import com.google.common.collect.ImmutableList.Builder; | |
| 18 | +import com.mumfrey.liteloader.util.log.LiteLoaderLogger; | |
| 19 | +import com.mumfrey.liteloader.util.log.LiteLoaderLogger.Verbosity; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * A mod container repository defined by JSON modlists | |
| 23 | + */ | |
| 24 | +public class Repository | |
| 25 | +{ | |
| 26 | + /** | |
| 27 | + * Default root which relative paths are relative to, usually the game | |
| 28 | + * directory | |
| 29 | + */ | |
| 30 | + private final File root; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * Fallback repository root in case things go wrong. Usually the versionsed | |
| 34 | + * mods directory | |
| 35 | + */ | |
| 36 | + private final File defaultRepositoryRoot; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * Resolvers in this repository | |
| 40 | + */ | |
| 41 | + private final Map<String, JsonResolver> resolvers = new TreeMap<String, JsonResolver>(); | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * Global list of resolved artefacts | |
| 45 | + */ | |
| 46 | + private final List<Artefact> artefacts = new ArrayList<Artefact>(); | |
| 47 | + | |
| 48 | + public Repository(File root, File defaultRepositoryRoot) | |
| 49 | + { | |
| 50 | + this.root = root; | |
| 51 | + this.defaultRepositoryRoot = defaultRepositoryRoot; | |
| 52 | + } | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Get the repository root, usually the game dir | |
| 56 | + */ | |
| 57 | + public File getRoot() | |
| 58 | + { | |
| 59 | + return this.root; | |
| 60 | + } | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Get the default repository location, usually the versioned mods dir | |
| 64 | + */ | |
| 65 | + public File getDefaultRepositoryRoot() | |
| 66 | + { | |
| 67 | + return this.defaultRepositoryRoot; | |
| 68 | + } | |
| 69 | + | |
| 70 | + Map<String, JsonResolver> getResolvers() | |
| 71 | + { | |
| 72 | + return this.resolvers; | |
| 73 | + } | |
| 74 | + | |
| 75 | + JsonResolver getResolver(File path) | |
| 76 | + { | |
| 77 | + String location = path.getAbsolutePath(); | |
| 78 | + JsonResolver resolver = this.resolvers.get(location); | |
| 79 | + if (resolver == null) | |
| 80 | + { | |
| 81 | + resolver = JsonResolver.createFrom(path); | |
| 82 | + this.resolvers.put(location, resolver); | |
| 83 | + } | |
| 84 | + return resolver; | |
| 85 | + } | |
| 86 | + | |
| 87 | + /** | |
| 88 | + * Resolve the specified modlist | |
| 89 | + * | |
| 90 | + * @param path modlist path | |
| 91 | + */ | |
| 92 | + public void resolve(File path) | |
| 93 | + { | |
| 94 | + JsonResolver resolver = this.getResolver(path); | |
| 95 | + resolver.resolve(this); | |
| 96 | + this.artefacts.addAll(resolver.getArtefacts().values()); | |
| 97 | + } | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * Get resolved artefacts from this repository | |
| 101 | + */ | |
| 102 | + public Collection<Artefact> getArtefacts() | |
| 103 | + { | |
| 104 | + return Collections.<Artefact>unmodifiableList(this.artefacts); | |
| 105 | + } | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * Get all resolved files in this repository | |
| 109 | + */ | |
| 110 | + public Collection<File> getFiles() | |
| 111 | + { | |
| 112 | + Builder<File> files = ImmutableList.<File>builder(); | |
| 113 | + for (Artefact artefact : this.artefacts) | |
| 114 | + { | |
| 115 | + if (artefact.exists()) | |
| 116 | + { | |
| 117 | + files.add(artefact.getFile()); | |
| 118 | + } | |
| 119 | + else | |
| 120 | + { | |
| 121 | + LiteLoaderLogger.info(Verbosity.REDUCED, "Rejecting non-existent artefact %s at %s", artefact.getArtefactId(), artefact.getFile()); | |
| 122 | + } | |
| 123 | + } | |
| 124 | + return files.build(); | |
| 125 | + } | |
| 126 | + | |
| 127 | + static boolean isAbsolutePath(String path) | |
| 128 | + { | |
| 129 | + return path.matches("^([a-zA-Z]:[/\\\\]|/).+$"); | |
| 130 | + } | |
| 131 | +} | ... | ... |
src/main/java/com/mumfrey/liteloader/interfaces/LoadableFile.java
| ... | ... | @@ -10,6 +10,8 @@ import java.io.IOException; |
| 10 | 10 | import java.net.MalformedURLException; |
| 11 | 11 | import java.net.URL; |
| 12 | 12 | import java.nio.charset.Charset; |
| 13 | +import java.util.ArrayList; | |
| 14 | +import java.util.Collection; | |
| 13 | 15 | import java.util.Collections; |
| 14 | 16 | import java.util.HashSet; |
| 15 | 17 | import java.util.List; |
| ... | ... | @@ -97,6 +99,11 @@ public class LoadableFile extends File implements TweakContainer<File> |
| 97 | 99 | * Mixin config resource names |
| 98 | 100 | */ |
| 99 | 101 | protected Set<String> mixinConfigs = new HashSet<String>(); |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Mixin errors | |
| 105 | + */ | |
| 106 | + protected List<Throwable> mixinErrors = new ArrayList<Throwable>(); | |
| 100 | 107 | |
| 101 | 108 | /** |
| 102 | 109 | * Create a new tweak container wrapping the specified file |
| ... | ... | @@ -344,6 +351,18 @@ public class LoadableFile extends File implements TweakContainer<File> |
| 344 | 351 | { |
| 345 | 352 | return this.mixinConfigs; |
| 346 | 353 | } |
| 354 | + | |
| 355 | + @Override | |
| 356 | + public void registerMixinError(Throwable th) | |
| 357 | + { | |
| 358 | + this.mixinErrors.add(th); | |
| 359 | + } | |
| 360 | + | |
| 361 | + @Override | |
| 362 | + public Collection<Throwable> getMixinErrors() | |
| 363 | + { | |
| 364 | + return this.mixinErrors; | |
| 365 | + } | |
| 347 | 366 | |
| 348 | 367 | @Override |
| 349 | 368 | public boolean hasEventTransformers() | ... | ... |
src/main/java/com/mumfrey/liteloader/interfaces/MixinContainer.java
| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | */ |
| 6 | 6 | package com.mumfrey.liteloader.interfaces; |
| 7 | 7 | |
| 8 | +import java.util.Collection; | |
| 8 | 9 | import java.util.Set; |
| 9 | 10 | |
| 10 | 11 | public interface MixinContainer<L> extends Loadable<L>, Injectable |
| ... | ... | @@ -19,5 +20,17 @@ public interface MixinContainer<L> extends Loadable<L>, Injectable |
| 19 | 20 | * Get this mod's list of mixin configs |
| 20 | 21 | */ |
| 21 | 22 | public abstract Set<String> getMixinConfigs(); |
| 23 | + | |
| 24 | + /** | |
| 25 | + * Register a mixin error with the container | |
| 26 | + * | |
| 27 | + * @param th caught throwable | |
| 28 | + */ | |
| 29 | + public abstract void registerMixinError(Throwable th); | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * @return mixin errors | |
| 33 | + */ | |
| 34 | + public abstract Collection<Throwable> getMixinErrors(); | |
| 22 | 35 | |
| 23 | 36 | } | ... | ... |
src/main/java/com/mumfrey/liteloader/launch/GameEnvironment.java
| ... | ... | @@ -30,4 +30,10 @@ public interface GameEnvironment |
| 30 | 30 | * config for legacy mods. |
| 31 | 31 | */ |
| 32 | 32 | public abstract File getModsFolder(); |
| 33 | + | |
| 34 | + /** | |
| 35 | + * Get the path to a JSON file describing a mod repository layout, can be | |
| 36 | + * null if not defined | |
| 37 | + */ | |
| 38 | + public abstract String getModsRepoFile(); | |
| 33 | 39 | } | ... | ... |
src/main/java/com/mumfrey/liteloader/launch/LiteLoaderTweaker.java
| ... | ... | @@ -41,7 +41,8 @@ public class LiteLoaderTweaker implements ITweaker |
| 41 | 41 | // TODO Version - 1.11.2 |
| 42 | 42 | public static final String VERSION = "1.11.2"; |
| 43 | 43 | |
| 44 | - protected static final String bootstrapClassName = "com.mumfrey.liteloader.core.LiteLoaderBootstrap"; | |
| 44 | + protected static final String BOOTSTRAP_CLASS = "com.mumfrey.liteloader.core.LiteLoaderBootstrap"; | |
| 45 | + private static final String CLIENT_API = "com.mumfrey.liteloader.client.api.LiteLoaderCoreAPIClient"; | |
| 45 | 46 | |
| 46 | 47 | /** |
| 47 | 48 | * Loader startup state |
| ... | ... | @@ -323,7 +324,7 @@ public class LiteLoaderTweaker implements ITweaker |
| 323 | 324 | { |
| 324 | 325 | this.initEnvironment(args, gameDirectory, assetsDirectory, profile); |
| 325 | 326 | |
| 326 | - this.bootstrap = this.spawnBootstrap(LiteLoaderTweaker.bootstrapClassName, Launch.classLoader); | |
| 327 | + this.bootstrap = this.spawnBootstrap(LiteLoaderTweaker.BOOTSTRAP_CLASS, Launch.classLoader); | |
| 327 | 328 | |
| 328 | 329 | this.transformerManager = new ClassTransformerManager(this.bootstrap.getRequiredTransformers()); |
| 329 | 330 | |
| ... | ... | @@ -347,7 +348,7 @@ public class LiteLoaderTweaker implements ITweaker |
| 347 | 348 | { |
| 348 | 349 | MixinBootstrap.init(); |
| 349 | 350 | |
| 350 | - this.bootstrap.preInit(Launch.classLoader, true, this.env.getModFilterList()); | |
| 351 | + this.bootstrap.preInit(Launch.classLoader, true); | |
| 351 | 352 | |
| 352 | 353 | this.injectDiscoveredTweakClasses(); |
| 353 | 354 | StartupState.PREINIT.completed(); |
| ... | ... | @@ -567,7 +568,7 @@ public class LiteLoaderTweaker implements ITweaker |
| 567 | 568 | @Override |
| 568 | 569 | public void registerCoreAPIs(List<String> apisToLoad) |
| 569 | 570 | { |
| 570 | - apisToLoad.add(0, "com.mumfrey.liteloader.client.api.LiteLoaderCoreAPIClient"); | |
| 571 | + apisToLoad.add(0, LiteLoaderTweaker.CLIENT_API); | |
| 571 | 572 | } |
| 572 | 573 | |
| 573 | 574 | @Override | ... | ... |
src/main/java/com/mumfrey/liteloader/launch/LiteLoaderTweakerServer.java
| ... | ... | @@ -13,9 +13,11 @@ import com.mumfrey.liteloader.util.log.LiteLoaderLogger.Verbosity; |
| 13 | 13 | |
| 14 | 14 | public class LiteLoaderTweakerServer extends LiteLoaderTweaker |
| 15 | 15 | { |
| 16 | + private static final String SERVER_API = "com.mumfrey.liteloader.server.api.LiteLoaderCoreAPIServer"; | |
| 17 | + | |
| 16 | 18 | public LiteLoaderTweakerServer() |
| 17 | 19 | { |
| 18 | - LiteLoaderLogger.verbosity = Verbosity.REDUCED; | |
| 20 | + LiteLoaderLogger.setVerbosity(Verbosity.REDUCED); | |
| 19 | 21 | } |
| 20 | 22 | |
| 21 | 23 | @Override |
| ... | ... | @@ -26,7 +28,7 @@ public class LiteLoaderTweakerServer extends LiteLoaderTweaker |
| 26 | 28 | @Override |
| 27 | 29 | public void registerCoreAPIs(List<String> apisToLoad) |
| 28 | 30 | { |
| 29 | - apisToLoad.add(0, "com.mumfrey.liteloader.server.api.LiteLoaderCoreAPIServer"); | |
| 31 | + apisToLoad.add(0, LiteLoaderTweakerServer.SERVER_API); | |
| 30 | 32 | } |
| 31 | 33 | |
| 32 | 34 | @Override |
| ... | ... | @@ -41,7 +43,6 @@ public class LiteLoaderTweakerServer extends LiteLoaderTweaker |
| 41 | 43 | public String getLaunchTarget() |
| 42 | 44 | { |
| 43 | 45 | super.getLaunchTarget(); |
| 44 | - | |
| 45 | 46 | return "net.minecraft.server.MinecraftServer"; |
| 46 | 47 | } |
| 47 | 48 | } | ... | ... |
src/main/java/com/mumfrey/liteloader/launch/LoaderBootstrap.java
| ... | ... | @@ -24,9 +24,8 @@ public interface LoaderBootstrap |
| 24 | 24 | * |
| 25 | 25 | * @param classLoader |
| 26 | 26 | * @param loadTweaks |
| 27 | - * @param modsToLoad | |
| 28 | 27 | */ |
| 29 | - public abstract void preInit(LaunchClassLoader classLoader, boolean loadTweaks, List<String> modsToLoad); | |
| 28 | + public abstract void preInit(LaunchClassLoader classLoader, boolean loadTweaks); | |
| 30 | 29 | |
| 31 | 30 | /** |
| 32 | 31 | * | ... | ... |
src/main/java/com/mumfrey/liteloader/launch/LoaderEnvironment.java
| ... | ... | @@ -11,6 +11,7 @@ import com.mumfrey.liteloader.api.manager.APIAdapter; |
| 11 | 11 | import com.mumfrey.liteloader.api.manager.APIProvider; |
| 12 | 12 | import com.mumfrey.liteloader.core.EnabledModsList; |
| 13 | 13 | import com.mumfrey.liteloader.core.LiteLoaderVersion; |
| 14 | +import com.mumfrey.liteloader.core.api.repository.Repository; | |
| 14 | 15 | import com.mumfrey.liteloader.interfaces.LoaderEnumerator; |
| 15 | 16 | |
| 16 | 17 | /** |
| ... | ... | @@ -49,6 +50,12 @@ public interface LoaderEnvironment extends GameEnvironment |
| 49 | 50 | * about which mods are enabled/disabled. |
| 50 | 51 | */ |
| 51 | 52 | public abstract EnabledModsList getEnabledModsList(); |
| 53 | + | |
| 54 | + /** | |
| 55 | + * The mod repository defined by command-line option which specifies a JSON | |
| 56 | + * file defining a mod repository | |
| 57 | + */ | |
| 58 | + public abstract Repository getModRepository(); | |
| 52 | 59 | |
| 53 | 60 | /** |
| 54 | 61 | * The enumerator manages mod container and class discovery | ... | ... |
src/main/java/com/mumfrey/liteloader/launch/StartupEnvironment.java
| ... | ... | @@ -31,6 +31,7 @@ public abstract class StartupEnvironment implements GameEnvironment |
| 31 | 31 | |
| 32 | 32 | private ArgumentAcceptingOptionSpec<String> modsDirOption; |
| 33 | 33 | private ArgumentAcceptingOptionSpec<String> modsOption; |
| 34 | + private ArgumentAcceptingOptionSpec<String> modsRepoOption; | |
| 34 | 35 | private ArgumentAcceptingOptionSpec<String> apisOption; |
| 35 | 36 | private NonOptionArgumentSpec<String> unparsedOptions; |
| 36 | 37 | private OptionSet parsedOptions; |
| ... | ... | @@ -84,6 +85,8 @@ public abstract class StartupEnvironment implements GameEnvironment |
| 84 | 85 | |
| 85 | 86 | this.modsOption = optionParser.accepts("mods", "Comma-separated list of mods to load") |
| 86 | 87 | .withRequiredArg().ofType(String.class).withValuesSeparatedBy(','); |
| 88 | + this.modsRepoOption = optionParser.accepts("modRepo", "Path to a JSON file which defines a mod repository") | |
| 89 | + .withRequiredArg().ofType(String.class); | |
| 87 | 90 | this.apisOption = optionParser.accepts("api", "Additional API classes to load") |
| 88 | 91 | .withRequiredArg().ofType(String.class); |
| 89 | 92 | this.modsDirOption = optionParser.accepts("modsDir", "Path to 'mods' folder to use instead of default") |
| ... | ... | @@ -239,4 +242,13 @@ public abstract class StartupEnvironment implements GameEnvironment |
| 239 | 242 | { |
| 240 | 243 | return this.getOptionalDirectory(this.gameDirectory, this.modsDirOption, "mods"); |
| 241 | 244 | } |
| 245 | + | |
| 246 | + /** | |
| 247 | + * Get the mods repo json path | |
| 248 | + */ | |
| 249 | + @Override | |
| 250 | + public String getModsRepoFile() | |
| 251 | + { | |
| 252 | + return (this.parsedOptions.has(this.modsRepoOption)) ? this.modsRepoOption.value(this.parsedOptions) : null; | |
| 253 | + } | |
| 242 | 254 | } | ... | ... |
src/main/java/com/mumfrey/liteloader/permissions/PermissionsManagerClient.java
| ... | ... | @@ -47,7 +47,7 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi |
| 47 | 47 | * Permissions permissible which is a proxy for permissions that are common |
| 48 | 48 | * to all mods. |
| 49 | 49 | */ |
| 50 | - private final static Permissible allMods = new PermissibleAllMods(); | |
| 50 | + private static final Permissible allMods = new PermissibleAllMods(); | |
| 51 | 51 | |
| 52 | 52 | /** |
| 53 | 53 | * List of registered client mods supporting permissions | ... | ... |
src/main/java/com/mumfrey/liteloader/transformers/IsolatedClassWriter.java
src/main/java/com/mumfrey/liteloader/util/jinput/ComponentRegistry.java
| ... | ... | @@ -98,7 +98,8 @@ public class ComponentRegistry |
| 98 | 98 | components.add(component); |
| 99 | 99 | } |
| 100 | 100 | |
| 101 | - } while (component != null && components.size() < 32); | |
| 101 | + } | |
| 102 | + while (component != null && components.size() < 32); | |
| 102 | 103 | |
| 103 | 104 | return components; |
| 104 | 105 | } |
| ... | ... | @@ -150,7 +151,8 @@ public class ComponentRegistry |
| 150 | 151 | controllers.add(controller); |
| 151 | 152 | } |
| 152 | 153 | |
| 153 | - } while (controller != null && controllers.size() < 32); | |
| 154 | + } | |
| 155 | + while (controller != null && controllers.size() < 32); | |
| 154 | 156 | |
| 155 | 157 | return controllers; |
| 156 | 158 | } | ... | ... |
src/main/java/com/mumfrey/liteloader/util/log/LiteLoaderLogger.java
| ... | ... | @@ -65,7 +65,7 @@ public class LiteLoaderLogger extends AbstractAppender |
| 65 | 65 | } |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | - public static Verbosity verbosity = LiteLoaderLogger.DEBUG ? Verbosity.VERBOSE : Verbosity.NORMAL; | |
| 68 | + private static Verbosity verbosity = LiteLoaderLogger.DEBUG ? Verbosity.VERBOSE : Verbosity.NORMAL; | |
| 69 | 69 | |
| 70 | 70 | static |
| 71 | 71 | { |
| ... | ... | @@ -77,6 +77,11 @@ public class LiteLoaderLogger extends AbstractAppender |
| 77 | 77 | super("Internal Log Appender", null, null); |
| 78 | 78 | this.start(); |
| 79 | 79 | } |
| 80 | + | |
| 81 | + public static void setVerbosity(Verbosity verbosity) | |
| 82 | + { | |
| 83 | + LiteLoaderLogger.verbosity = verbosity; | |
| 84 | + } | |
| 80 | 85 | |
| 81 | 86 | @Override |
| 82 | 87 | public void append(LogEvent event) | ... | ... |