From bf1274345720647b26dc9917476f1f57efe3fd58 Mon Sep 17 00:00:00 2001 From: khanhduytran0 Date: Fri, 27 May 2022 05:48:25 +0700 Subject: [PATCH] Moved the JVM entry point to start when needed --- .../java/net/kdt/pojavlaunch/PLaunchApp.java | 88 +-- .../main/java/net/kdt/pojavlaunch/Tools.java | 57 +- .../java/net/kdt/pojavlaunch/uikit/UIKit.java | 60 +- .../src/main/java/org/lwjgl/glfw/GLFW.java | 48 +- .../org/lwjgl/glfw/GLFWWindowProperties.java | 5 +- Natives/CMakeLists.txt | 1 + Natives/CustomControlsViewController.m | 10 +- Natives/JavaGUIViewController.m | 27 +- Natives/JavaLauncher.h | 17 +- Natives/JavaLauncher.m | 585 +++--------------- Natives/LauncherPreferences.h | 4 + Natives/LauncherPreferencesViewController.h | 5 + Natives/LauncherPreferencesViewController.m | 67 +- Natives/MinecraftDownloader.m | 11 +- Natives/SurfaceViewController.m | 9 +- Natives/authenticator/BaseAuthenticator.m | 11 +- Natives/customcontrols/CustomControlsUtils.m | 2 +- Natives/en.lproj/Localizable.strings | 2 + Natives/input_bridge_v3.m | 100 ++- Natives/ios_uikit_bridge.m | 12 +- Natives/main.m | 277 ++++++++- Natives/main_hook.m | 110 ++++ Natives/resources/launcher_profiles.json | 9 - Natives/utils.h | 11 +- Natives/utils.m | 4 +- 25 files changed, 748 insertions(+), 784 deletions(-) create mode 100644 Natives/main_hook.m delete mode 100644 Natives/resources/launcher_profiles.json diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/PLaunchApp.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/PLaunchApp.java index c397bc80..bdca3177 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/PLaunchApp.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/PLaunchApp.java @@ -5,13 +5,14 @@ import java.util.*; import java.util.concurrent.*; import org.lwjgl.glfw.CallbackBridge; +import org.lwjgl.glfw.GLFW; import net.kdt.pojavlaunch.uikit.*; import net.kdt.pojavlaunch.utils.*; import net.kdt.pojavlaunch.value.*; public class PLaunchApp { - private static float currProgress, maxProgress; + private static float currProgress, maxProgress; public static void main(String[] args) throws Throwable { try { @@ -20,57 +21,56 @@ public class PLaunchApp { // Not on JRE8, ignore exception } - // User might remove the minecraft folder, this can cause crashes, safety re-create it - try { - File mcDir = new File(Tools.DIR_GAME_NEW); - mcDir.mkdirs(); - new File(Tools.DIR_ACCOUNT_NEW).mkdirs(); - if (!new File(mcDir.getAbsolutePath() + "/launcher_profiles.json").exists()) { - Tools.write(mcDir.getAbsolutePath() + "/launcher_profiles.json", - Tools.read(Tools.DIR_BUNDLE + "/launcher_profiles.json")); + Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + + public void uncaughtException(Thread t, Throwable th) { + Tools.showError(th); + // Block this thread from exiting + while (true) {} } - } catch (IOException e) { - e.printStackTrace(); - } + }); - System.out.println("We are on java now! Starting UI..."); - UIKit.launchUI(); - } + System.setProperty("cacio.managed.screensize", args[2]); - public static String getStringFromPref(String pref) { - try { - String plistContent = Tools.read(Tools.DIR_APP_DATA + "/launcher_preferences.plist"); - plistContent = plistContent.substring(plistContent.indexOf("" + pref + "") + pref.length() + 11); - return plistContent.substring( - plistContent.indexOf("") + 8, - plistContent.indexOf("")); - } catch (IOException e) { - e.printStackTrace(); - return null; + if (args[0].equals(".LaunchJAR")) { + UIKit.callback_JavaGUIViewController_launchJarFile(args[1]); + } else { + launchMinecraft(args); } } - // Called from SurfaceViewController - public static void launchMinecraft() { - try { - MinecraftAccount account = MinecraftAccount.load(getStringFromPref("internal_selected_account")); - JMinecraftVersionList.Version version = Tools.getVersionInfo(getStringFromPref("selected_version")); - System.out.println("Launching Minecraft " + version.id); - String configPath; - if (version.logging != null) { - if (version.logging.client.file.id.equals("client-1.12.xml")) { - configPath = Tools.DIR_BUNDLE + "/log4j-rce-patch-1.12.xml"; - } else if (version.logging.client.file.id.equals("client-1.7.xml")) { - configPath = Tools.DIR_BUNDLE + "/log4j-rce-patch-1.7.xml"; - } else { - configPath = Tools.DIR_GAME_NEW + "/" + version.logging.client.file.id; - } - System.setProperty("log4j.configurationFile", configPath); + public static void launchMinecraft(String[] args) throws Throwable { + String[] size = args[2].split("x"); + + MCOptionUtils.load(); + MCOptionUtils.set("overrideWidth", size[0]); + MCOptionUtils.set("overrideHeight", size[1]); + MCOptionUtils.save(); + + System.setProperty("org.lwjgl.opengl.libname", System.getenv("POJAV_RENDERER")); + + Tools.mGLFWWindowWidth = Integer.parseInt(size[0]); + Tools.mGLFWWindowHeight = Integer.parseInt(size[1]); + //GLFW.internalChangeMonitorSize(width, height); + //CallbackBridge.mouseX = width / 2; + //CallbackBridge.mouseY = height / 2; + + MinecraftAccount account = MinecraftAccount.load(args[0]); + JMinecraftVersionList.Version version = Tools.getVersionInfo(args[1]); + System.out.println("Launching Minecraft " + version.id); + String configPath; + if (version.logging != null) { + if (version.logging.client.file.id.equals("client-1.12.xml")) { + configPath = Tools.DIR_BUNDLE + "/log4j-rce-patch-1.12.xml"; + } else if (version.logging.client.file.id.equals("client-1.7.xml")) { + configPath = Tools.DIR_BUNDLE + "/log4j-rce-patch-1.7.xml"; + } else { + configPath = Tools.DIR_GAME_NEW + "/" + version.logging.client.file.id; } - Tools.launchMinecraft(account, version); - } catch (Throwable th) { - Tools.showError(th); + System.setProperty("log4j.configurationFile", configPath); } + + Tools.launchMinecraft(account, version); } // TODO diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java index 2656ec5f..401859ab 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -37,12 +37,7 @@ import net.kdt.pojavlaunch.utils.JSONUtils; import net.kdt.pojavlaunch.value.DependentLibrary; import net.kdt.pojavlaunch.value.MinecraftAccount; import org.lwjgl.glfw.GLFW; -/* -import org.robovm.apple.foundation.*; -import org.robovm.apple.uikit.*; -import org.robovm.pods.dialog.*; -import org.robovm.pods.*; -*/ + public final class Tools { public static final boolean ENABLE_DEV_FEATURES = true; // BuildConfig.DEBUG; @@ -78,6 +73,8 @@ public final class Tools public static final String LIBNAME_OPTIFINE = "optifine:OptiFine"; + volatile public static int mGLFWWindowWidth, mGLFWWindowHeight; + public static void launchMinecraft(MinecraftAccount profile, final JMinecraftVersionList.Version versionInfo) throws Throwable { String javaVersion = System.getProperty("java.version"); if (javaVersion.startsWith("1.")) { @@ -125,31 +122,27 @@ public final class Tools } } */ - - new Thread(() -> { try { - System.out.println("Args init finished. Now starting game"); - - // URLClassLoader loader = new URLClassLoader(urlList.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); - - PojavClassLoader loader = (PojavClassLoader) ClassLoader.getSystemClassLoader(); - // add launcher.jar itself - loader.addURL(Tools.class.getProtectionDomain().getCodeSource().getLocation().toURI().toURL()); - for (String s : launchClassPath.split(":")) { - if (!s.isEmpty()) { - loader.addURL(new File(s).toURI().toURL()); - } - } - - Class clazz = loader.loadClass(versionInfo.mainClass); - Method method = clazz.getMethod("main", String[].class); - method.invoke(null, new Object[]{launchArgs}); - // throw new RuntimeException("Game exited. Check latestlog.txt for more details."); - } catch (Throwable th) { - showError(th); + System.out.println("Args init finished. Now starting game"); + + // URLClassLoader loader = new URLClassLoader(urlList.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); + + PojavClassLoader loader = (PojavClassLoader) ClassLoader.getSystemClassLoader(); + // add launcher.jar itself + loader.addURL(Tools.class.getProtectionDomain().getCodeSource().getLocation().toURI().toURL()); + for (String s : launchClassPath.split(":")) { + if (!s.isEmpty()) { + loader.addURL(new File(s).toURI().toURL()); + } } + + Class clazz = loader.loadClass(versionInfo.mainClass); + Method method = clazz.getMethod("main", String[].class); + method.invoke(null, new Object[]{launchArgs}); + + // throw new RuntimeException("Game exited. Check latestlog.txt for more details."); - }).start(); + //}).start(); // JREUtils.launchJavaVM(javaArgList); } @@ -203,13 +196,13 @@ public final class Tools } } minecraftArgs.add("--width"); - minecraftArgs.add(Integer.toString(GLFW.mGLFWWindowWidth)); + minecraftArgs.add(Integer.toString(mGLFWWindowWidth)); minecraftArgs.add("--height"); - minecraftArgs.add(Integer.toString(GLFW.mGLFWWindowHeight)); + minecraftArgs.add(Integer.toString(mGLFWWindowHeight)); minecraftArgs.add("--fullscreenWidth"); - minecraftArgs.add(Integer.toString(GLFW.mGLFWWindowWidth)); + minecraftArgs.add(Integer.toString(mGLFWWindowWidth)); minecraftArgs.add("--fullscreenHeight"); - minecraftArgs.add(Integer.toString(GLFW.mGLFWWindowHeight)); + minecraftArgs.add(Integer.toString(mGLFWWindowHeight)); String[] argsFromJson = JSONUtils.insertJSONValueList( splitAndFilterEmpty( versionInfo.minecraftArguments == null ? 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 0f9c3e14..98c72eab 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java @@ -29,9 +29,7 @@ public class UIKit { System.setProperty("os.name", osName); } - public static void callback_JavaGUIViewController_launchJarFile(final String filepath, int width, int height) { - System.setProperty("cacio.managed.screensize", width + "x" + height); - + public static void callback_JavaGUIViewController_launchJarFile(final String filepath) throws Throwable { // Thread for refreshing the AWT buffer new Thread(() -> { try { @@ -58,49 +56,27 @@ public class UIKit { } }, "AWTFBRefreshThread").start(); - // Thread for launching the JAR file - new Thread(() -> { - String mainClassName = null; - try { - JarFile jarfile = new JarFile(filepath); - String mainClass = jarfile.getManifest().getMainAttributes().getValue("Main-Class"); - jarfile.close(); - if (mainClass == null) { - throw new IllegalArgumentException("no main manifest attribute, in \"" + filepath + "\""); - } + // Launch the JAR file + String mainClassName = null; - PojavClassLoader loader = (PojavClassLoader) ClassLoader.getSystemClassLoader(); - loader.addURL(new File(filepath).toURI().toURL()); + JarFile jarfile = new JarFile(filepath); + String mainClass = jarfile.getManifest().getMainAttributes().getValue("Main-Class"); + jarfile.close(); + if (mainClass == null) { + throw new IllegalArgumentException("no main manifest attribute, in \"" + filepath + "\""); + } - // LabyMod Installer uses FlatLAF which has some macOS-specific codes, so we make it thinks it's running on Linux. - patch_FlatLAF_setLinux(); + PojavClassLoader loader = (PojavClassLoader) ClassLoader.getSystemClassLoader(); + loader.addURL(new File(filepath).toURI().toURL()); - Class clazz = loader.loadClass(mainClass); - Method method = clazz.getMethod("main", String[].class); - method.invoke(null, new Object[]{new String[]{}}); + // LabyMod Installer uses FlatLAF which has some macOS-specific codes, so we make it thinks it's running on Linux. + patch_FlatLAF_setLinux(); - // throw new RuntimeException("Application exited"); - } catch (Throwable th) { - Tools.showError(th, true); - } - }, "ModInstallerThread").start(); + Class clazz = loader.loadClass(mainClass); + Method method = clazz.getMethod("main", String[].class); + method.invoke(null, new Object[]{new String[]{}}); } - public static void callback_SurfaceViewController_launchMinecraft(int width, int height, String rendererLibName) { - MCOptionUtils.load(); - MCOptionUtils.set("overrideWidth", Integer.toString(width)); - MCOptionUtils.set("overrideHeight", Integer.toString(height)); - MCOptionUtils.save(); - - System.setProperty("cacio.managed.screensize", width + "x" + height); - System.setProperty("org.lwjgl.opengl.libname", rendererLibName); - - GLFW.internalChangeMonitorSize(width, height); - CallbackBridge.mouseX = width / 2; - CallbackBridge.mouseY = height / 2; - PLaunchApp.launchMinecraft(); - } - public static void callback_SurfaceViewController_onTouch(int event, float x, float y) { switch (event) { case ACTION_DOWN: @@ -110,7 +86,7 @@ public class UIKit { CallbackBridge.mouseY = y; } break; - + case ACTION_MOVE: if (GLFW.mGLFWIsGrabbing) { CallbackBridge.mouseX += x - CallbackBridge.mouseLastX; @@ -136,7 +112,7 @@ public class UIKit { String str = MCOptionUtils.get("guiScale"); guiScale = (str == null ? 0 :Integer.parseInt(str)); - int scale = Math.max(Math.min(GLFW.mGLFWWindowWidth / 320, GLFW.mGLFWWindowHeight / 240), 1); + int scale = Math.max(Math.min(Tools.mGLFWWindowWidth / 320, Tools.mGLFWWindowHeight / 240), 1); if(scale < guiScale || guiScale == 0){ guiScale = scale; } diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java b/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java index 01191915..28f99718 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java @@ -11,6 +11,8 @@ import java.nio.*; import javax.annotation.*; +import net.kdt.pojavlaunch.Tools; + import org.lwjgl.*; import org.lwjgl.opengl.GL; import org.lwjgl.system.*; @@ -484,7 +486,6 @@ public class GLFW /* volatile */ public static GLFWWindowRefreshCallback mGLFWWindowRefreshCallback; /* volatile */ public static GLFWWindowSizeCallback mGLFWWindowSizeCallback; - volatile public static int mGLFWWindowWidth, mGLFWWindowHeight; volatile public static double mGLFWCursorX, mGLFWCursorY, mGLFWCursorLastX, mGLFWCursorLastY; private static GLFWGammaRamp mGLFWGammaRamp; @@ -499,23 +500,26 @@ public class GLFW public static boolean mGLFWIsGrabbing, mGLFWIsInputReady, mGLFWIsUseStackQueue = false; public static final byte[] keyDownBuffer = new byte[317]; public static long mainContext = 0; - static { - try { + static { + try { System.load(System.getenv("BUNDLE_PATH") + "/PojavLauncher"); } catch (UnsatisfiedLinkError e) { e.printStackTrace(); } - - // Minecraft triggers a glfwPollEvents() on splash screen, so update window size there. - CallbackBridge.receiveCallback(CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE, mGLFWWindowWidth, mGLFWWindowHeight, 0, 0); - CallbackBridge.receiveCallback(CallbackBridge.EVENT_TYPE_WINDOW_SIZE, mGLFWWindowWidth, mGLFWWindowHeight, 0, 0); - mGLFWErrorCallback = GLFWErrorCallback.createPrint(); - mGLFWKeyCodes = new ArrayMap<>(); + // 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); + + mGLFWErrorCallback = GLFWErrorCallback.createPrint(); + mGLFWKeyCodes = new ArrayMap<>(); mGLFWWindowMap = new ArrayMap<>(); mGLFWVideoMode = new GLFWVidMode(ByteBuffer.allocateDirect(GLFWVidMode.SIZEOF)); + internalChangeMonitorSize(Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight); + /* memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.REDBITS, 8); memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.GREENBITS, 8); @@ -593,10 +597,10 @@ public class GLFW } public static void internalChangeMonitorSize(int width, int height) { - mGLFWWindowWidth = width; - mGLFWWindowHeight = height; - memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.WIDTH, mGLFWWindowWidth); - memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.HEIGHT, mGLFWWindowHeight); + Tools.mGLFWWindowWidth = width; + Tools.mGLFWWindowHeight = height; + memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.WIDTH, Tools.mGLFWWindowWidth); + memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.HEIGHT, Tools.mGLFWWindowHeight); } public static GLFWWindowProperties internalGetWindow(long window) { @@ -671,7 +675,7 @@ public class GLFW /* try { - mGLFWFramebufferSizeCallback.invoke(window, mGLFWWindowWidth, mGLFWWindowHeight); + mGLFWFramebufferSizeCallback.invoke(window, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight); } catch (Throwable th) {} */ @@ -781,7 +785,7 @@ public class GLFW mGLFWWindowSizeCallback = GLFWWindowSizeCallback.createSafe(nglfwSetWindowSizeCallback(window, memAddressSafe(cbfun))); try { - mGLFWWindowSizeCallback.invoke(window, mGLFWWindowWidth, mGLFWWindowHeight); + mGLFWWindowSizeCallback.invoke(window, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight); } catch (Throwable th) {} return lastCallback; @@ -855,8 +859,8 @@ public class GLFW xpos.put(0); ypos.put(0); - width.put(mGLFWWindowWidth); - height.put(mGLFWWindowHeight); + width.put(Tools.mGLFWWindowWidth); + height.put(Tools.mGLFWWindowHeight); } @NativeType("GLFWmonitor *") @@ -1101,11 +1105,11 @@ public class GLFW case CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE: case CallbackBridge.EVENT_TYPE_WINDOW_SIZE: internalChangeMonitorSize((int)dataArr[1], (int)dataArr[2]); - glfwSetWindowSize(ptr, mGLFWWindowWidth, mGLFWWindowHeight); + glfwSetWindowSize(ptr, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight); if ((int)dataArr[0] == CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE && mGLFWFramebufferSizeCallback != null) { - mGLFWFramebufferSizeCallback.invoke(ptr, mGLFWWindowWidth, mGLFWWindowHeight); + mGLFWFramebufferSizeCallback.invoke(ptr, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight); } else if ((int)dataArr[0] == CallbackBridge.EVENT_TYPE_WINDOW_SIZE && mGLFWWindowSizeCallback != null) { - mGLFWWindowSizeCallback.invoke(ptr, mGLFWWindowWidth, mGLFWWindowHeight); + mGLFWWindowSizeCallback.invoke(ptr, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight); } break; default: @@ -1303,8 +1307,8 @@ return false; xpos[0] = 0; ypos[0] = 0; - width[0] = mGLFWWindowWidth; - height[0] = mGLFWWindowHeight; + width[0] = Tools.mGLFWWindowWidth; + height[0] = Tools.mGLFWWindowHeight; } /** Array version of: {@link #glfwGetMonitorPhysicalSize GetMonitorPhysicalSize} */ diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java b/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java index b7f42df8..15a6c668 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java @@ -1,10 +1,11 @@ package org.lwjgl.glfw; import java.util.*; +import net.kdt.pojavlaunch.Tools; public class GLFWWindowProperties { - public int width = GLFW.mGLFWWindowWidth; - public int height = GLFW.mGLFWWindowHeight; + public int width = Tools.mGLFWWindowWidth; + public int height = Tools.mGLFWWindowHeight; public float x, y; public CharSequence title; public boolean shouldClose, isInitialSizeCalled, isCursorEntered; diff --git a/Natives/CMakeLists.txt b/Natives/CMakeLists.txt index be708ccd..52b30b38 100644 --- a/Natives/CMakeLists.txt +++ b/Natives/CMakeLists.txt @@ -50,6 +50,7 @@ target_link_libraries(libOSMesaOverride.dylib ${OSMESA_LIB}) add_executable(PojavLauncher main.m + main_hook.m log.m JavaLauncher.m external/fishhook/fishhook.c diff --git a/Natives/CustomControlsViewController.m b/Natives/CustomControlsViewController.m index b97bb3b4..a475d517 100644 --- a/Natives/CustomControlsViewController.m +++ b/Natives/CustomControlsViewController.m @@ -129,7 +129,7 @@ NSMutableArray *keyCodeMap, *keyValueMap; [self.offsetView addGestureRecognizer:longpressGesture]; self.currentFileName = [getPreference(@"default_ctrl") stringByDeletingPathExtension]; [self initKeyCodeMap]; - [self loadControlFile:[NSString stringWithFormat:@"%s/%@", getenv("POJAV_PATH_CONTROL"), getPreference(@"default_ctrl")]]; + [self loadControlFile:[NSString stringWithFormat:@"%s/controlmap/%@", getenv("POJAV_HOME"), getPreference(@"default_ctrl")]]; } - (void)loadControlFile:(NSString *)controlFilePath { @@ -210,7 +210,7 @@ NSMutableArray *keyCodeMap, *keyValueMap; - (void)actionMenuSave { UIAlertController *controller = [UIAlertController alertControllerWithTitle: @"Save" - message:[NSString stringWithFormat:@"File will be saved to %s directory.", getenv("POJAV_PATH_CONTROL")] + message:[NSString stringWithFormat:@"File will be saved to %s/controlmap directory.", getenv("POJAV_HOME")] preferredStyle:UIAlertControllerStyleAlert]; [controller addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = @"Name"; @@ -232,7 +232,7 @@ NSMutableArray *keyCodeMap, *keyValueMap; return; } NSString *jsonStr = [NSString stringWithUTF8String:jsonData.bytes]; - BOOL success = [jsonStr writeToFile:[NSString stringWithFormat:@"%s/%@.json", getenv("POJAV_PATH_CONTROL"), field.text] atomically:YES encoding:NSUTF8StringEncoding error:&error]; + BOOL success = [jsonStr writeToFile:[NSString stringWithFormat:@"%s/controlmap/%@.json", getenv("POJAV_HOME"), field.text] atomically:YES encoding:NSUTF8StringEncoding error:&error]; if (!success) { showDialog(self, @"Error while saving file", error.localizedDescription); return; @@ -263,14 +263,14 @@ NSMutableArray *keyCodeMap, *keyValueMap; - (void)actionMenuLoad { [self actionOpenFilePicker:^void(NSString* name) { self.currentFileName = name; - [self loadControlFile:[NSString stringWithFormat:@"%s/%@.json", getenv("POJAV_PATH_CONTROL"), name]]; + [self loadControlFile:[NSString stringWithFormat:@"%s/controlmap/%@.json", getenv("POJAV_HOME"), name]]; }]; } - (void)actionMenuSetDef { [self actionOpenFilePicker:^void(NSString* name) { self.currentFileName = name; - [self loadControlFile:[NSString stringWithFormat:@"%s/%@.json", getenv("POJAV_PATH_CONTROL"), name]]; + [self loadControlFile:[NSString stringWithFormat:@"%s/controlmap/%@.json", getenv("POJAV_HOME"), name]]; setPreference(@"default_ctrl", [NSString stringWithFormat:@"%@.json", name]); }]; } diff --git a/Natives/JavaGUIViewController.m b/Natives/JavaGUIViewController.m index 194d1c56..e94748e0 100644 --- a/Natives/JavaGUIViewController.m +++ b/Natives/JavaGUIViewController.m @@ -1,4 +1,5 @@ #import "JavaGUIViewController.h" +#import "JavaLauncher.h" #import "LauncherPreferences.h" #import "ios_uikit_bridge.h" #include "utils.h" @@ -10,6 +11,12 @@ jclass class_CTCAndroidInput; jmethodID method_ReceiveInput; JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_uikit_UIKit_refreshAWTBuffer(JNIEnv* env, jclass clazz, jintArray jreRgbArray) { + if (!runtimeJNIEnvPtr) { + dispatch_async(dispatch_get_main_queue(), ^{ + (*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr, NULL); + }); + } + int *tmpArray = (*env)->GetIntArrayElements(env, jreRgbArray, 0); memcpy(rgbArray, tmpArray, savedWidth * savedHeight * 4); (*env)->ReleaseIntArrayElements(env, jreRgbArray, tmpArray, JNI_ABORT); @@ -106,14 +113,16 @@ const void * _CGDataProviderGetBytePointerCallbackAWT(void *info) { rgbArray = calloc(4, (size_t) (savedWidth * savedHeight)); - UIKit_launchJarFile(self.filepath.UTF8String); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + launchJVM(@".LaunchJAR", self.filepath, savedWidth * resolutionScale, savedHeight * resolutionScale); + }); } - (void)surfaceOnClick:(UITapGestureRecognizer *)sender { if (method_ReceiveInput == NULL) { - class_CTCAndroidInput = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "net/java/openjdk/cacio/ctc/CTCAndroidInput"); + class_CTCAndroidInput = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "net/java/openjdk/cacio/ctc/CTCAndroidInput"); assert(class_CTCAndroidInput != NULL); - method_ReceiveInput = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, class_CTCAndroidInput, "receiveData", "(IIIII)V"); + method_ReceiveInput = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, class_CTCAndroidInput, "receiveData", "(IIIII)V"); assert(method_ReceiveInput != NULL); } @@ -123,20 +132,20 @@ const void * _CGDataProviderGetBytePointerCallbackAWT(void *info) { CGPoint location = [sender locationInView:sender.view]; CGFloat x = location.x * screenScale * resolution; CGFloat y = location.y * screenScale * resolution; - (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( - runtimeJNIEnvPtr_JRE, + (*runtimeJNIEnvPtr)->CallStaticVoidMethod( + runtimeJNIEnvPtr, class_CTCAndroidInput, method_ReceiveInput, EVENT_TYPE_CURSOR_POS, (int)x, (int)y, 0, 0 ); - (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( - runtimeJNIEnvPtr_JRE, + (*runtimeJNIEnvPtr)->CallStaticVoidMethod( + runtimeJNIEnvPtr, class_CTCAndroidInput, method_ReceiveInput, EVENT_TYPE_MOUSE_BUTTON, BUTTON1_DOWN_MASK, 1, 0, 0 ); - (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( - runtimeJNIEnvPtr_JRE, + (*runtimeJNIEnvPtr)->CallStaticVoidMethod( + runtimeJNIEnvPtr, class_CTCAndroidInput, method_ReceiveInput, EVENT_TYPE_MOUSE_BUTTON, BUTTON1_DOWN_MASK, 0, 0, 0 diff --git a/Natives/JavaLauncher.h b/Natives/JavaLauncher.h index ce0e43b1..5482b689 100644 --- a/Natives/JavaLauncher.h +++ b/Natives/JavaLauncher.h @@ -1,7 +1,20 @@ #pragma once #include +#include "jni.h" -static BOOL started = NO; +typedef jint JLI_Launch_func(int argc, char ** argv, /* main argc, argc */ + int jargc, const char** jargv, /* java args */ + int appclassc, const char** appclassv, /* app classpath */ + const char* fullversion, /* full version defined */ + const char* dotversion, /* dot version defined */ + const char* pname, /* program name */ + const char* lname, /* launcher name */ + jboolean javaargs, /* JAVA_ARGS */ + jboolean cpwildcard, /* classpath wildcard*/ + jboolean javaw, /* windows-only javaw */ + jint ergo /* ergonomics class policy */ +); +JLI_Launch_func *pJLI_Launch; -int launchJVM(int argc, char *argv[]); +int launchJVM(NSString *username, NSString *selectedVersion, int width, int height); diff --git a/Natives/JavaLauncher.m b/Natives/JavaLauncher.m index 89c70722..54cad6df 100644 --- a/Natives/JavaLauncher.m +++ b/Natives/JavaLauncher.m @@ -3,45 +3,23 @@ #include #include #include -#include #include #include #include #include +#include #include -#include -#include -#include -#include - -#include "jni.h" #include "log.h" #include "utils.h" #include "JavaLauncher.h" -#include "external/fishhook/fishhook.h" -#import "customcontrols/CustomControlsUtils.h" #import "LauncherPreferences.h" -// PojavLancher: fixme: are these wrong? -#define FULL_VERSION "1.8.0-internal" -#define DOT_VERSION "1.8" - -#if CONFIG_RELEASE == 1 -# define CONFIG_TYPE "release" -#else -# define CONFIG_TYPE "debug" -#endif - -#ifndef CONFIG_COMMIT -# define CONFIG_COMMIT unspecified -#endif +#define fm NSFileManager.defaultManager static char java_libs_path[2048]; static char args_path[2048]; -static char env_path[2048]; -static char log_path[2048]; extern char **environ; @@ -53,33 +31,8 @@ static const jboolean const_javaw = JNI_FALSE; static const jboolean const_cpwildcard = JNI_TRUE; static const jint const_ergo_class = 0; // DEFAULT_POLICY -typedef jint JLI_Launch_func(int argc, char ** argv, /* main argc, argc */ - int jargc, const char** jargv, /* java args */ - int appclassc, const char** appclassv, /* app classpath */ - const char* fullversion, /* full version defined */ - const char* dotversion, /* dot version defined */ - const char* pname, /* program name */ - const char* lname, /* launcher name */ - jboolean javaargs, /* JAVA_ARGS */ - jboolean cpwildcard, /* classpath wildcard*/ - jboolean javaw, /* windows-only javaw */ - jint ergo /* ergonomics class policy */ -); - -int main(int argc, char * argv[]); - -static int (*orig_dladdr)(const void* addr, Dl_info* info); -static void* (*orig_dlopen)(const char* path, int mode); -//static void* (*orig_mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset); -static char* (*orig_realpath)(const char *restrict path, char *restrict resolved_path); -//static void (*orig_sys_icache_invalidate)(void *start, size_t len); - static int margc = 0; static char* margv[1000]; -static int pfd[2]; -static int log_fd; -static pthread_t logger; -static BOOL filteredSessionID; const char *javaHome; const char *renderer; @@ -88,149 +41,10 @@ const char *multidir; char *homeDir; -NSString *javaHome_pre; NSString *renderer_pre; NSString *allocmem_pre; NSString *multidir_pre; -int hooked_dladdr(const void* addr, Dl_info* info) { - //NSLog(@"hook dladdr(%p, %p)", addr, info); - int retVal = orig_dladdr(addr, info); - if (addr == main) { - //NSLog(@"hooked dladdr"); - info->dli_fname = getenv("JAVA_EXT_EXECNAME"); - } else if (retVal != 0) { - //NSLog(@"hooked dladdr"); - char *libname = basename((char *)info->dli_fname); - char src[2048], dst[2048]; - sprintf((char *)src, "%s/Frameworks", getenv("BUNDLE_PATH")); - if (0 == strncmp(info->dli_fname, src, strlen(src))) { - if (0 == strncmp(libname, "libjli.dylib", 12)) { - info->dli_fname = getenv("INTERNAL_JLI_PATH"); - } else if (0 == strncmp(libname, "libjvm.dylib", 12)) { - sprintf((char *)dst, "%s/lib/server/libjvm.dylib", getenv("JAVA_HOME")); - info->dli_fname = (char *)dst; - } - } - } - //if (retVal) NSLog(@"dli_fname=%s", info->dli_fname); - return retVal; -} - -void* hooked_dlopen(const char* path, int mode) { - void *handle = orig_dlopen(path, mode); - if (handle) { - return handle; - } - - char src[2048], dst[2048]; - sprintf((char *)src, "%s/Frameworks", getenv("BUNDLE_PATH")); - //NSLog(@"path=%s, src=%s, length=%lu, compare=%d", path, src, strlen(src), strncmp(path, src, strlen(src))); - if (!strncmp(path, src, strlen(src))) { - //NSLog(@"hooked dlopen %s", path); - char *libname = basename((char *)path); - sprintf((char *)dst, "%s/%s.framework/%s", src, libname, libname); - handle = orig_dlopen(dst, mode); - if (handle) { - dlerror(); // clear error - } - } - - return handle; -} - -/* -void *hooked_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { - NSLog(@"mmap(%p, %ld, %d, %d, %d, %lld)", addr, len, prot, flags, fd, offset); - - if (flags & MAP_JIT) { - NSLog(@"'-> Found JIT mmap"); - //flags &= ~MAP_JIT; - } - - // raise(SIGINT); - return orig_mmap(addr, len, prot, flags, fd, offset); -} -*/ - -char *hooked_realpath(const char *restrict path, char *restrict resolved_path) { - //NSLog(@"hook realpath %s", path); - if (0 == strncmp(path, javaHome, strlen(javaHome))) { - strcpy(resolved_path, path); - return resolved_path; - } else { - return orig_realpath(path, resolved_path); - } -} - -/* -void hooked_sys_icache_invalidate(void *start, size_t len) { - // mprotect(start, 16384, PROT_EXEC | PROT_READ); - // NSLog(@"mprotect errno %d", errno); - orig_sys_icache_invalidate(start, len); -} -*/ - -static void *logger_thread() { - ssize_t rsize; - char buf[2048]; - while((rsize = read(pfd[0], buf, sizeof(buf)-1)) > 0) { - // Filter out Session ID here - int index; - if (!filteredSessionID) { - char *sessionStr = strstr(buf, "(Session ID is "); - if (sessionStr) { - char *censorStr = "(Session ID is )\n\0"; - strcpy(sessionStr, censorStr); - rsize = strlen(buf); - filteredSessionID = true; - } - } - write(log_fd, buf, rsize); - } - close(log_fd); - return NULL; -} - -void init_hookFunctions() { - // if (!started && strncmp(argv[0], "/Applications", 13)) - // Jailed only: hook some functions for symlinked JRE home dir - int retval = rebind_symbols((struct rebinding[3]){ - {"dladdr", hooked_dladdr, (void *)&orig_dladdr}, - {"dlopen", hooked_dlopen, (void *)&orig_dlopen}, - //{"realpath", hooked_realpath, (void *)&orig_realpath}, - {"realpath$DARWIN_EXTSN", hooked_realpath, (void *)&orig_realpath} - //{"mmap", hooked_mmap, (void *)&orig_mmap}, - //{"sys_icache_invalidate", hooked_sys_icache_invalidate, (void *)&orig_sys_icache_invalidate} - }, 3); - NSLog(@"hook retval = %d", retval); -} - -void init_loadCustomEnv() { - FILE *envFile = fopen(env_path, "r"); - - regLog("[Pre-init] Reading custom environment variables (custom_env.txt), opened=%d\n", envFile != NULL); - - if (envFile) { - char *line = NULL; - size_t len = 0; - ssize_t read; - while ((read = getline(&line, &len, envFile)) != -1) { - if (line[0] == '#' || line[0] == '\n') continue; - if (line[read-1] == '\n') { - line[read-1] = '\0'; - } - if (strchr(line, '=') != NULL) { - regLog("[Pre-init] Added custom env: %s", line); - setenv(strtok(line, "="), strtok(NULL, "="), 1); - } else { - regLog("[Pre-init] Warning: skipped empty value custom env: %s", line); - } - } - fclose(envFile); - } -} - void init_loadCustomJvmFlags() { NSString *jvmargs = getPreference(@"java_args"); BOOL isFirstArg = YES; @@ -250,193 +64,51 @@ void init_loadCustomJvmFlags() { } } -void init_migrateToPlist(char* prefKey, char* filename) { - // NSString *readmeStr = @"#README - this file has been merged into launcher_preferences.plist"; - NSError *error; - NSString *str, *path_str; - - // overrideargs.txt - path_str = [NSString stringWithFormat:@"%s/%s", getenv("POJAV_HOME"), filename]; - str = [NSString stringWithContentsOfFile:path_str encoding:NSUTF8StringEncoding error:&error]; - if (error == nil && ![str hasPrefix:@"#README"]) { - setPreference(@(prefKey), str); - [@"#README - this file has been merged into launcher_preferences.plist" writeToFile:path_str atomically:YES encoding:NSUTF8StringEncoding error:nil]; - } -} - -void init_logDeviceAndVer (char *argument) { - struct utsname systemInfo; - uname(&systemInfo); - // Hardware + software - const char *deviceHardware = systemInfo.machine; - const char *deviceSoftware = [[[UIDevice currentDevice] systemVersion] cStringUsingEncoding:NSUTF8StringEncoding]; - - // Jailbreak - const char *jbStrap; - if (strncmp(argument, "/Applications", 13) == 0) { - if ([[NSFileManager defaultManager] fileExistsAtPath:@"/.procursus_strapped"]) { - jbStrap = "Procursus"; - } else { - jbStrap = "Other"; - } - regLog("[Pre-Init] %s with iOS %s (%s)", deviceHardware, deviceSoftware, jbStrap); - } else { - regLog("[Pre-Init] %s with iOS %s", deviceHardware, deviceSoftware); - } - - // PojavLauncher version - regLog("[Pre-Init] PojavLauncher version: %s - %s", CONFIG_TYPE, CONFIG_COMMIT); - - setenv("POJAV_DETECTEDHW", deviceHardware, 1); - setenv("POJAV_DETECTEDSW", deviceSoftware, 1); - if (strncmp(argument, "/Applications", 13) == 0) { - setenv("POJAV_DETECTEDJB", jbStrap, 1); - } -} - -void init_redirectStdio(char* homeDir) { - regLog("[Pre-init] Staring logging STDIO as jrelog:V\n"); - // Redirect stdio to latestlog.txt - char newname[2048]; - sprintf(newname, "%s/latestlog.old.txt", homeDir); - rename(log_path, newname); - FILE* logFile = fopen(log_path, "w"); - if (!logFile) { - regLog("[Pre-init] Error: failed to open %s: %s", log_path, strerror(errno)); - assert(0 && "Failed to open latestlog.txt. Check oslog for more details."); - } - log_fd = fileno(logFile); - setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered - setvbuf(stderr, 0, _IONBF, 0); // make stderr unbuffered - - /* create the pipe and redirect stdout and stderr */ - pipe(pfd); - dup2(pfd[1], 1); - dup2(pfd[1], 2); - - /* spawn the logging thread */ - if(pthread_create(&logger, 0, logger_thread, 0) == -1) { - char *fail_str = "Failed to start logging!"; - write(log_fd, fail_str, strlen(fail_str)); - close(log_fd); - } - pthread_detach(logger); -} - -void environmentFailsafes(char *argv[]) { - if (strncmp(argv[0], "/Applications", 13) == 0) { - if (0 == access("/usr/lib/jvm/java-8-openjdk/", F_OK)) { - javaHome_pre = @"/usr/lib/jvm/java-8-openjdk"; - } else if (0 == access("/usr/lib/jvm/java-16-openjdk/", F_OK)) { +NSString* environmentFailsafes() { + NSString *javaHome_pre; + if (strncmp(getenv("BUNDLE_PATH"), "/Applications", 13) == 0) { + if ([fm fileExistsAtPath:JRE8_HOME_JB]) { + javaHome_pre = JRE8_HOME_JB; + } else if ([fm fileExistsAtPath:JRE16_HOME_JB]) { regLog("[Pre-init] Java 8 wasn't found on your device. Install Java 8 for more compatibility and the mod installer."); - javaHome_pre = @"/usr/lib/jvm/java-16-openjdk"; - } else if (0 == access("/usr/lib/jvm/java-17-openjdk/", F_OK)) { + javaHome_pre = JRE16_HOME_JB; + } else if ([fm fileExistsAtPath:JRE17_HOME_JB]) { regLog("[Pre-init] Java 8 wasn't found on your device. Install Java 8 for more compatibility and the mod installer."); - javaHome_pre = @"/usr/lib/jvm/java-17-openjdk"; + javaHome_pre = JRE17_HOME_JB; } else { regLog("[Pre-init] FATAL ERROR: Java wasn't found on your device, PojavLauncher cannot continue, aborting."); abort(); } - javaHome = [javaHome_pre cStringUsingEncoding:NSUTF8StringEncoding]; - setPreference(@"java_home", javaHome_pre); } else { - asprintf((char **)&javaHome, "%s/jre", homeDir); + javaHome_pre = [NSString stringWithFormat:@"%s/jre", getenv("POJAV_HOME")]; } + + javaHome = javaHome_pre.UTF8String; + setPreference(@"java_home", javaHome_pre); + return javaHome_pre; } -int launchJVM(int argc, char *argv[]) { - if (0 != [[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Documents/.pojavlauncher"] && 0 == [[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Documents/.pojavlauncher/migration_complete"]) { - NSString *newDir = @"/usr/share/pojavlauncher"; - if([[[UIDevice currentDevice] systemVersion] containsString:@"15."]) { - newDir = @"/private/preboot/procursus/usr/share/pojavlauncher"; - } - NSString *oldDir = @"/var/mobile/Documents/.pojavlauncher"; - NSFileManager *fm = [NSFileManager defaultManager]; - NSArray *files = [fm contentsOfDirectoryAtPath:oldDir error:nil]; - for (NSString *file in files) { - [fm moveItemAtPath:[oldDir stringByAppendingPathComponent:file] toPath:[newDir stringByAppendingPathComponent:file] error:nil]; - } - [fm removeItemAtPath:oldDir error:nil]; - symlink([newDir cStringUsingEncoding:NSUTF8StringEncoding], [oldDir cStringUsingEncoding:NSUTF8StringEncoding]); - FILE* file_ptr = fopen("/var/mobile/Documents/.pojavlauncher/migration_complete", "w"); - fprintf(file_ptr, "#README - The PojavLauncher data directory is now %s. All of your existing data has been moved to the new location.", [newDir cStringUsingEncoding:NSUTF8StringEncoding]); - fclose(file_ptr); - } - - if (!started) { - setenv("EXEC_PATH", argv[0], 1); - setenv("BUNDLE_PATH", dirname(argv[0]), 1); - - // Are we running on a jailbroken environment? - if (strncmp(argv[0], "/Applications", 13) == 0) { - setenv("HOME", "/usr/share", 1); - setenv("OLD_POJAV_HOME", "/var/mobile/Documents/.pojavlauncher", 1); - homeDir = "/usr/share/pojavlauncher"; - } else { - char pojavHome[2048]; - sprintf(pojavHome, "%s/Documents", getenv("HOME")); - homeDir = (char *) pojavHome; - - init_hookFunctions(); - } - setenv("POJAV_HOME", homeDir, 1); - } else { - homeDir = getenv("POJAV_HOME"); - } - - init_loadCustomEnv(); - - loadPreferences(); - - init_migrateToPlist("selected_version", "config_ver.txt"); - init_migrateToPlist("java_args", "overrideargs.txt"); - - sprintf((char*) env_path, "%s/custom_env.txt", homeDir); - sprintf((char*) log_path, "%s/latestlog.txt", homeDir); +int launchJVM(NSString *username, NSString *selectedVersion, int width, int height) { sprintf((char*) java_libs_path, "%s/libs", getenv("BUNDLE_PATH")); - - mkdir(dirname(log_path), 755); - if (!started) { - init_redirectStdio(homeDir); - } - - init_logDeviceAndVer(argv[0]); regLog("[Pre-init] Beginning JVM launch\n"); - - char javaAwtPath[4096]; - // I accidentally patched a bit wrong, the value should be a path containing libawt_xawt.dylib, but here is libawt.dylib path (no need to exist) - sprintf(javaAwtPath, "%s/Frameworks/libawt.dylib", getenv("BUNDLE_PATH")); - setenv("JAVA_AWT_PATH", javaAwtPath, 1); - // setenv("LIBGL_FB", "2", 1); - setenv("LIBGL_MIPMAP", "3", 1); - - // Fix white color on banner and sheep, since GL4ES 1.1.5 - setenv("LIBGL_NORMALIZE", "1", 1); - - // Disable overloaded functions hack for Minecraft 1.17+ - setenv("LIBGL_NOINTOVLHACK", "1", 1); - - // Override OpenGL version to 4.1 for Zink - setenv("MESA_GL_VERSION_OVERRIDE", "4.1", 1); - - javaHome_pre = getPreference(@"java_home"); - javaHome = [javaHome_pre cStringUsingEncoding:NSUTF8StringEncoding]; - if ([javaHome_pre length] == 0) { - environmentFailsafes(argv); + NSString *javaHome_pre = getPreference(@"java_home"); + javaHome = javaHome_pre.UTF8String; + if (javaHome_pre.length == 0) { + environmentFailsafes(); regLog("[Pre-init] JAVA_HOME environment variable was not set. Defaulting to %s for future use.\n", javaHome); } else { - if (0 == [[NSFileManager defaultManager] fileExistsAtPath:javaHome_pre]) { + if (![NSFileManager.defaultManager fileExistsAtPath:javaHome_pre]) { regLog("[Pre-Init] Failed to locate %s. Restoring default value for JAVA_HOME.", javaHome); - environmentFailsafes(argv); + environmentFailsafes(); } else { regLog("[Pre-Init] Restored preference: JAVA_HOME is set to %s\n", javaHome); } } setenv("JAVA_HOME", javaHome, 1); - if (!started && strncmp(argv[0], "/Applications", 13)) { + if (strncmp(getenv("BUNDLE_PATH"), "/Applications", 13)) { char src[2048], dst[2048]; // Symlink frameworks -> dylibs on jailed environment @@ -523,27 +195,20 @@ int launchJVM(int argc, char *argv[]) { } renderer_pre = getPreference(@"renderer"); - renderer = [renderer_pre cStringUsingEncoding:NSUTF8StringEncoding]; - if ([renderer_pre length] == 0) { + renderer = renderer_pre.UTF8String; + if (renderer_pre.length == 0) { renderer_pre = @"libgl4es_114.dylib"; setPreference(@"renderer", renderer_pre); renderer = [renderer_pre cStringUsingEncoding:NSUTF8StringEncoding]; - setenv("POJAV_RENDERER", renderer, 1); regLog("[Pre-init] RENDERER environment variable was not set. Defaulting to %s for future use.\n", renderer); } else { regLog("[Pre-Init] Restored preference: RENDERER is set to %s\n", renderer); } + setenv("POJAV_RENDERER", renderer, 1); allocmem_pre = [getPreference(@"allocated_memory") stringValue]; allocmem = [allocmem_pre cStringUsingEncoding:NSUTF8StringEncoding]; - char *controlPath; - asprintf(&controlPath, "%s/controlmap", homeDir); - mkdir(controlPath, S_IRWXU | S_IRWXG | S_IRWXO); - setenv("POJAV_PATH_CONTROL", controlPath, 1); - free(controlPath); - generateAndSaveDefaultControl(); - char classpath[10000]; // "/Applications/PojavLauncher.app/libs/launcher.jar:/Applications/PojavLauncher.app/libs/ExagearApacheCommons.jar:/Applications/PojavLauncher.app/libs/gson-2.8.6.jar:/Applications/PojavLauncher.app/libs/jsr305.jar:/Applications/PojavLauncher.app/libs/lwjgl3-minecraft.jar"; @@ -566,73 +231,37 @@ int launchJVM(int argc, char *argv[]) { closedir(d); } debugLog("[Pre-init] Classpath generated: %s", classpath); - - multidir_pre = getPreference(@"game_directory"); - multidir = [multidir_pre cStringUsingEncoding:NSUTF8StringEncoding]; - if ([multidir_pre length] == 0) { - multidir_pre = @"default"; - multidir = [multidir_pre cStringUsingEncoding:NSUTF8StringEncoding]; - setPreference(@"game_directory", multidir_pre); - regLog("[Pre-init] MULTI_DIR environment variable was not set. Defaulting to %s for future use.\n", multidir); - } else { - multidir = [multidir_pre cStringUsingEncoding:NSUTF8StringEncoding]; - regLog("[Pre-init] Restored preference: MULTI_DIR is set to %s\n", multidir); - } - char *multidir_char, *librarySym; - asprintf(&multidir_char, "%s/instances/%s", getenv("POJAV_HOME"), multidir); - asprintf(&librarySym, "%s/Library/Application Support/minecraft", getenv("POJAV_HOME")); - remove(librarySym); - if (0 != access(multidir_char, F_OK)) { - mkdir(multidir_char, 755); - } - symlink(multidir_char, librarySym); - setenv("POJAV_GAME_DIR", librarySym, 1); - - if (0 == access("/var/mobile/Documents/minecraft", F_OK)) { - rename("/var/mobile/Documents/minecraft", multidir_char); - regLog("[Pre-Init] Migrated old minecraft folder to new location."); - } - - if (0 == access("/var/mobile/Documents/Library", F_OK)) { - remove("/var/mobile/Documents/Library"); - } + // Check if JVM restarts - if (!started) { - char *frameworkPath, *javaPath, *jnaLibPath, *userDir, *userHome, *memMin, *memMax, *arcDNS; - asprintf(&frameworkPath, "-Djava.library.path=%s/Frameworks:%s/Frameworks/libOSMesaOverride.dylib.framework", getenv("BUNDLE_PATH"), getenv("BUNDLE_PATH")); - asprintf(&javaPath, "%s/bin/java", javaHome); - asprintf(&jnaLibPath, "-Djna.boot.library.path=%s/Frameworks/libjnidispatch.dylib.framework", getenv("BUNDLE_PATH")); - asprintf(&userDir, "-Duser.dir=%s", getenv("POJAV_GAME_DIR")); - asprintf(&userHome, "-Duser.home=%s", getenv("POJAV_HOME")); - asprintf(&memMin, "-Xms%sM", allocmem); - asprintf(&memMax, "-Xmx%sM", allocmem); - asprintf(&arcDNS, "-javaagent:%s/arc_dns_injector.jar=23.95.137.176", java_libs_path); - NSLog(@"[Pre-init] Java executable path: %s", javaPath); - setenv("JAVA_EXT_EXECNAME", javaPath, 1); + char *frameworkPath, *javaPath, *jnaLibPath, *userDir, *userHome, *memMin, *memMax, *arcDNS; + asprintf(&frameworkPath, "-Djava.library.path=%s/Frameworks:%s/Frameworks/libOSMesaOverride.dylib.framework", getenv("BUNDLE_PATH"), getenv("BUNDLE_PATH")); + asprintf(&javaPath, "%s/bin/java", javaHome); + asprintf(&jnaLibPath, "-Djna.boot.library.path=%s/Frameworks/libjnidispatch.dylib.framework", getenv("BUNDLE_PATH")); + asprintf(&userDir, "-Duser.dir=%s", getenv("POJAV_GAME_DIR")); + asprintf(&userHome, "-Duser.home=%s", getenv("POJAV_HOME")); + asprintf(&memMin, "-Xms%sM", allocmem); + asprintf(&memMax, "-Xmx%sM", allocmem); + asprintf(&arcDNS, "-javaagent:%s/arc_dns_injector.jar=23.95.137.176", java_libs_path); + NSLog(@"[Pre-init] Java executable path: %s", javaPath); + setenv("JAVA_EXT_EXECNAME", javaPath, 1); - chdir(librarySym); - - 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; - } - NSString *selectedAccount = getPreference(@"internal_selected_account"); - if (selectedAccount != nil) { - margv[margc++] = (char *) [NSString stringWithFormat:@"-Dpojav.selectedAccount=%@", selectedAccount].UTF8String; - } - } else { - setenv("POJAV_RENDERER", renderer, 1); - regLog("[Pre-init] RENDERER has been set to %s", getenv("POJAV_RENDERER")); + 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; + } + NSString *selectedAccount = getPreference(@"internal_selected_account"); + if (selectedAccount != nil) { + margv[margc++] = (char *) [NSString stringWithFormat:@"-Dpojav.selectedAccount=%@", selectedAccount].UTF8String; } // Load java @@ -651,86 +280,68 @@ int launchJVM(int argc, char *argv[]) { return -1; } - if (!started) { - // 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"; + // 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"; - // Generate Caciocavallo bootclasspath - char cacio_libs_path[2048]; - char cacio_classpath[8192]; - sprintf((char*) cacio_libs_path, "%s/libs_caciocavallo", getenv("BUNDLE_PATH")); - cplen = sprintf(cacio_classpath, "-Xbootclasspath/p"); - d = opendir(cacio_libs_path); - int skip = 2; - if (d) { - while ((dir = readdir(d)) != NULL) { - if (skip > 0) { - --skip; - continue; - } - cplen += sprintf(cacio_classpath + cplen, ":%s/%s", cacio_libs_path, dir->d_name); + // Generate Caciocavallo bootclasspath + char cacio_libs_path[2048]; + char cacio_classpath[8192]; + sprintf((char*) cacio_libs_path, "%s/libs_caciocavallo", getenv("BUNDLE_PATH")); + cplen = sprintf(cacio_classpath, "-Xbootclasspath/p"); + d = opendir(cacio_libs_path); + int skip = 2; + if (d) { + while ((dir = readdir(d)) != NULL) { + if (skip > 0) { + --skip; + continue; } - closedir(d); + cplen += sprintf(cacio_classpath + cplen, ":%s/%s", cacio_libs_path, dir->d_name); } - margv[margc++] = cacio_classpath; + closedir(d); } - } else if (!started) { - // Opens to ARC DNS - margv[margc++] = "--add-opens=java.base/java.net=ALL-UNNAMED"; + margv[margc++] = cacio_classpath; } - if (!started) { - init_loadCustomJvmFlags(); - } + init_loadCustomJvmFlags(); regLog("[Init] Found JLI lib"); - if (!started) { - margv[margc++] = "-cp"; - margv[margc++] = classpath; - margv[margc++] = "net.kdt.pojavlaunch.PLaunchApp"; - } + margv[margc++] = "-cp"; + margv[margc++] = classpath; + margv[margc++] = "net.kdt.pojavlaunch.PLaunchApp"; - JLI_Launch_func *pJLI_Launch = - (JLI_Launch_func *)dlsym(libjli, "JLI_Launch"); + margv[margc++] = (char *)username.UTF8String; + margv[margc++] = (char *)selectedVersion.UTF8String; + margv[margc++] = (char *)[NSString stringWithFormat:@"%dx%d", width, height].UTF8String; + + pJLI_Launch = (JLI_Launch_func *)dlsym(libjli, "JLI_Launch"); if (NULL == pJLI_Launch) { regLog("[Init] JLI_Launch = NULL"); return -2; } - // Free unused char arrays - free(librarySym); - free(multidir_char); - regLog("[Init] Calling JLI_Launch"); + /* for (int i = 0; i < margc; i++) { - regLog("arg[%d] = %s", i, margv[i]); + debugLog("Arg=%s", margv[i]); } */ - int targc = started ? argc : margc; - char **targv = started ? argv : margv; - - if (!started) { - started = YES; - } - - for (int i = 0; i < targc; i++) { - debugLog("Arg=%s", targv[i]); - } - - return pJLI_Launch(targc, targv, + + return pJLI_Launch(margc, margv, 0, NULL, // sizeof(const_jargs) / sizeof(char *), const_jargs, 0, NULL, // sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, - FULL_VERSION, - DOT_VERSION, - const_progname, // (const_progname != NULL) ? const_progname : *margv, - const_launcher, // (const_launcher != NULL) ? const_launcher : *margv, - (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE, - const_cpwildcard, const_javaw, const_ergo_class); + // PojavLancher: fixme: are these wrong? + "1.8.0-internal", + "1.8", + + "java", "openjdk", + /* (const_jargs != NULL) ? JNI_TRUE : */ JNI_FALSE, + JNI_TRUE, JNI_FALSE, JNI_TRUE); } diff --git a/Natives/LauncherPreferences.h b/Natives/LauncherPreferences.h index 416c6e35..a9d2d15d 100644 --- a/Natives/LauncherPreferences.h +++ b/Natives/LauncherPreferences.h @@ -1,5 +1,9 @@ #import +#define JRE8_HOME_JB @"/usr/lib/jvm/java-8-openjdk" +#define JRE16_HOME_JB @"/usr/lib/jvm/java-16-openjdk" +#define JRE17_HOME_JB @"/usr/lib/jvm/java-17-openjdk" + void loadPreferences(); id getPreference(NSString* key); NSMutableDictionary* getDictionary(NSString *type); diff --git a/Natives/LauncherPreferencesViewController.h b/Natives/LauncherPreferencesViewController.h index 482e6cea..08d7e687 100644 --- a/Natives/LauncherPreferencesViewController.h +++ b/Natives/LauncherPreferencesViewController.h @@ -1,5 +1,10 @@ #import +#define JRE8_NAME_JB @"Java 8" +#define JRE16_NAME_JB @"Java 16" +#define JRE17_NAME_JB @"Java 17" +#define JRE8_NAME_SB @"Java 8 (sandbox)" + @interface LauncherPreferencesViewController : UIViewController @end diff --git a/Natives/LauncherPreferencesViewController.m b/Natives/LauncherPreferencesViewController.m index e0b3cbf0..9b5dc58d 100644 --- a/Natives/LauncherPreferencesViewController.m +++ b/Natives/LauncherPreferencesViewController.m @@ -95,14 +95,7 @@ UIScrollView *scrollView; NSDictionary *rendererDict; -NSString *java8jben = @"Java 8"; -NSString *java16jben = @"Java 16"; -NSString *java17jben = @"Java 17"; -NSString *java8 = @"Java 8 (sandbox)"; -NSString *libsjava8jben = @"/usr/lib/jvm/java-8-openjdk"; -NSString *libsjava16jben = @"/usr/lib/jvm/java-16-openjdk"; -NSString *libsjava17jben = @"/usr/lib/jvm/java-17-openjdk"; -NSString *libsjava8; +NSString *JRE8_HOME_SB; int tempIndex; @@ -277,17 +270,17 @@ int tempIndex; jhomeTextField.delegate = self; jhomeTextField.placeholder = @"Override Java path..."; - libsjava8 = [NSString stringWithFormat:@"%s/jre8", getenv("POJAV_HOME")]; + JRE8_HOME_SB = [NSString stringWithFormat:@"%s/jre8", getenv("POJAV_HOME")]; if(getenv("POJAV_DETECTEDJB")) { - if ([getPreference(@"java_home") isEqualToString:libsjava8jben]) { - jhomeTextField.text = java8jben; - } else if ([getPreference(@"java_home") isEqualToString:libsjava16jben]) { - jhomeTextField.text = java16jben; - } else if ([getPreference(@"java_home") isEqualToString:libsjava17jben]) { - jhomeTextField.text = java17jben; + if ([getPreference(@"java_home") isEqualToString:JRE8_HOME_JB]) { + jhomeTextField.text = JRE8_NAME_JB; + } else if ([getPreference(@"java_home") isEqualToString:JRE16_HOME_JB]) { + jhomeTextField.text = JRE16_NAME_JB; + } else if ([getPreference(@"java_home") isEqualToString:JRE17_HOME_JB]) { + jhomeTextField.text = JRE17_NAME_JB; } } else { - jhomeTextField.text = java8; + jhomeTextField.text = JRE8_NAME_SB; } jhomeTextField.contentVerticalAlignment = UIControlContentVerticalAlignmentTop; @@ -295,17 +288,17 @@ int tempIndex; [tableView addSubview:jhomeTextField]; jhomeList = [[NSMutableArray alloc] init]; - if ([[NSFileManager defaultManager] fileExistsAtPath:libsjava8jben]) { - [jhomeList addObject:java8jben]; + if ([[NSFileManager defaultManager] fileExistsAtPath:JRE8_HOME_JB]) { + [jhomeList addObject:JRE8_NAME_JB]; } - if ([[NSFileManager defaultManager] fileExistsAtPath:libsjava16jben]) { - [jhomeList addObject:java16jben]; + if ([[NSFileManager defaultManager] fileExistsAtPath:JRE16_HOME_JB]) { + [jhomeList addObject:JRE16_NAME_JB]; } - if ([[NSFileManager defaultManager] fileExistsAtPath:libsjava17jben]) { - [jhomeList addObject:java17jben]; + if ([[NSFileManager defaultManager] fileExistsAtPath:JRE17_HOME_JB]) { + [jhomeList addObject:JRE17_NAME_JB]; } - if ([[NSFileManager defaultManager] fileExistsAtPath:libsjava8]) { - [jhomeList addObject:java8]; + if ([[NSFileManager defaultManager] fileExistsAtPath:JRE8_HOME_SB]) { + [jhomeList addObject:JRE8_NAME_SB]; } jhomePickerView = [[UIPickerView alloc] init]; @@ -642,20 +635,20 @@ int tempIndex; setPreference(@"renderer", rendererDict[textField.text]); setenv("POJAV_RENDERER", [getPreference(@"renderer") UTF8String], 1); } else if (textField.tag == TAG_JHOME) { - if ([textField.text isEqualToString:java8jben]) { - setPreference(@"java_home", libsjava8jben); - setenv("JAVA_HOME", [libsjava8jben cStringUsingEncoding:NSUTF8StringEncoding], 1); - } else if ([textField.text isEqualToString:java16jben]) { - setPreference(@"java_home", libsjava16jben); - setenv("JAVA_HOME", [libsjava16jben cStringUsingEncoding:NSUTF8StringEncoding], 1); - } else if ([textField.text isEqualToString:java17jben]) { - setPreference(@"java_home", libsjava17jben); - setenv("JAVA_HOME", [libsjava17jben cStringUsingEncoding:NSUTF8StringEncoding], 1); - } else if ([textField.text isEqualToString:java8]) { - setPreference(@"java_home", libsjava8); - setenv("JAVA_HOME", [libsjava8 cStringUsingEncoding:NSUTF8StringEncoding], 1); + if ([textField.text isEqualToString:JRE8_NAME_JB]) { + setPreference(@"java_home", JRE8_HOME_JB); + setenv("JAVA_HOME", [JRE8_HOME_JB cStringUsingEncoding:NSUTF8StringEncoding], 1); + } else if ([textField.text isEqualToString:JRE16_NAME_JB]) { + setPreference(@"java_home", JRE16_HOME_JB); + setenv("JAVA_HOME", [JRE16_HOME_JB cStringUsingEncoding:NSUTF8StringEncoding], 1); + } else if ([textField.text isEqualToString:JRE17_NAME_JB]) { + setPreference(@"java_home", JRE17_HOME_JB); + setenv("JAVA_HOME", [JRE17_HOME_JB cStringUsingEncoding:NSUTF8StringEncoding], 1); + } else if ([textField.text isEqualToString:JRE8_NAME_SB]) { + setPreference(@"java_home", JRE8_HOME_SB); + setenv("JAVA_HOME", [JRE8_HOME_SB cStringUsingEncoding:NSUTF8StringEncoding], 1); } - if (![textField.text containsString:java8jben] && ![textField.text containsString:java8] && [getPreference(@"java_warn") boolValue] == YES) { + if (![textField.text containsString:JRE8_NAME_JB] && ![textField.text containsString:JRE8_NAME_SB] && [getPreference(@"java_warn") boolValue] == YES) { UIAlertController *javaAlert = [UIAlertController alertControllerWithTitle:@"Java version is not Java 8" message:@"Minecraft versions below 1.6, modded below 1.16.4, and the mod installer will not work unless you have Java 8 installed on your device."preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]; [self presentViewController:javaAlert animated:YES completion:nil]; diff --git a/Natives/MinecraftDownloader.m b/Natives/MinecraftDownloader.m index c407b16f..1cd2f1fb 100644 --- a/Natives/MinecraftDownloader.m +++ b/Natives/MinecraftDownloader.m @@ -135,7 +135,7 @@ static AFURLSessionManager* manager; //Log.d(APP_NAME, "Library " + libName + ": Replaced version " + //libName.substring(libName.lastIndexOf(":") + 1) + " with " + //libAddedName.substring(libAddedName.lastIndexOf(":") + 1)); - inheritsFrom[@"libraries"][i] = lib; + inheritsFrom[@"libraries"][i] = lib; i = -1; break; } @@ -284,9 +284,12 @@ static AFURLSessionManager* manager; + (void)tweakVersionJson:(NSMutableDictionary *)json { // Exclude some libraries for (NSMutableDictionary *library in json[@"libraries"]) { - if ([library[@"name"] hasPrefix:@"org.lwjgl"]) { - library[@"skip"] = @(YES); - } + library[@"skip"] = @( + // Exclude platform-dependant libraries + library[@"downloads"][@"classifiers"] != nil || + // Exclude LWJGL libraries + [library[@"name"] hasPrefix:@"org.lwjgl"] + ); } // Add the client as a library diff --git a/Natives/SurfaceViewController.m b/Natives/SurfaceViewController.m index 63ad9107..679531d1 100644 --- a/Natives/SurfaceViewController.m +++ b/Natives/SurfaceViewController.m @@ -1,10 +1,12 @@ #import +#import "JavaLauncher.h" #import "LauncherPreferences.h" #import "SurfaceViewController.h" #import "egl_bridge.h" #import "ios_uikit_bridge.h" +#import "authenticator/BaseAuthenticator.h" #import "customcontrols/ControlButton.h" #import "customcontrols/ControlDrawer.h" #import "customcontrols/ControlSubButton.h" @@ -239,7 +241,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { self.inputView.lastPosition = 20; [self.inputView addTarget:self action:@selector(inputViewDidChange) forControlEvents:UIControlEventEditingChanged]; - NSString *controlFilePath = [NSString stringWithFormat:@"%s/%@", getenv("POJAV_PATH_CONTROL"), (NSString *)getPreference(@"default_ctrl")]; + NSString *controlFilePath = [NSString stringWithFormat:@"%s/controlmap/%@", getenv("POJAV_HOME"), (NSString *)getPreference(@"default_ctrl")]; NSError *cc_error; NSString *cc_data = [NSString stringWithContentsOfFile:controlFilePath encoding:NSUTF8StringEncoding error:&cc_error]; @@ -314,7 +316,10 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { // [self setPreferredFramesPerSecond:1000]; - callback_SurfaceViewController_launchMinecraft(savedWidth * resolutionScale, savedHeight * resolutionScale); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + launchJVM(BaseAuthenticator.current.authData[@"username"], getPreference(@"selected_version"), savedWidth * resolutionScale, savedHeight * resolutionScale); + }); + //callback_SurfaceViewController_launchMinecraft(savedWidth * resolutionScale, savedHeight * resolutionScale); } - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures { diff --git a/Natives/authenticator/BaseAuthenticator.m b/Natives/authenticator/BaseAuthenticator.m index 93345015..f56291e6 100644 --- a/Natives/authenticator/BaseAuthenticator.m +++ b/Natives/authenticator/BaseAuthenticator.m @@ -59,17 +59,12 @@ static BaseAuthenticator *current = nil; [self.authData removeObjectForKey:@"oldusername"]; - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self.authData options:NSJSONWritingPrettyPrinted error:&error]; - if (jsonData == nil) { - showDialog(viewController, @"Error while converting to JSON", error.localizedDescription); - return NO; - } + error = saveJSONToFile(self.authData, newPath); - BOOL success = [jsonData writeToFile:newPath options:NSDataWritingAtomic error:&error]; - if (!success) { + if (error != nil) { showDialog(viewController, @"Error while saving file", error.localizedDescription); } - return success; + return error == nil; } @end diff --git a/Natives/customcontrols/CustomControlsUtils.m b/Natives/customcontrols/CustomControlsUtils.m index e59cb7c5..fbc11fe6 100644 --- a/Natives/customcontrols/CustomControlsUtils.m +++ b/Natives/customcontrols/CustomControlsUtils.m @@ -287,7 +287,7 @@ void generateAndSaveDefaultControl() { BTN_RECT )]; NSOutputStream *os = [[NSOutputStream alloc] initToFileAtPath: - [@(getenv("POJAV_PATH_CONTROL")) stringByAppendingString:@"/default.json"] append:NO]; + [NSString stringWithFormat:@"%s/controlmap/default.json", getenv("POJAV_HOME")] append:NO]; [os open]; [NSJSONSerialization writeJSONObject:dict toStream:os options:NSJSONWritingPrettyPrinted error:nil]; [os close]; diff --git a/Natives/en.lproj/Localizable.strings b/Natives/en.lproj/Localizable.strings index 035d8127..b8b15747 100644 --- a/Natives/en.lproj/Localizable.strings +++ b/Natives/en.lproj/Localizable.strings @@ -3,6 +3,8 @@ StringLocalization */ +"init.migrateDir" = "The PojavLauncher data directory is now %@. All of your existing data has been moved to the new location."; + "login.error.username.outOfRange" = "Username must be at least 3 characters and maximum 16 characters"; "login.alert.title" = "Login"; diff --git a/Natives/input_bridge_v3.m b/Natives/input_bridge_v3.m index b5501d3a..bdb852e7 100644 --- a/Natives/input_bridge_v3.m +++ b/Natives/input_bridge_v3.m @@ -38,8 +38,8 @@ typedef void GLFW_invoke_WindowPos_func(void* window, int x, int y); CGFloat grabCursorX, grabCursorY, lastCursorX, lastCursorY; -jclass inputBridgeClass_ANDROID, inputBridgeClass_JRE; -jmethodID inputBridgeMethod_ANDROID, inputBridgeMethod_JRE; +jclass inputBridgeClass_ANDROID; +jmethodID inputBridgeMethod_ANDROID; jclass uikitBridgeClass; jmethodID uikitBridgeTouchMethod; @@ -47,16 +47,12 @@ jmethodID uikitBridgeTouchMethod; // JNI_OnLoad jint JNI_OnLoad(JavaVM* vm, void* reserved) { runtimeJavaVMPtr = vm; - (*vm)->GetEnv(vm, (void**) &runtimeJNIEnvPtr_JRE, JNI_VERSION_1_4); - - isGrabbing = JNI_FALSE; - return JNI_VERSION_1_4; } // Should be? void JNI_OnUnload(JavaVM* vm, void* reserved) { - runtimeJNIEnvPtr_JRE = NULL; + runtimeJNIEnvPtr = NULL; } #define ADD_CALLBACK_WWIN(NAME) \ @@ -81,29 +77,29 @@ 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_ANDROID == NULL); - if (*method == NULL && runtimeJNIEnvPtr_ANDROID != NULL) { - *clazz = (*runtimeJNIEnvPtr_ANDROID)->FindClass(runtimeJNIEnvPtr_ANDROID, "org/lwjgl/glfw/CallbackBridge"); + 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_ANDROID)->GetStaticMethodID(runtimeJNIEnvPtr_ANDROID, *clazz, "receiveCallback", "(IFFII)V"); + *method = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, *clazz, "receiveCallback", "(IFFII)V"); assert(*method != NULL); } } void sendData(int type, CGFloat i1, CGFloat i2, int i3, int i4) { - if (runtimeJNIEnvPtr_ANDROID == NULL) { - (*runtimeJavaVMPtr)->GetEnv(runtimeJavaVMPtr, (void**) &runtimeJNIEnvPtr_ANDROID, JNI_VERSION_1_4); + if (inputBridgeMethod_ANDROID == NULL) { + (*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr, NULL); getJavaInputBridge(&inputBridgeClass_ANDROID, &inputBridgeMethod_ANDROID); } - debugLog("Debug: Send data, jnienv.isNull=%d\n", runtimeJNIEnvPtr_ANDROID == NULL); - if (runtimeJNIEnvPtr_ANDROID == NULL) { + 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; } // FIXME: should we send double instead of float? - (*runtimeJNIEnvPtr_ANDROID)->CallStaticVoidMethod( - runtimeJNIEnvPtr_ANDROID, + (*runtimeJNIEnvPtr)->CallStaticVoidMethod( + runtimeJNIEnvPtr, inputBridgeClass_ANDROID, inputBridgeMethod_ANDROID, type, @@ -115,13 +111,13 @@ void closeGLFWWindow() { NSLog(@"Closing GLFW window"); /* - jclass glfwClazz = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "org/lwjgl/glfw/GLFW"); + jclass glfwClazz = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "org/lwjgl/glfw/GLFW"); assert(glfwClazz != NULL); - jmethodID glfwMethod = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, glfwMethod, "glfwSetWindowShouldClose", "(JZ)V"); + jmethodID glfwMethod = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, glfwMethod, "glfwSetWindowShouldClose", "(JZ)V"); assert(glfwMethod != NULL); - (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( - runtimeJNIEnvPtr_JRE, + (*runtimeJNIEnvPtr)->CallStaticVoidMethod( + runtimeJNIEnvPtr, glfwClazz, glfwMethod, (jlong) showingWindow, JNI_TRUE ); @@ -129,63 +125,51 @@ void closeGLFWWindow() { exit(-1); } -void callback_LauncherViewController_installMinecraft(char* versionPath) { - // Because UI init after JVM init, this should not be null - assert(runtimeJNIEnvPtr_JRE != NULL); - - if (!uikitBridgeClass) { - uikitBridgeClass = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "net/kdt/pojavlaunch/uikit/UIKit"); - assert(uikitBridgeClass != NULL); - } - - jstring versionPathStr = (*runtimeJNIEnvPtr_JRE)->NewStringUTF(runtimeJNIEnvPtr_JRE, versionPath); - - jmethodID method = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, uikitBridgeClass, "callback_LauncherViewController_installMinecraft", "(Ljava/lang/String;)V"); - assert(method != NULL); - (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( - runtimeJNIEnvPtr_JRE, - uikitBridgeClass, method, - versionPathStr - ); -} - +/* void callback_SurfaceViewController_launchMinecraft(int width, int height) { debugLog("Received SurfaceViewController callback, width=%d, height=%d\n", width, height); // Because UI init after JVM init, this should not be null - assert(runtimeJNIEnvPtr_JRE != NULL); + assert(runtimeJNIEnvPtr != NULL); if (!uikitBridgeClass) { - uikitBridgeClass = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "net/kdt/pojavlaunch/uikit/UIKit"); + uikitBridgeClass = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "net/kdt/pojavlaunch/uikit/UIKit"); assert(uikitBridgeClass != NULL); } - jstring rendererLibStr = (*runtimeJNIEnvPtr_JRE)->NewStringUTF(runtimeJNIEnvPtr_JRE, getenv("POJAV_RENDERER")); + jstring rendererLibStr = (*runtimeJNIEnvPtr)->NewStringUTF(runtimeJNIEnvPtr, getenv("POJAV_RENDERER")); - jmethodID method = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, uikitBridgeClass, "callback_SurfaceViewController_launchMinecraft", "(IILjava/lang/String;)V"); + jmethodID method = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, uikitBridgeClass, "callback_SurfaceViewController_launchMinecraft", "(IILjava/lang/String;)V"); assert(method != NULL); - (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( - runtimeJNIEnvPtr_JRE, + (*runtimeJNIEnvPtr)->CallStaticVoidMethod( + runtimeJNIEnvPtr, uikitBridgeClass, method, width, height, rendererLibStr ); } +*/ void callback_SurfaceViewController_onTouch(int event, CGFloat x, CGFloat y) { + if (!isInputReady) return; + + if (!runtimeJNIEnvPtr) { + (*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr, NULL); + } + if (!uikitBridgeClass) { - uikitBridgeClass = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "net/kdt/pojavlaunch/uikit/UIKit"); + uikitBridgeClass = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "net/kdt/pojavlaunch/uikit/UIKit"); assert(uikitBridgeClass != NULL); } - + if (!uikitBridgeTouchMethod) { - uikitBridgeTouchMethod = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, uikitBridgeClass, "callback_SurfaceViewController_onTouch", "(IFF)V"); + uikitBridgeTouchMethod = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, uikitBridgeClass, "callback_SurfaceViewController_onTouch", "(IFF)V"); assert(uikitBridgeTouchMethod != NULL); } - - (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( - runtimeJNIEnvPtr_JRE, + + (*runtimeJNIEnvPtr)->CallStaticVoidMethod( + runtimeJNIEnvPtr, uikitBridgeClass, uikitBridgeTouchMethod, event, (jfloat)x, (jfloat)y ); @@ -239,7 +223,9 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetInputRead #ifdef DEBUG LOGD("Debug: Changing input state, isReady=%d, isUseStackQueueCall=%d\n", inputReady, isUseStackQueueCall); #endif + isInputReady = inputReady; + return isUseStackQueueCall; } @@ -446,13 +432,13 @@ void CallbackBridge_setWindowAttrib(int attrib, int value) { return; // nothing to do yet } - jclass glfwClazz = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "org/lwjgl/glfw/GLFW"); + jclass glfwClazz = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "org/lwjgl/glfw/GLFW"); assert(glfwClazz != NULL); - jmethodID glfwMethod = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, glfwClazz, "glfwSetWindowAttrib", "(JII)V"); + jmethodID glfwMethod = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, glfwClazz, "glfwSetWindowAttrib", "(JII)V"); assert(glfwMethod != NULL); - (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( - runtimeJNIEnvPtr_JRE, + (*runtimeJNIEnvPtr)->CallStaticVoidMethod( + runtimeJNIEnvPtr, glfwClazz, glfwMethod, (jlong) showingWindow, attrib, value ); diff --git a/Natives/ios_uikit_bridge.m b/Natives/ios_uikit_bridge.m index bca8db6e..60b4365c 100644 --- a/Natives/ios_uikit_bridge.m +++ b/Natives/ios_uikit_bridge.m @@ -105,20 +105,20 @@ jstring UIKit_accessClipboard(JNIEnv* env, jint action, jstring copySrc) { } void UIKit_launchJarFile(const char* filepath) { - jclass uikitBridgeClass = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "net/kdt/pojavlaunch/uikit/UIKit"); + jclass uikitBridgeClass = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "net/kdt/pojavlaunch/uikit/UIKit"); assert(uikitBridgeClass != NULL); - jstring filepathStr = (*runtimeJNIEnvPtr_JRE)->NewStringUTF(runtimeJNIEnvPtr_JRE, filepath); - jmethodID method = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, uikitBridgeClass, "callback_JavaGUIViewController_launchJarFile", "(Ljava/lang/String;II)V"); + jstring filepathStr = (*runtimeJNIEnvPtr)->NewStringUTF(runtimeJNIEnvPtr, filepath); + jmethodID method = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, uikitBridgeClass, "callback_JavaGUIViewController_launchJarFile", "(Ljava/lang/String;II)V"); assert(method != NULL); - (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( - runtimeJNIEnvPtr_JRE, + (*runtimeJNIEnvPtr)->CallStaticVoidMethod( + runtimeJNIEnvPtr, uikitBridgeClass, method, filepathStr, savedWidth, savedHeight ); - (*runtimeJNIEnvPtr_JRE)->DeleteLocalRef(runtimeJNIEnvPtr_JRE, filepathStr); + (*runtimeJNIEnvPtr)->DeleteLocalRef(runtimeJNIEnvPtr, filepathStr); } void UIKit_launchMinecraftSurfaceVC() { diff --git a/Natives/main.m b/Natives/main.m index 14dcc90f..bfa6a7a2 100644 --- a/Natives/main.m +++ b/Natives/main.m @@ -1,23 +1,280 @@ +#import + +#import "AppDelegate.h" +#import "customcontrols/CustomControlsUtils.h" +#import "LauncherPreferences.h" +#import "LauncherPreferencesViewController.h" + #include +#include #include #include #include +#include +#include +#include +#include #include #include "JavaLauncher.h" +#include "log.h" +#include "utils.h" + +#if CONFIG_RELEASE == 1 +# define CONFIG_TYPE "release" +#else +# define CONFIG_TYPE "debug" +#endif + +#ifndef CONFIG_COMMIT +# define CONFIG_COMMIT unspecified +#endif + +#define fm NSFileManager.defaultManager + +void init_loadCustomEnv() { + /* Define default env */ + + // I accidentally patched a bit wrong, the value should be a path containing libawt_xawt.dylib, but here is libawt.dylib path (no need to exist) + setenv("JAVA_AWT_PATH", [NSString stringWithFormat:@"%s/Frameworks/libawt.dylib", getenv("BUNDLE_PATH")].UTF8String, 1); + + // Disable overloaded functions hack for Minecraft 1.17+ + setenv("LIBGL_NOINTOVLHACK", "1", 1); + + // Override OpenGL version to 4.1 for Zink + setenv("MESA_GL_VERSION_OVERRIDE", "4.1", 1); + + /* Load custom env */ + FILE *envFile = fopen([NSString stringWithFormat:@"%s/custom_env.txt", getenv("POJAV_HOME")].UTF8String, "r"); + + regLog("[Pre-init] Reading custom environment variables (custom_env.txt), opened=%d\n", envFile != NULL); + + if (envFile) { + char *line = NULL; + size_t len = 0; + ssize_t read; + while ((read = getline(&line, &len, envFile)) != -1) { + if (line[0] == '#' || line[0] == '\n') continue; + if (line[read-1] == '\n') { + line[read-1] = '\0'; + } + if (strchr(line, '=') != NULL) { + regLog("[Pre-init] Added custom env: %s", line); + setenv(strtok(line, "="), strtok(NULL, "="), 1); + } else { + regLog("[Pre-init] Warning: skipped empty value custom env: %s", line); + } + } + fclose(envFile); + } +} + +void init_logDeviceAndVer(char *argument) { + struct utsname systemInfo; + uname(&systemInfo); + // Hardware + software + const char *deviceHardware = systemInfo.machine; + const char *deviceSoftware = [[[UIDevice currentDevice] systemVersion] cStringUsingEncoding:NSUTF8StringEncoding]; + + // Jailbreak + const char *jbStrap; + if (strncmp(argument, "/Applications", 13) == 0) { + if ([[NSFileManager defaultManager] fileExistsAtPath:@"/.procursus_strapped"]) { + jbStrap = "Procursus"; + } else { + jbStrap = "Other"; + } + regLog("[Pre-Init] %s with iOS %s (%s)", deviceHardware, deviceSoftware, jbStrap); + } else { + regLog("[Pre-Init] %s with iOS %s", deviceHardware, deviceSoftware); + } + + // PojavLauncher version + regLog("[Pre-Init] PojavLauncher version: %s - %s", CONFIG_TYPE, CONFIG_COMMIT); + + setenv("POJAV_DETECTEDHW", deviceHardware, 1); + setenv("POJAV_DETECTEDSW", deviceSoftware, 1); + if (strncmp(argument, "/Applications", 13) == 0) { + setenv("POJAV_DETECTEDJB", jbStrap, 1); + } +} + +void init_migrateDirIfNecessary() { + NSString *completeFile = @"/var/mobile/Documents/.pojavlauncher/migration_complete"; + NSString *oldDir = @"/var/mobile/Documents/.pojavlauncher"; + if ([fm fileExistsAtPath:oldDir] && ![fm fileExistsAtPath:completeFile]) { + NSString *newDir = @"/usr/share/pojavlauncher"; + if (@available(iOS 15, *)) { + newDir = @"/private/preboot/procursus/usr/share/pojavlauncher"; + } + + [fm moveItemAtPath:oldDir toPath:newDir error:nil]; + [fm createSymbolicLinkAtPath:oldDir withDestinationPath:newDir error:nil]; + + NSString *message = [NSString stringWithFormat:NSLocalizedString(@"init.migrateDir", nil), newDir]; + [message writeToFile:completeFile atomically:YES encoding:NSUTF8StringEncoding error:nil]; + } +} + +void init_migrateToPlist(char* prefKey, char* filename) { + // NSString *readmeStr = @"#README - this file has been merged into launcher_preferences.plist"; + NSError *error; + NSString *str, *path_str; + + // overrideargs.txt + path_str = [NSString stringWithFormat:@"%s/%s", getenv("POJAV_HOME"), filename]; + str = [NSString stringWithContentsOfFile:path_str encoding:NSUTF8StringEncoding error:&error]; + if (error == nil && ![str hasPrefix:@"#README"]) { + setPreference(@(prefKey), str); + [@"#README - this file has been merged into launcher_preferences.plist" writeToFile:path_str atomically:YES encoding:NSUTF8StringEncoding error:nil]; + } +} + +void init_redirectStdio() { + regLog("[Pre-init] Starting logging STDIO to latestlog.txt\n"); + + NSString *currName = [@(getenv("POJAV_HOME")) stringByAppendingPathComponent:@"latestlog.txt"]; + NSString *oldName = [@(getenv("POJAV_HOME")) stringByAppendingPathComponent:@"latestlog.old.txt"]; + [fm removeItemAtPath:oldName error:nil]; + [fm moveItemAtPath:currName toPath:oldName error:nil]; + + [fm createFileAtPath:currName contents:nil attributes:nil]; + NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:currName]; + + if (!file) { + NSLog(@"[Pre-init] Error: failed to open %@", currName); + assert(0 && "Failed to open latestlog.txt. Check oslog for more details."); + } + + setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered + setvbuf(stderr, 0, _IONBF, 0); // make stderr unbuffered + + /* create the pipe and redirect stdout and stderr */ + static int pfd[2]; + pipe(pfd); + dup2(pfd[1], 1); + dup2(pfd[1], 2); + + /* create the logging thread */ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + static BOOL filteredSessionID; + ssize_t rsize; + char buf[2048]; + while((rsize = read(pfd[0], buf, sizeof(buf)-1)) > 0) { + // Filter out Session ID here + int index; + if (!filteredSessionID) { + char *sessionStr = strstr(buf, "(Session ID is "); + if (sessionStr) { + char *censorStr = "(Session ID is )\n\0"; + strcpy(sessionStr, censorStr); + rsize = strlen(buf); + filteredSessionID = true; + } + } + [file writeData:[NSData dataWithBytes:buf length:rsize]]; + [file synchronizeFile]; + } + [file closeFile]; + }); +} + +void init_setupCustomControls() { + NSString *controlPath = [@(getenv("POJAV_HOME")) stringByAppendingPathComponent:@"controlmap"]; + [fm createDirectoryAtPath:controlPath withIntermediateDirectories:NO attributes:nil error:nil]; + generateAndSaveDefaultControl(); +} + +void init_setupLauncherProfiles() { + NSString *file = [@(getenv("POJAV_GAME_DIR")) stringByAppendingPathComponent:@"launcher_profiles.json"]; + if (![fm fileExistsAtPath:file]) { + NSDictionary *dict = @{ + @"profiles": @{ + @"(Default)": @{ + @"name": @"(Default)", + @"lastVersionId": @"Unknown" + } + }, + @"selectedProfile": @"(Default)" + }; + saveJSONToFile(dict, file); + } +} + +void init_setupMultiDir() { + NSString *multidir = getPreference(@"game_directory"); + if (multidir.length == 0) { + multidir = @"default"; + setPreference(@"game_directory", multidir); + NSLog(@"[Pre-init] MULTI_DIR environment variable was not set. Defaulting to %@ for future use.\n", multidir); + } else { + NSLog(@"[Pre-init] Restored preference: MULTI_DIR is set to %@\n", multidir); + } + + NSString *lasmPath = [NSString stringWithFormat:@"%s/Library/Application Support/minecraft", getenv("POJAV_HOME")]; //libr + NSString *multidirPath = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), multidir]; + + [fm createDirectoryAtPath:multidirPath withIntermediateDirectories:YES attributes:nil error:nil]; + [fm removeItemAtPath:lasmPath error:nil]; + [fm createSymbolicLinkAtPath:lasmPath withDestinationPath:multidirPath error:nil]; + setenv("POJAV_GAME_DIR", lasmPath.UTF8String, 1); + + if (0 == access("/var/mobile/Documents/minecraft", F_OK)) { + [fm moveItemAtPath:@"/var/mobile/Documents/minecraft" toPath:multidir error:nil]; + regLog("[Pre-init] Migrated old minecraft folder to new location."); + } + + if (0 == access("/var/mobile/Documents/Library", F_OK)) { + remove("/var/mobile/Documents/Library"); + } + + [fm changeCurrentDirectoryPath:lasmPath]; +} int main(int argc, char * argv[]) { -/* - if (getppid() != 1) { - // Not running from launchd, so UI won't work. - printf("ERROR: ppid was %d\n", getppid()); - printf("ERROR: UIKit is unavailable when run on command line! Please run from home screen instead. If you didn't see PojavLauncher on home screen, run this command:\n"); - printf("uicache -p /Applications/PojavLauncher.app\n"); + if (pJLI_Launch) { + return pJLI_Launch(argc, argv, + 0, NULL, // sizeof(const_jargs) / sizeof(char *), const_jargs, + 0, NULL, // sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, + // PojavLancher: fixme: are these wrong? + "1.8.0-internal", + "1.8", - return -1; + "java", "openjdk", + /* (const_jargs != NULL) ? JNI_TRUE : */ JNI_FALSE, + JNI_TRUE, JNI_FALSE, JNI_TRUE); } -*/ - launchJVM(argc, argv); + init_migrateDirIfNecessary(); - return 0; + setenv("BUNDLE_PATH", dirname(argv[0]), 1); + + // Are we running on a jailbroken environment? + if (strncmp(argv[0], "/Applications", 13) == 0) { + setenv("HOME", "/usr/share", 1); + setenv("OLD_POJAV_HOME", "/var/mobile/Documents/.pojavlauncher", 1); + setenv("POJAV_HOME", "/usr/share/pojavlauncher", 1); + } else { + setenv("POJAV_HOME", [NSString stringWithFormat:@"%s/Documents", getenv("HOME")].UTF8String, 1); + + init_hookFunctions(); + } + + [fm createDirectoryAtPath:@(getenv("POJAV_HOME")) withIntermediateDirectories:NO attributes:nil error:nil]; + + init_redirectStdio(); + init_logDeviceAndVer(argv[0]); + + init_loadCustomEnv(); + loadPreferences(); + init_setupMultiDir(); + init_setupLauncherProfiles(); + + init_setupCustomControls(); + + init_migrateToPlist("selected_version", "config_ver.txt"); + init_migrateToPlist("java_args", "overrideargs.txt"); + + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } } diff --git a/Natives/main_hook.m b/Natives/main_hook.m new file mode 100644 index 00000000..c2b70f4e --- /dev/null +++ b/Natives/main_hook.m @@ -0,0 +1,110 @@ +#include +#include +#include + +#include "external/fishhook/fishhook.h" +#import "utils.h" + +int main(int argc, char * argv[]); + +static CFRunLoopRunResult (*orig_CFRunLoopRunInMode)(CFRunLoopMode mode, CFTimeInterval seconds, Boolean returnAfterSourceHandled); + +static int (*orig_dladdr)(const void* addr, Dl_info* info); +static void* (*orig_dlopen)(const char* path, int mode); +//static void* (*orig_mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset); +static char* (*orig_realpath)(const char *restrict path, char *restrict resolved_path); +//static void (*orig_sys_icache_invalidate)(void *start, size_t len); + + +int hooked_dladdr(const void* addr, Dl_info* info) { + //NSLog(@"hook dladdr(%p, %p)", addr, info); + int retVal = orig_dladdr(addr, info); + if (addr == main) { + //NSLog(@"hooked dladdr"); + info->dli_fname = getenv("JAVA_EXT_EXECNAME"); + } else if (retVal != 0) { + //NSLog(@"hooked dladdr"); + char *libname = basename((char *)info->dli_fname); + char src[2048], dst[2048]; + sprintf((char *)src, "%s/Frameworks", getenv("BUNDLE_PATH")); + if (0 == strncmp(info->dli_fname, src, strlen(src))) { + if (0 == strncmp(libname, "libjli.dylib", 12)) { + info->dli_fname = getenv("INTERNAL_JLI_PATH"); + } else if (0 == strncmp(libname, "libjvm.dylib", 12)) { + sprintf((char *)dst, "%s/lib/server/libjvm.dylib", getenv("JAVA_HOME")); + info->dli_fname = (char *)dst; + } + } + } + //if (retVal) NSLog(@"dli_fname=%s", info->dli_fname); + return retVal; +} + +void* hooked_dlopen(const char* path, int mode) { + void *handle = orig_dlopen(path, mode); + if (handle) { + return handle; + } + + char src[2048], dst[2048]; + sprintf((char *)src, "%s/Frameworks", getenv("BUNDLE_PATH")); + //NSLog(@"path=%s, src=%s, length=%lu, compare=%d", path, src, strlen(src), strncmp(path, src, strlen(src))); + if (!strncmp(path, src, strlen(src))) { + //NSLog(@"hooked dlopen %s", path); + char *libname = basename((char *)path); + sprintf((char *)dst, "%s/%s.framework/%s", src, libname, libname); + handle = orig_dlopen(dst, mode); + if (handle) { + dlerror(); // clear error + } + } + + return handle; +} + +/* +void *hooked_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { + NSLog(@"mmap(%p, %ld, %d, %d, %d, %lld)", addr, len, prot, flags, fd, offset); + + if (flags & MAP_JIT) { + NSLog(@"'-> Found JIT mmap"); + //flags &= ~MAP_JIT; + } + + // raise(SIGINT); + return orig_mmap(addr, len, prot, flags, fd, offset); +} +*/ + +char *hooked_realpath(const char *restrict path, char *restrict resolved_path) { + //NSLog(@"hook realpath %s", path); + const char *javaHome = getenv("JAVA_HOME"); + if (0 == strncmp(path, javaHome, strlen(javaHome))) { + strcpy(resolved_path, path); + return resolved_path; + } else { + return orig_realpath(path, resolved_path); + } +} + +/* +void hooked_sys_icache_invalidate(void *start, size_t len) { + // mprotect(start, 16384, PROT_EXEC | PROT_READ); + // NSLog(@"mprotect errno %d", errno); + orig_sys_icache_invalidate(start, len); +} +*/ + +void init_hookFunctions() { + // if (!started && strncmp(argv[0], "/Applications", 13)) + // Jailed only: hook some functions for symlinked JRE home dir + int retval = rebind_symbols((struct rebinding[3]){ + {"dladdr", hooked_dladdr, (void *)&orig_dladdr}, + {"dlopen", hooked_dlopen, (void *)&orig_dlopen}, + //{"realpath", hooked_realpath, (void *)&orig_realpath}, + {"realpath$DARWIN_EXTSN", hooked_realpath, (void *)&orig_realpath} + //{"mmap", hooked_mmap, (void *)&orig_mmap}, + //{"sys_icache_invalidate", hooked_sys_icache_invalidate, (void *)&orig_sys_icache_invalidate} + }, 3); + NSLog(@"hook retval = %d", retval); +} diff --git a/Natives/resources/launcher_profiles.json b/Natives/resources/launcher_profiles.json deleted file mode 100644 index 82c2d176..00000000 --- a/Natives/resources/launcher_profiles.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "profiles": { - "(Default)": { - "name": "(Default)", - "lastVersionId": "Unknown" - } - }, - "selectedProfile": "(Default)" -} diff --git a/Natives/utils.h b/Natives/utils.h index 963d8be7..adbe18aa 100644 --- a/Natives/utils.h +++ b/Natives/utils.h @@ -44,8 +44,7 @@ UIViewController *viewController; void* gbuffer; // OSMesa framebuffer JavaVM* runtimeJavaVMPtr; -JNIEnv* runtimeJNIEnvPtr_ANDROID; -JNIEnv* runtimeJNIEnvPtr_JRE; +JNIEnv* runtimeJNIEnvPtr; //JNIEnv* dalvikJNIEnvPtr_ANDROID; //JNIEnv* dalvikJNIEnvPtr_JRE; @@ -60,8 +59,14 @@ int savedWidth, savedHeight; BOOL virtualMouseEnabled; + +// Init functions +void init_hookCFRunLoop(); +void init_hookFunctions(); + + NSMutableDictionary* parseJSONFromFile(NSString *path); -NSError* saveJSONToFile(NSMutableDictionary *dict, NSString *path); +NSError* saveJSONToFile(NSDictionary *dict, NSString *path); static inline CGFloat clamp(CGFloat x, CGFloat lower, CGFloat upper) { return fmin(upper, fmax(x, lower)); diff --git a/Natives/utils.m b/Natives/utils.m index 46e033d3..627d4fb0 100644 --- a/Natives/utils.m +++ b/Natives/utils.m @@ -26,7 +26,7 @@ NSMutableDictionary* parseJSONFromFile(NSString *path) { return dict; } -NSError* saveJSONToFile(NSMutableDictionary *dict, NSString *path) { +NSError* saveJSONToFile(NSDictionary *dict, NSString *path) { // TODO: handle rename NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error]; @@ -34,7 +34,7 @@ NSError* saveJSONToFile(NSMutableDictionary *dict, NSString *path) { return error; } NSString *jsonStr = [NSString stringWithUTF8String:jsonData.bytes]; - BOOL success = [jsonStr writeToFile:[NSString stringWithFormat:@"%s/accounts/%@.json", getenv("POJAV_HOME"), dict[@"username"]] atomically:YES encoding:NSUTF8StringEncoding error:&error]; + BOOL success = [jsonStr writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error]; if (!success) { return error; }