Add in the capability to have multiple tweakers on the command line.

Also add in a simple 'shared blackboard' Map for tweaker IPC.
This commit is contained in:
Christian 2013-08-23 13:25:38 -04:00
parent 6ee0ba5518
commit 0a55602e9f

View file

@ -7,13 +7,20 @@ import joptsimple.OptionSpec;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
public class Launch {
private static final String DEFAULT_TWEAK = "net.minecraft.launchwrapper.VanillaTweaker";
public static File minecraftHome;
public static File assetsDir;
public static Map<String,Object> blackboard;
public static void main(String[] args) {
new Launch().launch(args);
}
@ -23,6 +30,7 @@ public class Launch {
private Launch() {
final URLClassLoader ucl = (URLClassLoader) getClass().getClassLoader();
classLoader = new LaunchClassLoader(ucl.getURLs());
blackboard = new HashMap<String,Object>();
}
private void launch(String[] args) {
@ -32,29 +40,60 @@ public class Launch {
final OptionSpec<String> profileOption = parser.accepts("version", "The version we launched with").withRequiredArg();
final OptionSpec<File> gameDirOption = parser.accepts("gameDir", "Alternative game directory").withRequiredArg().ofType(File.class);
final OptionSpec<File> assetsDirOption = parser.accepts("assetsDir", "Assets directory").withRequiredArg().ofType(File.class);
final OptionSpec<String> tweakClassOption = parser.accepts("tweakClass", "Tweak class to load").withRequiredArg().defaultsTo(DEFAULT_TWEAK);
final OptionSpec<String> tweakClassOption = parser.accepts("tweakClass", "Tweak class(es) to load").withRequiredArg().defaultsTo(DEFAULT_TWEAK);
final OptionSpec<String> nonOption = parser.nonOptions();
final OptionSet options = parser.parse(args);
minecraftHome = options.valueOf(gameDirOption);
assetsDir = options.valueOf(assetsDirOption);
final String profileName = options.valueOf(profileOption);
final String tweakClassName = options.valueOf(tweakClassOption);
final List<String> tweakClassNames = new ArrayList<String>(options.valuesOf(tweakClassOption));
final List<String> argumentList = new ArrayList<String>();
blackboard.put("TweakClasses", tweakClassNames);
blackboard.put("ArgumentList", argumentList);
final List<ITweaker> allTweakers = new ArrayList<ITweaker>();
try {
LogWrapper.log(Level.INFO, "Using tweak class name %s", tweakClassName);
final List<ITweaker> tweakers = new ArrayList(tweakClassNames.size() + 1);
blackboard.put("Tweaks", tweakers);
ITweaker primaryTweaker = null;
do {
for (final Iterator<String> it = tweakClassNames.iterator(); it.hasNext(); ) {
final String tweakName = it.next();
LogWrapper.log(Level.INFO, "Loading tweak class name %s", tweakName);
// Ensure we allow the tweak class to load with the parent classloader
classLoader.addClassLoaderExclusion(tweakName.substring(0,tweakName.lastIndexOf('.')));
final ITweaker tweaker = (ITweaker) Class.forName(tweakName, true, classLoader).newInstance();
tweakers.add(tweaker);
it.remove();
if (primaryTweaker == null) {
LogWrapper.log(Level.INFO, "Using primary tweak class name %s", tweakName);
primaryTweaker = tweaker;
}
}
for (final Iterator<ITweaker> it = tweakers.iterator(); it.hasNext(); ) {
final ITweaker tweaker = it.next();
LogWrapper.log(Level.INFO, "Calling tweak class %s", tweaker.getClass().getName());
tweaker.acceptOptions(options.valuesOf(nonOption), minecraftHome, assetsDir, profileName);
tweaker.injectIntoClassLoader(classLoader);
allTweakers.add(tweaker);
it.remove();
}
} while (!tweakClassNames.isEmpty());
// Ensure we allow the tweak class to load with the parent classloader
classLoader.addClassLoaderExclusion(tweakClassName.substring(0,tweakClassName.lastIndexOf('.')));
final ITweaker tweaker = (ITweaker) Class.forName(tweakClassName, true, classLoader).newInstance();
tweaker.acceptOptions(options.valuesOf(nonOption), minecraftHome, assetsDir, profileName);
tweaker.injectIntoClassLoader(classLoader);
final Class<?> clazz = Class.forName(tweaker.getLaunchTarget(), false, classLoader);
for (final ITweaker tweaker : allTweakers) {
argumentList.addAll(Arrays.asList(tweaker.getLaunchArguments()));
}
final String launchTarget = primaryTweaker.getLaunchTarget();
final Class<?> clazz = Class.forName(launchTarget, false, classLoader);
final Method mainMethod = clazz.getMethod("main", new Class[]{String[].class});
LogWrapper.info("Launching wrapped minecraft");
mainMethod.invoke(null, (Object) tweaker.getLaunchArguments());
LogWrapper.info("Launching wrapped minecraft {%s}", launchTarget);
mainMethod.invoke(null, (Object) argumentList.toArray(new String[argumentList.size()]));
} catch (Exception e) {
LogWrapper.log(Level.SEVERE, e, "Unable to launch");
}