diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java index cab751237..7bbd81bab 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -314,7 +314,7 @@ public final class Tools { } LauncherProfiles.load(); File gamedir = Tools.getGameDirPath(minecraftProfile); - startControllableMitigation(gamedir); + startControllableMitigation(activity, gamedir); startOldLegacy4JMitigation(activity, gamedir); if(checkRenderDistance(gamedir)) { LifecycleAwareAlertDialog.DialogCreator dialogCreator = ((alertDialog, dialogBuilder) -> @@ -380,37 +380,68 @@ public final class Tools { // If we returned, this means that the JVM exit dialog has been shown and we don't need to be active anymore. // We never return otherwise. The process will be killed anyway, and thus we will become inactive } - + private static Logger.eventLogListener controllableMitigationLogListener; /* * This is does not work when debugging. This is not reliable. * This is a monstrosity that races the mod, trying to ensure that when the folder is checked * after extraction but before dlopen, it is empty, so it loads the bundled SDL2 we have instead */ - private static void startControllableMitigation(File gamedir) { - File deleted = new File(gamedir + "/" + "controllable_natives"); - try { - org.apache.commons.io.FileUtils.deleteDirectory(deleted); - } catch (IOException e) { - Log.i("ModMitigation", "Failed to execute Controllable mitigation"); - } - FileObserver controllableMitigation = new FileObserver(gamedir) { - @Override - public void onEvent(int event, @Nullable String path) { - Log.i("ModMitigation", "onEvent: " + Integer.toHexString(event) + ", " + path); - if (path != null && path.equals("controllable_natives")){ - Log.i("ModMitigation", "Attempting MrCrayfish's Controllable forced incorrect native extraction mitigation"); - try { - org.apache.commons.io.FileUtils.deleteDirectory(deleted); - } catch (IOException e) { - Log.i("ModMitigation", "Failed to execute Controllable mitigation"); - } + private static void startControllableMitigation(Activity activity ,File gamedir) { + String TAG = "ControllableMitigation"; + File deleted = new File(gamedir + "/controllable_natives/SDL"); + boolean hasControllable = false; + File modsDir = new File(gamedir, "mods"); + File[] mods = modsDir.listFiles(file -> file.isFile() && file.getName().endsWith(".jar")); + if (mods != null) { + for (File file : mods) { + String name = file.getName(); + if (name.contains("controllable")) { + hasControllable = true; + break; } } - }; - controllableMitigation.startWatching(); + } + if (hasControllable) { + Tools.runOnUiThread(() -> { + Tools.dialog(activity, activity.getString(R.string.global_warning), activity.getString(R.string.controllableFound)); + }); + Thread mitigationThread = new Thread(() -> { + // This is total garbage but it seems to be the best jank for the job + Log.i(TAG, "Controllable detected! Starting mitigation thread"); + try {org.apache.commons.io.FileUtils.deleteDirectory(deleted);} catch (IOException ignored) {} + while (!Thread.currentThread().isInterrupted()) { + // Looks for controllable_natives/SDL//libSDL2.so and + // deletes it. We can assume array index 0 because this dir gets fully deleted + // before the loop is started. + if (deleted.isDirectory()) { + if (deleted.listFiles().length > 0) { + if (deleted.listFiles()[0].listFiles().length > 0) { + if (deleted.listFiles()[0].listFiles()[0].exists()) { + deleted.listFiles()[0].listFiles()[0].delete(); + break; + } + } + } + } + } + // We can end here because SdlNativeLibraryLoader only extracts libSDL2.so once + // If NativeLibrary can't find it in the folder to load() it uses java.library.path + Log.i(TAG, "Success! Ending Controllable crash mitigation.."); + }); + mitigationThread.start(); + controllableMitigationLogListener = loggedLine -> { + // Hard off switch if it somehow didn't delete anything, just in case. + if (loggedLine.contains("Sound engine started") && mitigationThread.isAlive()) { + Log.i(TAG, "Nothing happened. Ending Controllable crash mitigation.."); + Logger.removeLogListener(controllableMitigationLogListener); + mitigationThread.interrupt(); + } + }; + Logger.addLogListener(controllableMitigationLogListener); + } } - private static Logger.eventLogListener eventLogListener; + private static Logger.eventLogListener oldL4JMitigationLogListener; /// TODO: Remove when the time is right /** * Legacy4J for a long time had broken SDL detection for android, we need to check and @@ -436,21 +467,20 @@ public final class Tools { if (hasLegacy4J) { String TAG = "OldLegacy4JMitigation"; Log.i(TAG, "Legacy4J detected!"); - eventLogListener = loggedLine -> { - Log.i(TAG, loggedLine); + oldL4JMitigationLogListener = loggedLine -> { if (LauncherPreferences.PREF_GAMEPAD_SDL_PASSTHRU && loggedLine.contains("literal{SDL3 (isXander's libsdl4j)} isn't supported in this system. GLFW will be used instead.")) { Log.i(TAG, "Old version of Legacy4J detected! Force enabling SDL"); Tools.SDL.initializeControllerSubsystems(); Tools.runOnUiThread(() -> { Tools.dialog(activity, activity.getString(R.string.global_warning), activity.getString(R.string.oldL4JFound)); }); - Logger.removeLogListener(eventLogListener); + Logger.removeLogListener(oldL4JMitigationLogListener); } else if (LauncherPreferences.PREF_GAMEPAD_SDL_PASSTHRU && loggedLine.contains("Added SDL Controller Mappings")) { Log.i(TAG, "Fixed version of Legacy4J detected! Have fun!"); - Logger.removeLogListener(eventLogListener); + Logger.removeLogListener(oldL4JMitigationLogListener); } }; - Logger.addLogListener(eventLogListener); + Logger.addLogListener(oldL4JMitigationLogListener); } } diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index 63ae6cc3e..31233fd65 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -481,4 +481,5 @@ SDL Settings You are using a version of Legacy4J without the android fixes! You will need to manually enable SDL in the controller settings to get the best experience! Warning! + Controllable currently has a random chance of crashing on launch. Either keep trying again and hope it launches or use another mod like Controlify.