Feat[jre_unpack]: add the ability to include multiple integrated runtimes

This commit is contained in:
artdeell 2024-06-14 13:29:59 +03:00 committed by Maksim Belov
parent 0797b7942e
commit eccef88183
7 changed files with 158 additions and 118 deletions

1
.gitignore vendored
View File

@ -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/

View File

@ -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));
}
}

View File

@ -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<InternalRuntime> 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;
}
}
}

View File

@ -10,6 +10,7 @@ import com.kdt.mcgui.ProgressLayout;
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 class MultiRTUtils {
public static String getNearestJreName(int majorVersion) {
List<Runtime> 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 class MultiRTUtils {
}
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;
}

View File

@ -31,7 +31,7 @@ public class 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) {

View File

@ -13,7 +13,7 @@ import com.kdt.mcgui.ProgressLayout;
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 @@ public class MinecraftDownloader {
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;
}

View File

@ -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 class MathUtils {
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 <T> the object type that is used for the search.
*/
public static <T> T findNearestPositive(int targetValue, List<T> objects, ValueProvider<T> 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<T> {
int getValue(T object);
}
}