119 lines
3.8 KiB
Java
119 lines
3.8 KiB
Java
|
|
import java.io.ByteArrayOutputStream;
|
||
|
|
import java.io.IOException;
|
||
|
|
import java.lang.reflect.Method;
|
||
|
|
import java.lang.reflect.Modifier;
|
||
|
|
import java.util.Arrays;
|
||
|
|
|
||
|
|
public final class MinecraftLaunch {
|
||
|
|
public static void main(String[] args) throws IOException, ReflectiveOperationException {
|
||
|
|
final String mainClass = args[0];
|
||
|
|
final String[] gameArgs = Arrays.copyOfRange(args, 1, args.length);
|
||
|
|
|
||
|
|
System.setProperty("modrinth.process.args", String.join("\u001f", gameArgs));
|
||
|
|
parseInput();
|
||
|
|
|
||
|
|
relaunch(mainClass, gameArgs);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void parseInput() throws IOException {
|
||
|
|
final ByteArrayOutputStream line = new ByteArrayOutputStream();
|
||
|
|
while (true) {
|
||
|
|
final int b = System.in.read();
|
||
|
|
if (b < 0) {
|
||
|
|
throw new IllegalStateException("Stdin terminated while parsing");
|
||
|
|
}
|
||
|
|
if (b != '\n') {
|
||
|
|
line.write(b);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (handleLine(line.toString("UTF-8"))) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
line.reset();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static boolean handleLine(String line) {
|
||
|
|
final String[] parts = line.split("\t", 2);
|
||
|
|
switch (parts[0]) {
|
||
|
|
case "property": {
|
||
|
|
final String[] keyValue = parts[1].split("\t", 2);
|
||
|
|
System.setProperty(keyValue[0], keyValue[1]);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
case "launch":
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
System.err.println("Unknown input line " + line);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void relaunch(String mainClassName, String[] args) throws ReflectiveOperationException {
|
||
|
|
final int javaVersion = getJavaVersion();
|
||
|
|
final Class<?> mainClass = Class.forName(mainClassName);
|
||
|
|
|
||
|
|
if (javaVersion >= 25) {
|
||
|
|
Method mainMethod;
|
||
|
|
try {
|
||
|
|
mainMethod = findMainMethodJep512(mainClass);
|
||
|
|
} catch (ReflectiveOperationException e) {
|
||
|
|
System.err
|
||
|
|
.println("[MODRINTH] Unable to call JDK findMainMethod. Falling back to pre-Java 25 main method finding.");
|
||
|
|
// If the above fails due to JDK implementation details changing
|
||
|
|
try {
|
||
|
|
mainMethod = findSimpleMainMethod(mainClass);
|
||
|
|
} catch (ReflectiveOperationException innerE) {
|
||
|
|
e.addSuppressed(innerE);
|
||
|
|
throw e;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (mainMethod == null) {
|
||
|
|
throw new IllegalArgumentException("Could not find main() method");
|
||
|
|
}
|
||
|
|
|
||
|
|
Object thisObject = null;
|
||
|
|
if (!Modifier.isStatic(mainMethod.getModifiers())) {
|
||
|
|
thisObject = mainClass.getDeclaredConstructor().newInstance();
|
||
|
|
}
|
||
|
|
|
||
|
|
final Object[] parameters = mainMethod.getParameterCount() > 0
|
||
|
|
? new Object[] { args }
|
||
|
|
: new Object[] {};
|
||
|
|
|
||
|
|
mainMethod.invoke(thisObject, parameters);
|
||
|
|
} else {
|
||
|
|
findSimpleMainMethod(mainClass).invoke(null, new Object[] { args });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static int getJavaVersion() {
|
||
|
|
String javaVersion = System.getProperty("java.version");
|
||
|
|
|
||
|
|
final int dotIndex = javaVersion.indexOf('.');
|
||
|
|
if (dotIndex != -1) {
|
||
|
|
javaVersion = javaVersion.substring(0, dotIndex);
|
||
|
|
}
|
||
|
|
|
||
|
|
final int dashIndex = javaVersion.indexOf('-');
|
||
|
|
if (dashIndex != -1) {
|
||
|
|
javaVersion = javaVersion.substring(0, dashIndex);
|
||
|
|
}
|
||
|
|
|
||
|
|
return Integer.parseInt(javaVersion);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Method findMainMethodJep512(Class<?> mainClass) throws ReflectiveOperationException {
|
||
|
|
// BEWARE BELOW: This code may break if JDK internals to find the main method
|
||
|
|
// change.
|
||
|
|
final Class<?> methodFinderClass = Class.forName("jdk.internal.misc.MethodFinder");
|
||
|
|
final Method methodFinderMethod = methodFinderClass.getDeclaredMethod("findMainMethod", Class.class);
|
||
|
|
final Object result = methodFinderMethod.invoke(null, mainClass);
|
||
|
|
return (Method) result;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Method findSimpleMainMethod(Class<?> mainClass) throws NoSuchMethodException {
|
||
|
|
return mainClass.getMethod("main", String[].class);
|
||
|
|
}
|
||
|
|
}
|