From b12429b01a508ccfbf5eca3ac25957756ed8b42c Mon Sep 17 00:00:00 2001 From: artdeell Date: Fri, 14 Jun 2024 13:29:59 +0300 Subject: [PATCH] Feat[jre_unpack]: add the ability to include multiple integrated runtimes --- .gitignore | 1 + .../java/net/kdt/pojavlaunch/JRE17Util.java | 98 --------------- .../java/net/kdt/pojavlaunch/NewJREUtil.java | 115 ++++++++++++++++++ .../kdt/pojavlaunch/multirt/MultiRTUtils.java | 25 ++-- .../pojavlaunch/tasks/AsyncAssetManager.java | 2 +- .../tasks/MinecraftDownloader.java | 4 +- .../net/kdt/pojavlaunch/utils/MathUtils.java | 31 +++++ 7 files changed, 158 insertions(+), 118 deletions(-) delete mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JRE17Util.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/NewJREUtil.java diff --git a/.gitignore b/.gitignore index 798bb76779..ff3508cdb5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /build /*/build app_pojavlauncher/src/main/assets/components/jre +/app_pojavlauncher/src/main/assets/components/jre-new/ local.properties .idea/ app_pojavlauncher/.cxx/ diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JRE17Util.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JRE17Util.java deleted file mode 100644 index 1cd0dca35b..0000000000 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JRE17Util.java +++ /dev/null @@ -1,98 +0,0 @@ -package net.kdt.pojavlaunch; - -import static net.kdt.pojavlaunch.Architecture.archAsString; - -import android.app.Activity; -import android.content.res.AssetManager; -import android.util.Log; - -import net.kdt.pojavlaunch.multirt.MultiRTUtils; -import net.kdt.pojavlaunch.multirt.Runtime; -import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles; -import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile; - -import java.io.IOException; - -public class JRE17Util { - public static final String NEW_JRE_NAME = "Internal-17"; - public static boolean checkInternalNewJre(AssetManager assetManager) { - String launcher_jre17_version; - String installed_jre17_version = MultiRTUtils.__internal__readBinpackVersion(NEW_JRE_NAME); - try { - launcher_jre17_version = Tools.read(assetManager.open("components/jre-new/version")); - }catch (IOException exc) { - //we don't have a runtime included! - return installed_jre17_version != null; //if we have one installed -> return true -> proceed (no updates but the current one should be functional) - //if we don't -> return false -> Cannot find compatible Java runtime - } - if(!launcher_jre17_version.equals(installed_jre17_version)) // this implicitly checks for null, so it will unpack the runtime even if we don't have one installed - return unpackJre17(assetManager, launcher_jre17_version); - else return true; - } - - private static boolean unpackJre17(AssetManager assetManager, String rt_version) { - try { - MultiRTUtils.installRuntimeNamedBinpack( - assetManager.open("components/jre-new/universal.tar.xz"), - assetManager.open("components/jre-new/bin-" + archAsString(Tools.DEVICE_ARCHITECTURE) + ".tar.xz"), - "Internal-17", rt_version); - MultiRTUtils.postPrepare("Internal-17"); - return true; - }catch (IOException e) { - Log.e("JRE17Auto", "Internal JRE unpack failed", e); - return false; - } - } - public static boolean isInternalNewJRE(String s_runtime) { - Runtime runtime = MultiRTUtils.read(s_runtime); - if(runtime == null) return false; - return NEW_JRE_NAME.equals(runtime.name); - } - - /** @return true if everything is good, false otherwise. */ - public static boolean installNewJreIfNeeded(Activity activity, JMinecraftVersionList.Version versionInfo) { - //Now we have the reliable information to check if our runtime settings are good enough - if (versionInfo.javaVersion == null || versionInfo.javaVersion.component.equalsIgnoreCase("jre-legacy")) - return true; - - LauncherProfiles.load(); - MinecraftProfile minecraftProfile = LauncherProfiles.getCurrentProfile(); - - String selectedRuntime = Tools.getSelectedRuntime(minecraftProfile); - - Runtime runtime = MultiRTUtils.read(selectedRuntime); - if (runtime.javaVersion >= versionInfo.javaVersion.majorVersion) { - return true; - } - - String appropriateRuntime = MultiRTUtils.getNearestJreName(versionInfo.javaVersion.majorVersion); - if (appropriateRuntime != null) { - if (JRE17Util.isInternalNewJRE(appropriateRuntime)) { - JRE17Util.checkInternalNewJre(activity.getAssets()); - } - minecraftProfile.javaDir = Tools.LAUNCHERPROFILES_RTPREFIX + appropriateRuntime; - LauncherProfiles.load(); - } else { - if (versionInfo.javaVersion.majorVersion <= 17) { // there's a chance we have an internal one for this case - if (!JRE17Util.checkInternalNewJre(activity.getAssets())){ - showRuntimeFail(activity, versionInfo); - return false; - } else { - minecraftProfile.javaDir = Tools.LAUNCHERPROFILES_RTPREFIX + JRE17Util.NEW_JRE_NAME; - LauncherProfiles.load(); - } - } else { - showRuntimeFail(activity, versionInfo); - return false; - } - } - - return true; - } - - private static void showRuntimeFail(Activity activity, JMinecraftVersionList.Version verInfo) { - Tools.dialogOnUiThread(activity, activity.getString(R.string.global_error), - activity.getString(R.string.multirt_nocompartiblert, verInfo.javaVersion.majorVersion)); - } - -} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/NewJREUtil.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/NewJREUtil.java new file mode 100644 index 0000000000..1f264557b9 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/NewJREUtil.java @@ -0,0 +1,115 @@ +package net.kdt.pojavlaunch; + +import static net.kdt.pojavlaunch.Architecture.archAsString; + +import android.app.Activity; +import android.content.res.AssetManager; +import android.util.Log; + +import net.kdt.pojavlaunch.multirt.MultiRTUtils; +import net.kdt.pojavlaunch.multirt.Runtime; +import net.kdt.pojavlaunch.utils.MathUtils; +import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles; +import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +public class NewJREUtil { + private static boolean checkInternalRuntime(AssetManager assetManager, InternalRuntime internalRuntime) { + String launcher_runtime_version; + String installed_runtime_version = MultiRTUtils.readInternalRuntimeVersion(internalRuntime.name); + try { + launcher_runtime_version = Tools.read(assetManager.open(internalRuntime.path+"/version")); + }catch (IOException exc) { + //we don't have a runtime included! + //if we have one installed -> return true -> proceed (no updates but the current one should be functional) + //if we don't -> return false -> Cannot find compatible Java runtime + return installed_runtime_version != null; + } + // this implicitly checks for null, so it will unpack the runtime even if we don't have one installed + if(!launcher_runtime_version.equals(installed_runtime_version)) + return unpackInternalRuntime(assetManager, internalRuntime, launcher_runtime_version); + else return true; + } + + private static boolean unpackInternalRuntime(AssetManager assetManager, InternalRuntime internalRuntime, String version) { + try { + MultiRTUtils.installRuntimeNamedBinpack( + assetManager.open(internalRuntime.path+"/universal.tar.xz"), + assetManager.open(internalRuntime.path+"/bin-" + archAsString(Tools.DEVICE_ARCHITECTURE) + ".tar.xz"), + internalRuntime.name, version); + MultiRTUtils.postPrepare(internalRuntime.name); + return true; + }catch (IOException e) { + Log.e("NewJREAuto", "Internal JRE unpack failed", e); + return false; + } + } + public static InternalRuntime getInternalRuntime(String s_runtime) { + Runtime runtime = MultiRTUtils.read(s_runtime); + if(runtime == null) return null; + for(InternalRuntime internalRuntime : InternalRuntime.values()) { + if(internalRuntime.name.equals(runtime.name)) return internalRuntime; + } + return null; + } + + private static InternalRuntime findAppropriateInternalRuntime(int targetVersion) { + List runtimeList = Arrays.asList(InternalRuntime.values()); + return MathUtils.findNearestPositive(targetVersion, runtimeList, (runtime)->runtime.majorVersion); + } + + /** @return true if everything is good, false otherwise. */ + public static boolean installNewJreIfNeeded(Activity activity, JMinecraftVersionList.Version versionInfo) { + //Now we have the reliable information to check if our runtime settings are good enough + if (versionInfo.javaVersion == null || versionInfo.javaVersion.component.equalsIgnoreCase("jre-legacy")) + return true; + + LauncherProfiles.load(); + MinecraftProfile minecraftProfile = LauncherProfiles.getCurrentProfile(); + String selectedRuntime = Tools.getSelectedRuntime(minecraftProfile); + Runtime runtime = MultiRTUtils.read(selectedRuntime); + if (runtime.javaVersion >= versionInfo.javaVersion.majorVersion) { + return true; + } + + String appropriateRuntime = MultiRTUtils.getNearestJreName(versionInfo.javaVersion.majorVersion); + boolean failOnMiss = false; + InternalRuntime internalRuntime; + if(appropriateRuntime == null) { + internalRuntime = NewJREUtil.findAppropriateInternalRuntime(versionInfo.javaVersion.majorVersion); + failOnMiss = true; + }else { + internalRuntime = NewJREUtil.getInternalRuntime(appropriateRuntime); + } + + if((internalRuntime == null || !NewJREUtil.checkInternalRuntime(activity.getAssets(), internalRuntime)) && failOnMiss) { + showRuntimeFail(activity, versionInfo); + return false; + } + + minecraftProfile.javaDir = Tools.LAUNCHERPROFILES_RTPREFIX + appropriateRuntime; + LauncherProfiles.write(); + return true; + } + + private static void showRuntimeFail(Activity activity, JMinecraftVersionList.Version verInfo) { + Tools.dialogOnUiThread(activity, activity.getString(R.string.global_error), + activity.getString(R.string.multirt_nocompartiblert, verInfo.javaVersion.majorVersion)); + } + + private enum InternalRuntime { + JRE_17(17, "Internal-17", "components/jre-new"); + public final int majorVersion; + public final String name; + public final String path; + InternalRuntime(int majorVersion, String name, String path) { + this.majorVersion = majorVersion; + this.name = name; + this.path = path; + } + } + +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/MultiRTUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/MultiRTUtils.java index 7d008b3f03..52d07063bc 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/MultiRTUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/MultiRTUtils.java @@ -10,6 +10,7 @@ import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.Tools; +import net.kdt.pojavlaunch.utils.MathUtils; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; @@ -60,19 +61,9 @@ public static String getExactJreName(int majorVersion) { public static String getNearestJreName(int majorVersion) { List runtimes = getRuntimes(); - int diff_factor = Integer.MAX_VALUE; - String result = null; - for(Runtime r : runtimes) { - if(r.javaVersion < majorVersion) continue; // lower - not useful - - int currentFactor = r.javaVersion - majorVersion; - if(diff_factor > currentFactor) { - result = r.name; - diff_factor = currentFactor; - } - } - - return result; + Runtime nearestRuntime = MathUtils.findNearestPositive(majorVersion, runtimes, (runtime)->runtime.javaVersion); + if(nearestRuntime == null) return null; + return nearestRuntime.name; } public static void installRuntimeNamed(String nativeLibDir, InputStream runtimeInputStream, String name) throws IOException { @@ -120,11 +111,11 @@ public static void installRuntimeNamedBinpack(InputStream universalFileInputStre } - public static String __internal__readBinpackVersion(String name) { - File binpack_verfile = new File(RUNTIME_FOLDER,"/" + name + "/pojav_version"); + public static String readInternalRuntimeVersion(String name) { + File versionFile = new File(RUNTIME_FOLDER,"/" + name + "/pojav_version"); try { - if (binpack_verfile.exists()) { - return Tools.read(binpack_verfile.getAbsolutePath()); + if (versionFile.exists()) { + return Tools.read(versionFile.getAbsolutePath()); }else{ return null; } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/AsyncAssetManager.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/AsyncAssetManager.java index 0b13f357d7..e2cb008277 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/AsyncAssetManager.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/AsyncAssetManager.java @@ -31,7 +31,7 @@ private AsyncAssetManager(){} public static void unpackRuntime(AssetManager am) { /* Check if JRE is included */ String rt_version = null; - String current_rt_version = MultiRTUtils.__internal__readBinpackVersion("Internal"); + String current_rt_version = MultiRTUtils.readInternalRuntimeVersion("Internal"); try { rt_version = Tools.read(am.open("components/jre/version")); } catch (IOException e) { diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloader.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloader.java index 167c165382..5abaa57fdb 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloader.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloader.java @@ -13,7 +13,7 @@ import net.kdt.pojavlaunch.JAssetInfo; import net.kdt.pojavlaunch.JAssets; import net.kdt.pojavlaunch.JMinecraftVersionList; -import net.kdt.pojavlaunch.JRE17Util; +import net.kdt.pojavlaunch.NewJREUtil; import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.mirrors.DownloadMirror; @@ -203,7 +203,7 @@ private boolean downloadAndProcessMetadata(Activity activity, JMinecraftVersionL throw new IOException("Unable to read Version JSON for version " + versionName); } - if(activity != null && !JRE17Util.installNewJreIfNeeded(activity, verInfo)){ + if(activity != null && !NewJREUtil.installNewJreIfNeeded(activity, verInfo)){ return false; } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/MathUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/MathUtils.java index e292f382c1..f26b3af2e5 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/MathUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/MathUtils.java @@ -1,5 +1,7 @@ package net.kdt.pojavlaunch.utils; +import java.util.List; + public class MathUtils { //Ported from https://www.arduino.cc/reference/en/language/functions/math/map/ @@ -14,4 +16,33 @@ public static float dist(float x1, float y1, float x2, float y2) { return (float) Math.hypot(x, y); } + /** + * Find the object T with the closest (or higher) value compared to targetValue + * @param targetValue the target value + * @param objects the list of objects that the search will be performed on + * @param valueProvider the provider for each values + * @return the object which has the closest value to targetValue, or null if values of all + * objects are less than targetValue + * @param the object type that is used for the search. + */ + public static T findNearestPositive(int targetValue, List objects, ValueProvider valueProvider) { + int delta = Integer.MAX_VALUE; + T selectedObject = null; + for(T object : objects) { + int objectValue = valueProvider.getValue(object); + if(objectValue < targetValue) continue; + + int currentDelta = objectValue - targetValue; + if(currentDelta == 0) return object; + if(currentDelta >= delta) continue; + + selectedObject = object; + delta = currentDelta; + } + return selectedObject; + } + + public interface ValueProvider { + int getValue(T object); + } }