Merge pull request #520 from icelimetea/refactor-java-launcher-v2
This commit is contained in:
commit
2646ae29f0
@ -4,17 +4,18 @@ find_package(Java 1.7 REQUIRED COMPONENTS Development)
|
|||||||
|
|
||||||
include(UseJava)
|
include(UseJava)
|
||||||
set(CMAKE_JAVA_JAR_ENTRY_POINT org.multimc.EntryPoint)
|
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
|
set(SRC
|
||||||
org/multimc/EntryPoint.java
|
org/multimc/EntryPoint.java
|
||||||
org/multimc/Launcher.java
|
org/multimc/Launcher.java
|
||||||
org/multimc/LegacyFrame.java
|
org/multimc/LauncherFactory.java
|
||||||
org/multimc/NotFoundException.java
|
org/multimc/impl/OneSixLauncher.java
|
||||||
org/multimc/ParamBucket.java
|
org/multimc/applet/LegacyFrame.java
|
||||||
org/multimc/ParseException.java
|
org/multimc/exception/ParameterNotFoundException.java
|
||||||
org/multimc/Utils.java
|
org/multimc/exception/ParseException.java
|
||||||
org/multimc/onesix/OneSixLauncher.java
|
org/multimc/utils/Parameters.java
|
||||||
|
org/multimc/utils/Utils.java
|
||||||
net/minecraft/Launcher.java
|
net/minecraft/Launcher.java
|
||||||
)
|
)
|
||||||
add_jar(NewLaunch ${SRC})
|
add_jar(NewLaunch ${SRC})
|
||||||
|
@ -16,31 +16,28 @@
|
|||||||
|
|
||||||
package net.minecraft;
|
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.Applet;
|
||||||
import java.applet.AppletStub;
|
import java.applet.AppletStub;
|
||||||
|
import java.awt.*;
|
||||||
import java.net.MalformedURLException;
|
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 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.setLayout(new BorderLayout());
|
||||||
|
|
||||||
this.add(applet, "Center");
|
this.add(applet, "Center");
|
||||||
|
|
||||||
this.wrappedApplet = applet;
|
this.wrappedApplet = applet;
|
||||||
this.documentBase = documentBase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParameter(String name, String value)
|
public void setParameter(String name, String value)
|
||||||
@ -48,84 +45,61 @@ public class Launcher extends Applet implements AppletStub
|
|||||||
params.put(name, value);
|
params.put(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replace(Applet applet)
|
|
||||||
{
|
|
||||||
this.wrappedApplet = applet;
|
|
||||||
|
|
||||||
applet.setStub(this);
|
|
||||||
applet.setSize(getWidth(), getHeight());
|
|
||||||
|
|
||||||
this.setLayout(new BorderLayout());
|
|
||||||
this.add(applet, "Center");
|
|
||||||
|
|
||||||
applet.init();
|
|
||||||
active = true;
|
|
||||||
applet.start();
|
|
||||||
validate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getParameter(String name)
|
public String getParameter(String name) {
|
||||||
{
|
|
||||||
String param = params.get(name);
|
String param = params.get(name);
|
||||||
|
|
||||||
if (param != null)
|
if (param != null)
|
||||||
return param;
|
return param;
|
||||||
try
|
|
||||||
{
|
try {
|
||||||
return super.getParameter(name);
|
return super.getParameter(name);
|
||||||
} catch (Exception ignore) {}
|
} catch (Exception ignore) {}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isActive()
|
public boolean isActive() {
|
||||||
{
|
|
||||||
return active;
|
return active;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appletResize(int width, int height)
|
public void appletResize(int width, int height) {
|
||||||
{
|
|
||||||
wrappedApplet.resize(width, height);
|
wrappedApplet.resize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resize(int width, int height)
|
public void resize(int width, int height) {
|
||||||
{
|
|
||||||
wrappedApplet.resize(width, height);
|
wrappedApplet.resize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resize(Dimension d)
|
public void resize(Dimension d) {
|
||||||
{
|
|
||||||
wrappedApplet.resize(d);
|
wrappedApplet.resize(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init()
|
public void init() {
|
||||||
{
|
|
||||||
if (wrappedApplet != null)
|
if (wrappedApplet != null)
|
||||||
{
|
|
||||||
wrappedApplet.init();
|
wrappedApplet.init();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start()
|
public void start() {
|
||||||
{
|
|
||||||
wrappedApplet.start();
|
wrappedApplet.start();
|
||||||
|
|
||||||
active = true;
|
active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop()
|
public void stop() {
|
||||||
{
|
|
||||||
wrappedApplet.stop();
|
wrappedApplet.stop();
|
||||||
|
|
||||||
active = false;
|
active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy()
|
public void destroy() {
|
||||||
{
|
|
||||||
wrappedApplet.destroy();
|
wrappedApplet.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,34 +110,34 @@ public class Launcher extends Applet implements AppletStub
|
|||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getDocumentBase()
|
public URL getDocumentBase() {
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
// Special case only for Classic versions
|
// Special case only for Classic versions
|
||||||
if (wrappedApplet.getClass().getCanonicalName().startsWith("com.mojang")) {
|
if (wrappedApplet.getClass().getCanonicalName().startsWith("com.mojang"))
|
||||||
return new URL("http", "www.minecraft.net", 80, "/game/", null);
|
return new URL("http", "www.minecraft.net", 80, "/game/");
|
||||||
}
|
|
||||||
return new URL("http://www.minecraft.net/game/");
|
return new URL("http://www.minecraft.net/game/");
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setVisible(boolean b)
|
public void setVisible(boolean b) {
|
||||||
{
|
|
||||||
super.setVisible(b);
|
super.setVisible(b);
|
||||||
|
|
||||||
wrappedApplet.setVisible(b);
|
wrappedApplet.setVisible(b);
|
||||||
}
|
}
|
||||||
public void update(Graphics paramGraphics)
|
|
||||||
{
|
public void update(Graphics paramGraphics) {}
|
||||||
}
|
|
||||||
public void paint(Graphics paramGraphics)
|
public void paint(Graphics paramGraphics) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,5 +1,24 @@
|
|||||||
package org.multimc;/*
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
* Copyright 2012-2021 MultiMC Contributors
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -14,7 +33,10 @@ package org.multimc;/*
|
|||||||
* limitations under the License.
|
* 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.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -23,31 +45,25 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class EntryPoint
|
public final class EntryPoint {
|
||||||
{
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger("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();
|
EntryPoint listener = new EntryPoint();
|
||||||
|
|
||||||
int retCode = listener.listen();
|
int retCode = listener.listen();
|
||||||
|
|
||||||
if (retCode != 0)
|
if (retCode != 0) {
|
||||||
{
|
|
||||||
LOGGER.info("Exiting with " + retCode);
|
LOGGER.info("Exiting with " + retCode);
|
||||||
|
|
||||||
System.exit(retCode);
|
System.exit(retCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Action parseLine(String inData) throws ParseException
|
private Action parseLine(String inData) throws ParseException {
|
||||||
{
|
|
||||||
String[] tokens = inData.split("\\s+", 2);
|
String[] tokens = inData.split("\\s+", 2);
|
||||||
|
|
||||||
if (tokens.length == 0)
|
if (tokens.length == 0)
|
||||||
@ -62,21 +78,6 @@ public class EntryPoint
|
|||||||
return Action.Abort;
|
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: {
|
default: {
|
||||||
if (tokens.length != 2)
|
if (tokens.length != 2)
|
||||||
throw new ParseException("Error while parsing:" + inData);
|
throw new ParseException("Error while parsing:" + inData);
|
||||||
@ -88,8 +89,7 @@ public class EntryPoint
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int listen()
|
public int listen() {
|
||||||
{
|
|
||||||
Action action = Action.Proceed;
|
Action action = Action.Proceed;
|
||||||
|
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
@ -112,21 +112,30 @@ public class EntryPoint
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
if (action == Action.Abort)
|
if (action == Action.Abort) {
|
||||||
{
|
|
||||||
LOGGER.info("Launch aborted by the launcher.");
|
LOGGER.info("Launch aborted by the launcher.");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (launcher != null)
|
try {
|
||||||
{
|
Launcher launcher =
|
||||||
return launcher.launch(params);
|
LauncherFactory
|
||||||
}
|
.getInstance()
|
||||||
|
.createLauncher(params);
|
||||||
|
|
||||||
LOGGER.log(Level.SEVERE, "No valid launcher implementation specified.");
|
launcher.launch();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Wrong argument.", e);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Exception caught from launcher.", e);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum Action {
|
private enum Action {
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
|
|
||||||
package org.multimc;
|
package org.multimc;
|
||||||
|
|
||||||
public interface Launcher
|
public interface Launcher {
|
||||||
{
|
|
||||||
int launch(ParamBucket params);
|
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.
|
* 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.
|
* 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) {
|
public ParseException(String message) {
|
||||||
super(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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.multimc;
|
package org.multimc.utils;
|
||||||
|
|
||||||
|
import org.multimc.exception.ParameterNotFoundException;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ParamBucket
|
public final class Parameters {
|
||||||
{
|
|
||||||
|
|
||||||
private final Map<String, List<String>> paramsMap = new HashMap<>();
|
private final Map<String, List<String>> paramsMap = new HashMap<>();
|
||||||
|
|
||||||
public void add(String key, String value)
|
public void add(String key, String value) {
|
||||||
{
|
List<String> params = paramsMap.get(key);
|
||||||
paramsMap.computeIfAbsent(key, k -> new ArrayList<>())
|
|
||||||
.add(value);
|
if (params == null) {
|
||||||
|
params = new ArrayList<>();
|
||||||
|
|
||||||
|
paramsMap.put(key, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> all(String key) throws NotFoundException
|
params.add(value);
|
||||||
{
|
}
|
||||||
|
|
||||||
|
public List<String> all(String key) throws ParameterNotFoundException {
|
||||||
List<String> params = paramsMap.get(key);
|
List<String> params = paramsMap.get(key);
|
||||||
|
|
||||||
if (params == null)
|
if (params == null)
|
||||||
throw new NotFoundException();
|
throw new ParameterNotFoundException(key);
|
||||||
|
|
||||||
return params;
|
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);
|
List<String> params = paramsMap.get(key);
|
||||||
|
|
||||||
if (params == null || params.isEmpty())
|
if (params == null || params.isEmpty())
|
||||||
@ -52,23 +57,16 @@ public class ParamBucket
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> allSafe(String key)
|
public String first(String key) throws ParameterNotFoundException {
|
||||||
{
|
|
||||||
return allSafe(key, new ArrayList<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String first(String key) throws NotFoundException
|
|
||||||
{
|
|
||||||
List<String> list = all(key);
|
List<String> list = all(key);
|
||||||
|
|
||||||
if (list.isEmpty())
|
if (list.isEmpty())
|
||||||
throw new NotFoundException();
|
throw new ParameterNotFoundException(key);
|
||||||
|
|
||||||
return list.get(0);
|
return list.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String firstSafe(String key, String def)
|
public String firstSafe(String key, String def) {
|
||||||
{
|
|
||||||
List<String> params = paramsMap.get(key);
|
List<String> params = paramsMap.get(key);
|
||||||
|
|
||||||
if (params == null || params.isEmpty())
|
if (params == null || params.isEmpty())
|
||||||
@ -77,9 +75,4 @@ public class ParamBucket
|
|||||||
return params.get(0);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user