From c1f7dda8fe412263ccd82fbf3d56687bd291c73c Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 21 May 2015 17:23:20 -0400 Subject: NOISSUE redo the launcher part --- depends/launcher/CMakeLists.txt | 7 +- depends/launcher/org/multimc/EntryPoint.java | 1 - depends/launcher/org/multimc/IconLoader.java | 132 ----------------- depends/launcher/org/multimc/Utils.java | 104 ------------- .../org/multimc/onesix/MMCClassLoader.java | 42 ++++++ .../org/multimc/onesix/OneSixLauncher.java | 162 +++++++++------------ 6 files changed, 113 insertions(+), 335 deletions(-) delete mode 100644 depends/launcher/org/multimc/IconLoader.java create mode 100644 depends/launcher/org/multimc/onesix/MMCClassLoader.java diff --git a/depends/launcher/CMakeLists.txt b/depends/launcher/CMakeLists.txt index 7564161d..804e93ae 100644 --- a/depends/launcher/CMakeLists.txt +++ b/depends/launcher/CMakeLists.txt @@ -18,17 +18,20 @@ set(SRC # The launcher has to be there for silly FML/Forge relauncher. net/minecraft/Launcher.java org/multimc/legacy/LegacyLauncher.java - org/multimc/LegacyFrame.java # onesix launcher org/multimc/onesix/OneSixLauncher.java + org/multimc/onesix/MMCClassLoader.java # generic launcher org/multimc/EntryPoint.java org/multimc/Launcher.java + org/multimc/LegacyFrame.java + org/multimc/NotFoundException.java + org/multimc/ParamBucket.java org/multimc/ParseException.java org/multimc/Utils.java - org/multimc/IconLoader.java + ) add_jar(NewLaunch ${SRC}) diff --git a/depends/launcher/org/multimc/EntryPoint.java b/depends/launcher/org/multimc/EntryPoint.java index d1fc54a8..b8cc6c41 100644 --- a/depends/launcher/org/multimc/EntryPoint.java +++ b/depends/launcher/org/multimc/EntryPoint.java @@ -102,7 +102,6 @@ public class EntryPoint } m_params.add(command, param); - //System.out.println(command + " : " + param); return Action.Proceed; } diff --git a/depends/launcher/org/multimc/IconLoader.java b/depends/launcher/org/multimc/IconLoader.java deleted file mode 100644 index f1638f3a..00000000 --- a/depends/launcher/org/multimc/IconLoader.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.multimc; - -import javax.imageio.ImageIO; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; - -/***************************************************************************** - * A convenience class for loading icons from images. - * - * Icons loaded from this class are formatted to fit within the required - * dimension (16x16, 32x32, or 128x128). If the source image is larger than the - * target dimension, it is shrunk down to the minimum size that will fit. If it - * is smaller, then it is only scaled up if the new scale can be a per-pixel - * linear scale (i.e., x2, x3, x4, etc). In both cases, the image's width/height - * ratio is kept the same as the source image. - * - * @author Chris Molini - *****************************************************************************/ -public class IconLoader -{ - /************************************************************************* - * Loads an icon in ByteBuffer form. - * - * @param filepath - * The location of the Image to use as an icon. - * - * @return An array of ByteBuffers containing the pixel data for the icon in - * various sizes (as recommended by the OS). - *************************************************************************/ - public static ByteBuffer[] load(String filepath) - { - BufferedImage image; - try { - image = ImageIO.read ( new File( filepath ) ); - } catch ( IOException e ) { - e.printStackTrace(); - return new ByteBuffer[0]; - } - ByteBuffer[] buffers; - buffers = new ByteBuffer[1]; - buffers[0] = loadInstance(image, 128); - return buffers; - } - - /************************************************************************* - * Copies the supplied image into a square icon at the indicated size. - * - * @param image - * The image to place onto the icon. - * @param dimension - * The desired size of the icon. - * - * @return A ByteBuffer of pixel data at the indicated size. - *************************************************************************/ - private static ByteBuffer loadInstance(BufferedImage image, int dimension) - { - BufferedImage scaledIcon = new BufferedImage(dimension, dimension, - BufferedImage.TYPE_INT_ARGB_PRE); - Graphics2D g = scaledIcon.createGraphics(); - double ratio = getIconRatio(image, scaledIcon); - double width = image.getWidth() * ratio; - double height = image.getHeight() * ratio; - g.drawImage(image, (int) ((scaledIcon.getWidth() - width) / 2), - (int) ((scaledIcon.getHeight() - height) / 2), (int) (width), - (int) (height), null); - g.dispose(); - - return convertToByteBuffer(scaledIcon); - } - - /************************************************************************* - * Gets the width/height ratio of the icon. This is meant to simplify - * scaling the icon to a new dimension. - * - * @param src - * The base image that will be placed onto the icon. - * @param icon - * The icon that will have the image placed on it. - * - * @return The amount to scale the source image to fit it onto the icon - * appropriately. - *************************************************************************/ - private static double getIconRatio(BufferedImage src, BufferedImage icon) - { - double ratio = 1; - if (src.getWidth() > icon.getWidth()) - ratio = (double) (icon.getWidth()) / src.getWidth(); - else - ratio = (int) (icon.getWidth() / src.getWidth()); - if (src.getHeight() > icon.getHeight()) - { - double r2 = (double) (icon.getHeight()) / src.getHeight(); - if (r2 < ratio) - ratio = r2; - } - else - { - double r2 = (int) (icon.getHeight() / src.getHeight()); - if (r2 < ratio) - ratio = r2; - } - return ratio; - } - - /************************************************************************* - * Converts a BufferedImage into a ByteBuffer of pixel data. - * - * @param image - * The image to convert. - * - * @return A ByteBuffer that contains the pixel data of the supplied image. - *************************************************************************/ - public static ByteBuffer convertToByteBuffer(BufferedImage image) - { - byte[] buffer = new byte[image.getWidth() * image.getHeight() * 4]; - int counter = 0; - for (int i = 0; i < image.getHeight(); i++) - for (int j = 0; j < image.getWidth(); j++) - { - int colorSpace = image.getRGB(j, i); - buffer[counter + 0] = (byte) ((colorSpace << 8) >> 24); - buffer[counter + 1] = (byte) ((colorSpace << 16) >> 24); - buffer[counter + 2] = (byte) ((colorSpace << 24) >> 24); - buffer[counter + 3] = (byte) (colorSpace >> 24); - counter += 4; - } - return ByteBuffer.wrap(buffer); - } -} \ No newline at end of file diff --git a/depends/launcher/org/multimc/Utils.java b/depends/launcher/org/multimc/Utils.java index e6be25aa..cbe11fb1 100644 --- a/depends/launcher/org/multimc/Utils.java +++ b/depends/launcher/org/multimc/Utils.java @@ -34,110 +34,6 @@ import java.util.zip.ZipFile; public class Utils { - /** - * Combine two parts of a path. - * - * @param path1 - * @param path2 - * @return the paths, combined - */ - public static String combine(String path1, String path2) - { - File file1 = new File(path1); - File file2 = new File(file1, path2); - return file2.getPath(); - } - - /** - * Join a list of strings into a string using a separator! - * - * @param strings the string list to join - * @param separator the glue - * @return the result. - */ - public static String join(List strings, String separator) - { - StringBuilder sb = new StringBuilder(); - String sep = ""; - for (String s : strings) - { - sb.append(sep).append(s); - sep = separator; - } - return sb.toString(); - } - - /** - * Adds the specified library to the classpath - * - * @param s the path to add - * @throws Exception - */ - public static void addToClassPath(String s) throws Exception - { - File f = new File(s); - URL u = f.toURI().toURL(); - URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); - Class urlClass = URLClassLoader.class; - Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class}); - method.setAccessible(true); - method.invoke(urlClassLoader, new Object[]{u}); - } - - /** - * Adds many libraries to the classpath - * - * @param jars the paths to add - */ - public static boolean addToClassPath(List jars) - { - boolean pure = true; - // initialize the class path - for (String jar : jars) - { - try - { - Utils.addToClassPath(jar); - } catch (Exception e) - { - System.err.println("Unable to load: " + jar); - e.printStackTrace(System.err); - pure = false; - } - } - return pure; - } - - /** - * Adds the specified path to the java library path - * - * @param pathToAdd the path to add - * @throws Exception - */ - @Deprecated - public static void addLibraryPath(String pathToAdd) throws Exception - { - final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths"); - usrPathsField.setAccessible(true); - - //get array of paths - final String[] paths = (String[]) usrPathsField.get(null); - - //check if the path to add is already present - for (String path : paths) - { - if (path.equals(pathToAdd)) - { - return; - } - } - - //add the new path - final String[] newPaths = Arrays.copyOf(paths, paths.length + 1); - newPaths[newPaths.length - 1] = pathToAdd; - usrPathsField.set(null, newPaths); - } - /** * Finds a field that looks like a Minecraft base folder in a supplied class * diff --git a/depends/launcher/org/multimc/onesix/MMCClassLoader.java b/depends/launcher/org/multimc/onesix/MMCClassLoader.java new file mode 100644 index 00000000..6c768ffe --- /dev/null +++ b/depends/launcher/org/multimc/onesix/MMCClassLoader.java @@ -0,0 +1,42 @@ +package org.multimc.onesix; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Arrays; +import java.util.List; + +public class MMCClassLoader extends URLClassLoader +{ + public MMCClassLoader(String natives, List allJars) + throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, + InvocationTargetException, IllegalAccessException, NoSuchFieldException + { + super(process(allJars)); + Method setProperty = loadClass("java.lang.System").getMethod("setProperty", String.class, String.class); + setProperty.invoke(null, "java.library.path", natives); + setProperty.invoke(null, "org.lwjgl.librarypath", natives); + setProperty.invoke(null, "net.java.games.input.librarypath", natives); + } + + private static URL[] process(List allJars) throws MalformedURLException + { + URL[] urls = new URL[allJars.size()]; + for (int i = 0; i < allJars.size(); i++) + { + String jar = allJars.get(i); + urls[i] = new File(jar).toURI().toURL(); + } + return urls; + } + + // TODO: use this method to use custom log configs + // @Override + // public URL findResource(String name) + // { + // return super.findResource(name); + // } +} diff --git a/depends/launcher/org/multimc/onesix/OneSixLauncher.java b/depends/launcher/org/multimc/onesix/OneSixLauncher.java index 8ef6376d..6f9ce874 100644 --- a/depends/launcher/org/multimc/onesix/OneSixLauncher.java +++ b/depends/launcher/org/multimc/onesix/OneSixLauncher.java @@ -18,8 +18,8 @@ package org.multimc.onesix; import org.multimc.*; import java.applet.Applet; -import java.io.File; import java.awt.*; +import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -49,13 +49,13 @@ public class OneSixLauncher implements Launcher private String cwd; // the much abused system classloader, for convenience (for further abuse) - private ClassLoader cl; + private MMCClassLoader cl; private void processParams(ParamBucket params) throws NotFoundException { libraries = params.all("cp"); extlibs = params.all("ext"); - mcparams = params.allSafe("param", new ArrayList() ); + mcparams = params.allSafe("param", new ArrayList()); mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft"); appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet"); mods = params.allSafe("mod", new ArrayList()); @@ -84,7 +84,10 @@ public class OneSixLauncher implements Launcher try { winSize = new Dimension(Integer.parseInt(dimStrings[0]), Integer.parseInt(dimStrings[1])); - } catch (NumberFormatException ignored) {} + } + catch (NumberFormatException ignored) + { + } } } @@ -117,7 +120,7 @@ public class OneSixLauncher implements Launcher } Utils.log(); - if(mods.size() > 0) + if (mods.size() > 0) { Utils.log("Mods:"); for (String s : mods) @@ -150,10 +153,14 @@ public class OneSixLauncher implements Launcher Utils.log("Params:"); Utils.log(" " + mcparams.toString()); Utils.log(); - if(maximize) + if (maximize) + { Utils.log("Window size: max (if available)"); + } else + { Utils.log("Window size: " + Integer.toString(winSize.width) + " x " + Integer.toString(winSize.height)); + } Utils.log(); } @@ -176,7 +183,8 @@ public class OneSixLauncher implements Launcher f.setAccessible(true); f.set(null, new File(cwd)); } - } catch (Exception e) + } + catch (Exception e) { System.err.println("Could not set base folder. Failed to find/access Minecraft main class:"); e.printStackTrace(System.err); @@ -193,10 +201,11 @@ public class OneSixLauncher implements Launcher try { Class MCAppletClass = cl.loadClass(appletClass); - Applet mcappl = (Applet) MCAppletClass.newInstance(); + Applet mcappl = (Applet)MCAppletClass.newInstance(); LegacyFrame mcWindow = new LegacyFrame(windowTitle); mcWindow.start(mcappl, userName, sessionId, winSize, maximize); - } catch (Exception e) + } + catch (Exception e) { Utils.log("Applet wrapper failed:", "Error"); e.printStackTrace(System.err); @@ -204,8 +213,9 @@ public class OneSixLauncher implements Launcher Utils.log("Falling back to compatibility mode."); try { - mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs); - } catch (Exception e1) + mc.getMethod("main", String[].class).invoke(null, (Object)mcArgs); + } + catch (Exception e1) { Utils.log("Failed to invoke the Minecraft main class:", "Fatal"); e1.printStackTrace(System.err); @@ -237,7 +247,8 @@ public class OneSixLauncher implements Launcher try { mc = cl.loadClass(mainClass); - } catch (ClassNotFoundException e) + } + catch (ClassNotFoundException e) { System.err.println("Failed to find Minecraft main class:"); e.printStackTrace(System.err); @@ -249,66 +260,22 @@ public class OneSixLauncher implements Launcher try { meth = mc.getMethod("main", String[].class); - } catch (NoSuchMethodException e) + } + catch (NoSuchMethodException e) { System.err.println("Failed to acquire the main method:"); e.printStackTrace(System.err); return -1; } - /* - final java.nio.ByteBuffer[] icons = IconLoader.load("icon.png"); - new Thread() { - public void run() { - ClassLoader cl = ClassLoader.getSystemClassLoader(); - try - { - Class Display; - Method isCreated; - Method setTitle; - Method setIcon; - Field fieldWindowCreated; - Boolean created = false; - Display = cl.loadClass("org.lwjgl.opengl.Display"); - fieldWindowCreated = Display.getDeclaredField("window_created"); - fieldWindowCreated.setAccessible( true ); - setTitle = Display.getMethod("setTitle", String.class); - setIcon = Display.getMethod("setIcon", java.nio.ByteBuffer[].class); - created = (Boolean) fieldWindowCreated.get( null ); - // set the window title? Maybe? - while(!created) - { - try - { - Thread.sleep(150); - created = (Boolean) fieldWindowCreated.get( null ); - } catch (InterruptedException ignored) {} - } - // Give it a bit more time ;) - Thread.sleep(150); - // set the title - setTitle.invoke(null,windowTitle); - // only set icon when there's actually something to set... - if(icons.length > 0) - { - setIcon.invoke(null,(Object)icons); - } - } - catch (Exception e) - { - System.err.println("Couldn't set window icon or title."); - e.printStackTrace(System.err); - } - } - } - .start(); - */ + // init params for the main method to chomp on. String[] paramsArray = mcparams.toArray(new String[mcparams.size()]); try { // static method doesn't have an instance - meth.invoke(null, (Object) paramsArray); - } catch (Exception e) + meth.invoke(null, (Object)paramsArray); + } + catch (Exception e) { System.err.println("Failed to start Minecraft:"); e.printStackTrace(System.err); @@ -317,35 +284,29 @@ public class OneSixLauncher implements Launcher return 0; } - @Override - public int launch(ParamBucket params) + @Override public int launch(ParamBucket params) { // get and process the launch script params try { processParams(params); - } catch (NotFoundException e) + } + catch (NotFoundException e) { System.err.println("Not enough arguments."); e.printStackTrace(System.err); return -1; } - // add libraries to classpath - if(!Utils.addToClassPath(libraries)) - { - System.err.println("Halting launch due to previous errors."); - return -1; - } - // print the pretty things printStats(); // extract native libs (depending on platform here... java!) Utils.log("Preparing native libraries..."); String property = System.getProperty("os.arch"); - boolean is_64 = property.equalsIgnoreCase("x86_64") || property.equalsIgnoreCase("amd64"); - for(String extlib: extlibs) + boolean is_64 = + property.equalsIgnoreCase("x86_64") || property.equalsIgnoreCase("amd64"); + for (String extlib : extlibs) { try { @@ -353,7 +314,8 @@ public class OneSixLauncher implements Launcher File cleanlibf = new File(cleanlib); Utils.log("Extracting " + cleanlibf.getName()); Utils.unzipNatives(cleanlibf, new File(natives)); - } catch (IOException e) + } + catch (IOException e) { System.err.println("Failed to extract native library:"); e.printStackTrace(System.err); @@ -362,36 +324,44 @@ public class OneSixLauncher implements Launcher } Utils.log(); - // set the native libs path... the brute force way try { - System.setProperty("java.library.path", natives); - System.setProperty("org.lwjgl.librarypath", natives); - System.setProperty("net.java.games.input.librarypath", natives); - // by the power of reflection, initialize native libs again. DIRTY! - // this is SO BAD. imagine doing that to ld - Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths"); - fieldSysPath.setAccessible( true ); - fieldSysPath.set( null, null ); - } catch (Exception e) + cl = new MMCClassLoader(natives, libraries); + } + catch (Exception e) { - System.err.println("Failed to set the native library path:"); - e.printStackTrace(System.err); - return -1; + e.printStackTrace(); } - // grab the system classloader and ... - cl = ClassLoader.getSystemClassLoader(); + final int[] result = {-1}; - if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch") ) + // fix log4j by sticking it in a thread with custom contextclassloader + Thread t = new Thread("main") + { + @Override public void run() + { + if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch")) + { + // legacy launch uses the applet wrapper + result[0] = legacyLaunch(); + } + else + { + // normal launch just calls main() + result[0] = launchWithMainClass(); + } + } + }; + t.setContextClassLoader(cl); + t.start(); + try { - // legacy launch uses the applet wrapper - return legacyLaunch(); + t.join(); } - else + catch (InterruptedException e) { - // normal launch just calls main() - return launchWithMainClass(); + e.printStackTrace(); } + return result[0]; } } -- cgit v1.2.3