// // Copyright 2012 MultiMC Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // import java.applet.Applet; import java.awt.Dimension; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import org.simplericity.macify.eawt.Application; import org.simplericity.macify.eawt.DefaultApplication; public class MultiMCLauncher { /** * @param args * The arguments you want to launch Minecraft with. New path, * Username, Session ID. */ public static void main(String[] args) { if (args.length < 3) { System.out.println("Not enough arguments."); System.exit(-1); } // Set the OSX application icon first, if we are on OSX. Application application = new DefaultApplication(); if(application.isMac()) { try { BufferedImage image = ImageIO.read(new File("icon.png")); application.setApplicationIconImage(image); } catch (IOException e) { e.printStackTrace(); } } String userName = args[0]; String sessionId = args[1]; String windowtitle = args[2]; String windowParams = args[3]; String lwjgl = args[4]; String cwd = System.getProperty("user.dir"); Dimension winSize = new Dimension(854, 480); boolean maximize = false; boolean compatMode = false; String[] dimStrings = windowParams.split("x"); if (windowParams.equalsIgnoreCase("compatmode")) { compatMode = true; } else if (windowParams.equalsIgnoreCase("max")) { maximize = true; } else if (dimStrings.length == 2) { try { winSize = new Dimension(Integer.parseInt(dimStrings[0]), Integer.parseInt(dimStrings[1])); } catch (NumberFormatException e) { System.out.println("Invalid Window size argument, " + "using default."); } } else { System.out.println("Invalid Window size argument, " + "using default."); } try { File binDir = new File(cwd, "bin"); File lwjglDir; if(lwjgl.equalsIgnoreCase("Mojang")) lwjglDir = binDir; else lwjglDir = new File(lwjgl); System.out.println("Loading jars..."); String[] lwjglJars = new String[] { "lwjgl.jar", "lwjgl_util.jar", "jinput.jar" }; URL[] urls = new URL[4]; try { File f = new File(binDir, "minecraft.jar"); urls[0] = f.toURI().toURL(); System.out.println("Loading URL: " + urls[0].toString()); for (int i = 1; i < urls.length; i++) { File jar = new File(lwjglDir, lwjglJars[i-1]); urls[i] = jar.toURI().toURL(); System.out.println("Loading URL: " + urls[i].toString()); } } catch (MalformedURLException e) { System.err.println("MalformedURLException, " + e.toString()); System.exit(5); } System.out.println("Loading natives..."); String nativesDir = new File(lwjglDir, "natives").toString(); System.setProperty("org.lwjgl.librarypath", nativesDir); System.setProperty("net.java.games.input.librarypath", nativesDir); URLClassLoader cl = new URLClassLoader(urls, MultiMCLauncher.class.getClassLoader()); // Get the Minecraft Class. Class mc = null; try { mc = cl.loadClass("net.minecraft.client.Minecraft"); Field f = getMCPathField(mc); if (f == null) { System.err.println("Could not find Minecraft path field. Launch failed."); System.exit(-1); } f.setAccessible(true); f.set(null, new File(cwd)); // And set it. System.out.println("Fixed Minecraft Path: Field was " + f.toString()); } catch (ClassNotFoundException e) { System.err.println("Can't find main class. Searching..."); // Look for any class that looks like the main class. File mcJar = new File(new File(cwd, "bin"), "minecraft.jar"); ZipFile zip = null; try { zip = new ZipFile(mcJar); } catch (ZipException e1) { e1.printStackTrace(); System.err.println("Search failed."); System.exit(-1); } catch (IOException e1) { e1.printStackTrace(); System.err.println("Search failed."); System.exit(-1); } Enumeration entries = zip.entries(); ArrayList classes = new ArrayList(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); if (entry.getName().endsWith(".class")) { String entryName = entry.getName().substring(0, entry.getName().lastIndexOf('.')); entryName = entryName.replace('/', '.'); System.out.println("Found class: " + entryName); classes.add(entryName); } } for (String clsName : classes) { try { Class cls = cl.loadClass(clsName); if (!Runnable.class.isAssignableFrom(cls)) { continue; } else { System.out.println("Found class implementing runnable: " + cls.getName()); } if (getMCPathField(cls) == null) { continue; } else { System.out.println("Found class implementing runnable " + "with mcpath field: " + cls.getName()); } mc = cls; break; } catch (ClassNotFoundException e1) { // Ignore continue; } } if (mc == null) { System.err.println("Failed to find Minecraft main class."); System.exit(-1); } else { System.out.println("Found main class: " + mc.getName()); } } System.setProperty("minecraft.applet.TargetDirectory", cwd); String[] mcArgs = new String[2]; mcArgs[0] = userName; mcArgs[1] = sessionId; if (compatMode) { System.out.println("Launching in compatibility mode..."); mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs); } else { System.out.println("Launching with applet wrapper..."); try { Class MCAppletClass = cl.loadClass( "net.minecraft.client.MinecraftApplet"); Applet mcappl = (Applet) MCAppletClass.newInstance(); MCFrame mcWindow = new MCFrame(windowtitle); mcWindow.start(mcappl, userName, sessionId, winSize, maximize); } catch (InstantiationException e) { System.out.println("Applet wrapper failed! Falling back " + "to compatibility mode."); mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs); } } } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(1); } catch (IllegalArgumentException e) { e.printStackTrace(); System.exit(2); } catch (IllegalAccessException e) { e.printStackTrace(); System.exit(2); } catch (InvocationTargetException e) { e.printStackTrace(); System.exit(3); } catch (NoSuchMethodException e) { e.printStackTrace(); System.exit(3); } catch (SecurityException e) { e.printStackTrace(); System.exit(4); } } public static Field getMCPathField(Class mc) { Field[] fields = mc.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field f = fields[i]; if (f.getType() != File.class) { // Has to be File continue; } if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC)) { // And Private Static. continue; } return f; } return null; } }