From d7b3887fe1e754aa0ec5970a175e439aa5c8fe86 Mon Sep 17 00:00:00 2001
From: Petr Mrázek <peterix@gmail.com>
Date: Fri, 14 Aug 2015 23:30:12 +0200
Subject: Revert "NOISSUE redo the launcher part"

This reverts commit c1f7dda8fe412263ccd82fbf3d56687bd291c73c.
---
 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, 335 insertions(+), 113 deletions(-)
 create mode 100644 depends/launcher/org/multimc/IconLoader.java
 delete mode 100644 depends/launcher/org/multimc/onesix/MMCClassLoader.java

diff --git a/depends/launcher/CMakeLists.txt b/depends/launcher/CMakeLists.txt
index 804e93ae..7564161d 100644
--- a/depends/launcher/CMakeLists.txt
+++ b/depends/launcher/CMakeLists.txt
@@ -18,20 +18,17 @@ 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 b8cc6c41..d1fc54a8 100644
--- a/depends/launcher/org/multimc/EntryPoint.java
+++ b/depends/launcher/org/multimc/EntryPoint.java
@@ -102,6 +102,7 @@ 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
new file mode 100644
index 00000000..f1638f3a
--- /dev/null
+++ b/depends/launcher/org/multimc/IconLoader.java
@@ -0,0 +1,132 @@
+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 c850f96d..1077065a 100644
--- a/depends/launcher/org/multimc/Utils.java
+++ b/depends/launcher/org/multimc/Utils.java
@@ -34,6 +34,110 @@ 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<String> 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<String> 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
deleted file mode 100644
index 6c768ffe..00000000
--- a/depends/launcher/org/multimc/onesix/MMCClassLoader.java
+++ /dev/null
@@ -1,42 +0,0 @@
-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<String> 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<String> 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 6f9ce874..8ef6376d 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.awt.*;
 import java.io.File;
+import java.awt.*;
 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 MMCClassLoader cl;
+	private ClassLoader cl;
 
 	private void processParams(ParamBucket params) throws NotFoundException
 	{
 		libraries = params.all("cp");
 		extlibs = params.all("ext");
-		mcparams = params.allSafe("param", new ArrayList<String>());
+		mcparams = params.allSafe("param", new ArrayList<String>() );
 		mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft");
 		appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet");
 		mods = params.allSafe("mod", new ArrayList<String>());
@@ -84,10 +84,7 @@ public class OneSixLauncher implements Launcher
 			try
 			{
 				winSize = new Dimension(Integer.parseInt(dimStrings[0]), Integer.parseInt(dimStrings[1]));
-			}
-			catch (NumberFormatException ignored)
-			{
-			}
+			} catch (NumberFormatException ignored) {}
 		}
 	}
 
@@ -120,7 +117,7 @@ public class OneSixLauncher implements Launcher
 		}
 		Utils.log();
 
-		if (mods.size() > 0)
+		if(mods.size() > 0)
 		{
 			Utils.log("Mods:");
 			for (String s : mods)
@@ -153,14 +150,10 @@ 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();
 	}
 
@@ -183,8 +176,7 @@ 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);
@@ -201,11 +193,10 @@ 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);
@@ -213,9 +204,8 @@ 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);
@@ -247,8 +237,7 @@ 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);
@@ -260,22 +249,66 @@ 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);
@@ -284,29 +317,35 @@ 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
 			{
@@ -314,8 +353,7 @@ 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);
@@ -324,44 +362,36 @@ public class OneSixLauncher implements Launcher
 		}
 		Utils.log();
 
+		// set the native libs path... the brute force way
 		try
 		{
-			cl = new MMCClassLoader(natives, libraries);
-		}
-		catch (Exception e)
+			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)
 		{
-			e.printStackTrace();
+			System.err.println("Failed to set the native library path:");
+			e.printStackTrace(System.err);
+			return -1;
 		}
 
-		final int[] result = {-1};
+		// grab the system classloader and ...
+		cl = ClassLoader.getSystemClassLoader();
 
-		// 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
+		if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch") )
 		{
-			t.join();
+			// legacy launch uses the applet wrapper
+			return legacyLaunch();
 		}
-		catch (InterruptedException e)
+		else
 		{
-			e.printStackTrace();
+			// normal launch just calls main()
+			return launchWithMainClass();
 		}
-		return result[0];
 	}
 }
-- 
cgit