Enhance JavaVersionConstraint

This commit is contained in:
Glavo
2021-10-14 00:35:58 +08:00
committed by Yuhui Huang
parent db105c90b5
commit 9595626a27
4 changed files with 74 additions and 42 deletions

View File

@@ -17,6 +17,7 @@
*/
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Range;
import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.JavaVersion;
@@ -24,6 +25,7 @@ import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LAUNCH_WRAPPER_MAIN;
@@ -39,16 +41,18 @@ public enum JavaVersionConstraint {
// Minecraft<=1.7.2+Forge requires Java<=7
MODDED_JAVA_7(JavaVersionConstraint.RULE_SUGGESTED, versionRange(JavaVersionConstraint.MIN, "1.7.2"), versionRange(JavaVersionConstraint.MIN, "1.7.999")) {
@Override
public boolean appliesToVersion(@Nullable VersionNumber gameVersion, @Nullable Version version) {
if (version == null) return false;
public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version,
@Nullable JavaVersion javaVersion) {
if (!getGameVersionRange().contains(gameVersionNumber) || version == null) return false;
return LAUNCH_WRAPPER_MAIN.equals(version.getMainClass());
}
},
// LaunchWrapper<=1.12 will crash because of assuming the system class loader is an instance of URLClassLoader (Java 8)
LAUNCH_WRAPPER(JavaVersionConstraint.RULE_MANDATORY, versionRange("0", "1.12.999"), versionRange("0", "1.8.999")) {
@Override
public boolean appliesToVersion(VersionNumber gameVersion, Version version) {
if (version == null) return false;
public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version,
@Nullable JavaVersion javaVersion) {
if (!getGameVersionRange().contains(gameVersionNumber) || version == null) return false;
return LAUNCH_WRAPPER_MAIN.equals(version.getMainClass()) &&
version.getLibraries().stream()
.filter(library -> "launchwrapper".equals(library.getArtifactId()))
@@ -60,14 +64,15 @@ public enum JavaVersionConstraint {
// Minecraft with suggested java version recorded in game json is restrictedly constrained.
GAME_JSON(JavaVersionConstraint.RULE_MANDATORY, versionRange(JavaVersionConstraint.MIN, JavaVersionConstraint.MAX), versionRange(JavaVersionConstraint.MIN, JavaVersionConstraint.MAX)) {
@Override
public boolean appliesToVersion(VersionNumber gameVersion, Version version) {
if (gameVersion == null || version == null) return false;
public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version,
@Nullable JavaVersion javaVersion) {
if (!getGameVersionRange().contains(gameVersionNumber) || version == null) return false;
// We only checks for 1.7.10 and above, since 1.7.2 with Forge can only run on Java 7, but it is recorded Java 8 in game json, which is not correct.
return gameVersion.compareTo(VersionNumber.asVersion("1.7.10")) >= 0 && version.getJavaVersion() != null;
return gameVersionNumber.compareTo(VersionNumber.asVersion("1.7.10")) >= 0 && version.getJavaVersion() != null;
}
@Override
public Range<VersionNumber> getJavaVersion(Version version) {
public Range<VersionNumber> getJavaVersionRange(Version version) {
String javaVersion;
if (Objects.requireNonNull(version.getJavaVersion()).getMajorVersion() >= 9) {
javaVersion = "" + version.getJavaVersion().getMajorVersion();
@@ -81,44 +86,60 @@ public enum JavaVersionConstraint {
// For example, JDK 9+ 64-bit cannot load 32-bit lwjgl native library.
VANILLA_LINUX_JAVA_8(JavaVersionConstraint.RULE_MANDATORY, versionRange("0", "1.12.999"), versionRange(JavaVersionConstraint.MIN, "1.8.999")) {
@Override
public boolean appliesToVersion(@Nullable VersionNumber gameVersion, @Nullable Version version) {
return OperatingSystem.CURRENT_OS == OperatingSystem.LINUX && Architecture.SYSTEM_ARCH == Architecture.X86_64;
public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version,
@Nullable JavaVersion javaVersion) {
return getGameVersionRange().contains(gameVersionNumber)
&& OperatingSystem.CURRENT_OS == OperatingSystem.LINUX
&& Architecture.SYSTEM_ARCH == Architecture.X86_64
&& (javaVersion == null || javaVersion.getArchitecture() == Architecture.X86_64);
}
}
;
@Override
public boolean checkJava(VersionNumber gameVersionNumber, Version version, JavaVersion javaVersion) {
return javaVersion.getArchitecture() != Architecture.X86_64 || super.checkJava(gameVersionNumber, version, javaVersion);
}
};
private final int type;
private final Range<VersionNumber> gameVersion;
private final Range<VersionNumber> javaVersion;
private final Range<VersionNumber> gameVersionRange;
private final Range<VersionNumber> javaVersionRange;
JavaVersionConstraint(int type, Range<VersionNumber> gameVersion, Range<VersionNumber> javaVersion) {
JavaVersionConstraint(int type, Range<VersionNumber> gameVersionRange, Range<VersionNumber> javaVersionRange) {
this.type = type;
this.gameVersion = gameVersion;
this.javaVersion = javaVersion;
this.gameVersionRange = gameVersionRange;
this.javaVersionRange = javaVersionRange;
}
public int getType() {
return type;
}
public Range<VersionNumber> getGameVersion() {
return gameVersion;
public Range<VersionNumber> getGameVersionRange() {
return gameVersionRange;
}
public Range<VersionNumber> getJavaVersion(Version version) {
return javaVersion;
public Range<VersionNumber> getJavaVersionRange(Version version) {
return javaVersionRange;
}
public boolean appliesToVersion(@Nullable VersionNumber gameVersion, @Nullable Version version) {
return true;
public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version,
@Nullable JavaVersion javaVersion) {
return gameVersionRange.contains(gameVersionNumber);
}
public static VersionRange findSuitableJavaVersionRange(VersionNumber gameVersion, Version version) {
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean checkJava(VersionNumber gameVersionNumber, Version version, JavaVersion javaVersion) {
return getJavaVersionRange(version).contains(javaVersion.getVersionNumber());
}
public static final List<JavaVersionConstraint> ALL = Lang.immutableListOf(values());
public static VersionRanges findSuitableJavaVersionRange(VersionNumber gameVersion, Version version) {
Range<VersionNumber> mandatoryJavaRange = versionRange(MIN, MAX);
Range<VersionNumber> suggestedJavaRange = versionRange(MIN, MAX);
for (JavaVersionConstraint java : values()) {
if (java.gameVersion.contains(gameVersion) && java.appliesToVersion(gameVersion, version)) {
Range<VersionNumber> javaVersionRange = java.getJavaVersion(version);
for (JavaVersionConstraint java : ALL) {
if (java.appliesToVersion(gameVersion, version, null)) {
Range<VersionNumber> javaVersionRange = java.getJavaVersionRange(version);
if (java.type == RULE_MANDATORY) {
mandatoryJavaRange = mandatoryJavaRange.intersectionWith(javaVersionRange);
suggestedJavaRange = suggestedJavaRange.intersectionWith(javaVersionRange);
@@ -127,26 +148,27 @@ public enum JavaVersionConstraint {
}
}
}
return new VersionRange(mandatoryJavaRange, suggestedJavaRange);
return new VersionRanges(mandatoryJavaRange, suggestedJavaRange);
}
@Nullable
public static JavaVersion findSuitableJavaVersion(VersionNumber gameVersion, Version version) throws InterruptedException {
VersionRange range = findSuitableJavaVersionRange(gameVersion, version);
VersionRanges range = findSuitableJavaVersionRange(gameVersion, version);
JavaVersion mandatory = null;
JavaVersion suggested = null;
for (JavaVersion javaVersion : JavaVersion.getJavas()) {
// select the latest java version that this version accepts.
if (range.getMandatory().contains(javaVersion.getVersionNumber())) {
VersionNumber javaVersionNumber = javaVersion.getVersionNumber();
if (range.getMandatory().contains(javaVersionNumber)) {
if (mandatory == null) mandatory = javaVersion;
else if (javaVersion.getVersionNumber().compareTo(mandatory.getVersionNumber()) > 0) {
else if (javaVersionNumber.compareTo(mandatory.getVersionNumber()) > 0) {
mandatory = javaVersion;
}
}
if (range.getSuggested().contains(javaVersion.getVersionNumber())) {
if (range.getSuggested().contains(javaVersionNumber)) {
if (suggested == null) suggested = javaVersion;
else if (javaVersion.getVersionNumber().compareTo(suggested.getVersionNumber()) > 0) {
else if (javaVersionNumber.compareTo(suggested.getVersionNumber()) > 0) {
suggested = javaVersion;
}
}
@@ -166,11 +188,11 @@ public enum JavaVersionConstraint {
return Range.between(VersionNumber.asVersion(fromInclusive), VersionNumber.asVersion(toExclusive));
}
public static class VersionRange {
public static class VersionRanges {
private final Range<VersionNumber> mandatory;
private final Range<VersionNumber> suggested;
public VersionRange(Range<VersionNumber> mandatory, Range<VersionNumber> suggested) {
public VersionRanges(Range<VersionNumber> mandatory, Range<VersionNumber> suggested) {
this.mandatory = mandatory;
this.suggested = suggested;
}

View File

@@ -68,6 +68,10 @@ public final class JavaVersion {
return platform;
}
public Architecture getArchitecture() {
return platform.getArchitecture();
}
public Bits getBits() {
return platform.getBits();
}

View File

@@ -26,7 +26,7 @@ public class JavaVersionConstraintTest {
@Test
public void vanillaJava16() {
JavaVersionConstraint.VersionRange range = JavaVersionConstraint.findSuitableJavaVersionRange(
JavaVersionConstraint.VersionRanges range = JavaVersionConstraint.findSuitableJavaVersionRange(
VersionNumber.asVersion("1.17"),
null
);