diff options
Diffstat (limited to 'libraries/launcher/org/multimc/onesix/OneSixLauncher.java')
-rw-r--r-- | libraries/launcher/org/multimc/onesix/OneSixLauncher.java | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/libraries/launcher/org/multimc/onesix/OneSixLauncher.java b/libraries/launcher/org/multimc/onesix/OneSixLauncher.java new file mode 100644 index 00000000..179df0ee --- /dev/null +++ b/libraries/launcher/org/multimc/onesix/OneSixLauncher.java @@ -0,0 +1,367 @@ +/* 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.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.Method; +import java.util.ArrayList; +import java.util.List; + +public class OneSixLauncher implements Launcher +{ + // parameters, separated from ParamBucket + private List<String> libraries; + private List<String> extlibs; + private List<String> extlibs32; + private List<String> extlibs64; + private List<String> mcparams; + private List<String> mods; + private List<String> jarmods; + private List<String> coremods; + private List<String> traits; + private String appletClass; + private String mainClass; + private String nativePath; + 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 + { + libraries = params.all("cp"); + extlibs = params.allSafe("ext", new ArrayList<String>()); + extlibs32 = params.allSafe("ext32", new ArrayList<String>()); + extlibs64 = params.allSafe("ext64", new ArrayList<String>()); + + // Unify the extracted native libs according to actual system architecture + String property = System.getProperty("os.arch"); + boolean is_64 = property.equalsIgnoreCase("x86_64") || property.equalsIgnoreCase("amd64"); + if(is_64) + { + extlibs.addAll(extlibs64); + } + else + { + extlibs.addAll(extlibs32); + } + + 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>()); + jarmods = params.allSafe("jarmod", new ArrayList<String>()); + coremods = params.allSafe("coremod", new ArrayList<String>()); + traits = params.allSafe("traits", new ArrayList<String>()); + nativePath = params.first("natives"); + + 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")) + { + maximize = true; + } + else if (dimStrings.length == 2) + { + 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(); + + Utils.log("Native path:"); + Utils.log(" " + nativePath); + Utils.log(); + + Utils.log("Traits:"); + Utils.log(" " + traits); + Utils.log(); + + Utils.log("Libraries:"); + for (String s : libraries) + { + File f = new File(s); + if (f.exists()) + { + Utils.log(" " + s); + } + else + { + Utils.log(" " + s + " (missing)", "Warning"); + } + } + Utils.log(); + + if(mods.size() > 0) + { + Utils.log("Mods:"); + for (String s : mods) + { + Utils.log(" " + s); + } + Utils.log(); + } + + if(coremods.size() > 0) + { + Utils.log("Core Mods:"); + for (String s : coremods) + { + Utils.log(" " + s); + } + Utils.log(); + } + + if(jarmods.size() > 0) + { + Utils.log("Jar Mods:"); + for (String s : jarmods) + { + Utils.log(" " + s); + } + Utils.log(); + } + + Utils.log("Params:"); + Utils.log(" " + mcparams.toString()); + Utils.log(); + 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(); + } + + int legacyLaunch() + { + // Get the Minecraft Class and set the base folder + Class<?> mc; + try + { + mc = cl.loadClass(mainClass); + + Field f = Utils.getMCPathField(mc); + + if (f == null) + { + System.err.println("Could not find Minecraft path field."); + } + else + { + f.setAccessible(true); + f.set(null, new File(cwd)); + } + } catch (Exception e) + { + 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(appletClass); + 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() + { + // window size, title and state, onesix + if (maximize) + { + // FIXME: there is no good way to maximize the minecraft window in onesix. + // the following often breaks linux screen setups + // mcparams.add("--fullscreen"); + } + else + { + mcparams.add("--width"); + mcparams.add(Integer.toString(winSize.width)); + mcparams.add("--height"); + mcparams.add(Integer.toString(winSize.height)); + } + + System.setProperty("minecraft.applet.TargetDirectory", cwd); + + // Get the Minecraft Class. + Class<?> mc; + try + { + mc = cl.loadClass(mainClass); + } catch (ClassNotFoundException e) + { + System.err.println("Failed to find Minecraft main class:"); + e.printStackTrace(System.err); + return -1; + } + + // get the main method. + Method meth; + try + { + meth = mc.getMethod("main", String[].class); + } catch (NoSuchMethodException e) + { + System.err.println("Failed to acquire the main method:"); + 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; + } + + // 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..."); + for(String extlib: extlibs) + { + try + { + File extlibf = new File(extlib); + Utils.log("Extracting " + extlibf.getName()); + Utils.unzipNatives(extlibf, new File(nativePath)); + } 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", nativePath); + System.setProperty("org.lwjgl.librarypath", nativePath); + System.setProperty("net.java.games.input.librarypath", nativePath); + // 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); + System.err.println("Minecraft might fail to launch..."); + } + + // grab the system classloader and ... + cl = ClassLoader.getSystemClassLoader(); + + if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch") ) + { + // legacy launch uses the applet wrapper + return legacyLaunch(); + } + else + { + // normal launch just calls main() + return launchWithMainClass(); + } + } +} |