aboutsummaryrefslogtreecommitdiff
path: root/libraries/launcher
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2016-04-10 15:53:05 +0200
committerPetr Mrázek <peterix@gmail.com>2016-05-01 00:00:14 +0200
commitb6d455a02bd338e9dc0faa09d4d8177ecd8d569a (patch)
tree41982bca1ede50049f2f8c7109dd18edeefde6d0 /libraries/launcher
parent47e37635f50c09b4f9a9ee7699e3120bab3e4088 (diff)
downloadPrismLauncher-b6d455a02bd338e9dc0faa09d4d8177ecd8d569a.tar.gz
PrismLauncher-b6d455a02bd338e9dc0faa09d4d8177ecd8d569a.tar.bz2
PrismLauncher-b6d455a02bd338e9dc0faa09d4d8177ecd8d569a.zip
NOISSUE reorganize and document libraries
Diffstat (limited to 'libraries/launcher')
-rw-r--r--libraries/launcher/.gitignore6
-rw-r--r--libraries/launcher/CMakeLists.txt34
-rw-r--r--libraries/launcher/net/minecraft/Launcher.java165
-rw-r--r--libraries/launcher/org/multimc/EntryPoint.java178
-rw-r--r--libraries/launcher/org/multimc/IconLoader.java132
-rw-r--r--libraries/launcher/org/multimc/Launcher.java22
-rw-r--r--libraries/launcher/org/multimc/LegacyFrame.java112
-rw-r--r--libraries/launcher/org/multimc/NotFoundException.java21
-rw-r--r--libraries/launcher/org/multimc/ParamBucket.java86
-rw-r--r--libraries/launcher/org/multimc/ParseException.java22
-rw-r--r--libraries/launcher/org/multimc/Utils.java280
-rw-r--r--libraries/launcher/org/multimc/legacy/LegacyLauncher.java175
-rw-r--r--libraries/launcher/org/multimc/onesix/OneSixLauncher.java367
-rw-r--r--libraries/launcher/org/simplericity/macify/eawt/Application.java176
-rw-r--r--libraries/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java48
-rw-r--r--libraries/launcher/org/simplericity/macify/eawt/ApplicationEvent.java25
-rw-r--r--libraries/launcher/org/simplericity/macify/eawt/ApplicationListener.java27
-rw-r--r--libraries/launcher/org/simplericity/macify/eawt/DefaultApplication.java418
18 files changed, 2294 insertions, 0 deletions
diff --git a/libraries/launcher/.gitignore b/libraries/launcher/.gitignore
new file mode 100644
index 00000000..cc1c52bf
--- /dev/null
+++ b/libraries/launcher/.gitignore
@@ -0,0 +1,6 @@
+.idea
+*.iml
+out
+.classpath
+.idea
+.project
diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt
new file mode 100644
index 00000000..b62805e0
--- /dev/null
+++ b/libraries/launcher/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.1)
+project(launcher Java)
+find_package(Java 1.6 REQUIRED COMPONENTS Development)
+
+include(UseJava)
+set(CMAKE_JAVA_JAR_ENTRY_POINT org.multimc.EntryPoint)
+set(CMAKE_JAVA_COMPILE_FLAGS -target 1.6 -source 1.6 -Xlint:deprecation -Xlint:unchecked)
+
+set(SRC
+ # OSX things
+ org/simplericity/macify/eawt/Application.java
+ org/simplericity/macify/eawt/ApplicationAdapter.java
+ org/simplericity/macify/eawt/ApplicationEvent.java
+ org/simplericity/macify/eawt/ApplicationListener.java
+ org/simplericity/macify/eawt/DefaultApplication.java
+
+ # legacy applet wrapper thing.
+ # 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
+
+ # generic launcher
+ org/multimc/EntryPoint.java
+ org/multimc/Launcher.java
+ org/multimc/ParseException.java
+ org/multimc/Utils.java
+ org/multimc/IconLoader.java
+)
+add_jar(NewLaunch ${SRC})
+
diff --git a/libraries/launcher/net/minecraft/Launcher.java b/libraries/launcher/net/minecraft/Launcher.java
new file mode 100644
index 00000000..a53501ec
--- /dev/null
+++ b/libraries/launcher/net/minecraft/Launcher.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2012-2014 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.
+ */
+
+package net.minecraft;
+
+import java.util.TreeMap;
+import java.util.Map;
+import java.net.URL;
+import java.awt.Dimension;
+import java.awt.BorderLayout;
+import java.awt.Graphics;
+import java.applet.Applet;
+import java.applet.AppletStub;
+import java.net.MalformedURLException;
+
+public class Launcher extends Applet implements AppletStub
+{
+ private Applet wrappedApplet;
+ private URL documentBase;
+ private boolean active = false;
+ private final Map<String, String> params;
+
+ public Launcher(Applet applet, URL documentBase)
+ {
+ params = new TreeMap<String, String>();
+
+ this.setLayout(new BorderLayout());
+ this.add(applet, "Center");
+ this.wrappedApplet = applet;
+ this.documentBase = documentBase;
+ }
+
+ public void setParameter(String name, String value)
+ {
+ params.put(name, value);
+ }
+
+ public void replace(Applet applet)
+ {
+ this.wrappedApplet = applet;
+
+ applet.setStub(this);
+ applet.setSize(getWidth(), getHeight());
+
+ this.setLayout(new BorderLayout());
+ this.add(applet, "Center");
+
+ applet.init();
+ active = true;
+ applet.start();
+ validate();
+ }
+
+ @Override
+ public String getParameter(String name)
+ {
+ String param = params.get(name);
+ if (param != null)
+ return param;
+ try
+ {
+ return super.getParameter(name);
+ } catch (Exception ignore){}
+ return null;
+ }
+
+ @Override
+ public boolean isActive()
+ {
+ return active;
+ }
+
+ @Override
+ public void appletResize(int width, int height)
+ {
+ wrappedApplet.resize(width, height);
+ }
+
+ @Override
+ public void resize(int width, int height)
+ {
+ wrappedApplet.resize(width, height);
+ }
+
+ @Override
+ public void resize(Dimension d)
+ {
+ wrappedApplet.resize(d);
+ }
+
+ @Override
+ public void init()
+ {
+ if (wrappedApplet != null)
+ {
+ wrappedApplet.init();
+ }
+ }
+
+ @Override
+ public void start()
+ {
+ wrappedApplet.start();
+ active = true;
+ }
+
+ @Override
+ public void stop()
+ {
+ wrappedApplet.stop();
+ active = false;
+ }
+
+ public void destroy()
+ {
+ wrappedApplet.destroy();
+ }
+
+ @Override
+ public URL getCodeBase() {
+ try {
+ return new URL("http://www.minecraft.net/game/");
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public URL getDocumentBase()
+ {
+ try {
+ return new URL("http://www.minecraft.net/game/");
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public void setVisible(boolean b)
+ {
+ super.setVisible(b);
+ wrappedApplet.setVisible(b);
+ }
+ public void update(Graphics paramGraphics)
+ {
+ }
+ public void paint(Graphics paramGraphics)
+ {
+ }
+} \ No newline at end of file
diff --git a/libraries/launcher/org/multimc/EntryPoint.java b/libraries/launcher/org/multimc/EntryPoint.java
new file mode 100644
index 00000000..d1fc54a8
--- /dev/null
+++ b/libraries/launcher/org/multimc/EntryPoint.java
@@ -0,0 +1,178 @@
+package org.multimc;/*
+ * Copyright 2012-2014 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 org.multimc.legacy.LegacyLauncher;
+import org.multimc.onesix.OneSixLauncher;
+import org.simplericity.macify.eawt.Application;
+import org.simplericity.macify.eawt.DefaultApplication;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.nio.charset.Charset;
+
+public class EntryPoint
+{
+ private enum Action
+ {
+ Proceed,
+ Launch,
+ Abort
+ }
+
+ public static void main(String[] args)
+ {
+ // 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();
+ }
+ }
+
+ EntryPoint listener = new EntryPoint();
+ int retCode = listener.listen();
+ if (retCode != 0)
+ {
+ System.out.println("Exiting with " + retCode);
+ System.exit(retCode);
+ }
+ }
+
+ private Action parseLine(String inData) throws ParseException
+ {
+ String[] pair = inData.split(" ", 2);
+
+ if(pair.length == 1)
+ {
+ String command = pair[0];
+ if (pair[0].equals("launch"))
+ return Action.Launch;
+
+ else if (pair[0].equals("abort"))
+ return Action.Abort;
+
+ else throw new ParseException();
+ }
+
+ if(pair.length != 2)
+ throw new ParseException();
+
+ String command = pair[0];
+ String param = pair[1];
+
+ if(command.equals("launcher"))
+ {
+ if(param.equals("legacy"))
+ {
+ m_launcher = new LegacyLauncher();
+ Utils.log("Using legacy launcher.");
+ Utils.log();
+ return Action.Proceed;
+ }
+ if(param.equals("onesix"))
+ {
+ m_launcher = new OneSixLauncher();
+ Utils.log("Using onesix launcher.");
+ Utils.log();
+ return Action.Proceed;
+ }
+ else
+ throw new ParseException();
+ }
+
+ m_params.add(command, param);
+ //System.out.println(command + " : " + param);
+ return Action.Proceed;
+ }
+
+ public int listen()
+ {
+ BufferedReader buffer;
+ try
+ {
+ buffer = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
+ } catch (UnsupportedEncodingException e)
+ {
+ System.err.println("For some reason, your java does not support UTF-8. Consider living in the current century.");
+ e.printStackTrace();
+ return 1;
+ }
+ boolean isListening = true;
+ boolean isAborted = false;
+ // Main loop
+ while (isListening)
+ {
+ String inData;
+ try
+ {
+ // Read from the pipe one line at a time
+ inData = buffer.readLine();
+ if (inData != null)
+ {
+ Action a = parseLine(inData);
+ if(a == Action.Abort)
+ {
+ isListening = false;
+ isAborted = true;
+ }
+ if(a == Action.Launch)
+ {
+ isListening = false;
+ }
+ }
+ else
+ {
+ isListening = false;
+ isAborted = true;
+ }
+ }
+ catch (IOException e)
+ {
+ System.err.println("Launcher ABORT due to IO exception:");
+ e.printStackTrace();
+ return 1;
+ }
+ catch (ParseException e)
+ {
+ System.err.println("Launcher ABORT due to PARSE exception:");
+ e.printStackTrace();
+ return 1;
+ }
+ }
+ if(isAborted)
+ {
+ System.err.println("Launch aborted by MultiMC.");
+ return 1;
+ }
+ if(m_launcher != null)
+ {
+ return m_launcher.launch(m_params);
+ }
+ System.err.println("No valid launcher implementation specified.");
+ return 1;
+ }
+
+ private ParamBucket m_params = new ParamBucket();
+ private org.multimc.Launcher m_launcher;
+}
diff --git a/libraries/launcher/org/multimc/IconLoader.java b/libraries/launcher/org/multimc/IconLoader.java
new file mode 100644
index 00000000..f1638f3a
--- /dev/null
+++ b/libraries/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/libraries/launcher/org/multimc/Launcher.java b/libraries/launcher/org/multimc/Launcher.java
new file mode 100644
index 00000000..1aa2b21f
--- /dev/null
+++ b/libraries/launcher/org/multimc/Launcher.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2012-2014 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.
+ */
+
+package org.multimc;
+
+public interface Launcher
+{
+ abstract int launch(ParamBucket params);
+}
diff --git a/libraries/launcher/org/multimc/LegacyFrame.java b/libraries/launcher/org/multimc/LegacyFrame.java
new file mode 100644
index 00000000..a081f3ae
--- /dev/null
+++ b/libraries/launcher/org/multimc/LegacyFrame.java
@@ -0,0 +1,112 @@
+package org.multimc;/*
+ * Copyright 2012-2014 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 net.minecraft.Launcher;
+
+import javax.imageio.ImageIO;
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class LegacyFrame extends Frame implements WindowListener
+{
+ private Launcher appletWrap = null;
+ public LegacyFrame(String title)
+ {
+ super ( title );
+ BufferedImage image;
+ try {
+ image = ImageIO.read ( new File ( "icon.png" ) );
+ setIconImage ( image );
+ } catch ( IOException e ) {
+ e.printStackTrace();
+ }
+ this.addWindowListener ( this );
+ }
+
+ public void start ( Applet mcApplet, String user, String session, Dimension winSize, boolean maximize )
+ {
+ try {
+ appletWrap = new Launcher( mcApplet, new URL ( "http://www.minecraft.net/game" ) );
+ } catch ( MalformedURLException ignored ) {}
+ appletWrap.setParameter ( "username", user );
+ appletWrap.setParameter ( "sessionid", session );
+ appletWrap.setParameter ( "stand-alone", "true" ); // Show the quit button.
+ appletWrap.setParameter ( "demo", "false" );
+ appletWrap.setParameter("fullscreen", "false");
+ mcApplet.setStub(appletWrap);
+ this.add ( appletWrap );
+ appletWrap.setPreferredSize ( winSize );
+ this.pack();
+ this.setLocationRelativeTo ( null );
+ this.setResizable ( true );
+ if ( maximize ) {
+ this.setExtendedState ( MAXIMIZED_BOTH );
+ }
+ validate();
+ appletWrap.init();
+ appletWrap.start();
+ setVisible ( true );
+ }
+
+ @Override
+ public void windowActivated ( WindowEvent e ) {}
+
+ @Override
+ public void windowClosed ( WindowEvent e ) {}
+
+ @Override
+ public void windowClosing ( WindowEvent e )
+ {
+ new Thread() {
+ public void run() {
+ try {
+ Thread.sleep ( 30000L );
+ } catch ( InterruptedException localInterruptedException ) {
+ localInterruptedException.printStackTrace();
+ }
+ System.out.println ( "FORCING EXIT!" );
+ System.exit ( 0 );
+ }
+ }
+ .start();
+
+ if ( appletWrap != null ) {
+ appletWrap.stop();
+ appletWrap.destroy();
+ }
+ // old minecraft versions can hang without this >_<
+ System.exit ( 0 );
+ }
+
+ @Override
+ public void windowDeactivated ( WindowEvent e ) {}
+
+ @Override
+ public void windowDeiconified ( WindowEvent e ) {}
+
+ @Override
+ public void windowIconified ( WindowEvent e ) {}
+
+ @Override
+ public void windowOpened ( WindowEvent e ) {}
+}
diff --git a/libraries/launcher/org/multimc/NotFoundException.java b/libraries/launcher/org/multimc/NotFoundException.java
new file mode 100644
index 00000000..fe154a2f
--- /dev/null
+++ b/libraries/launcher/org/multimc/NotFoundException.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2012-2014 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.
+ */
+
+package org.multimc;
+
+public class NotFoundException extends Exception
+{
+}
diff --git a/libraries/launcher/org/multimc/ParamBucket.java b/libraries/launcher/org/multimc/ParamBucket.java
new file mode 100644
index 00000000..2e197d9f
--- /dev/null
+++ b/libraries/launcher/org/multimc/ParamBucket.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2012-2014 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.
+ */
+
+package org.multimc;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ParamBucket
+{
+ public void add(String key, String value)
+ {
+ List<String> coll = null;
+ if(!m_params.containsKey(key))
+ {
+ coll = new ArrayList<String>();
+ m_params.put(key, coll);
+ }
+ else
+ {
+ coll = m_params.get(key);
+ }
+ coll.add(value);
+ }
+
+ public List<String> all(String key) throws NotFoundException
+ {
+ if(!m_params.containsKey(key))
+ throw new NotFoundException();
+ return m_params.get(key);
+ }
+
+ public List<String> allSafe(String key, List<String> def)
+ {
+ if(!m_params.containsKey(key) || m_params.get(key).size() < 1)
+ {
+ return def;
+ }
+ return m_params.get(key);
+ }
+
+ public List<String> allSafe(String key)
+ {
+ return allSafe(key, new ArrayList<String>());
+ }
+
+ public String first(String key) throws NotFoundException
+ {
+ List<String> list = all(key);
+ if(list.size() < 1)
+ {
+ throw new NotFoundException();
+ }
+ return list.get(0);
+ }
+
+ public String firstSafe(String key, String def)
+ {
+ if(!m_params.containsKey(key) || m_params.get(key).size() < 1)
+ {
+ return def;
+ }
+ return m_params.get(key).get(0);
+ }
+
+ public String firstSafe(String key)
+ {
+ return firstSafe(key, "");
+ }
+
+ private HashMap<String, List<String>> m_params = new HashMap<String, List<String>>();
+}
diff --git a/libraries/launcher/org/multimc/ParseException.java b/libraries/launcher/org/multimc/ParseException.java
new file mode 100644
index 00000000..d9e8e53e
--- /dev/null
+++ b/libraries/launcher/org/multimc/ParseException.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2012-2014 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.
+ */
+
+package org.multimc;
+
+public class ParseException extends java.lang.Exception
+{
+
+}
diff --git a/libraries/launcher/org/multimc/Utils.java b/libraries/launcher/org/multimc/Utils.java
new file mode 100644
index 00000000..32cf7919
--- /dev/null
+++ b/libraries/launcher/org/multimc/Utils.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2012-2014 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.
+ */
+
+package org.multimc;
+
+import java.io.*;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+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
+ *
+ * @param mc the class to scan