summaryrefslogtreecommitdiff
path: root/meshmc/libraries/launcher
diff options
context:
space:
mode:
Diffstat (limited to 'meshmc/libraries/launcher')
-rw-r--r--meshmc/libraries/launcher/.gitignore6
-rw-r--r--meshmc/libraries/launcher/CMakeLists.txt22
-rw-r--r--meshmc/libraries/launcher/net/minecraft/MeshMC.java208
-rw-r--r--meshmc/libraries/launcher/org/projecttick/EntryPoint.java200
-rw-r--r--meshmc/libraries/launcher/org/projecttick/LegacyFrame.java217
-rw-r--r--meshmc/libraries/launcher/org/projecttick/MeshMC.java61
-rw-r--r--meshmc/libraries/launcher/org/projecttick/NotFoundException.java60
-rw-r--r--meshmc/libraries/launcher/org/projecttick/ParamBucket.java125
-rw-r--r--meshmc/libraries/launcher/org/projecttick/ParseException.java64
-rw-r--r--meshmc/libraries/launcher/org/projecttick/Utils.java158
-rw-r--r--meshmc/libraries/launcher/org/projecttick/modern/ModernLauncher.java309
-rw-r--r--meshmc/libraries/launcher/org/projecttick/onesix/OneSixLauncher.java288
12 files changed, 1718 insertions, 0 deletions
diff --git a/meshmc/libraries/launcher/.gitignore b/meshmc/libraries/launcher/.gitignore
new file mode 100644
index 0000000000..cc1c52bf4d
--- /dev/null
+++ b/meshmc/libraries/launcher/.gitignore
@@ -0,0 +1,6 @@
+.idea
+*.iml
+out
+.classpath
+.idea
+.project
diff --git a/meshmc/libraries/launcher/CMakeLists.txt b/meshmc/libraries/launcher/CMakeLists.txt
new file mode 100644
index 0000000000..860776385f
--- /dev/null
+++ b/meshmc/libraries/launcher/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.25)
+project(launcher Java)
+find_package(Java 1.7 REQUIRED COMPONENTS Development)
+
+include(UseJava)
+set(CMAKE_JAVA_JAR_ENTRY_POINT org.projecttick.EntryPoint)
+set(CMAKE_JAVA_COMPILE_FLAGS -target 7 -source 7 -Xlint:deprecation -Xlint:unchecked)
+
+set(SRC
+ org/projecttick/EntryPoint.java
+ org/projecttick/MeshMC.java
+ org/projecttick/LegacyFrame.java
+ org/projecttick/NotFoundException.java
+ org/projecttick/ParamBucket.java
+ org/projecttick/ParseException.java
+ org/projecttick/Utils.java
+ org/projecttick/onesix/OneSixLauncher.java
+ org/projecttick/modern/ModernLauncher.java
+ net/minecraft/MeshMC.java
+)
+add_jar(NewLaunch ${SRC})
+install_jar(NewLaunch "${JARS_DEST_DIR}")
diff --git a/meshmc/libraries/launcher/net/minecraft/MeshMC.java b/meshmc/libraries/launcher/net/minecraft/MeshMC.java
new file mode 100644
index 0000000000..0d4da46d70
--- /dev/null
+++ b/meshmc/libraries/launcher/net/minecraft/MeshMC.java
@@ -0,0 +1,208 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library. Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give
+ * you permission to link this library with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also meet,
+ * for each linked independent module, the terms and conditions of the
+ * license of that module. An independent module is a module which is
+ * not derived from or based on this library. If you modify this
+ * library, you may extend this exception to your version of the
+ * library, but you are not obliged to do so. If you do not wish to do
+ * so, delete this exception statement from your version.
+ *
+ * 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 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 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.net.MalformedURLException;
+
+public class MeshMC extends Applet implements AppletStub
+{
+ private Applet wrappedApplet;
+ private URL documentBase;
+ private boolean active = false;
+ private final Map<String, String> params;
+
+ public MeshMC(Applet applet, URL documentBase)
+ {
+ params = new TreeMap<String, String>();
+
+ this.setLayout(new BorderLayout());
+ this.add(applet, "Center");
+ this.wrappedApplet = applet;
+ this.documentBase = documentBase;
+ }
+
+ public void setParameter(String name, String 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
+ public String getParameter(String name)
+ {
+ String param = params.get(name);
+ if (param != null)
+ return param;
+ try
+ {
+ return super.getParameter(name);
+ } catch (Exception ignore){}
+ return null;
+ }
+
+ @Override
+ public boolean isActive()
+ {
+ return active;
+ }
+
+ @Override
+ public void appletResize(int width, int height)
+ {
+ wrappedApplet.resize(width, height);
+ }
+
+ @Override
+ public void resize(int width, int height)
+ {
+ wrappedApplet.resize(width, height);
+ }
+
+ @Override
+ public void resize(Dimension d)
+ {
+ wrappedApplet.resize(d);
+ }
+
+ @Override
+ public void init()
+ {
+ if (wrappedApplet != null)
+ {
+ wrappedApplet.init();
+ }
+ }
+
+ @Override
+ public void start()
+ {
+ wrappedApplet.start();
+ active = true;
+ }
+
+ @Override
+ public void stop()
+ {
+ wrappedApplet.stop();
+ active = false;
+ }
+
+ public void destroy()
+ {
+ wrappedApplet.destroy();
+ }
+
+ @Override
+ public URL getCodeBase() {
+ try {
+ return new URL("http://www.minecraft.net/game/");
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ 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);
+ }
+ return new URL("http://www.minecraft.net/game/");
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public void setVisible(boolean b)
+ {
+ super.setVisible(b);
+ wrappedApplet.setVisible(b);
+ }
+ public void update(Graphics paramGraphics)
+ {
+ }
+ public void paint(Graphics paramGraphics)
+ {
+ }
+} \ No newline at end of file
diff --git a/meshmc/libraries/launcher/org/projecttick/EntryPoint.java b/meshmc/libraries/launcher/org/projecttick/EntryPoint.java
new file mode 100644
index 0000000000..ca0c63f22d
--- /dev/null
+++ b/meshmc/libraries/launcher/org/projecttick/EntryPoint.java
@@ -0,0 +1,200 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library. Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give
+ * you permission to link this library with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also meet,
+ * for each linked independent module, the terms and conditions of the
+ * license of that module. An independent module is a module which is
+ * not derived from or based on this library. If you modify this
+ * library, you may extend this exception to your version of the
+ * library, but you are not obliged to do so. If you do not wish to do
+ * so, delete this exception statement from your version.
+ *
+ * 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 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.projecttick;
+
+import org.projecttick.modern.ModernLauncher;
+import org.projecttick.onesix.OneSixLauncher;
+
+import java.io.*;
+import java.nio.charset.Charset;
+
+public class EntryPoint
+{
+ private enum Action
+ {
+ Proceed,
+ Launch,
+ Abort
+ }
+
+ public static void main(String[] args)
+ {
+ EntryPoint listener = new EntryPoint();
+ int retCode = listener.listen();
+ if (retCode != 0)
+ {
+ System.out.println("Exiting with " + retCode);
+ System.exit(retCode);
+ }
+ }
+
+ private Action parseLine(String inData) throws ParseException
+ {
+ String[] pair = inData.split(" ", 2);
+
+ if(pair.length == 1)
+ {
+ String command = pair[0];
+ if (pair[0].equals("launch"))
+ return Action.Launch;
+
+ else if (pair[0].equals("abort"))
+ return Action.Abort;
+
+ else throw new ParseException("Error while parsing:" + pair[0]);
+ }
+
+ if(pair.length != 2)
+ throw new ParseException("Pair length is not 2.");
+
+ String command = pair[0];
+ String param = pair[1];
+
+ if(command.equals("launcher"))
+ {
+ if(param.equals("onesix"))
+ {
+ m_launcher = new OneSixLauncher();
+ Utils.log("Using onesix launcher.");
+ Utils.log();
+ return Action.Proceed;
+ }
+ else if(param.equals("modern"))
+ {
+ m_launcher = new ModernLauncher();
+ Utils.log("Using modern launcher (subprocess mode).");
+ Utils.log();
+ return Action.Proceed;
+ }
+ else
+ throw new ParseException("Invalid launcher type: " + param);
+ }
+
+ m_params.add(command, param);
+ //System.out.println(command + " : " + param);
+ return Action.Proceed;
+ }
+
+ public int listen()
+ {
+ BufferedReader buffer;
+ try
+ {
+ buffer = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
+ } catch (UnsupportedEncodingException e)
+ {
+ System.err.println("For some reason, your java does not support UTF-8. Consider living in the current century.");
+ e.printStackTrace();
+ return 1;
+ }
+ boolean isListening = true;
+ boolean isAborted = false;
+ // Main loop
+ while (isListening)
+ {
+ String inData;
+ try
+ {
+ // Read from the pipe one line at a time
+ inData = buffer.readLine();
+ if (inData != null)
+ {
+ Action a = parseLine(inData);
+ if(a == Action.Abort)
+ {
+ isListening = false;
+ isAborted = true;
+ }
+ if(a == Action.Launch)
+ {
+ isListening = false;
+ }
+ }
+ else
+ {
+ isListening = false;
+ isAborted = true;
+ }
+ }
+ catch (IOException e)
+ {
+ System.err.println("MeshMC ABORT due to IO exception:");
+ e.printStackTrace();
+ return 1;
+ }
+ catch (ParseException e)
+ {
+ System.err.println("MeshMC ABORT due to PARSE exception:");
+ e.printStackTrace();
+ return 1;
+ }
+ }
+ if(isAborted)
+ {
+ System.err.println("Launch aborted by MeshMC.");
+ return 1;
+ }
+ if(m_launcher != null)
+ {
+ return m_launcher.launch(m_params);
+ }
+ System.err.println("No valid launcher implementation specified.");
+ return 1;
+ }
+
+ private ParamBucket m_params = new ParamBucket();
+ private org.projecttick.MeshMC m_launcher;
+}
diff --git a/meshmc/libraries/launcher/org/projecttick/LegacyFrame.java b/meshmc/libraries/launcher/org/projecttick/LegacyFrame.java
new file mode 100644
index 0000000000..0ea9936e33
--- /dev/null
+++ b/meshmc/libraries/launcher/org/projecttick/LegacyFrame.java
@@ -0,0 +1,217 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library. Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give
+ * you permission to link this library with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also meet,
+ * for each linked independent module, the terms and conditions of the
+ * license of that module. An independent module is a module which is
+ * not derived from or based on this library. If you modify this
+ * library, you may extend this exception to your version of the
+ * library, but you are not obliged to do so. If you do not wish to do
+ * so, delete this exception statement from your version.
+ *
+ * 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 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.projecttick;
+
+import net.minecraft.MeshMC;
+
+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 MeshMC 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 MeshMC( 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 ) {}
+}
diff --git a/meshmc/libraries/launcher/org/projecttick/MeshMC.java b/meshmc/libraries/launcher/org/projecttick/MeshMC.java
new file mode 100644
index 0000000000..dae081c70f
--- /dev/null
+++ b/meshmc/libraries/launcher/org/projecttick/MeshMC.java
@@ -0,0 +1,61 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library. Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give
+ * you permission to link this library with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also meet,
+ * for each linked independent module, the terms and conditions of the
+ * license of that module. An independent module is a module which is
+ * not derived from or based on this library. If you modify this
+ * library, you may extend this exception to your version of the
+ * library, but you are not obliged to do so. If you do not wish to do
+ * so, delete this exception statement from your version.
+ *
+ * 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 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.projecttick;
+
+public interface MeshMC
+{
+ abstract int launch(ParamBucket params);
+}
diff --git a/meshmc/libraries/launcher/org/projecttick/NotFoundException.java b/meshmc/libraries/launcher/org/projecttick/NotFoundException.java
new file mode 100644
index 0000000000..fdf94ace4c
--- /dev/null
+++ b/meshmc/libraries/launcher/org/projecttick/NotFoundException.java
@@ -0,0 +1,60 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library. Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give
+ * you permission to link this library with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also meet,
+ * for each linked independent module, the terms and conditions of the
+ * license of that module. An independent module is a module which is
+ * not derived from or based on this library. If you modify this
+ * library, you may extend this exception to your version of the
+ * library, but you are not obliged to do so. If you do not wish to do
+ * so, delete this exception statement from your version.
+ *
+ * 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 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.projecttick;
+
+public class NotFoundException extends Exception
+{
+}
diff --git a/meshmc/libraries/launcher/org/projecttick/ParamBucket.java b/meshmc/libraries/launcher/org/projecttick/ParamBucket.java
new file mode 100644
index 0000000000..97773c9605
--- /dev/null
+++ b/meshmc/libraries/launcher/org/projecttick/ParamBucket.java
@@ -0,0 +1,125 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library. Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give
+ * you permission to link this library with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also meet,
+ * for each linked independent module, the terms and conditions of the
+ * license of that module. An independent module is a module which is
+ * not derived from or based on this library. If you modify this
+ * library, you may extend this exception to your version of the
+ * library, but you are not obliged to do so. If you do not wish to do
+ * so, delete this exception statement from your version.
+ *
+ * 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 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.projecttick;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ParamBucket
+{
+ public void add(String key, String value)
+ {
+ List<String> coll = null;
+ if(!m_params.containsKey(key))
+ {
+ coll = new ArrayList<String>();
+ m_params.put(key, coll);
+ }
+ else
+ {
+ coll = m_params.get(key);
+ }
+ coll.add(value);
+ }
+
+ public List<String> all(String key) throws NotFoundException
+ {
+ if(!m_params.containsKey(key))
+ throw new NotFoundException();
+ return m_params.get(key);
+ }
+
+ public List<String> allSafe(String key, List<String> def)
+ {
+ if(!m_params.containsKey(key) || m_params.get(key).size() < 1)
+ {
+ return def;
+ }
+ return m_params.get(key);
+ }
+
+ public List<String> allSafe(String key)
+ {
+ return allSafe(key, new ArrayList<String>());
+ }
+
+ public String first(String key) throws NotFoundException
+ {
+ List<String> list = all(key);
+ if(list.size() < 1)
+ {
+ throw new NotFoundException();
+ }
+ return list.get(0);
+ }
+
+ public String firstSafe(String key, String def)
+ {
+ if(!m_params.containsKey(key) || m_params.get(key).size() < 1)
+ {
+ return def;
+ }
+ return m_params.get(key).get(0);
+ }
+
+ public String firstSafe(String key)
+ {
+ return firstSafe(key, "");
+ }
+
+ private HashMap<String, List<String>> m_params = new HashMap<String, List<String>>();
+}
diff --git a/meshmc/libraries/launcher/org/projecttick/ParseException.java b/meshmc/libraries/launcher/org/projecttick/ParseException.java
new file mode 100644
index 0000000000..5e3ca0df1a
--- /dev/null
+++ b/meshmc/libraries/launcher/org/projecttick/ParseException.java
@@ -0,0 +1,64 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library. Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give
+ * you permission to link this library with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also meet,
+ * for each linked independent module, the terms and conditions of the
+ * license of that module. An independent module is a module which is
+ * not derived from or based on this library. If you modify this
+ * library, you may extend this exception to your version of the
+ * library, but you are not obliged to do so. If you do not wish to do
+ * so, delete this exception statement from your version.
+ *
+ * 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 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.projecttick;
+
+public class ParseException extends java.lang.Exception
+{
+ public ParseException() { super(); }
+ public ParseException(String message) {
+ super(message);
+ }
+}
diff --git a/meshmc/libraries/launcher/org/projecttick/Utils.java b/meshmc/libraries/launcher/org/projecttick/Utils.java
new file mode 100644
index 0000000000..0dab388eff
--- /dev/null
+++ b/meshmc/libraries/launcher/org/projecttick/Utils.java
@@ -0,0 +1,158 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library. Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give
+ * you permission to link this library with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also meet,
+ * for each linked independent module, the terms and conditions of the
+ * license of that module. An independent module is a module which is
+ * not derived from or based on this library. If you modify this
+ * library, you may extend this exception to your version of the
+ * library, but you are not obliged to do so. If you do not wish to do
+ * so, delete this exception statement from your version.
+ *
+ * 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 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.projecttick;
+
+import java.io.*;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class Utils
+{
+ /**
+ * Combine two parts of a path.
+ *
+ * @param path1
+ * @param path2
+ * @return the paths, combined
+ */
+ public static String combine(String path1, String path2)
+ {
+ 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;
+ }
+
+ /**
+ * Log to MeshMC console
+ *
+ * @param message A String containing the message
+ * @param level A String containing the level name. See MinecraftLauncher::getLevel()
+ */
+ public static void log(String message, String level)
+ {
+ // Kinda dirty
+ String tag = "!![" + level + "]!";
+ System.out.println(tag + message.replace("\n", "\n" + tag));
+ }
+
+ public static void log(String message)
+ {
+ log(message, "MeshMC");
+ }
+
+ public static void log()
+ {
+ System.out.println();
+ }
+}
+
diff --git a/meshmc/libraries/launcher/org/projecttick/modern/ModernLauncher.java b/meshmc/libraries/launcher/org/projecttick/modern/ModernLauncher.java
new file mode 100644
index 0000000000..41616c346b
--- /dev/null
+++ b/meshmc/libraries/launcher/org/projecttick/modern/ModernLauncher.java
@@ -0,0 +1,309 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library. Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give
+ * you permission to link this library with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also meet,
+ * for each linked independent module, the terms and conditions of the
+ * license of that module. An independent module is a module which is
+ * not derived from or based on this library. If you modify this
+ * library, you may extend this exception to your version of the
+ * library, but you are not obliged to do so. If you do not wish to do
+ * so, delete this exception statement from your version.
+ *
+ * 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 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.projecttick.modern;
+
+import org.projecttick.MeshMC;
+import org.projecttick.ParamBucket;
+import org.projecttick.Utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Modern launcher implementation for Minecraft 1.0 and above.
+ *
+ * Unlike OneSixLauncher which loads the game in-process via reflection,
+ * ModernLauncher spawns Minecraft as a separate child process using the
+ * Java binary specified by MeshMC. This decouples the JVM version
+ * running MeshMC library from the JVM version required by the game,
+ * allowing Minecraft versions that require Java 21+ or newer (e.g., class
+ * file version 69.0 / Java 25) to be launched correctly even when the
+ * launcher itself runs on an older JVM.
+ *
+ * Parameters consumed from ParamBucket:
+ * javaPath - Path to the Java binary for the game process (required)
+ * cp - Classpath entries, one per entry (required)
+ * mainClass - Main class to invoke (default: net.minecraft.client.main.Main)
+ * param - Game arguments, one per entry
+ * jvmArg - JVM arguments to forward to the game process, one per arg
+ * natives - Path to the native libraries directory
+ * serverAddress - Server address for direct-connect on launch (optional)
+ * serverPort - Server port for direct-connect on launch (optional)
+ */
+public class ModernLauncher implements MeshMC
+{
+ @Override
+ public int launch(ParamBucket params)
+ {
+ try
+ {
+ return doLaunch(params);
+ }
+ catch (Exception e)
+ {
+ Utils.log("ModernLauncher encountered a fatal error: " + e.getMessage(), "Error");
+ e.printStackTrace();
+ return 1;
+ }
+ }
+
+ private int doLaunch(ParamBucket params) throws Exception
+ {
+ // --- Java binary ---
+ String javaPath = params.firstSafe("javaPath", "java");
+ Utils.log("Java binary: " + javaPath);
+
+ // --- Main class ---
+ String mainClass = params.firstSafe("mainClass", "net.minecraft.client.main.Main");
+ Utils.log("Main class: " + mainClass);
+
+ // --- Classpath ---
+ // "cp" = regular game libraries
+ // "ext" = native-classifier JARs (e.g. lwjgl-3.x-natives-linux.jar) that
+ // LWJGL 3's SharedLibraryLoader needs to find on the classpath.
+ // OneSixLauncher works without these because it runs in-process and
+ // MeshMC JVM already has them on its own classpath. For
+ // ModernLauncher we must include them explicitly.
+ List<String> cpEntries = params.allSafe("cp", Collections.<String>emptyList());
+ List<String> extEntries = params.allSafe("ext", Collections.<String>emptyList());
+ List<String> allCpEntries = new ArrayList<String>(cpEntries);
+ allCpEntries.addAll(extEntries);
+ if (allCpEntries.isEmpty())
+ {
+ Utils.log("No classpath entries provided to ModernLauncher.", "Error");
+ return 1;
+ }
+ String classpath = buildClassPath(allCpEntries);
+
+ // --- Native library path ---
+ String natives = params.firstSafe("natives", "");
+
+ // --- JVM arguments (Xmx, Xms, GC flags, platform-specific flags, etc.) ---
+ List<String> jvmArgs = params.allSafe("jvmArg", Collections.<String>emptyList());
+
+ // --- Game arguments ---
+ // param entries are already pre-expanded by the C++ launcher (auth tokens,
+ // game directory, asset index, resolution, etc.)
+ List<String> gameArgs = new ArrayList<String>(
+ params.allSafe("param", Collections.<String>emptyList())
+ );
+
+ // Direct-connect: server address / port are passed as separate keys and
+ // must be appended to game args manually (processMinecraftArgs skips them
+ // when a launch script is used).
+ String serverAddress = params.firstSafe("serverAddress", "");
+ String serverPort = params.firstSafe("serverPort", "");
+ if (serverAddress != null && !serverAddress.isEmpty())
+ {
+ gameArgs.add("--server");
+ gameArgs.add(serverAddress);
+ if (serverPort != null && !serverPort.isEmpty())
+ {
+ gameArgs.add("--port");
+ gameArgs.add(serverPort);
+ }
+ }
+
+ // --- Build the full command ---
+ List<String> command = buildCommand(javaPath, jvmArgs, natives, classpath, mainClass, gameArgs);
+
+ // Log the full command for diagnostics (visible in launcher console)
+ StringBuilder cmdLog = new StringBuilder("Spawning game process:\n CMD: ");
+ for (String s : command)
+ {
+ cmdLog.append(s).append(" ");
+ }
+ Utils.log(cmdLog.toString().trim());
+
+ ProcessBuilder pb = new ProcessBuilder(command);
+ // Let the game process inherit the working directory from us (set by LauncherPartLaunch)
+ pb.directory(null);
+
+ // Set JAVA_HOME so the game and any native launchers can locate Java correctly
+ File javaFile = new File(javaPath);
+ File javaParent = javaFile.getParentFile();
+ if (javaParent != null && javaParent.getParentFile() != null)
+ {
+ pb.environment().put("JAVA_HOME", javaParent.getParent());
+ }
+
+ final Process process = pb.start();
+
+ // Pipe stdout and stderr from the child process to our own streams so
+ // the C++ launcher's LoggedProcess can capture and display them.
+ Thread outPipe = pipeStream(process.getInputStream(), System.out, "stdout");
+ Thread errPipe = pipeStream(process.getErrorStream(), System.err, "stderr");
+ outPipe.start();
+ errPipe.start();
+
+ // Shutdown hook: ensure the game process is terminated if MeshMC is
+ // forcefully killed (e.g., SIGKILL from within MeshMC UI).
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ if (process.isAlive())
+ {
+ process.destroyForcibly();
+ }
+ }
+ }, "ModernLauncher-ShutdownHook"));
+
+ // Block until the game process exits
+ int exitCode = process.waitFor();
+
+ outPipe.join();
+ errPipe.join();
+
+ if (exitCode != 0)
+ {
+ Utils.log("Game process exited with code " + exitCode, "Error");
+ }
+
+ return exitCode;
+ }
+
+ private String buildClassPath(List<String> entries)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < entries.size(); i++)
+ {
+ if (i > 0)
+ sb.append(File.pathSeparator);
+ sb.append(entries.get(i));
+ }
+ return sb.toString();
+ }
+
+ private List<String> buildCommand(
+ String javaPath,
+ List<String> jvmArgs,
+ String natives,
+ String classpath,
+ String mainClass,
+ List<String> gameArgs)
+ {
+ List<String> cmd = new ArrayList<String>();
+
+ // Java executable
+ cmd.add(javaPath);
+
+ // JVM arguments (memory settings, GC options, platform flags, etc.)
+ cmd.addAll(jvmArgs);
+
+ // Native library path - needed for LWJGL and other native dependencies.
+ // Pass both the standard JVM property and the LWJGL-specific property:
+ // java.library.path - used by java.lang.System.loadLibrary()
+ // org.lwjgl.librarypath - checked first by LWJGL 3.3+ before java.library.path
+ if (natives != null && !natives.isEmpty())
+ {
+ cmd.add("-Djava.library.path=" + natives);
+ cmd.add("-Dorg.lwjgl.librarypath=" + natives);
+ }
+
+ // Classpath
+ if (!classpath.isEmpty())
+ {
+ cmd.add("-cp");
+ cmd.add(classpath);
+ }
+
+ // Main class
+ cmd.add(mainClass);
+
+ // Game arguments
+ cmd.addAll(gameArgs);
+
+ return cmd;
+ }
+
+ /**
+ * Reads bytes from {@code src} and writes them to {@code dst} on a dedicated
+ * daemon thread so neither stream blocks the main thread.
+ */
+ private Thread pipeStream(final InputStream src, final PrintStream dst, final String name)
+ {
+ Thread t = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ byte[] buffer = new byte[8192];
+ int read;
+ try
+ {
+ while ((read = src.read(buffer)) != -1)
+ {
+ dst.write(buffer, 0, read);
+ dst.flush();
+ }
+ }
+ catch (IOException e)
+ {
+ // Stream closed - expected when the child process exits
+ }
+ }
+ }, "ModernLauncher-" + name + "-pipe");
+ t.setDaemon(true);
+ return t;
+ }
+}
diff --git a/meshmc/libraries/launcher/org/projecttick/onesix/OneSixLauncher.java b/meshmc/libraries/launcher/org/projecttick/onesix/OneSixLauncher.java
new file mode 100644
index 0000000000..25936149f9
--- /dev/null
+++ b/meshmc/libraries/launcher/org/projecttick/onesix/OneSixLauncher.java
@@ -0,0 +1,288 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library. Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give
+ * you permission to link this library with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also meet,
+ * for each linked independent module, the terms and conditions of the
+ * license of that module. An independent module is a module which is
+ * not derived from or based on this library. If you modify this
+ * library, you may extend this exception to your version of the
+ * library, but you are not obliged to do so. If you do not wish to do
+ * so, delete this exception statement from your version.
+ *
+ * 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 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.projecttick.onesix;
+
+import org.projecttick.*;
+
+import java.applet.Applet;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+public class OneSixLauncher implements MeshMC
+{
+ // 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)
+ {
+ System.err.println("Could not find Minecraft path field.");
+ }
+ else
+ {
+ f.setAccessible(true);
+ f.set(null, new File(cwd));
+ }
+ } catch (Exception e)
+ {
+ System.err.println("Could not set base folder. Failed to find/access Minecraft main class:");
+ e.printStackTrace(System.err);
+ return -1;
+ }
+
+ System.setProperty("minecraft.applet.TargetDirectory", cwd);
+
+ if(!traits.contains("noapplet"))
+ {
+ Utils.log("Launching with applet wrapper...");
+ try
+ {
+ Class<?> MCAppletClass = cl.loadClass(appletClass);
+ Applet mcappl = (Applet) MCAppletClass.newInstance();
+ LegacyFrame mcWindow = new LegacyFrame(windowTitle);
+ mcWindow.start(mcappl, userName, sessionId, winSizeW, winSizeH, maximize, serverAddress, serverPort);
+ return 0;
+ } catch (Exception e)
+ {
+ Utils.log("Applet wrapper failed:", "Error");
+ e.printStackTrace(System.err);
+ Utils.log();
+ Utils.log("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)
+ {
+ Utils.log("Failed to invoke the Minecraft main class:", "Fatal");
+ e.printStackTrace(System.err);
+ 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)
+ {
+ System.err.println("Failed to find Minecraft main class:");
+ e.printStackTrace(System.err);
+ return -1;
+ }
+
+ // get the main method.
+ Method meth;
+ try
+ {
+ meth = mc.getMethod("main", String[].class);
+ } catch (NoSuchMethodException e)
+ {
+ System.err.println("Failed to acquire the main method:");
+ e.printStackTrace(System.err);
+ return -1;
+ }
+
+ // init params for the main method to chomp on.
+ String[] paramsArray = mcparams.toArray(new String[mcparams.size()]);
+ try
+ {
+ // static method doesn't have an instance
+ meth.invoke(null, (Object) paramsArray);
+ } catch (Exception e)
+ {
+ System.err.println("Failed to start Minecraft:");
+ e.printStackTrace(System.err);
+ return -1;
+ }
+ return 0;
+ }
+
+ @Override
+ public int launch(ParamBucket params)
+ {
+ // get and process the launch script params
+ try
+ {
+ processParams(params);
+ } catch (NotFoundException e)
+ {
+ System.err.println("Not enough arguments.");
+ e.printStackTrace(System.err);
+ return -1;
+ }
+
+ // 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();
+ }
+ }
+}