Commit a2a91d215292d0946429af6f018e64abe60e2927

Authored by Mumfrey
1 parent 42582df7

Add JSON modlist resolver support, closes #34

src/main/java/com/mumfrey/liteloader/api/EnumeratorModule.java
@@ -36,10 +36,7 @@ public interface EnumeratorModule @@ -36,10 +36,7 @@ public interface EnumeratorModule
36 public abstract void writeSettings(LoaderEnvironment environment, LoaderProperties properties); 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 * <p>This method is called during loader PREINIT phase so <b>do not use any 41 * <p>This method is called during loader PREINIT phase so <b>do not use any
45 * game classes here</b>!</p> 42 * game classes here</b>!</p>
@@ -48,6 +45,20 @@ public interface EnumeratorModule @@ -48,6 +45,20 @@ public interface EnumeratorModule
48 * @param profile 45 * @param profile
49 */ 46 */
50 public abstract void enumerate(ModularEnumerator enumerator, String profile); 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 * The enumerator module should inject (as required) any discovered 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,7 +8,6 @@ package com.mumfrey.liteloader.core;
8 import java.io.File; 8 import java.io.File;
9 import java.io.FileReader; 9 import java.io.FileReader;
10 import java.io.FileWriter; 10 import java.io.FileWriter;
11 -import java.io.IOException;  
12 import java.util.List; 11 import java.util.List;
13 import java.util.Map; 12 import java.util.Map;
14 import java.util.TreeMap; 13 import java.util.TreeMap;
@@ -186,12 +185,9 @@ public final class EnabledModsList @@ -186,12 +185,9 @@ public final class EnabledModsList
186 { 185 {
187 if (file.exists()) 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 instance.setEnabledModsFile(file); 191 instance.setEnabledModsFile(file);
196 return instance; 192 return instance;
197 } 193 }
@@ -199,20 +195,6 @@ public final class EnabledModsList @@ -199,20 +195,6 @@ public final class EnabledModsList
199 { 195 {
200 ex.printStackTrace(); 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 EnabledModsList instance = new EnabledModsList(); 200 EnabledModsList instance = new EnabledModsList();
@@ -229,31 +211,14 @@ public final class EnabledModsList @@ -229,31 +211,14 @@ public final class EnabledModsList
229 { 211 {
230 if (!this.allowSave) return; 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 catch (Exception ex) 218 catch (Exception ex)
240 { 219 {
241 ex.printStackTrace(); 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
@@ -30,6 +30,7 @@ import com.mumfrey.liteloader.api.manager.APIProvider; @@ -30,6 +30,7 @@ import com.mumfrey.liteloader.api.manager.APIProvider;
30 import com.mumfrey.liteloader.api.manager.APIRegistry; 30 import com.mumfrey.liteloader.api.manager.APIRegistry;
31 import com.mumfrey.liteloader.common.LoadingProgress; 31 import com.mumfrey.liteloader.common.LoadingProgress;
32 import com.mumfrey.liteloader.core.api.LiteLoaderCoreAPI; 32 import com.mumfrey.liteloader.core.api.LiteLoaderCoreAPI;
  33 +import com.mumfrey.liteloader.core.api.repository.Repository;
33 import com.mumfrey.liteloader.interfaces.LoaderEnumerator; 34 import com.mumfrey.liteloader.interfaces.LoaderEnumerator;
34 import com.mumfrey.liteloader.launch.ClassTransformerManager; 35 import com.mumfrey.liteloader.launch.ClassTransformerManager;
35 import com.mumfrey.liteloader.launch.LiteLoaderTweaker; 36 import com.mumfrey.liteloader.launch.LiteLoaderTweaker;
@@ -103,6 +104,16 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP @@ -103,6 +104,16 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
103 * Folder containing version-specific configuration 104 * Folder containing version-specific configuration
104 */ 105 */
105 private final File versionConfigFolder; 106 private final File versionConfigFolder;
  107 +
  108 + /**
  109 + * Mods repo file
  110 + */
  111 + private final String repositoryFile;
  112 +
  113 + /**
  114 + * Mod repository defined in JSON
  115 + */
  116 + private final Repository repository;
106 117
107 /** 118 /**
108 * File to write log entries to 119 * File to write log entries to
@@ -139,6 +150,8 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP @@ -139,6 +150,8 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
139 150
140 private LaunchClassLoader classLoader; 151 private LaunchClassLoader classLoader;
141 152
  153 + private final StartupEnvironment env;
  154 +
142 private final ITweaker tweaker; 155 private final ITweaker tweaker;
143 156
144 private final APIRegistry apiRegistry; 157 private final APIRegistry apiRegistry;
@@ -158,7 +171,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP @@ -158,7 +171,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
158 * List of mods passed into the command line 171 * List of mods passed into the command line
159 */ 172 */
160 private EnabledModsList enabledModsList; 173 private EnabledModsList enabledModsList;
161 - 174 +
162 /** 175 /**
163 * @param env 176 * @param env
164 * @param tweaker 177 * @param tweaker
@@ -166,6 +179,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP @@ -166,6 +179,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
166 public LiteLoaderBootstrap(StartupEnvironment env, ITweaker tweaker) 179 public LiteLoaderBootstrap(StartupEnvironment env, ITweaker tweaker)
167 { 180 {
168 this.environmentType = EnvironmentType.values()[env.getEnvironmentTypeId()]; 181 this.environmentType = EnvironmentType.values()[env.getEnvironmentTypeId()];
  182 + this.env = env;
169 this.tweaker = tweaker; 183 this.tweaker = tweaker;
170 184
171 this.apiRegistry = new APIRegistry(this.getEnvironment(), this.getProperties()); 185 this.apiRegistry = new APIRegistry(this.getEnvironment(), this.getProperties());
@@ -174,6 +188,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP @@ -174,6 +188,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
174 this.assetsDirectory = env.getAssetsDirectory(); 188 this.assetsDirectory = env.getAssetsDirectory();
175 this.profile = env.getProfile(); 189 this.profile = env.getProfile();
176 this.modsFolder = env.getModsFolder(); 190 this.modsFolder = env.getModsFolder();
  191 + this.repositoryFile = env.getModsRepoFile();
177 192
178 this.versionedModsFolder = new File(this.modsFolder, LiteLoaderVersion.CURRENT.getMinecraftVersion()); 193 this.versionedModsFolder = new File(this.modsFolder, LiteLoaderVersion.CURRENT.getMinecraftVersion());
179 this.configBaseFolder = new File(this.gameDirectory, "liteconfig"); 194 this.configBaseFolder = new File(this.gameDirectory, "liteconfig");
@@ -184,17 +199,27 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP @@ -184,17 +199,27 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
184 this.commonConfigFolder = new File(this.configBaseFolder, "common"); 199 this.commonConfigFolder = new File(this.configBaseFolder, "common");
185 this.versionConfigFolder = this.inflectVersionedConfigPath(LiteLoaderVersion.CURRENT); 200 this.versionConfigFolder = this.inflectVersionedConfigPath(LiteLoaderVersion.CURRENT);
186 201
187 - if (!this.modsFolder.exists()) this.modsFolder.mkdirs();  
188 - if (!this.versionedModsFolder.exists()) this.versionedModsFolder.mkdirs();  
189 - if (!this.configBaseFolder.exists()) this.configBaseFolder.mkdirs();  
190 - if (!this.commonConfigFolder.exists()) this.commonConfigFolder.mkdirs();  
191 - if (!this.versionConfigFolder.exists()) this.versionConfigFolder.mkdirs(); 202 + this.repository = new Repository(this.gameDirectory, this.versionedModsFolder);
  203 +
  204 + this.mkdir(this.modsFolder);
  205 + this.mkdir(this.versionedModsFolder);
  206 + this.mkdir(this.configBaseFolder);
  207 + this.mkdir(this.commonConfigFolder);
  208 + this.mkdir(this.versionConfigFolder);
192 209
193 this.initAPIs(env.getAPIsToLoad()); 210 this.initAPIs(env.getAPIsToLoad());
194 this.apiProvider = this.apiRegistry.getProvider(); 211 this.apiProvider = this.apiRegistry.getProvider();
195 this.apiAdapter = this.apiRegistry.getAdapter(); 212 this.apiAdapter = this.apiRegistry.getAdapter();
196 } 213 }
197 214
  215 + private void mkdir(File dir)
  216 + {
  217 + if (!dir.isDirectory())
  218 + {
  219 + dir.mkdirs();
  220 + }
  221 + }
  222 +
198 /** 223 /**
199 * @param version 224 * @param version
200 */ 225 */
@@ -250,6 +275,12 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP @@ -250,6 +275,12 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
250 { 275 {
251 return this.enabledModsList; 276 return this.enabledModsList;
252 } 277 }
  278 +
  279 + @Override
  280 + public Repository getModRepository()
  281 + {
  282 + return this.repository;
  283 + }
253 284
254 @Override 285 @Override
255 public LoaderEnumerator getEnumerator() 286 public LoaderEnumerator getEnumerator()
@@ -302,15 +333,20 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP @@ -302,15 +333,20 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
302 * #preInit(net.minecraft.launchwrapper.LaunchClassLoader, boolean) 333 * #preInit(net.minecraft.launchwrapper.LaunchClassLoader, boolean)
303 */ 334 */
304 @Override 335 @Override
305 - public void preInit(LaunchClassLoader classLoader, boolean loadTweaks, List<String> modsToLoad) 336 + public void preInit(LaunchClassLoader classLoader, boolean loadTweaks)
306 { 337 {
  338 + List<String> modsToLoad = this.env.getModFilterList();
  339 +
307 this.classLoader = classLoader; 340 this.classLoader = classLoader;
308 this.loadTweaks = loadTweaks; 341 this.loadTweaks = loadTweaks;
309 342
310 LiteLoaderLogger.info(Verbosity.REDUCED, "LiteLoader begin PREINIT..."); 343 LiteLoaderLogger.info(Verbosity.REDUCED, "LiteLoader begin PREINIT...");
311 344
312 // Set up the bootstrap 345 // Set up the bootstrap
313 - if (!this.prepare()) return; 346 + if (!this.prepare())
  347 + {
  348 + return;
  349 + }
314 350
315 LiteLoaderLogger.info(Verbosity.REDUCED, "LiteLoader %s starting up...", LiteLoaderVersion.CURRENT.getLoaderVersion()); 351 LiteLoaderLogger.info(Verbosity.REDUCED, "LiteLoader %s starting up...", LiteLoaderVersion.CURRENT.getLoaderVersion());
316 352
@@ -324,7 +360,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP @@ -324,7 +360,7 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
324 360
325 this.enabledModsList = EnabledModsList.createFrom(this.enabledModsFile); 361 this.enabledModsList = EnabledModsList.createFrom(this.enabledModsFile);
326 this.enabledModsList.processModsList(this.profile, modsToLoad); 362 this.enabledModsList.processModsList(this.profile, modsToLoad);
327 - 363 +
328 this.enumerator = this.spawnEnumerator(classLoader); 364 this.enumerator = this.spawnEnumerator(classLoader);
329 this.enumerator.onPreInit(); 365 this.enumerator.onPreInit();
330 366
@@ -614,6 +650,16 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP @@ -614,6 +650,16 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
614 { 650 {
615 return this.versionConfigFolder; 651 return this.versionConfigFolder;
616 } 652 }
  653 +
  654 + /**
  655 + * Get the path to a JSON file describing a mod repository layout, can be
  656 + * null if not defined
  657 + */
  658 + @Override
  659 + public String getModsRepoFile()
  660 + {
  661 + return this.repositoryFile;
  662 + }
617 663
618 /** 664 /**
619 * Get a boolean propery from the properties file and also write the new 665 * Get a boolean propery from the properties file and also write the new
src/main/java/com/mumfrey/liteloader/core/LiteLoaderEnumerator.java
@@ -396,11 +396,13 @@ public class LiteLoaderEnumerator implements LoaderEnumerator @@ -396,11 +396,13 @@ public class LiteLoaderEnumerator implements LoaderEnumerator
396 { 396 {
397 this.gotoState(EnumeratorState.DISCOVER); 397 this.gotoState(EnumeratorState.DISCOVER);
398 398
  399 + String profile = this.environment.getProfile();
  400 +
399 for (EnumeratorModule module : this.modules) 401 for (EnumeratorModule module : this.modules)
400 { 402 {
401 try 403 try
402 { 404 {
403 - module.enumerate(this, this.environment.getProfile()); 405 + module.enumerate(this, profile);
404 } 406 }
405 catch (Throwable th) 407 catch (Throwable th)
406 { 408 {
@@ -408,6 +410,18 @@ public class LiteLoaderEnumerator implements LoaderEnumerator @@ -408,6 +410,18 @@ public class LiteLoaderEnumerator implements LoaderEnumerator
408 } 410 }
409 } 411 }
410 412
  413 + for (EnumeratorModule module : this.modules)
  414 + {
  415 + try
  416 + {
  417 + module.register(this, profile);
  418 + }
  419 + catch (Throwable th)
  420 + {
  421 + LiteLoaderLogger.warning(th, "Enumerator Module %s encountered an error whilst enumerating", module.getClass().getName());
  422 + }
  423 + }
  424 +
411 this.checkDependencies(); 425 this.checkDependencies();
412 } 426 }
413 427
src/main/java/com/mumfrey/liteloader/core/api/EnumeratorModuleClassPath.java
@@ -82,37 +82,43 @@ public class EnumeratorModuleClassPath implements EnumeratorModule @@ -82,37 +82,43 @@ public class EnumeratorModuleClassPath implements EnumeratorModule
82 @Override 82 @Override
83 public void enumerate(ModularEnumerator enumerator, String profile) 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,50 +6,19 @@
6 package com.mumfrey.liteloader.core.api; 6 package com.mumfrey.liteloader.core.api;
7 7
8 import java.io.File; 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 import com.mumfrey.liteloader.interfaces.ModularEnumerator; 10 import com.mumfrey.liteloader.interfaces.ModularEnumerator;
26 -import com.mumfrey.liteloader.interfaces.TweakContainer;  
27 import com.mumfrey.liteloader.launch.LoaderEnvironment; 11 import com.mumfrey.liteloader.launch.LoaderEnvironment;
28 import com.mumfrey.liteloader.launch.LoaderProperties; 12 import com.mumfrey.liteloader.launch.LoaderProperties;
29 import com.mumfrey.liteloader.util.log.LiteLoaderLogger; 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 * Enumerator module which searches for mods and tweaks in a folder 16 * Enumerator module which searches for mods and tweaks in a folder
36 * 17 *
37 * @author Adam Mummery-Smith 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 protected File directory; 22 protected File directory;
54 23
55 protected boolean readJarFiles; 24 protected boolean readJarFiles;
@@ -62,13 +31,13 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule @@ -62,13 +31,13 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule
62 */ 31 */
63 protected final boolean loadTweakJars; 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 @Override 41 @Override
73 public void init(LoaderEnvironment environment, LoaderProperties properties) 42 public void init(LoaderEnvironment environment, LoaderProperties properties)
74 { 43 {
@@ -76,7 +45,7 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule @@ -76,7 +45,7 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule
76 this.readJarFiles = properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_SEARCH_JARFILES, true); 45 this.readJarFiles = properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_SEARCH_JARFILES, true);
77 this.forceInjection = properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_FORCE_INJECTION, false); 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,6 +57,36 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule
88 properties.setBooleanProperty(LoaderProperties.OPTION_SEARCH_JARFILES, this.readJarFiles); 57 properties.setBooleanProperty(LoaderProperties.OPTION_SEARCH_JARFILES, this.readJarFiles);
89 properties.setBooleanProperty(LoaderProperties.OPTION_FORCE_INJECTION, this.forceInjection); 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 /* (non-Javadoc) 91 /* (non-Javadoc)
93 * @see java.lang.Object#toString() 92 * @see java.lang.Object#toString()
@@ -107,34 +106,6 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule @@ -107,34 +106,6 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule
107 } 106 }
108 107
109 /* (non-Javadoc) 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 * @see com.mumfrey.liteloader.core.Enumerator 109 * @see com.mumfrey.liteloader.core.Enumerator
139 * #enumerate(com.mumfrey.liteloader.core.EnabledModsList, 110 * #enumerate(com.mumfrey.liteloader.core.EnabledModsList,
140 * java.lang.String) 111 * java.lang.String)
@@ -145,272 +116,22 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule @@ -145,272 +116,22 @@ public class EnumeratorModuleFolder implements FilenameFilter, EnumeratorModule
145 if (this.directory.exists() && this.directory.isDirectory()) 116 if (this.directory.exists() && this.directory.isDirectory())
146 { 117 {
147 LiteLoaderLogger.info("Discovering valid mod files in folder %s", this.directory.getPath()); 118 LiteLoaderLogger.info("Discovering valid mod files in folder %s", this.directory.getPath());
148 -  
149 this.findValidFiles(enumerator); 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 @Override 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,6 +14,7 @@ import com.mumfrey.liteloader.api.EnumeratorModule;
14 import com.mumfrey.liteloader.api.LiteAPI; 14 import com.mumfrey.liteloader.api.LiteAPI;
15 import com.mumfrey.liteloader.api.MixinConfigProvider; 15 import com.mumfrey.liteloader.api.MixinConfigProvider;
16 import com.mumfrey.liteloader.core.LiteLoaderVersion; 16 import com.mumfrey.liteloader.core.LiteLoaderVersion;
  17 +import com.mumfrey.liteloader.core.api.EnumeratorModuleFiles.ContainerEnvironment;
17 import com.mumfrey.liteloader.interfaces.ObjectFactory; 18 import com.mumfrey.liteloader.interfaces.ObjectFactory;
18 import com.mumfrey.liteloader.launch.LoaderEnvironment; 19 import com.mumfrey.liteloader.launch.LoaderEnvironment;
19 import com.mumfrey.liteloader.launch.LoaderProperties; 20 import com.mumfrey.liteloader.launch.LoaderProperties;
@@ -133,17 +134,26 @@ public abstract class LiteLoaderCoreAPI implements LiteAPI, MixinConfigProvider @@ -133,17 +134,26 @@ public abstract class LiteLoaderCoreAPI implements LiteAPI, MixinConfigProvider
133 { 134 {
134 enumeratorModules.add(new EnumeratorModuleClassPath()); 135 enumeratorModules.add(new EnumeratorModuleClassPath());
135 } 136 }
  137 +
  138 + ContainerEnvironment containers = new ContainerEnvironment();
136 139
137 if (this.searchModsFolder) 140 if (this.searchModsFolder)
138 { 141 {
139 File modsFolder = this.environment.getModsFolder(); 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 File versionedModsFolder = this.environment.getVersionedModsFolder(); 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 \ No newline at end of file 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/launch/GameEnvironment.java
@@ -30,4 +30,10 @@ public interface GameEnvironment @@ -30,4 +30,10 @@ public interface GameEnvironment
30 * config for legacy mods. 30 * config for legacy mods.
31 */ 31 */
32 public abstract File getModsFolder(); 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,7 +41,8 @@ public class LiteLoaderTweaker implements ITweaker
41 // TODO Version - 1.12.1 41 // TODO Version - 1.12.1
42 public static final String VERSION = "1.12.1"; 42 public static final String VERSION = "1.12.1";
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 * Loader startup state 48 * Loader startup state
@@ -323,7 +324,7 @@ public class LiteLoaderTweaker implements ITweaker @@ -323,7 +324,7 @@ public class LiteLoaderTweaker implements ITweaker
323 { 324 {
324 this.initEnvironment(args, gameDirectory, assetsDirectory, profile); 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 this.transformerManager = new ClassTransformerManager(this.bootstrap.getRequiredTransformers()); 329 this.transformerManager = new ClassTransformerManager(this.bootstrap.getRequiredTransformers());
329 330
@@ -347,7 +348,7 @@ public class LiteLoaderTweaker implements ITweaker @@ -347,7 +348,7 @@ public class LiteLoaderTweaker implements ITweaker
347 { 348 {
348 MixinBootstrap.init(); 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 this.injectDiscoveredTweakClasses(); 353 this.injectDiscoveredTweakClasses();
353 StartupState.PREINIT.completed(); 354 StartupState.PREINIT.completed();
@@ -567,7 +568,7 @@ public class LiteLoaderTweaker implements ITweaker @@ -567,7 +568,7 @@ public class LiteLoaderTweaker implements ITweaker
567 @Override 568 @Override
568 public void registerCoreAPIs(List<String> apisToLoad) 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 @Override 574 @Override
src/main/java/com/mumfrey/liteloader/launch/LiteLoaderTweakerServer.java
@@ -13,9 +13,11 @@ import com.mumfrey.liteloader.util.log.LiteLoaderLogger.Verbosity; @@ -13,9 +13,11 @@ import com.mumfrey.liteloader.util.log.LiteLoaderLogger.Verbosity;
13 13
14 public class LiteLoaderTweakerServer extends LiteLoaderTweaker 14 public class LiteLoaderTweakerServer extends LiteLoaderTweaker
15 { 15 {
  16 + private static final String SERVER_API = "com.mumfrey.liteloader.server.api.LiteLoaderCoreAPIServer";
  17 +
16 public LiteLoaderTweakerServer() 18 public LiteLoaderTweakerServer()
17 { 19 {
18 - LiteLoaderLogger.verbosity = Verbosity.REDUCED; 20 + LiteLoaderLogger.setVerbosity(Verbosity.REDUCED);
19 } 21 }
20 22
21 @Override 23 @Override
@@ -26,7 +28,7 @@ public class LiteLoaderTweakerServer extends LiteLoaderTweaker @@ -26,7 +28,7 @@ public class LiteLoaderTweakerServer extends LiteLoaderTweaker
26 @Override 28 @Override
27 public void registerCoreAPIs(List<String> apisToLoad) 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 @Override 34 @Override
@@ -41,7 +43,6 @@ public class LiteLoaderTweakerServer extends LiteLoaderTweaker @@ -41,7 +43,6 @@ public class LiteLoaderTweakerServer extends LiteLoaderTweaker
41 public String getLaunchTarget() 43 public String getLaunchTarget()
42 { 44 {
43 super.getLaunchTarget(); 45 super.getLaunchTarget();
44 -  
45 return "net.minecraft.server.MinecraftServer"; 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,9 +24,8 @@ public interface LoaderBootstrap
24 * 24 *
25 * @param classLoader 25 * @param classLoader
26 * @param loadTweaks 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,6 +11,7 @@ import com.mumfrey.liteloader.api.manager.APIAdapter;
11 import com.mumfrey.liteloader.api.manager.APIProvider; 11 import com.mumfrey.liteloader.api.manager.APIProvider;
12 import com.mumfrey.liteloader.core.EnabledModsList; 12 import com.mumfrey.liteloader.core.EnabledModsList;
13 import com.mumfrey.liteloader.core.LiteLoaderVersion; 13 import com.mumfrey.liteloader.core.LiteLoaderVersion;
  14 +import com.mumfrey.liteloader.core.api.repository.Repository;
14 import com.mumfrey.liteloader.interfaces.LoaderEnumerator; 15 import com.mumfrey.liteloader.interfaces.LoaderEnumerator;
15 16
16 /** 17 /**
@@ -49,6 +50,12 @@ public interface LoaderEnvironment extends GameEnvironment @@ -49,6 +50,12 @@ public interface LoaderEnvironment extends GameEnvironment
49 * about which mods are enabled/disabled. 50 * about which mods are enabled/disabled.
50 */ 51 */
51 public abstract EnabledModsList getEnabledModsList(); 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 * The enumerator manages mod container and class discovery 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,6 +31,7 @@ public abstract class StartupEnvironment implements GameEnvironment
31 31
32 private ArgumentAcceptingOptionSpec<String> modsDirOption; 32 private ArgumentAcceptingOptionSpec<String> modsDirOption;
33 private ArgumentAcceptingOptionSpec<String> modsOption; 33 private ArgumentAcceptingOptionSpec<String> modsOption;
  34 + private ArgumentAcceptingOptionSpec<String> modsRepoOption;
34 private ArgumentAcceptingOptionSpec<String> apisOption; 35 private ArgumentAcceptingOptionSpec<String> apisOption;
35 private NonOptionArgumentSpec<String> unparsedOptions; 36 private NonOptionArgumentSpec<String> unparsedOptions;
36 private OptionSet parsedOptions; 37 private OptionSet parsedOptions;
@@ -84,6 +85,8 @@ public abstract class StartupEnvironment implements GameEnvironment @@ -84,6 +85,8 @@ public abstract class StartupEnvironment implements GameEnvironment
84 85
85 this.modsOption = optionParser.accepts("mods", "Comma-separated list of mods to load") 86 this.modsOption = optionParser.accepts("mods", "Comma-separated list of mods to load")
86 .withRequiredArg().ofType(String.class).withValuesSeparatedBy(','); 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 this.apisOption = optionParser.accepts("api", "Additional API classes to load") 90 this.apisOption = optionParser.accepts("api", "Additional API classes to load")
88 .withRequiredArg().ofType(String.class); 91 .withRequiredArg().ofType(String.class);
89 this.modsDirOption = optionParser.accepts("modsDir", "Path to 'mods' folder to use instead of default") 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,4 +242,13 @@ public abstract class StartupEnvironment implements GameEnvironment
239 { 242 {
240 return this.getOptionalDirectory(this.gameDirectory, this.modsDirOption, "mods"); 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/util/log/LiteLoaderLogger.java
@@ -64,7 +64,7 @@ public class LiteLoaderLogger extends AbstractAppender @@ -64,7 +64,7 @@ public class LiteLoaderLogger extends AbstractAppender
64 } 64 }
65 } 65 }
66 66
67 - public static Verbosity verbosity = LiteLoaderLogger.DEBUG ? Verbosity.VERBOSE : Verbosity.NORMAL; 67 + private static Verbosity verbosity = LiteLoaderLogger.DEBUG ? Verbosity.VERBOSE : Verbosity.NORMAL;
68 68
69 static 69 static
70 { 70 {
@@ -76,6 +76,11 @@ public class LiteLoaderLogger extends AbstractAppender @@ -76,6 +76,11 @@ public class LiteLoaderLogger extends AbstractAppender
76 super("Internal Log Appender", null, null); 76 super("Internal Log Appender", null, null);
77 this.start(); 77 this.start();
78 } 78 }
  79 +
  80 + public static void setVerbosity(Verbosity verbosity)
  81 + {
  82 + LiteLoaderLogger.verbosity = verbosity;
  83 + }
79 84
80 @Override 85 @Override
81 public void append(LogEvent event) 86 public void append(LogEvent event)