From 2590c6be15ab549256f0a39028aefb887ac5131a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 6 May 2014 22:38:28 +0200 Subject: [PATCH] Fix launcher part for legacy in onesix. --- depends/launcher/CMakeLists.txt | 2 +- .../org/multimc/{legacy => }/LegacyFrame.java | 2 +- .../org/multimc/legacy/LegacyLauncher.java | 5 +- .../org/multimc/onesix/OneSixLauncher.java | 332 ++++++++++++------ logic/OneSixInstance.cpp | 64 +++- 5 files changed, 280 insertions(+), 125 deletions(-) rename depends/launcher/org/multimc/{legacy => }/LegacyFrame.java (99%) diff --git a/depends/launcher/CMakeLists.txt b/depends/launcher/CMakeLists.txt index ad06fa7be..42c77a89b 100644 --- a/depends/launcher/CMakeLists.txt +++ b/depends/launcher/CMakeLists.txt @@ -18,7 +18,7 @@ set(SRC # The launcher has to be there for silly FML/Forge relauncher. net/minecraft/Launcher.java org/multimc/legacy/LegacyLauncher.java - org/multimc/legacy/LegacyFrame.java + org/multimc/LegacyFrame.java # onesix launcher org/multimc/onesix/OneSixLauncher.java diff --git a/depends/launcher/org/multimc/legacy/LegacyFrame.java b/depends/launcher/org/multimc/LegacyFrame.java similarity index 99% rename from depends/launcher/org/multimc/legacy/LegacyFrame.java rename to depends/launcher/org/multimc/LegacyFrame.java index c3c0cafc8..a081f3ae3 100644 --- a/depends/launcher/org/multimc/legacy/LegacyFrame.java +++ b/depends/launcher/org/multimc/LegacyFrame.java @@ -1,4 +1,4 @@ -package org.multimc.legacy;/* +package org.multimc;/* * Copyright 2012-2014 MultiMC Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/depends/launcher/org/multimc/legacy/LegacyLauncher.java b/depends/launcher/org/multimc/legacy/LegacyLauncher.java index 1ca37c4ae..347bb1a23 100644 --- a/depends/launcher/org/multimc/legacy/LegacyLauncher.java +++ b/depends/launcher/org/multimc/legacy/LegacyLauncher.java @@ -14,10 +14,7 @@ package org.multimc.legacy;/* * limitations under the License. */ -import org.multimc.Launcher; -import org.multimc.NotFoundException; -import org.multimc.ParamBucket; -import org.multimc.Utils; +import org.multimc.*; import java.applet.Applet; import java.awt.*; diff --git a/depends/launcher/org/multimc/onesix/OneSixLauncher.java b/depends/launcher/org/multimc/onesix/OneSixLauncher.java index a908f6f3c..0bd5c7ce5 100644 --- a/depends/launcher/org/multimc/onesix/OneSixLauncher.java +++ b/depends/launcher/org/multimc/onesix/OneSixLauncher.java @@ -17,7 +17,9 @@ package org.multimc.onesix; import org.multimc.*; +import java.applet.Applet; import java.io.File; +import java.awt.*; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -30,117 +32,156 @@ import java.util.List; public class OneSixLauncher implements Launcher { - @Override - public int launch(ParamBucket params) + // parameters, separated from ParamBucket + private List libraries; + private List extlibs; + private List mcparams; + private List mods; + private List traits; + private String mainClass; + private String natives; + private String userName, sessionId; + private String windowTitle; + private String windowParams; + + // secondary parameters + private Dimension winSize; + private boolean maximize; + private String cwd; + + // the much abused system classloader, for convenience (for further abuse) + private ClassLoader cl; + + private void processParams(ParamBucket params) throws NotFoundException { - // get and process the launch script params - List libraries; - List extlibs; - List mcparams; - List mods; - List traits; - String mainClass; - String natives; - final String windowTitle; - String windowParams; - try - { - libraries = params.all("cp"); - extlibs = params.all("ext"); - mcparams = params.all("param"); - mainClass = params.first("mainClass"); - mods = params.allSafe("mods", new ArrayList()); - traits = params.allSafe("traits", new ArrayList()); - natives = params.first("natives"); + libraries = params.all("cp"); + extlibs = params.all("ext"); + mcparams = params.all("param"); + mainClass = params.first("mainClass"); + mods = params.allSafe("mods", new ArrayList()); + traits = params.allSafe("traits", new ArrayList()); + natives = params.first("natives"); - windowTitle = params.first("windowTitle"); - // windowParams = params.first("windowParams"); - } catch (NotFoundException e) + userName = params.first("userName"); + sessionId = params.first("sessionId"); + windowTitle = params.firstSafe("windowTitle", "Minecraft"); + windowParams = params.firstSafe("windowParams", "854x480"); + + cwd = System.getProperty("user.dir"); + winSize = new Dimension(854, 480); + maximize = false; + + String[] dimStrings = windowParams.split("x"); + + if (windowParams.equalsIgnoreCase("max")) { - System.err.println("Not enough arguments."); - e.printStackTrace(System.err); - return -1; + maximize = true; } - - List allJars = new ArrayList(); - allJars.addAll(mods); - allJars.addAll(libraries); - - if(!Utils.addToClassPath(allJars)) + else if (dimStrings.length == 2) { - System.err.println("Halting launch due to previous errors."); - return -1; + try + { + winSize = new Dimension(Integer.parseInt(dimStrings[0]), Integer.parseInt(dimStrings[1])); + } catch (NumberFormatException ignored) {} } + } + + private void printStats() + { + Utils.log("Main Class:"); + Utils.log(" " + mainClass); + Utils.log(); - // print the pretty things + Utils.log("Native path:"); + Utils.log(" " + natives); + Utils.log(); + + Utils.log("Traits:"); + Utils.log(" " + traits); + Utils.log(); + + Utils.log("Libraries:"); + for (String s : libraries) { - Utils.log("Main Class:"); - Utils.log(" " + mainClass); - Utils.log(); + Utils.log(" " + s); + } + Utils.log(); - Utils.log("Native path:"); - Utils.log(" " + natives); - Utils.log(); - - Utils.log("Libraries:"); - for (String s : libraries) + if(mods.size() > 0) + { + Utils.log("Class Path Mods:"); + for (String s : mods) { Utils.log(" " + s); } Utils.log(); - - if(mods.size() > 0) - { - Utils.log("Class Path Mods:"); - for (String s : mods) - { - Utils.log(" " + s); - } - Utils.log(); - } - - Utils.log("Params:"); - Utils.log(" " + mcparams.toString()); - Utils.log(); } - // set up the natives path(s). - 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("Params:"); + Utils.log(" " + mcparams.toString()); Utils.log(); - - System.setProperty("java.library.path", natives); - Field fieldSysPath; + } + + int legacyLaunch() + { + // Get the Minecraft Class and set the base folder + Class mc; try { - fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths"); - fieldSysPath.setAccessible( true ); - fieldSysPath.set( null, null ); + mc = cl.loadClass(mainClass); + + Field f = Utils.getMCPathField(mc); + + if (f == null) + { + System.err.println("Could not find Minecraft path field. Launch failed."); + return -1; + } + + f.setAccessible(true); + f.set(null, new File(cwd)); } catch (Exception e) { - System.err.println("Failed to set the native library path:"); + System.err.println("Could not set base folder. Failed to find/access Minecraft main class:"); e.printStackTrace(System.err); return -1; } + System.setProperty("minecraft.applet.TargetDirectory", cwd); + + String[] mcArgs = new String[2]; + mcArgs[0] = userName; + mcArgs[1] = sessionId; + + Utils.log("Launching with applet wrapper..."); + try + { + Class MCAppletClass = cl.loadClass("net.minecraft.client.MinecraftApplet"); + Applet mcappl = (Applet) MCAppletClass.newInstance(); + LegacyFrame mcWindow = new LegacyFrame(windowTitle); + mcWindow.start(mcappl, userName, sessionId, winSize, maximize); + } catch (Exception e) + { + Utils.log("Applet wrapper failed:", "Error"); + e.printStackTrace(System.err); + Utils.log(); + Utils.log("Falling back to compatibility mode."); + try + { + 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); + return -1; + } + } + return 0; + } + + int launchWithMainClass() + { // Get the Minecraft Class. - final ClassLoader cl = ClassLoader.getSystemClassLoader(); Class mc; try { @@ -163,8 +204,109 @@ public class OneSixLauncher implements Launcher e.printStackTrace(System.err); return -1; } + + // 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) + { + System.err.println("Failed to start Minecraft:"); + e.printStackTrace(System.err); + return -1; + } + return 0; + } + + @Override + public int launch(ParamBucket params) + { + // get and process the launch script params + try + { + processParams(params); + } catch (NotFoundException e) + { + System.err.println("Not enough arguments."); + e.printStackTrace(System.err); + return -1; + } - // FIXME: works only on linux, we need a better solution + // do some horrible black magic with the classpath + { + List allJars = new ArrayList(); + allJars.addAll(mods); + allJars.addAll(libraries); + + if(!Utils.addToClassPath(allJars)) + { + 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) + { + 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(); + + // 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) + { + System.err.println("Failed to set the native library path:"); + e.printStackTrace(System.err); + return -1; + } + + // grab the system classloader and ... + cl = ClassLoader.getSystemClassLoader(); + + if (traits.contains("legacyLaunch")) + { + // legacy launch uses the applet wrapper + return legacyLaunch(); + } + else + { + // normal launch just calls main() + return launchWithMainClass(); + } + } +} + + +// FIXME: works only on linux, we need a better solution /* final java.nio.ByteBuffer[] icons = IconLoader.load("icon.png"); new Thread() { @@ -208,18 +350,4 @@ public class OneSixLauncher implements Launcher } } .start(); -*/ - // start Minecraft - String[] paramsArray = mcparams.toArray(new String[mcparams.size()]); // init params accordingly - try - { - meth.invoke(null, (Object) paramsArray); // static method doesn't have an instance - } catch (Exception e) - { - System.err.println("Failed to start Minecraft:"); - e.printStackTrace(System.err); - return -1; - } - return 0; - } -} +*/ \ No newline at end of file diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp index 9057a6e30..ffd40325c 100644 --- a/logic/OneSixInstance.cpp +++ b/logic/OneSixInstance.cpp @@ -200,6 +200,8 @@ bool OneSixInstance::prepareForLaunch(AuthSessionPtr account, QString &launchScr auto version = d->version; if (!version) return nullptr; + + // libraries and class path. { auto libs = version->getActiveNormalLibs(); for (auto lib : libs) @@ -223,36 +225,64 @@ bool OneSixInstance::prepareForLaunch(AuthSessionPtr account, QString &launchScr } launchScript += "mainClass " + version->mainClass + "\n"; + // generic minecraft params for (auto param : processMinecraftArgs(account)) { launchScript += "param " + param + "\n"; } - // Set the width and height for 1.6 instances - bool maximize = settings().get("LaunchMaximized").toBool(); - if (maximize) + // window size, title and state, legacy { - // this is probably a BAD idea - // launchScript += "param --fullscreen\n"; + QString windowParams; + if (settings().get("LaunchMaximized").toBool()) + windowParams = "max"; + else + windowParams = QString("%1x%2") + .arg(settings().get("MinecraftWinWidth").toInt()) + .arg(settings().get("MinecraftWinHeight").toInt()); + launchScript += "windowTitle " + windowTitle() + "\n"; + launchScript += "windowParams " + windowParams + "\n"; } - else + + // window size, title and state, onesix { - launchScript += - "param --width\nparam " + settings().get("MinecraftWinWidth").toString() + "\n"; - launchScript += - "param --height\nparam " + settings().get("MinecraftWinHeight").toString() + "\n"; + bool maximize = settings().get("LaunchMaximized").toBool(); + if (maximize) + { + // FIXME: there is no good way to maximize the minecraft window in onesix. + // this is probably a BAD idea + // launchScript += "param --fullscreen\n"; + } + else + { + launchScript += + "param --width\nparam " + settings().get("MinecraftWinWidth").toString() + "\n"; + launchScript += + "param --height\nparam " + settings().get("MinecraftWinHeight").toString() + "\n"; + } } - QDir natives_dir(PathCombine(instanceRoot(), "natives/")); - launchScript += "windowTitle " + windowTitle() + "\n"; - for (auto native : version->getActiveNativeLibs()) + + // legacy auth { - QFileInfo finfo(PathCombine("libraries", native->storagePath())); - launchScript += "ext " + finfo.absoluteFilePath() + "\n"; + launchScript += "userName " + session->player_name + "\n"; + launchScript += "sessionId " + session->session + "\n"; } - launchScript += "natives " + natives_dir.absolutePath() + "\n"; + + // native libraries (mostly LWJGL) + { + QDir natives_dir(PathCombine(instanceRoot(), "natives/")); + for (auto native : version->getActiveNativeLibs()) + { + QFileInfo finfo(PathCombine("libraries", native->storagePath())); + launchScript += "ext " + finfo.absoluteFilePath() + "\n"; + } + launchScript += "natives " + natives_dir.absolutePath() + "\n"; + } + + // traits. including legacyLaunch and others ;) for (auto trait : version->traits) { - launchScript += "trait " + trait + "\n"; + launchScript += "traits " + trait + "\n"; } launchScript += "launcher onesix\n"; return true;