diff --git a/JavaApp/src/main/java/HelloWorld.java b/JavaApp/src/main/java/HelloWorld.java deleted file mode 100644 index 5fb508c2..00000000 --- a/JavaApp/src/main/java/HelloWorld.java +++ /dev/null @@ -1,144 +0,0 @@ -import org.lwjgl.*; -import org.lwjgl.glfw.*; -import org.lwjgl.opengl.*; -import org.lwjgl.system.*; - -import java.nio.*; - -import static org.lwjgl.glfw.Callbacks.*; -import static org.lwjgl.glfw.GLFW.*; -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.system.MemoryStack.*; -import static org.lwjgl.system.MemoryUtil.*; - -public class HelloWorld { - - // The window handle - private long window; - protected boolean noLoop = false; - - public void run() { - System.out.println("Hello LWJGL " + Version.getVersion() + "!"); - - init(); - loop(); - - // Free the window callbacks and destroy the window - glfwFreeCallbacks(window); - glfwDestroyWindow(window); - - // Terminate GLFW and free the error callback - glfwTerminate(); - glfwSetErrorCallback(null).free(); - } - - private void init() { - // Setup an error callback. The default implementation - // will print the error message in System.err. - GLFWErrorCallback.createPrint(System.err).set(); - - // Initialize GLFW. Most GLFW functions will not work before doing this. - if ( !glfwInit() ) - throw new IllegalStateException("Unable to initialize GLFW"); - - // Configure GLFW - glfwDefaultWindowHints(); // optional, the current window hints are already the default - glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation - glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable - - // Create the window - window = glfwCreateWindow(300, 300, "Hello World!", NULL, NULL); - if ( window == NULL ) - throw new RuntimeException("Failed to create the GLFW window"); - - // Setup a key callback. It will be called every time a key is pressed, repeated or released. - glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> { - if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE ) - glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop - }); - - System.out.println("ThreadOutsideCallback=" + Thread.currentThread().getName()); - glfwSetCursorPosCallback(0, (window, x, y) -> { - System.out.println("ThreadInsideCallback=" + Thread.currentThread().getName() + ", x=" + x + ", y=" + y); - }); - - // Get the thread stack and push a new frame - try { - MemoryStack stack = stackPush(); - IntBuffer pWidth = stack.mallocInt(1); // int* - IntBuffer pHeight = stack.mallocInt(1); // int* - - // Get the window size passed to glfwCreateWindow - glfwGetWindowSize(window, pWidth, pHeight); - - // Get the resolution of the primary monitor - GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor()); - - System.out.println("MONITOR SPEC"); - System.out.println("width=" + vidmode.width()); - System.out.println("height=" + vidmode.height()); - System.out.println("red=" + vidmode.redBits()); - System.out.println("green=" + vidmode.greenBits()); - System.out.println("blue=" + vidmode.blueBits()); - System.out.println("refresh=" + vidmode.refreshRate()); - - // Center the window - glfwSetWindowPos( - window, - (vidmode.width() - pWidth.get(0)) / 2, - (vidmode.height() - pHeight.get(0)) / 2 - ); - } finally {} // the stack frame is popped automatically - - // Make the OpenGL context current - glfwMakeContextCurrent(window); - // Enable v-sync - glfwSwapInterval(1); - - // Make the window visible - glfwShowWindow(window); - - // glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - } - - private boolean grabbing = false; - private long lastTime; - private void loop() { - // This line is critical for LWJGL's interoperation with GLFW's - // OpenGL context, or any context that is managed externally. - // LWJGL detects the context that is current in the current thread, - // creates the GLCapabilities instance and makes the OpenGL - // bindings available for use. - org.lwjgl.opengl.GL.createCapabilities(); - - // Set the clear color - glClearColor(0.0f, 0.2f, 0.0f, 1.0f); - - // Run the rendering loop until the user has attempted to close - // the window or has pressed the ESCAPE key. - if (noLoop) return; - while ( !glfwWindowShouldClose(window) ) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer - - glfwSwapBuffers(window); // swap the color buffers - - // Poll for window events. The key callback above will only be - // invoked during this call. - glfwPollEvents(); - - if (System.currentTimeMillis() - lastTime >= 5000) { - glClearColor(grabbing ? 0.0f : 0.2f, grabbing ? 0.2f : 0.0f, 0.0f, 1.0f); - - lastTime = System.currentTimeMillis(); - grabbing = !grabbing; - glfwSetInputMode(window, GLFW_CURSOR, grabbing ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_HIDDEN); - System.out.println("Grab state=" + Boolean.toString(grabbing)); - } - } - } - - public static void main(String[] args) { - new HelloWorld().run(); - } - -} diff --git a/JavaApp/src/main/java/HelloWorldNoLoop.java b/JavaApp/src/main/java/HelloWorldNoLoop.java deleted file mode 100644 index 9f229960..00000000 --- a/JavaApp/src/main/java/HelloWorldNoLoop.java +++ /dev/null @@ -1,11 +0,0 @@ - -public class HelloWorldNoLoop extends HelloWorld { - public HelloWorldNoLoop() { - super(); - noLoop = true; - } - - public static void main(String[] args) { - new HelloWorldNoLoop().run(); - } -} diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java index 401859ab..12eb1a3e 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -419,7 +419,10 @@ public final class Tools if (libItem._skip) continue; String[] libInfos = libItem.name.split(":"); - libDir.add(Tools.DIR_HOME_LIBRARY + "/" + Tools.artifactToPath(libInfos[0], libInfos[1], libInfos[2])); + String fullPath = Tools.DIR_HOME_LIBRARY + "/" + Tools.artifactToPath(libInfos[0], libInfos[1], libInfos[2]); + if (!libDir.contains(fullPath)) { + libDir.add(fullPath); + } } return libDir.toArray(new String[0]); } @@ -458,11 +461,11 @@ public final class Tools libAdded.name.substring(libAddedName.length() + 1) + " with " + lib.name.substring(libName.length() + 1)); libList.set(i, lib); - continue loop_1; + libName = null; } } - libList.add(lib); + if (libName != null) libList.add(lib); } } finally { inheritsVer.libraries = libList.toArray(new DependentLibrary[0]); diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java index 98c72eab..7997e812 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java @@ -125,10 +125,9 @@ public class UIKit { public static native void refreshAWTBuffer(int[] array); - public static native int launchUI(); // public static native void runOnUIThread(UIKitCallback callback); - + public static native void showError(String title, String message, boolean exitIfOk); - + private static native void updateMCGuiScale(int scale); - } +} diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/utils/MCOptionUtils.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/utils/MCOptionUtils.java index a6c8ddc9..ac98a151 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/utils/MCOptionUtils.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/utils/MCOptionUtils.java @@ -71,5 +71,6 @@ public class MCOptionUtils System.err.println("Could not save options.txt"); e.printStackTrace(); } + mLineList = null; } } diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java b/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java index 933cbbbc..eb6b9473 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java @@ -6,6 +6,7 @@ import android.util.*; import net.kdt.pojavlaunch.*; import net.kdt.pojavlaunch.uikit.UIKit; +import net.kdt.pojavlaunch.utils.MCOptionUtils; public class CallbackBridge { public static final int CLIPBOARD_COPY = 2000; @@ -36,7 +37,19 @@ public class CallbackBridge { static { System.load(System.getenv("BUNDLE_PATH") + "/PojavLauncher"); - + + // Forge 1.17+ initialize their very own space (both Java and JNI) so we re-init stuff here + MCOptionUtils.load(); + Tools.mGLFWWindowWidth = Integer.parseInt(MCOptionUtils.get("overrideWidth")); + Tools.mGLFWWindowHeight = Integer.parseInt(MCOptionUtils.get("overrideHeight")); + MCOptionUtils.save(); // Free the loaded data + CallbackBridge.setClass(); + try { + Class.forName("net.kdt.pojavlaunch.uikit.UIKit"); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + INPUT_DEBUG_ENABLED = Boolean.parseBoolean(System.getProperty("glfwstub.debugInput", "false")); } @@ -184,8 +197,8 @@ public class CallbackBridge { nativeSetGrabbing(grab, xset, yset); } - // Called from native code - public static void receiveCallback(int type, float i1, float i2, int i3, int i4) { + // Called from native code + public static void receiveCallback(int type, float i1, float i2, int i3, int i4) { /* if (INPUT_DEBUG_ENABLED) { System.out.println("LWJGL GLFW Callback received type=" + Integer.toString(type) + ", data=" + i1 + ", " + i2 + ", " + i3 + ", " + i4); @@ -201,7 +214,7 @@ public class CallbackBridge { PENDING_EVENT_LIST.add(new Object[]{type, (int)i1, (int)i2, i3, i4}); } } // else System.out.println("Event input is not ready yet!"); - } + } // public static native void nativeSendData(boolean isAndroid, int type, String data); public static boolean nativeSetInputReady(boolean ready) { @@ -211,5 +224,6 @@ public class CallbackBridge { public static native String nativeClipboard(int action, String copy); private static native void nativeSetGrabbing(boolean grab, float xset, float yset); + public static native void setClass(); } diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java b/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java index 2e8942fd..16e26dbf 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java @@ -14,7 +14,6 @@ import javax.annotation.*; import net.kdt.pojavlaunch.Tools; import org.lwjgl.*; -import org.lwjgl.opengl.GL; import org.lwjgl.system.*; import static org.lwjgl.system.APIUtil.*; @@ -508,9 +507,8 @@ public class GLFW } // Minecraft triggers a glfwPollEvents() on splash screen, so update window size there. - // TODO objc-rewrite: commented out for testing only - //CallbackBridge.receiveCallback(CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight, 0, 0); - //CallbackBridge.receiveCallback(CallbackBridge.EVENT_TYPE_WINDOW_SIZE, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight, 0, 0); + CallbackBridge.receiveCallback(CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight, 0, 0); + CallbackBridge.receiveCallback(CallbackBridge.EVENT_TYPE_WINDOW_SIZE, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight, 0, 0); mGLFWErrorCallback = GLFWErrorCallback.createPrint(); mGLFWKeyCodes = new ArrayMap<>(); @@ -1060,12 +1058,7 @@ public class GLFW // Indirect event while (CallbackBridge.PENDING_EVENT_LIST.size() > 0) { Object[] dataArr = CallbackBridge.PENDING_EVENT_LIST.remove(0); - - if (dataArr == null) { // It should not be null, but still should be catched - // System.out.println("GLFW: popped callback is null, skipping"); - continue; - } - + for (Long ptr : mGLFWWindowMap.keySet()) { switch ((int)dataArr[0]) { case CallbackBridge.EVENT_TYPE_CHAR: diff --git a/Makefile b/Makefile index ee0b68a8..f3ce6406 100644 --- a/Makefile +++ b/Makefile @@ -135,13 +135,13 @@ DEPLOY = \ $(WORKINGDIR)/libOSMesaOverride.dylib.framework \ $(WORKINGDIR)/libawt_xawt.dylib \ $(WORKINGDIR)/PojavLauncher.app/PojavLauncher \ - $(SOURCEDIR)/JavaApp/local_out/launcher.jar \ + $(SOURCEDIR)/JavaApp/local_out/*.jar \ root@$(DEVICE_IP):/var/tmp/; \ ssh root@$(DEVICE_IP) -p $(DEVICE_PORT) -t " \ mv /var/tmp/libawt_xawt.dylib $(1)/Applications/PojavLauncher.app/Frameworks/libawt_xawt.dylib && \ mv /var/tmp/libOSMesaOverride.dylib.framework $(1)/Applications/PojavLauncher.app/Frameworks/libOSMesaOverride.dylib.framework && \ mv /var/tmp/PojavLauncher $(1)/Applications/PojavLauncher.app/PojavLauncher && \ - mv /var/tmp/launcher.jar $(1)/Applications/PojavLauncher.app/libs/launcher.jar && \ + mv /var/tmp/*.jar $(1)/Applications/PojavLauncher.app/libs/ && \ cd $(1)/Applications/PojavLauncher.app/Frameworks && \ ln -sf libawt_xawt.dylib libawt_headless.dylib && \ chown -R 501:501 $(1)/Applications/PojavLauncher.app/*"; \ @@ -149,7 +149,7 @@ DEPLOY = \ sudo mv $(WORKINGDIR)/libawt_xawt.dylib $(1)/Applications/PojavLauncher.app/Frameworks/libawt_xawt.dylib; \ sudo mv $(WORKINGDIR)/libOSMesaOverride.dylib.framework $(1)/Applications/PojavLauncher.app/Frameworks/libOSMesaOverride.dylib.framework; \ sudo mv $(WORKINGDIR)/PojavLauncher $(1)/Applications/PojavLauncher.app/PojavLauncher; \ - sudo mv $(WORKINGDIR)/launcher.jar $(1)/Applications/PojavLauncher.app/libs/launcher.jar; \ + sudo mv $(WORKINGDIR)/*.jar $(1)/Applications/PojavLauncher.app/libs/; \ cd $(1)/Applications/PojavLauncher.app/Frameworks; \ sudo ln -sf libawt_xawt.dylib libawt_headless.dylib; \ sudo chown -R 501:501 $(1)/Applications/PojavLauncher.app/*; \ @@ -254,7 +254,9 @@ java: mkdir -p local_out/classes; \ $(BOOTJDK)/javac -cp "libs/*:libs_caciocavallo/*" -d local_out/classes $$(find src -type f -name "*.java" -print) -XDignore.symbol.file || exit 1; \ cd local_out/classes; \ - $(BOOTJDK)/jar -cf ../launcher.jar * || exit 1 + $(BOOTJDK)/jar -cf ../launcher.jar android com net || exit 1; \ + cp $(SOURCEDIR)/JavaApp/libs/lwjgl3-minecraft.jar ../lwjgl3-minecraft.jar; \ + $(BOOTJDK)/jar -uf ../lwjgl3-minecraft.jar org || exit 1; @echo 'Building PojavLauncher $(VERSION) - JAVA - End' extras: @@ -282,7 +284,7 @@ deb: native java extras @cp $(WORKINGDIR)/libawt_xawt.dylib $(WORKINGDIR)/PojavLauncher.app/Frameworks/ || exit 1 @( cd $(WORKINGDIR)/PojavLauncher.app/Frameworks; ln -sf libawt_xawt.dylib libawt_headless.dylib ) || exit 1 @cp -R $(WORKINGDIR)/libOSMesaOverride.dylib.framework $(WORKINGDIR)/PojavLauncher.app/Frameworks/ || exit 1 - @cp $(SOURCEDIR)/JavaApp/local_out/launcher.jar $(WORKINGDIR)/PojavLauncher.app/libs/launcher.jar || exit 1 + @cp $(SOURCEDIR)/JavaApp/local_out/*.jar $(WORKINGDIR)/PojavLauncher.app/libs/ || exit 1 @cp -R $(SOURCEDIR)/JavaApp/libs/* $(WORKINGDIR)/PojavLauncher.app/libs/ || exit 1 @cp -R $(SOURCEDIR)/JavaApp/libs_caciocavallo/* $(WORKINGDIR)/PojavLauncher.app/libs_caciocavallo/ || exit 1 @cp -R $(SOURCEDIR)/Natives/*.lproj $(WORKINGDIR)/PojavLauncher.app/ || exit 1 diff --git a/Natives/JavaLauncher.h b/Natives/JavaLauncher.h index c35cea50..d07cfa58 100644 --- a/Natives/JavaLauncher.h +++ b/Natives/JavaLauncher.h @@ -17,4 +17,4 @@ typedef jint JLI_Launch_func(int argc, char ** argv, /* main argc, argc */ ); JLI_Launch_func *pJLI_Launch; -int launchJVM(NSString *username, NSString *selectedVersion, int width, int height, int minVersion); +int launchJVM(NSString *username, id launchTarget, int width, int height, int minVersion); diff --git a/Natives/JavaLauncher.m b/Natives/JavaLauncher.m index 1f815bb0..7550eac4 100644 --- a/Natives/JavaLauncher.m +++ b/Natives/JavaLauncher.m @@ -32,7 +32,7 @@ static const jboolean const_javaw = JNI_FALSE; static const jboolean const_cpwildcard = JNI_TRUE; static const jint const_ergo_class = 0; // DEFAULT_POLICY -static int margc = 0; +static int margc = -1; static char* margv[1000]; const char *javaHome; @@ -90,6 +90,7 @@ void init_loadCustomJvmFlags() { if ([jvmarg length] == 0) continue; //margv[margc] = (char *) [jvmarg UTF8String]; + ++margc; if (isFirstArg) { isFirstArg = NO; margv[margc] = (char *) [jvmarg UTF8String]; @@ -98,7 +99,6 @@ void init_loadCustomJvmFlags() { } NSLog(@"[JavaLauncher] Added custom JVM flag: %s", margv[margc]); - ++margc; } } @@ -128,7 +128,7 @@ NSString* environmentFailsafes(int minVersion) { return javaHome; } -int launchJVM(NSString *username, NSString *selectedVersion, int width, int height, int minVersion) { +int launchJVM(NSString *username, id launchTarget, int width, int height, int minVersion) { sprintf((char*) java_libs_path, "%s/libs", getenv("BUNDLE_PATH")); init_loadCustomEnv(); @@ -139,8 +139,9 @@ int launchJVM(NSString *username, NSString *selectedVersion, int width, int heig // We handle unset JAVA_HOME right there if (username == nil || getSelectedJavaVersion() < minVersion) { + NSLog(@"[JavaLauncher] Attempting to change to Java %d (actual might be higher)", minVersion); javaHome_pre = environmentFailsafes(minVersion); - NSLog(@"[JavaLauncher] Changed to Java %d for the request", minVersion); + NSLog(@"[JavaLauncher] JAVA_HOME is now set to %@", javaHome_pre); } /* else if (javaHome_pre.length == 0) { javaHome_pre = environmentFailsafes(minVersion); setPreference(@"java_home", javaHome_pre); @@ -299,23 +300,23 @@ int launchJVM(NSString *username, NSString *selectedVersion, int width, int heig NSLog(@"[JavaLauncher] Java executable path: %s", javaPath); setenv("JAVA_EXT_EXECNAME", javaPath, 1); - margv[margc++] = javaPath; - margv[margc++] = "-XstartOnFirstThread"; - margv[margc++] = "-Djava.system.class.loader=net.kdt.pojavlaunch.PojavClassLoader"; - margv[margc++] = memMin; - margv[margc++] = memMax; - margv[margc++] = frameworkPath; - margv[margc++] = jnaLibPath; - margv[margc++] = userDir; - margv[margc++] = userHome; - margv[margc++] = "-Dorg.lwjgl.system.allocator=system"; - margv[margc++] = "-Dlog4j2.formatMsgNoLookups=true"; + margv[++margc] = javaPath; + margv[++margc] = "-XstartOnFirstThread"; + margv[++margc] = "-Djava.system.class.loader=net.kdt.pojavlaunch.PojavClassLoader"; + margv[++margc] = memMin; + margv[++margc] = memMax; + margv[++margc] = frameworkPath; + margv[++margc] = jnaLibPath; + margv[++margc] = userDir; + margv[++margc] = userHome; + margv[++margc] = "-Dorg.lwjgl.system.allocator=system"; + margv[++margc] = "-Dlog4j2.formatMsgNoLookups=true"; if([getPreference(@"arccapes_enable") boolValue]) { - margv[margc++] = arcDNS; + margv[++margc] = arcDNS; } NSString *selectedAccount = getPreference(@"internal_selected_account"); if (selectedAccount != nil) { - margv[margc++] = (char *) [NSString stringWithFormat:@"-Dpojav.selectedAccount=%@", selectedAccount].UTF8String; + margv[++margc] = (char *) [NSString stringWithFormat:@"-Dpojav.selectedAccount=%@", selectedAccount].UTF8String; } // Load java @@ -335,12 +336,12 @@ int launchJVM(NSString *username, NSString *selectedVersion, int width, int heig } // Setup Caciocavallo - margv[margc++] = "-Djava.awt.headless=false"; - margv[margc++] = "-Dcacio.font.fontmanager=sun.awt.X11FontManager"; - margv[margc++] = "-Dcacio.font.fontscaler=sun.font.FreetypeFontScaler"; - margv[margc++] = "-Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel"; - margv[margc++] = "-Dawt.toolkit=net.java.openjdk.cacio.ctc.CTCToolkit"; - margv[margc++] = "-Djava.awt.graphicsenv=net.java.openjdk.cacio.ctc.CTCGraphicsEnvironment"; + margv[++margc] = "-Djava.awt.headless=false"; + margv[++margc] = "-Dcacio.font.fontmanager=sun.awt.X11FontManager"; + margv[++margc] = "-Dcacio.font.fontscaler=sun.font.FreetypeFontScaler"; + margv[++margc] = "-Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel"; + margv[++margc] = "-Dawt.toolkit=net.java.openjdk.cacio.ctc.CTCToolkit"; + margv[++margc] = "-Djava.awt.graphicsenv=net.java.openjdk.cacio.ctc.CTCGraphicsEnvironment"; // Generate Caciocavallo bootclasspath char cacio_libs_path[2048]; @@ -359,23 +360,38 @@ int launchJVM(NSString *username, NSString *selectedVersion, int width, int heig } closedir(d); } - margv[margc++] = cacio_classpath; + margv[++margc] = cacio_classpath; + } else { + margv[++margc] = "--add-opens=java.base/java.net=ALL-UNNAMED"; + + // TODO: workaround, will be removed once the startup part works without PLaunchApp + margv[++margc] = "--add-exports=cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED"; + } + + if ([launchTarget isKindOfClass:NSDictionary.class]) { + for (NSString *arg in launchTarget[@"arguments"][@"jvm_processed"]) { + margv[++margc] = (char *)arg.UTF8String; + } } init_loadCustomJvmFlags(); regLog("[Init] Found JLI lib"); - margv[margc++] = "-cp"; - margv[margc++] = classpath; - margv[margc++] = "net.kdt.pojavlaunch.PLaunchApp"; + margv[++margc] = "-cp"; + margv[++margc] = classpath; + margv[++margc] = "net.kdt.pojavlaunch.PLaunchApp"; if (username == nil) { - margv[margc++] = ".LaunchJAR"; + margv[++margc] = ".LaunchJAR"; } else { - margv[margc++] = (char *)username.UTF8String; + margv[++margc] = (char *)username.UTF8String; } - margv[margc++] = (char *)selectedVersion.UTF8String; - margv[margc++] = (char *)[NSString stringWithFormat:@"%dx%d", width, height].UTF8String; + if ([launchTarget isKindOfClass:NSDictionary.class]) { + margv[++margc] = (char *)[launchTarget[@"id"] UTF8String]; + } else { + margv[++margc] = (char *)[launchTarget UTF8String]; + } + margv[++margc] = (char *)[NSString stringWithFormat:@"%dx%d", width, height].UTF8String; pJLI_Launch = (JLI_Launch_func *)dlsym(libjli, "JLI_Launch"); @@ -392,7 +408,7 @@ int launchJVM(NSString *username, NSString *selectedVersion, int width, int heig } */ - return pJLI_Launch(margc, margv, + return pJLI_Launch(++margc, margv, 0, NULL, // sizeof(const_jargs) / sizeof(char *), const_jargs, 0, NULL, // sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, // PojavLancher: fixme: are these wrong? diff --git a/Natives/LauncherViewController.m b/Natives/LauncherViewController.m index cd6cf653..e1c0d505 100644 --- a/Natives/LauncherViewController.m +++ b/Natives/LauncherViewController.m @@ -269,7 +269,7 @@ int versionSelectedAt = 0; - (void)launchMinecraft:(UIButton *)sender { sender.enabled = NO; [self.navigationItem setHidesBackButton:YES animated:YES]; - + NSObject *object = [versionList objectAtIndex:[versionPickerView selectedRowInComponent:0]]; [MinecraftDownloader start:object callback:^(NSString *stage, NSProgress *mainProgress, NSProgress *progress) { diff --git a/Natives/MinecraftDownloader.h b/Natives/MinecraftDownloader.h index 2b59fb92..9c8d1703 100644 --- a/Natives/MinecraftDownloader.h +++ b/Natives/MinecraftDownloader.h @@ -4,6 +4,7 @@ typedef void (^MDCallback)(NSString *stage, NSProgress *mainProgress, NSProgress @interface MinecraftDownloader : NSObject ++ (void)downloadClientJson:(NSObject *)version progress:(NSProgress *)mainProgress callback:(MDCallback)callback success:(void (^)(NSMutableDictionary *json))success; + (void)start:(NSObject *)version callback:(void (^)(NSString *stage, NSProgress *mainProgress, NSProgress *progress))callback; @end diff --git a/Natives/MinecraftDownloader.m b/Natives/MinecraftDownloader.m index f5929074..97e1116e 100644 --- a/Natives/MinecraftDownloader.m +++ b/Natives/MinecraftDownloader.m @@ -120,9 +120,11 @@ static AFURLSessionManager* manager; [self downloadClientJson:object progress:mainProgress callback:callback success:^(NSMutableDictionary *inheritsFrom){ [self insertSafety:inheritsFrom from:json arr:@[ @"assetIndex", @"assets", @"id", + @"inheritsFrom", @"mainClass", @"minecraftArguments", @"optifineLib", @"releaseTime", @"time", @"type" ]]; + inheritsFrom[@"arguments"] = json[@"arguments"]; for (NSMutableDictionary *lib in json[@"libraries"]) { NSString *libName = [lib[@"name"] substringToIndex:[lib[@"name"] rangeOfString:@":" options:NSBackwardsSearch].location]; @@ -477,7 +479,6 @@ static AFURLSessionManager* manager; if (!success) return; isUseStackQueueCall = json[@"arguments"] != nil; - minJavaVersion = [json[@"javaVersion"][@"majorVersion"] intValue]; dispatch_async(dispatch_get_main_queue(), ^{ callback(nil, mainProgress, nil); diff --git a/Natives/SurfaceViewController.m b/Natives/SurfaceViewController.m index 2e50857c..ad6d1331 100644 --- a/Natives/SurfaceViewController.m +++ b/Natives/SurfaceViewController.m @@ -2,6 +2,7 @@ #import "JavaLauncher.h" #import "LauncherPreferences.h" +#import "MinecraftDownloader.h" #import "SurfaceViewController.h" #import "egl_bridge.h" #import "ios_uikit_bridge.h" @@ -204,7 +205,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { longpressGesture.delegate = self; longpressGesture.minimumPressDuration = [getPreference(@"time_longPressTrigger") floatValue] / 1000; [self.surfaceView addGestureRecognizer:longpressGesture]; - + self.scrollPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnTouchesScroll:)]; self.scrollPanGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; @@ -316,10 +317,46 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { // [self setPreferredFramesPerSecond:1000]; + [self launchMinecraft]; +} + +- (void)processMinecraftJVMArgs:(NSMutableDictionary *)json { + // Parse Forge 1.17+ additional JVM Arguments + if (json[@"inheritsFrom"] == nil || json[@"arguments"][@"jvm"] == nil) { + return; + } + + json[@"arguments"][@"jvm_processed"] = [[NSMutableArray alloc] init]; + + NSDictionary *varArgMap = @{ + @"${classpath_separator}": @":", + @"${library_directory}": [NSString stringWithFormat:@"%s/libraries", getenv("POJAV_GAME_DIR")], + @"${version_name}": json[@"id"] + }; + + for (id arg in json[@"arguments"][@"jvm"]) { + if ([arg isKindOfClass:NSString.class]) { + NSString *argStr = arg; + for (NSString *key in varArgMap.allKeys) { + argStr = [argStr stringByReplacingOccurrencesOfString:key withString:varArgMap[key]]; + } + [json[@"arguments"][@"jvm_processed"] addObject:argStr]; + } + } +} + +- (void)launchMinecraft { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - launchJVM(BaseAuthenticator.current.authData[@"username"], getPreference(@"selected_version"), savedWidth * resolutionScale, savedHeight * resolutionScale, minJavaVersion); + [MinecraftDownloader downloadClientJson:getPreference(@"selected_version") progress:nil callback:nil success:^(NSMutableDictionary *json) { + [self processMinecraftJVMArgs:json]; + launchJVM( + BaseAuthenticator.current.authData[@"username"], + json, + savedWidth * resolutionScale, savedHeight * resolutionScale, + [json[@"javaVersion"][@"majorVersion"] intValue] + ); + }]; }); - //callback_SurfaceViewController_launchMinecraft(savedWidth * resolutionScale, savedHeight * resolutionScale); } - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures { diff --git a/Natives/input_bridge_v3.m b/Natives/input_bridge_v3.m index bdb852e7..1d8ee24c 100644 --- a/Natives/input_bridge_v3.m +++ b/Natives/input_bridge_v3.m @@ -76,28 +76,12 @@ ADD_CALLBACK_WWIN(WindowPos); #undef ADD_CALLBACK_WWIN -void getJavaInputBridge(jclass* clazz, jmethodID* method) { - debugLog("Debug: Initializing input bridge, method.isNull=%d, jnienv.isNull=%d\n", *method == NULL, runtimeJNIEnvPtr == NULL); - if (*method == NULL && runtimeJNIEnvPtr != NULL) { - *clazz = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "org/lwjgl/glfw/CallbackBridge"); - assert(*clazz != NULL); - *method = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, *clazz, "receiveCallback", "(IFFII)V"); - assert(*method != NULL); - } -} - void sendData(int type, CGFloat i1, CGFloat i2, int i3, int i4) { - if (inputBridgeMethod_ANDROID == NULL) { - (*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr, NULL); - getJavaInputBridge(&inputBridgeClass_ANDROID, &inputBridgeMethod_ANDROID); - } - debugLog("Debug: Send data, jnienv.isNull=%d\n", runtimeJNIEnvPtr == NULL); if (runtimeJNIEnvPtr == NULL) { - debugLog("BUG: Input is ready but thread is not attached yet."); - return; + (*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr, NULL); } - // FIXME: should we send double instead of float? + if(inputBridgeClass_ANDROID == NULL) return; (*runtimeJNIEnvPtr)->CallStaticVoidMethod( runtimeJNIEnvPtr, inputBridgeClass_ANDROID, @@ -158,15 +142,6 @@ void callback_SurfaceViewController_onTouch(int event, CGFloat x, CGFloat y) { (*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr, NULL); } - if (!uikitBridgeClass) { - uikitBridgeClass = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "net/kdt/pojavlaunch/uikit/UIKit"); - assert(uikitBridgeClass != NULL); - } - - if (!uikitBridgeTouchMethod) { - uikitBridgeTouchMethod = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, uikitBridgeClass, "callback_SurfaceViewController_onTouch", "(IFF)V"); - assert(uikitBridgeTouchMethod != NULL); - } (*runtimeJNIEnvPtr)->CallStaticVoidMethod( runtimeJNIEnvPtr, @@ -443,3 +418,16 @@ void CallbackBridge_setWindowAttrib(int attrib, int value) { (jlong) showingWindow, attrib, value ); } + +JNIEXPORT void JNICALL +Java_org_lwjgl_glfw_CallbackBridge_setClass(JNIEnv *env, jclass clazz) { + inputBridgeMethod_ANDROID = (*env)->GetStaticMethodID(env, clazz, "receiveCallback", "(IFFII)V"); + assert(inputBridgeMethod_ANDROID != NULL); + inputBridgeClass_ANDROID = (*env)->NewGlobalRef(env, clazz); + assert(inputBridgeClass_ANDROID != NULL); + + uikitBridgeClass = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "net/kdt/pojavlaunch/uikit/UIKit")); + assert(uikitBridgeClass != NULL); + uikitBridgeTouchMethod = (*env)->GetStaticMethodID(env, uikitBridgeClass, "callback_SurfaceViewController_onTouch", "(IFF)V"); + assert(uikitBridgeTouchMethod != NULL); +} diff --git a/Natives/utils.h b/Natives/utils.h index d155962f..a2bf0d9e 100644 --- a/Natives/utils.h +++ b/Natives/utils.h @@ -36,7 +36,6 @@ #define SPECIALBTN_SCROLLUP -7 #define SPECIALBTN_SCROLLDOWN -8 -int minJavaVersion; JavaVM* runtimeJavaVMPtr; JNIEnv* runtimeJNIEnvPtr; __weak UIViewController *viewController;