diff --git a/depends/launcher/org/multimc/EntryPoint.java b/depends/launcher/org/multimc/EntryPoint.java index 83f232f14..e2721ffa8 100644 --- a/depends/launcher/org/multimc/EntryPoint.java +++ b/depends/launcher/org/multimc/EntryPoint.java @@ -22,6 +22,7 @@ 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 { @@ -93,12 +94,21 @@ public class EntryPoint public int listen() { - BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in)); + 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; // Main loop while (isListening) { - String inData=""; + String inData; try { // Read from the pipe one line at a time @@ -113,11 +123,13 @@ public class EntryPoint } 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; } diff --git a/depends/launcher/org/multimc/Utils.java b/depends/launcher/org/multimc/Utils.java index df0ef861c..f3bac91d4 100644 --- a/depends/launcher/org/multimc/Utils.java +++ b/depends/launcher/org/multimc/Utils.java @@ -16,24 +16,28 @@ package org.multimc; -import java.io.File; +import java.io.*; 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.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) + public static String combine(String path1, String path2) { File file1 = new File(path1); File file2 = new File(file1, path2); @@ -42,15 +46,16 @@ public class Utils /** * Join a list of strings into a string using a separator! - * @param strings the string list to join + * + * @param strings the string list to join * @param separator the glue * @return the result. */ - public static String join (List strings, String separator) + public static String join(List strings, String separator) { StringBuilder sb = new StringBuilder(); String sep = ""; - for(String s: strings) + for (String s : strings) { sb.append(sep).append(s); sep = separator; @@ -105,7 +110,8 @@ public class Utils * @param pathToAdd the path to add * @throws Exception */ - @Deprecated public static void addLibraryPath(String pathToAdd) throws Exception + @Deprecated + public static void addLibraryPath(String pathToAdd) throws Exception { final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths"); usrPathsField.setAccessible(true); @@ -154,26 +160,83 @@ public class Utils return null; } - /** - * Log to the MultiMC console - * - * @param message A String containing the message - * @param level A String containing the level name. See MinecraftProcess::getLevel() - */ - public static void log(String message, String level) - { - // Kinda dirty - String tag = "!![" + level + "]!"; - System.out.println(tag + message.replace("\n", "\n" + tag)); - } + /** + * Log to the MultiMC console + * + * @param message A String containing the message + * @param level A String containing the level name. See MinecraftProcess::getLevel() + */ + public static void log(String message, String level) + { + // Kinda dirty + String tag = "!![" + level + "]!"; + System.out.println(tag + message.replace("\n", "\n" + tag)); + } - public static void log(String message) - { - log(message, "MultiMC"); - } + public static void log(String message) + { + log(message, "MultiMC"); + } - public static void log() - { - System.out.println(); - } + public static void log() + { + System.out.println(); + } + + /** + * Pushes bytes from in to out. Closes both streams no matter what. + * @param in the input stream + * @param out the output stream + * @throws IOException + */ + private static void copyStream(InputStream in, OutputStream out) throws IOException + { + try + { + byte[] buffer = new byte[4096]; + int len; + + while((len = in.read(buffer)) >= 0) + out.write(buffer, 0, len); + } finally + { + in.close(); + out.close(); + } + } + + /** + * Unzip zip file 'source' into the folder 'targetFolder' + * @param source + * @param targetFolder + * @throws IOException + */ + public static void unzip(File source, File targetFolder) throws IOException + { + ZipFile zip = new ZipFile(source); + try + { + Enumeration entries = zip.entries(); + + while (entries.hasMoreElements()) + { + ZipEntry entry = (ZipEntry) entries.nextElement(); + + File targetFile = new File(targetFolder, entry.getName()); + if (targetFile.getParentFile() != null) + { + targetFile.getParentFile().mkdirs(); + } + + if (entry.isDirectory()) + continue; + + copyStream(zip.getInputStream(entry), new BufferedOutputStream(new FileOutputStream(targetFile))); + } + } finally + { + zip.close(); + } + } } + diff --git a/depends/launcher/org/multimc/onesix/OneSixLauncher.java b/depends/launcher/org/multimc/onesix/OneSixLauncher.java index c1676c945..28f8e6ee3 100644 --- a/depends/launcher/org/multimc/onesix/OneSixLauncher.java +++ b/depends/launcher/org/multimc/onesix/OneSixLauncher.java @@ -18,6 +18,7 @@ package org.multimc.onesix; import org.multimc.*; import java.io.File; +import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -34,6 +35,7 @@ public class OneSixLauncher implements Launcher { // get and process the launch script params List libraries; + List extlibs; List mcparams; List mods; String mainClass; @@ -43,10 +45,12 @@ public class OneSixLauncher implements Launcher try { libraries = params.all("cp"); + extlibs = params.all("ext"); mcparams = params.all("param"); mainClass = params.first("mainClass"); mods = params.allSafe("mods", new ArrayList()); natives = params.first("natives"); + windowTitle = params.first("windowTitle"); // windowParams = params.first("windowParams"); } catch (NotFoundException e) @@ -66,23 +70,14 @@ public class OneSixLauncher implements Launcher return -1; } - String property = System.getProperty("os.arch"); - List allNativePaths = new ArrayList(); - boolean is_64 = property.equalsIgnoreCase("x86_64") || property.equalsIgnoreCase("amd64"); - allNativePaths.add(natives); - allNativePaths.add(natives + "/" + (is_64 ? "64" : "32")); - // print the pretty things { Utils.log("Main Class:"); Utils.log(" " + mainClass); Utils.log(); - Utils.log("Native paths:"); - for (String s : allNativePaths) - { - Utils.log(" " + s); - } + Utils.log("Native path:"); + Utils.log(" " + natives); Utils.log(); Utils.log("Libraries:"); @@ -107,11 +102,28 @@ public class OneSixLauncher implements Launcher Utils.log(); } - final ClassLoader cl = ClassLoader.getSystemClassLoader(); - // set up the natives path(s). - String libpath = Utils.join(allNativePaths, String.valueOf(File.pathSeparatorChar)); - System.setProperty("java.library.path", libpath); + 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) + { + try + { + String cleanlib = extlib.replace("${arch}", is_64 ? "64" : "32"); + File cleanlibf = new File(cleanlib); + Utils.log("Extracting " + cleanlibf.getName()); + Utils.unzip(cleanlibf, new File(natives)); + } catch (IOException e) + { + System.err.println("Failed to extract native library:"); + e.printStackTrace(System.err); + return -1; + } + } + Utils.log(); + + System.setProperty("java.library.path", natives); Field fieldSysPath; try { @@ -126,6 +138,7 @@ public class OneSixLauncher implements Launcher } // Get the Minecraft Class. + final ClassLoader cl = ClassLoader.getSystemClassLoader(); Class mc; try { diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp index 3cfc1c76d..ab87a1db3 100644 --- a/logic/OneSixInstance.cpp +++ b/logic/OneSixInstance.cpp @@ -228,6 +228,11 @@ MinecraftProcess *OneSixInstance::prepareForLaunch(MojangAccountPtr account) } QDir natives_dir(PathCombine(instanceRoot(), "natives/")); launchScript += "windowTitle " + windowTitle() + "\n"; + for(auto native: version->getActiveNativeLibs()) + { + QFileInfo finfo(PathCombine("libraries", native->storagePath())); + launchScript += "ext " + finfo.absoluteFilePath() + "\n"; + } launchScript += "natives " + natives_dir.absolutePath() + "\n"; launchScript += "launch onesix\n"; diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp index 0119ab07d..ae647bfe6 100644 --- a/logic/OneSixUpdate.cpp +++ b/logic/OneSixUpdate.cpp @@ -349,11 +349,6 @@ void OneSixUpdate::prepareForLaunch() return; } /* - * emitFailed("Could not create the native library folder:\n" + natives_dir_raw + - "\nMake sure MultiMC has appropriate permissions and there is enough - space " - "on the storage device."); - */ for (auto lib : version->getActiveNativeLibs()) { if (!lib->filesExist()) @@ -372,6 +367,6 @@ void OneSixUpdate::prepareForLaunch() return; } } - +*/ emitSucceeded(); }