Merge pull request #520 from icelimetea/refactor-java-launcher-v2
This commit is contained in:
		| @@ -4,17 +4,18 @@ find_package(Java 1.7 REQUIRED COMPONENTS Development) | ||||
|  | ||||
| include(UseJava) | ||||
| set(CMAKE_JAVA_JAR_ENTRY_POINT org.multimc.EntryPoint) | ||||
| set(CMAKE_JAVA_COMPILE_FLAGS -target 8 -source 8 -Xlint:deprecation -Xlint:unchecked) | ||||
| set(CMAKE_JAVA_COMPILE_FLAGS -target 7 -source 7 -Xlint:deprecation -Xlint:unchecked) | ||||
|  | ||||
| set(SRC | ||||
|     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/onesix/OneSixLauncher.java | ||||
|     org/multimc/LauncherFactory.java | ||||
|     org/multimc/impl/OneSixLauncher.java | ||||
|     org/multimc/applet/LegacyFrame.java | ||||
|     org/multimc/exception/ParameterNotFoundException.java | ||||
|     org/multimc/exception/ParseException.java | ||||
|     org/multimc/utils/Parameters.java | ||||
|     org/multimc/utils/Utils.java | ||||
|     net/minecraft/Launcher.java | ||||
| ) | ||||
| add_jar(NewLaunch ${SRC}) | ||||
|   | ||||
| @@ -16,31 +16,28 @@ | ||||
|  | ||||
| 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.awt.*; | ||||
| import java.net.MalformedURLException; | ||||
| import java.net.URL; | ||||
| import java.util.Map; | ||||
| import java.util.TreeMap; | ||||
|  | ||||
| public final class Launcher extends Applet implements AppletStub { | ||||
|  | ||||
|     private final Map<String, String> params = new TreeMap<>(); | ||||
|  | ||||
|     private final Applet wrappedApplet; | ||||
|  | ||||
| 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>(); | ||||
|  | ||||
|     public Launcher(Applet applet) { | ||||
|         this.setLayout(new BorderLayout()); | ||||
|  | ||||
|         this.add(applet, "Center"); | ||||
|  | ||||
|         this.wrappedApplet = applet; | ||||
|         this.documentBase = documentBase; | ||||
|     } | ||||
|  | ||||
|     public void setParameter(String name, String value) | ||||
| @@ -48,84 +45,61 @@ public class Launcher extends Applet implements AppletStub | ||||
|         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) | ||||
|     { | ||||
|     public String getParameter(String name) { | ||||
|         String param = params.get(name); | ||||
|  | ||||
|         if (param != null) | ||||
|             return param; | ||||
|         try | ||||
|         { | ||||
|  | ||||
|         try { | ||||
|             return super.getParameter(name); | ||||
|         } catch (Exception ignore){} | ||||
|         } catch (Exception ignore) {} | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isActive() | ||||
|     { | ||||
|     public boolean isActive() { | ||||
|         return active; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void appletResize(int width, int height) | ||||
|     { | ||||
|     public void appletResize(int width, int height) { | ||||
|         wrappedApplet.resize(width, height); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void resize(int width, int height) | ||||
|     { | ||||
|     public void resize(int width, int height) { | ||||
|         wrappedApplet.resize(width, height); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void resize(Dimension d) | ||||
|     { | ||||
|     public void resize(Dimension d) { | ||||
|         wrappedApplet.resize(d); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void init() | ||||
|     { | ||||
|     public void init() { | ||||
|         if (wrappedApplet != null) | ||||
|         { | ||||
|             wrappedApplet.init(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void start() | ||||
|     { | ||||
|     public void start() { | ||||
|         wrappedApplet.start(); | ||||
|  | ||||
|         active = true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void stop() | ||||
|     { | ||||
|     public void stop() { | ||||
|         wrappedApplet.stop(); | ||||
|  | ||||
|         active = false; | ||||
|     } | ||||
|  | ||||
|     public void destroy() | ||||
|     { | ||||
|     public void destroy() { | ||||
|         wrappedApplet.destroy(); | ||||
|     } | ||||
|  | ||||
| @@ -136,34 +110,34 @@ public class Launcher extends Applet implements AppletStub | ||||
|         } catch (MalformedURLException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public URL getDocumentBase() | ||||
|     { | ||||
|     public URL getDocumentBase() { | ||||
|         try { | ||||
|             // Special case only for Classic versions | ||||
|             if (wrappedApplet.getClass().getCanonicalName().startsWith("com.mojang")) { | ||||
|                 return new URL("http", "www.minecraft.net", 80, "/game/", null); | ||||
|             } | ||||
|             if (wrappedApplet.getClass().getCanonicalName().startsWith("com.mojang")) | ||||
|                 return new URL("http", "www.minecraft.net", 80, "/game/"); | ||||
|  | ||||
|             return new URL("http://www.minecraft.net/game/"); | ||||
|         } catch (MalformedURLException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void setVisible(boolean b) | ||||
|     { | ||||
|     public void setVisible(boolean b) { | ||||
|         super.setVisible(b); | ||||
|  | ||||
|         wrappedApplet.setVisible(b); | ||||
|     } | ||||
|     public void update(Graphics paramGraphics) | ||||
|     { | ||||
|     } | ||||
|     public void paint(Graphics paramGraphics) | ||||
|     { | ||||
|     } | ||||
| } | ||||
|  | ||||
|     public void update(Graphics paramGraphics) {} | ||||
|  | ||||
|     public void paint(Graphics paramGraphics) {} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,42 @@ | ||||
| package org.multimc;/* | ||||
|  * Copyright 2012-2021 MultiMC Contributors | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 icelimetea, <fr3shtea@outlook.com> | ||||
|  * | ||||
|  * 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 | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, version 3. | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  *  This program is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  * 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. | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * This file incorporates work covered by the following copyright and | ||||
|  * permission notice: | ||||
|  * | ||||
|  *      Copyright 2013-2021 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.onesix.OneSixLauncher; | ||||
| package org.multimc; | ||||
|  | ||||
| import org.multimc.exception.ParseException; | ||||
| import org.multimc.utils.Parameters; | ||||
|  | ||||
| import java.io.BufferedReader; | ||||
| import java.io.IOException; | ||||
| @@ -23,31 +45,25 @@ import java.nio.charset.StandardCharsets; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| public class EntryPoint | ||||
| { | ||||
| public final class EntryPoint { | ||||
|  | ||||
|     private static final Logger LOGGER = Logger.getLogger("EntryPoint"); | ||||
|  | ||||
|     private final ParamBucket params = new ParamBucket(); | ||||
|     private final Parameters params = new Parameters(); | ||||
|  | ||||
|     private org.multimc.Launcher launcher; | ||||
|  | ||||
|     public static void main(String[] args) | ||||
|     { | ||||
|     public static void main(String[] args) { | ||||
|         EntryPoint listener = new EntryPoint(); | ||||
|  | ||||
|         int retCode = listener.listen(); | ||||
|  | ||||
|         if (retCode != 0) | ||||
|         { | ||||
|         if (retCode != 0) { | ||||
|             LOGGER.info("Exiting with " + retCode); | ||||
|  | ||||
|             System.exit(retCode); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private Action parseLine(String inData) throws ParseException | ||||
|     { | ||||
|     private Action parseLine(String inData) throws ParseException { | ||||
|         String[] tokens = inData.split("\\s+", 2); | ||||
|  | ||||
|         if (tokens.length == 0) | ||||
| @@ -62,21 +78,6 @@ public class EntryPoint | ||||
|                 return Action.Abort; | ||||
|             } | ||||
|  | ||||
|             case "launcher": { | ||||
|                 if (tokens.length != 2) | ||||
|                     throw new ParseException("Expected 2 tokens, got " + tokens.length); | ||||
|  | ||||
|                 if (tokens[1].equals("onesix")) { | ||||
|                     launcher = new OneSixLauncher(); | ||||
|  | ||||
|                     LOGGER.info("Using onesix launcher."); | ||||
|  | ||||
|                     return Action.Proceed; | ||||
|                 } else { | ||||
|                     throw new ParseException("Invalid launcher type: " + tokens[1]); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             default: { | ||||
|                 if (tokens.length != 2) | ||||
|                     throw new ParseException("Error while parsing:" + inData); | ||||
| @@ -88,8 +89,7 @@ public class EntryPoint | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public int listen() | ||||
|     { | ||||
|     public int listen() { | ||||
|         Action action = Action.Proceed; | ||||
|  | ||||
|         try (BufferedReader reader = new BufferedReader(new InputStreamReader( | ||||
| @@ -112,21 +112,30 @@ public class EntryPoint | ||||
|         } | ||||
|  | ||||
|         // Main loop | ||||
|         if (action == Action.Abort) | ||||
|         { | ||||
|         if (action == Action.Abort) { | ||||
|             LOGGER.info("Launch aborted by the launcher."); | ||||
|  | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|         if (launcher != null) | ||||
|         { | ||||
|             return launcher.launch(params); | ||||
|         try { | ||||
|             Launcher launcher = | ||||
|                     LauncherFactory | ||||
|                             .getInstance() | ||||
|                             .createLauncher(params); | ||||
|  | ||||
|             launcher.launch(); | ||||
|  | ||||
|             return 0; | ||||
|         } catch (IllegalArgumentException e) { | ||||
|             LOGGER.log(Level.SEVERE, "Wrong argument.", e); | ||||
|  | ||||
|             return 1; | ||||
|         } catch (Exception e) { | ||||
|             LOGGER.log(Level.SEVERE, "Exception caught from launcher.", e); | ||||
|  | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|         LOGGER.log(Level.SEVERE, "No valid launcher implementation specified."); | ||||
|  | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     private enum Action { | ||||
|   | ||||
| @@ -16,7 +16,8 @@ | ||||
|  | ||||
| package org.multimc; | ||||
|  | ||||
| public interface Launcher | ||||
| { | ||||
|     int launch(ParamBucket params); | ||||
| public interface Launcher { | ||||
|  | ||||
|     void launch() throws Exception; | ||||
|  | ||||
| } | ||||
|   | ||||
							
								
								
									
										63
									
								
								libraries/launcher/org/multimc/LauncherFactory.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								libraries/launcher/org/multimc/LauncherFactory.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 icelimetea, <fr3shtea@outlook.com> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, version 3. | ||||
|  * | ||||
|  *  This program is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package org.multimc; | ||||
|  | ||||
| import org.multimc.impl.OneSixLauncher; | ||||
| import org.multimc.utils.Parameters; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| public final class LauncherFactory { | ||||
|  | ||||
|     private static final LauncherFactory INSTANCE = new LauncherFactory(); | ||||
|  | ||||
|     private final Map<String, LauncherProvider> launcherRegistry = new HashMap<>(); | ||||
|  | ||||
|     private LauncherFactory() { | ||||
|         launcherRegistry.put("onesix", new LauncherProvider() { | ||||
|             @Override | ||||
|             public Launcher provide(Parameters parameters) { | ||||
|                 return new OneSixLauncher(parameters); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     public Launcher createLauncher(Parameters parameters) { | ||||
|         String name = parameters.first("launcher"); | ||||
|  | ||||
|         LauncherProvider launcherProvider = launcherRegistry.get(name); | ||||
|  | ||||
|         if (launcherProvider == null) | ||||
|             throw new IllegalArgumentException("Invalid launcher type: " + name); | ||||
|  | ||||
|         return launcherProvider.provide(parameters); | ||||
|     } | ||||
|  | ||||
|     public static LauncherFactory getInstance() { | ||||
|         return INSTANCE; | ||||
|     } | ||||
|  | ||||
|     public interface LauncherProvider { | ||||
|  | ||||
|         Launcher provide(Parameters parameters); | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,176 +0,0 @@ | ||||
| package org.multimc;/* | ||||
|  * Copyright 2012-2021 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.FileInputStream; | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.IOException; | ||||
| import java.net.MalformedURLException; | ||||
| import java.net.URL; | ||||
| import java.util.Scanner; | ||||
|  | ||||
| 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, | ||||
|         int winSizeW, | ||||
|         int winSizeH, | ||||
|         boolean maximize, | ||||
|         String serverAddress, | ||||
|         String serverPort | ||||
|     ) | ||||
|     { | ||||
|         try { | ||||
|             appletWrap = new Launcher( mcApplet, new URL ( "http://www.minecraft.net/game" ) ); | ||||
|         } catch ( MalformedURLException ignored ) {} | ||||
|          | ||||
|         // Implements support for launching in to multiplayer on classic servers using a mpticket | ||||
|         // file generated by an external program and stored in the instance's root folder. | ||||
|         File mpticketFile = null; | ||||
|         Scanner fileReader = null; | ||||
|         try { | ||||
|             mpticketFile = new File(System.getProperty("user.dir") + "/../mpticket").getCanonicalFile(); | ||||
|             fileReader = new Scanner(new FileInputStream(mpticketFile), "ascii"); | ||||
|             String[] mpticketParams = new String[3]; | ||||
|              | ||||
|             for(int i=0;i<3;i++) { | ||||
|                 if(fileReader.hasNextLine()) { | ||||
|                     mpticketParams[i] = fileReader.nextLine(); | ||||
|                 } else { | ||||
|                     throw new IllegalArgumentException(); | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             // Assumes parameters are valid and in the correct order | ||||
|             appletWrap.setParameter("server", mpticketParams[0]); | ||||
|             appletWrap.setParameter("port", mpticketParams[1]); | ||||
|             appletWrap.setParameter("mppass", mpticketParams[2]); | ||||
|              | ||||
|             fileReader.close(); | ||||
|             mpticketFile.delete(); | ||||
|         } | ||||
|         catch (FileNotFoundException e) {} | ||||
|         catch (IllegalArgumentException e) { | ||||
|              | ||||
|             fileReader.close(); | ||||
|             File mpticketFileCorrupt = new File(System.getProperty("user.dir") + "/../mpticket.corrupt"); | ||||
|             if(mpticketFileCorrupt.exists()) { | ||||
|                 mpticketFileCorrupt.delete(); | ||||
|             } | ||||
|             mpticketFile.renameTo(mpticketFileCorrupt); | ||||
|              | ||||
|             System.err.println("Malformed mpticket file, missing argument."); | ||||
|             e.printStackTrace(System.err); | ||||
|             System.exit(-1); | ||||
|         } | ||||
|         catch (Exception e) { | ||||
|             e.printStackTrace(System.err); | ||||
|             System.exit(-1); | ||||
|         } | ||||
|  | ||||
|         if (serverAddress != null) | ||||
|         { | ||||
|             appletWrap.setParameter("server", serverAddress); | ||||
|             appletWrap.setParameter("port", serverPort); | ||||
|         } | ||||
|  | ||||
|         appletWrap.setParameter ( "username", user ); | ||||
|         appletWrap.setParameter ( "sessionid", session ); | ||||
|         appletWrap.setParameter ( "stand-alone", "true" ); // Show the quit button. | ||||
|         appletWrap.setParameter ( "haspaid", "true" ); // Some old versions need this for world saves to work. | ||||
|         appletWrap.setParameter ( "demo", "false" ); | ||||
|         appletWrap.setParameter ( "fullscreen", "false" ); | ||||
|         mcApplet.setStub(appletWrap); | ||||
|         this.add ( appletWrap ); | ||||
|         appletWrap.setPreferredSize ( new Dimension (winSizeW, winSizeH) ); | ||||
|         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 ) {} | ||||
| } | ||||
| @@ -1,86 +0,0 @@ | ||||
| /* | ||||
|  * Copyright 2012-2021 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.File; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Modifier; | ||||
| import java.util.List; | ||||
|  | ||||
| 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(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Finds a field that looks like a Minecraft base folder in a supplied class | ||||
|      * | ||||
|      * @param mc the class to scan | ||||
|      */ | ||||
|     public static Field getMCPathField(Class<?> mc) | ||||
|     { | ||||
|         Field[] fields = mc.getDeclaredFields(); | ||||
|  | ||||
|         for (Field f : fields) | ||||
|         { | ||||
|             if (f.getType() != File.class) | ||||
|             { | ||||
|                 // Has to be File | ||||
|                 continue; | ||||
|             } | ||||
|             if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC)) | ||||
|             { | ||||
|                 // And Private Static. | ||||
|                 continue; | ||||
|             } | ||||
|             return f; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
							
								
								
									
										162
									
								
								libraries/launcher/org/multimc/applet/LegacyFrame.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								libraries/launcher/org/multimc/applet/LegacyFrame.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| /* | ||||
|  * Copyright 2012-2021 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.applet; | ||||
|  | ||||
| import net.minecraft.Launcher; | ||||
|  | ||||
| import javax.imageio.ImageIO; | ||||
| import java.applet.Applet; | ||||
| import java.awt.*; | ||||
| import java.awt.event.WindowAdapter; | ||||
| import java.awt.event.WindowEvent; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.nio.file.Paths; | ||||
| import java.nio.file.StandardCopyOption; | ||||
| import java.util.List; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| public final class LegacyFrame extends Frame { | ||||
|  | ||||
|     private static final Logger LOGGER = Logger.getLogger("LegacyFrame"); | ||||
|  | ||||
|     private final Launcher appletWrap; | ||||
|  | ||||
|     public LegacyFrame(String title, Applet mcApplet) { | ||||
|         super(title); | ||||
|  | ||||
|         appletWrap = new Launcher(mcApplet); | ||||
|  | ||||
|         mcApplet.setStub(appletWrap); | ||||
|  | ||||
|         try { | ||||
|             setIconImage(ImageIO.read(new File("icon.png"))); | ||||
|         } catch (IOException e) { | ||||
|             LOGGER.log(Level.WARNING, "Unable to read Minecraft icon!", e); | ||||
|         } | ||||
|  | ||||
|         addWindowListener(new ForceExitHandler()); | ||||
|     } | ||||
|  | ||||
|     public void start ( | ||||
|         String user, | ||||
|         String session, | ||||
|         int winSizeW, | ||||
|         int winSizeH, | ||||
|         boolean maximize, | ||||
|         String serverAddress, | ||||
|         String serverPort | ||||
|     ) { | ||||
|         // Implements support for launching in to multiplayer on classic servers using a mpticket | ||||
|         // file generated by an external program and stored in the instance's root folder. | ||||
|  | ||||
|         Path mpticketFile = | ||||
|                 Paths.get(System.getProperty("user.dir"), "..", "mpticket"); | ||||
|  | ||||
|         Path mpticketFileCorrupt = | ||||
|                 Paths.get(System.getProperty("user.dir"), "..", "mpticket.corrupt"); | ||||
|  | ||||
|         if (Files.exists(mpticketFile)) { | ||||
|             try { | ||||
|                 List<String> lines = Files.readAllLines(mpticketFile, StandardCharsets.UTF_8); | ||||
|  | ||||
|                 if (lines.size() < 3) { | ||||
|                     Files.move( | ||||
|                             mpticketFile, | ||||
|                             mpticketFileCorrupt, | ||||
|                             StandardCopyOption.REPLACE_EXISTING | ||||
|                     ); | ||||
|  | ||||
|                     LOGGER.warning("Mpticket file is corrupted!"); | ||||
|                 } else { | ||||
|                     // Assumes parameters are valid and in the correct order | ||||
|                     appletWrap.setParameter("server", lines.get(0)); | ||||
|                     appletWrap.setParameter("port", lines.get(1)); | ||||
|                     appletWrap.setParameter("mppass", lines.get(2)); | ||||
|                 } | ||||
|             } catch (IOException e) { | ||||
|                 LOGGER.log(Level.WARNING, "Unable to read mpticket file!", e); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (serverAddress != null) { | ||||
|             appletWrap.setParameter("server", serverAddress); | ||||
|             appletWrap.setParameter("port", serverPort); | ||||
|         } | ||||
|  | ||||
|         appletWrap.setParameter("username", user); | ||||
|         appletWrap.setParameter("sessionid", session); | ||||
|         appletWrap.setParameter("stand-alone", "true"); // Show the quit button. | ||||
|         appletWrap.setParameter("haspaid", "true"); // Some old versions need this for world saves to work. | ||||
|         appletWrap.setParameter("demo", "false"); | ||||
|         appletWrap.setParameter("fullscreen", "false"); | ||||
|  | ||||
|         add(appletWrap); | ||||
|  | ||||
|         appletWrap.setPreferredSize(new Dimension(winSizeW, winSizeH)); | ||||
|  | ||||
|         pack(); | ||||
|  | ||||
|         setLocationRelativeTo(null); | ||||
|         setResizable(true); | ||||
|  | ||||
|         if (maximize) | ||||
|             this.setExtendedState(MAXIMIZED_BOTH); | ||||
|  | ||||
|         validate(); | ||||
|  | ||||
|         appletWrap.init(); | ||||
|         appletWrap.start(); | ||||
|  | ||||
|         setVisible(true); | ||||
|     } | ||||
|  | ||||
|     private final class ForceExitHandler extends WindowAdapter { | ||||
|  | ||||
|         @Override | ||||
|         public void windowClosing(WindowEvent e) { | ||||
|             new Thread(new Runnable() { | ||||
|                 @Override | ||||
|                 public void run() { | ||||
|                     try { | ||||
|                         Thread.sleep(30000L); | ||||
|                     } catch (InterruptedException localInterruptedException) { | ||||
|                         localInterruptedException.printStackTrace(); | ||||
|                     } | ||||
|  | ||||
|                     LOGGER.info("Forcing exit!"); | ||||
|  | ||||
|                     System.exit(0); | ||||
|                 } | ||||
|             }).start(); | ||||
|  | ||||
|             if (appletWrap != null) { | ||||
|                 appletWrap.stop(); | ||||
|                 appletWrap.destroy(); | ||||
|             } | ||||
|  | ||||
|             // old minecraft versions can hang without this >_< | ||||
|             System.exit(0); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -14,8 +14,12 @@ | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.multimc; | ||||
| package org.multimc.exception; | ||||
| 
 | ||||
| public final class ParameterNotFoundException extends IllegalArgumentException { | ||||
| 
 | ||||
|     public ParameterNotFoundException(String key) { | ||||
|         super("Unknown parameter name: " + key); | ||||
|     } | ||||
| 
 | ||||
| public class NotFoundException extends Exception | ||||
| { | ||||
| } | ||||
| @@ -14,12 +14,12 @@ | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.multimc; | ||||
| package org.multimc.exception; | ||||
| 
 | ||||
| public final class ParseException extends IllegalArgumentException { | ||||
| 
 | ||||
| public class ParseException extends java.lang.Exception | ||||
| { | ||||
|     public ParseException() { super(); } | ||||
|     public ParseException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										189
									
								
								libraries/launcher/org/multimc/impl/OneSixLauncher.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								libraries/launcher/org/multimc/impl/OneSixLauncher.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,189 @@ | ||||
| /* Copyright 2012-2021 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.impl; | ||||
|  | ||||
| import org.multimc.Launcher; | ||||
| import org.multimc.applet.LegacyFrame; | ||||
| import org.multimc.utils.Parameters; | ||||
| import org.multimc.utils.Utils; | ||||
|  | ||||
| import java.applet.Applet; | ||||
| import java.io.File; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Method; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| public final class OneSixLauncher implements Launcher { | ||||
|  | ||||
|     private static final int DEFAULT_WINDOW_WIDTH = 854; | ||||
|     private static final int DEFAULT_WINDOW_HEIGHT = 480; | ||||
|  | ||||
|     private static final Logger LOGGER = Logger.getLogger("OneSixLauncher"); | ||||
|  | ||||
|     // parameters, separated from ParamBucket | ||||
|     private final List<String> mcParams; | ||||
|     private final List<String> traits; | ||||
|     private final String appletClass; | ||||
|     private final String mainClass; | ||||
|     private final String userName, sessionId; | ||||
|     private final String windowTitle; | ||||
|  | ||||
|     // secondary parameters | ||||
|     private final int winSizeW; | ||||
|     private final int winSizeH; | ||||
|     private final boolean maximize; | ||||
|     private final String cwd; | ||||
|  | ||||
|     private final String serverAddress; | ||||
|     private final String serverPort; | ||||
|  | ||||
|     private final ClassLoader classLoader; | ||||
|  | ||||
|     public OneSixLauncher(Parameters params) { | ||||
|         classLoader = ClassLoader.getSystemClassLoader(); | ||||
|  | ||||
|         mcParams = params.allSafe("param", Collections.<String>emptyList()); | ||||
|         mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft"); | ||||
|         appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet"); | ||||
|         traits = params.allSafe("traits", Collections.<String>emptyList()); | ||||
|  | ||||
|         userName = params.first("userName"); | ||||
|         sessionId = params.first("sessionId"); | ||||
|         windowTitle = params.firstSafe("windowTitle", "Minecraft"); | ||||
|  | ||||
|         serverAddress = params.firstSafe("serverAddress", null); | ||||
|         serverPort = params.firstSafe("serverPort", null); | ||||
|  | ||||
|         cwd = System.getProperty("user.dir"); | ||||
|  | ||||
|         String windowParams = params.firstSafe("windowParams", null); | ||||
|  | ||||
|         if (windowParams != null) { | ||||
|             String[] dimStrings = windowParams.split("x"); | ||||
|  | ||||
|             if (windowParams.equalsIgnoreCase("max")) { | ||||
|                 maximize = true; | ||||
|  | ||||
|                 winSizeW = DEFAULT_WINDOW_WIDTH; | ||||
|                 winSizeH = DEFAULT_WINDOW_HEIGHT; | ||||
|             } else if (dimStrings.length == 2) { | ||||
|                 maximize = false; | ||||
|  | ||||
|                 winSizeW = Integer.parseInt(dimStrings[0]); | ||||
|                 winSizeH = Integer.parseInt(dimStrings[1]); | ||||
|             } else { | ||||
|                 throw new IllegalArgumentException("Unexpected window size parameter value: " + windowParams); | ||||
|             } | ||||
|         } else { | ||||
|             maximize = false; | ||||
|  | ||||
|             winSizeW = DEFAULT_WINDOW_WIDTH; | ||||
|             winSizeH = DEFAULT_WINDOW_HEIGHT; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void invokeMain(Class<?> mainClass) throws Exception { | ||||
|         Method method = mainClass.getMethod("main", String[].class); | ||||
|  | ||||
|         method.invoke(null, (Object) mcParams.toArray(new String[0])); | ||||
|     } | ||||
|  | ||||
|     private void legacyLaunch() throws Exception { | ||||
|         // Get the Minecraft Class and set the base folder | ||||
|         Class<?> minecraftClass = classLoader.loadClass(mainClass); | ||||
|  | ||||
|         Field baseDirField = Utils.getMinecraftBaseDirField(minecraftClass); | ||||
|  | ||||
|         if (baseDirField == null) { | ||||
|             LOGGER.warning("Could not find Minecraft path field."); | ||||
|         } else { | ||||
|             baseDirField.setAccessible(true); | ||||
|  | ||||
|             baseDirField.set(null, new File(cwd)); | ||||
|         } | ||||
|  | ||||
|         System.setProperty("minecraft.applet.TargetDirectory", cwd); | ||||
|  | ||||
|         if (!traits.contains("noapplet")) { | ||||
|             LOGGER.info("Launching with applet wrapper..."); | ||||
|  | ||||
|             try { | ||||
|                 Class<?> mcAppletClass = classLoader.loadClass(appletClass); | ||||
|  | ||||
|                 Applet mcApplet = (Applet) mcAppletClass.getConstructor().newInstance(); | ||||
|  | ||||
|                 LegacyFrame mcWindow = new LegacyFrame(windowTitle, mcApplet); | ||||
|  | ||||
|                 mcWindow.start( | ||||
|                         userName, | ||||
|                         sessionId, | ||||
|                         winSizeW, | ||||
|                         winSizeH, | ||||
|                         maximize, | ||||
|                         serverAddress, | ||||
|                         serverPort | ||||
|                 ); | ||||
|  | ||||
|                 return; | ||||
|             } catch (Exception e) { | ||||
|                 LOGGER.log(Level.SEVERE, "Applet wrapper failed: ", e); | ||||
|  | ||||
|                 LOGGER.warning("Falling back to using main class."); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         invokeMain(minecraftClass); | ||||
|     } | ||||
|  | ||||
|     private void launchWithMainClass() throws Exception { | ||||
|         // window size, title and state, onesix | ||||
|  | ||||
|         // FIXME: there is no good way to maximize the minecraft window in onesix. | ||||
|         // the following often breaks linux screen setups | ||||
|         // mcparams.add("--fullscreen"); | ||||
|  | ||||
|         if (!maximize) { | ||||
|             mcParams.add("--width"); | ||||
|             mcParams.add(Integer.toString(winSizeW)); | ||||
|             mcParams.add("--height"); | ||||
|             mcParams.add(Integer.toString(winSizeH)); | ||||
|         } | ||||
|  | ||||
|         if (serverAddress != null) { | ||||
|             mcParams.add("--server"); | ||||
|             mcParams.add(serverAddress); | ||||
|             mcParams.add("--port"); | ||||
|             mcParams.add(serverPort); | ||||
|         } | ||||
|  | ||||
|         invokeMain(classLoader.loadClass(mainClass)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void launch() throws Exception { | ||||
|         if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch")) { | ||||
|             // legacy launch uses the applet wrapper | ||||
|             legacyLaunch(); | ||||
|         } else { | ||||
|             // normal launch just calls main() | ||||
|             launchWithMainClass(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,256 +0,0 @@ | ||||
| /* Copyright 2012-2021 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.lang.reflect.Field; | ||||
| import java.lang.reflect.Method; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| public class OneSixLauncher implements Launcher | ||||
| { | ||||
|  | ||||
|     private static final Logger LOGGER = Logger.getLogger("OneSixLauncher"); | ||||
|  | ||||
|     // parameters, separated from ParamBucket | ||||
|     private List<String> libraries; | ||||
|     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 int winSizeW; | ||||
|     private int winSizeH; | ||||
|     private boolean maximize; | ||||
|     private String cwd; | ||||
|  | ||||
|     private String serverAddress; | ||||
|     private String serverPort; | ||||
|  | ||||
|     // the much abused system classloader, for convenience (for further abuse) | ||||
|     private ClassLoader cl; | ||||
|  | ||||
|     private void processParams(ParamBucket params) throws NotFoundException | ||||
|     { | ||||
|         libraries = params.all("cp"); | ||||
|         mcparams = params.allSafe("param", new ArrayList<String>() ); | ||||
|         mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft"); | ||||
|         appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet"); | ||||
|         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"); | ||||
|  | ||||
|         serverAddress = params.firstSafe("serverAddress", null); | ||||
|         serverPort = params.firstSafe("serverPort", null); | ||||
|  | ||||
|         cwd = System.getProperty("user.dir"); | ||||
|  | ||||
|         winSizeW = 854; | ||||
|         winSizeH = 480; | ||||
|         maximize = false; | ||||
|  | ||||
|         String[] dimStrings = windowParams.split("x"); | ||||
|  | ||||
|         if (windowParams.equalsIgnoreCase("max")) | ||||
|         { | ||||
|             maximize = true; | ||||
|         } | ||||
|         else if (dimStrings.length == 2) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 winSizeW = Integer.parseInt(dimStrings[0]); | ||||
|                 winSizeH = Integer.parseInt(dimStrings[1]); | ||||
|             } catch (NumberFormatException ignored) {} | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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) | ||||
|             { | ||||
|                 LOGGER.warning("Could not find Minecraft path field."); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 f.setAccessible(true); | ||||
|                 f.set(null, new File(cwd)); | ||||
|             } | ||||
|         } catch (Exception e) | ||||
|         { | ||||
|             LOGGER.log( | ||||
|                     Level.SEVERE, | ||||
|                     "Could not set base folder. Failed to find/access Minecraft main class:", | ||||
|                     e | ||||
|             ); | ||||
|  | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         System.setProperty("minecraft.applet.TargetDirectory", cwd); | ||||
|  | ||||
|         if(!traits.contains("noapplet")) | ||||
|         { | ||||
|             LOGGER.info("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, winSizeW, winSizeH, maximize, serverAddress, serverPort); | ||||
|                 return 0; | ||||
|             } catch (Exception e) | ||||
|             { | ||||
|                 LOGGER.log(Level.SEVERE, "Applet wrapper failed:", e); | ||||
|  | ||||
|                 LOGGER.warning("Falling back to using main class."); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // init params for the main method to chomp on. | ||||
|         String[] paramsArray = mcparams.toArray(new String[mcparams.size()]); | ||||
|         try | ||||
|         { | ||||
|             mc.getMethod("main", String[].class).invoke(null, (Object) paramsArray); | ||||
|             return 0; | ||||
|         } catch (Exception e) | ||||
|         { | ||||
|             LOGGER.log(Level.SEVERE, "Failed to invoke the Minecraft main class:", e); | ||||
|  | ||||
|             return -1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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(winSizeW)); | ||||
|             mcparams.add("--height"); | ||||
|             mcparams.add(Integer.toString(winSizeH)); | ||||
|         } | ||||
|  | ||||
|         if (serverAddress != null) | ||||
|         { | ||||
|             mcparams.add("--server"); | ||||
|             mcparams.add(serverAddress); | ||||
|             mcparams.add("--port"); | ||||
|             mcparams.add(serverPort); | ||||
|         } | ||||
|  | ||||
|         // Get the Minecraft Class. | ||||
|         Class<?> mc; | ||||
|         try | ||||
|         { | ||||
|             mc = cl.loadClass(mainClass); | ||||
|         } catch (ClassNotFoundException e) | ||||
|         { | ||||
|             LOGGER.log(Level.SEVERE, "Failed to find Minecraft main class:", e); | ||||
|  | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         // get the main method. | ||||
|         Method meth; | ||||
|         try | ||||
|         { | ||||
|             meth = mc.getMethod("main", String[].class); | ||||
|         } catch (NoSuchMethodException e) | ||||
|         { | ||||
|             LOGGER.log(Level.SEVERE, "Failed to acquire the main method:", e); | ||||
|  | ||||
|             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) | ||||
|         { | ||||
|             LOGGER.log(Level.SEVERE, "Failed to start Minecraft:", e); | ||||
|  | ||||
|             return -1; | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int launch(ParamBucket params) | ||||
|     { | ||||
|         // get and process the launch script params | ||||
|         try | ||||
|         { | ||||
|             processParams(params); | ||||
|         } catch (NotFoundException e) | ||||
|         { | ||||
|             LOGGER.log(Level.SEVERE, "Not enough arguments!"); | ||||
|  | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         // 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(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -14,36 +14,41 @@ | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.multimc; | ||||
| package org.multimc.utils; | ||||
| 
 | ||||
| import org.multimc.exception.ParameterNotFoundException; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class ParamBucket | ||||
| { | ||||
| public final class Parameters { | ||||
| 
 | ||||
|     private final Map<String, List<String>> paramsMap = new HashMap<>(); | ||||
| 
 | ||||
|     public void add(String key, String value) | ||||
|     { | ||||
|         paramsMap.computeIfAbsent(key, k -> new ArrayList<>()) | ||||
|                 .add(value); | ||||
|     public void add(String key, String value) { | ||||
|         List<String> params = paramsMap.get(key); | ||||
| 
 | ||||
|         if (params == null) { | ||||
|             params = new ArrayList<>(); | ||||
| 
 | ||||
|             paramsMap.put(key, params); | ||||
|         } | ||||
| 
 | ||||
|         params.add(value); | ||||
|     } | ||||
| 
 | ||||
|     public List<String> all(String key) throws NotFoundException | ||||
|     { | ||||
|     public List<String> all(String key) throws ParameterNotFoundException { | ||||
|         List<String> params = paramsMap.get(key); | ||||
| 
 | ||||
|         if (params == null) | ||||
|             throw new NotFoundException(); | ||||
|             throw new ParameterNotFoundException(key); | ||||
| 
 | ||||
|         return params; | ||||
|     } | ||||
| 
 | ||||
|     public List<String> allSafe(String key, List<String> def) | ||||
|     { | ||||
|     public List<String> allSafe(String key, List<String> def) { | ||||
|         List<String> params = paramsMap.get(key); | ||||
| 
 | ||||
|         if (params == null || params.isEmpty()) | ||||
| @@ -52,23 +57,16 @@ public class ParamBucket | ||||
|         return params; | ||||
|     } | ||||
| 
 | ||||
|     public List<String> allSafe(String key) | ||||
|     { | ||||
|         return allSafe(key, new ArrayList<>()); | ||||
|     } | ||||
| 
 | ||||
|     public String first(String key) throws NotFoundException | ||||
|     { | ||||
|     public String first(String key) throws ParameterNotFoundException { | ||||
|         List<String> list = all(key); | ||||
| 
 | ||||
|         if (list.isEmpty()) | ||||
|             throw new NotFoundException(); | ||||
|             throw new ParameterNotFoundException(key); | ||||
| 
 | ||||
|         return list.get(0); | ||||
|     } | ||||
| 
 | ||||
|     public String firstSafe(String key, String def) | ||||
|     { | ||||
|     public String firstSafe(String key, String def) { | ||||
|         List<String> params = paramsMap.get(key); | ||||
| 
 | ||||
|         if (params == null || params.isEmpty()) | ||||
| @@ -77,9 +75,4 @@ public class ParamBucket | ||||
|         return params.get(0); | ||||
|     } | ||||
| 
 | ||||
|     public String firstSafe(String key) | ||||
|     { | ||||
|         return firstSafe(key, ""); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										49
									
								
								libraries/launcher/org/multimc/utils/Utils.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								libraries/launcher/org/multimc/utils/Utils.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| /* | ||||
|  * Copyright 2012-2021 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.utils; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Modifier; | ||||
|  | ||||
| public final class Utils { | ||||
|  | ||||
|     private Utils() {} | ||||
|  | ||||
|     /** | ||||
|      * Finds a field that looks like a Minecraft base folder in a supplied class | ||||
|      * | ||||
|      * @param clazz the class to scan | ||||
|      */ | ||||
|     public static Field getMinecraftBaseDirField(Class<?> clazz) { | ||||
|         for (Field f : clazz.getDeclaredFields()) { | ||||
|             // Has to be File | ||||
|             if (f.getType() != File.class) | ||||
|                 continue; | ||||
|  | ||||
|             // And Private Static. | ||||
|             if (!Modifier.isStatic(f.getModifiers()) || !Modifier.isPrivate(f.getModifiers())) | ||||
|                 continue; | ||||
|  | ||||
|             return f; | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user