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

@@ -92,7 +92,8 @@ public final class LauncherHelper {
this.launchingStepsPane.setTitle(i18n("version.launch")); this.launchingStepsPane.setTitle(i18n("version.launch"));
} }
private final TaskExecutorDialogPane launchingStepsPane = new TaskExecutorDialogPane(it -> {}); private final TaskExecutorDialogPane launchingStepsPane = new TaskExecutorDialogPane(it -> {
});
public void setTestMode() { public void setTestMode() {
launcherVisibility = LauncherVisibility.KEEP; launcherVisibility = LauncherVisibility.KEEP;
@@ -342,9 +343,9 @@ public final class LauncherHelper {
JavaVersionConstraint violatedMandatoryConstraint = null; JavaVersionConstraint violatedMandatoryConstraint = null;
JavaVersionConstraint violatedSuggestedConstraint = null; JavaVersionConstraint violatedSuggestedConstraint = null;
for (JavaVersionConstraint constraint : JavaVersionConstraint.values()) { for (JavaVersionConstraint constraint : JavaVersionConstraint.ALL) {
if (constraint.getGameVersion().contains(gameVersion) && constraint.appliesToVersion(gameVersion, version)) { if (constraint.appliesToVersion(gameVersion, version, javaVersion)) {
if (!constraint.getJavaVersion(version).contains(javaVersion.getVersionNumber())) { if (!constraint.checkJava(gameVersion, version, javaVersion)) {
if (constraint.getType() == JavaVersionConstraint.RULE_MANDATORY) { if (constraint.getType() == JavaVersionConstraint.RULE_MANDATORY) {
violatedMandatoryConstraint = constraint; violatedMandatoryConstraint = constraint;
} else if (constraint.getType() == JavaVersionConstraint.RULE_SUGGESTED) { } else if (constraint.getType() == JavaVersionConstraint.RULE_SUGGESTED) {
@@ -423,8 +424,12 @@ public final class LauncherHelper {
Controllers.dialog(i18n("launch.advice.java8_1_13"), i18n("message.error"), MessageType.ERROR, breakAction); Controllers.dialog(i18n("launch.advice.java8_1_13"), i18n("message.error"), MessageType.ERROR, breakAction);
return null; return null;
case VANILLA_LINUX_JAVA_8: case VANILLA_LINUX_JAVA_8:
Controllers.dialog(i18n("launch.advice.vanilla_linux_java_8"), i18n("message.error"), MessageType.ERROR, breakAction); if (setting.getNativesDirType() == NativesDirectoryType.VERSION_FOLDER) {
return null; Controllers.dialog(i18n("launch.advice.vanilla_linux_java_8"), i18n("message.error"), MessageType.ERROR, breakAction);
return null;
} else {
break;
}
case LAUNCH_WRAPPER: case LAUNCH_WRAPPER:
Controllers.dialog(i18n("launch.advice.java9") + "\n" + i18n("launch.advice.uncorrected"), i18n("message.error"), MessageType.ERROR, breakAction); Controllers.dialog(i18n("launch.advice.java9") + "\n" + i18n("launch.advice.uncorrected"), i18n("message.error"), MessageType.ERROR, breakAction);
return null; return null;
@@ -696,6 +701,7 @@ public final class LauncherHelper {
} }
public static final Queue<ManagedProcess> PROCESSES = new ConcurrentLinkedQueue<>(); public static final Queue<ManagedProcess> PROCESSES = new ConcurrentLinkedQueue<>();
public static void stopManagedProcesses() { public static void stopManagedProcesses() {
while (!PROCESSES.isEmpty()) while (!PROCESSES.isEmpty())
Optional.ofNullable(PROCESSES.poll()).ifPresent(ManagedProcess::stop); Optional.ofNullable(PROCESSES.poll()).ifPresent(ManagedProcess::stop);

View File

@@ -17,6 +17,7 @@
*/ */
package org.jackhuang.hmcl.game; package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Range; import org.jackhuang.hmcl.util.Range;
import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.JavaVersion; 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.jackhuang.hmcl.util.versioning.VersionNumber;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LAUNCH_WRAPPER_MAIN; 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 // 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")) { MODDED_JAVA_7(JavaVersionConstraint.RULE_SUGGESTED, versionRange(JavaVersionConstraint.MIN, "1.7.2"), versionRange(JavaVersionConstraint.MIN, "1.7.999")) {
@Override @Override
public boolean appliesToVersion(@Nullable VersionNumber gameVersion, @Nullable Version version) { public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version,
if (version == null) return false; @Nullable JavaVersion javaVersion) {
if (!getGameVersionRange().contains(gameVersionNumber) || version == null) return false;
return LAUNCH_WRAPPER_MAIN.equals(version.getMainClass()); 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) // 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")) { LAUNCH_WRAPPER(JavaVersionConstraint.RULE_MANDATORY, versionRange("0", "1.12.999"), versionRange("0", "1.8.999")) {
@Override @Override
public boolean appliesToVersion(VersionNumber gameVersion, Version version) { public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version,
if (version == null) return false; @Nullable JavaVersion javaVersion) {
if (!getGameVersionRange().contains(gameVersionNumber) || version == null) return false;
return LAUNCH_WRAPPER_MAIN.equals(version.getMainClass()) && return LAUNCH_WRAPPER_MAIN.equals(version.getMainClass()) &&
version.getLibraries().stream() version.getLibraries().stream()
.filter(library -> "launchwrapper".equals(library.getArtifactId())) .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. // 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)) { GAME_JSON(JavaVersionConstraint.RULE_MANDATORY, versionRange(JavaVersionConstraint.MIN, JavaVersionConstraint.MAX), versionRange(JavaVersionConstraint.MIN, JavaVersionConstraint.MAX)) {
@Override @Override
public boolean appliesToVersion(VersionNumber gameVersion, Version version) { public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version,
if (gameVersion == null || version == null) return false; @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. // 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 @Override
public Range<VersionNumber> getJavaVersion(Version version) { public Range<VersionNumber> getJavaVersionRange(Version version) {
String javaVersion; String javaVersion;
if (Objects.requireNonNull(version.getJavaVersion()).getMajorVersion() >= 9) { if (Objects.requireNonNull(version.getJavaVersion()).getMajorVersion() >= 9) {
javaVersion = "" + version.getJavaVersion().getMajorVersion(); javaVersion = "" + version.getJavaVersion().getMajorVersion();
@@ -81,44 +86,60 @@ public enum JavaVersionConstraint {
// For example, JDK 9+ 64-bit cannot load 32-bit lwjgl native library. // 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")) { VANILLA_LINUX_JAVA_8(JavaVersionConstraint.RULE_MANDATORY, versionRange("0", "1.12.999"), versionRange(JavaVersionConstraint.MIN, "1.8.999")) {
@Override @Override
public boolean appliesToVersion(@Nullable VersionNumber gameVersion, @Nullable Version version) { public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version,
return OperatingSystem.CURRENT_OS == OperatingSystem.LINUX && Architecture.SYSTEM_ARCH == Architecture.X86_64; @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 int type;
private final Range<VersionNumber> gameVersion; private final Range<VersionNumber> gameVersionRange;
private final Range<VersionNumber> javaVersion; 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.type = type;
this.gameVersion = gameVersion; this.gameVersionRange = gameVersionRange;
this.javaVersion = javaVersion; this.javaVersionRange = javaVersionRange;
} }
public int getType() { public int getType() {
return type; return type;
} }
public Range<VersionNumber> getGameVersion() { public Range<VersionNumber> getGameVersionRange() {
return gameVersion; return gameVersionRange;
} }
public Range<VersionNumber> getJavaVersion(Version version) { public Range<VersionNumber> getJavaVersionRange(Version version) {
return javaVersion; return javaVersionRange;
} }
public boolean appliesToVersion(@Nullable VersionNumber gameVersion, @Nullable Version version) { public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version,
return true; @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> mandatoryJavaRange = versionRange(MIN, MAX);
Range<VersionNumber> suggestedJavaRange = versionRange(MIN, MAX); Range<VersionNumber> suggestedJavaRange = versionRange(MIN, MAX);
for (JavaVersionConstraint java : values()) { for (JavaVersionConstraint java : ALL) {
if (java.gameVersion.contains(gameVersion) && java.appliesToVersion(gameVersion, version)) { if (java.appliesToVersion(gameVersion, version, null)) {
Range<VersionNumber> javaVersionRange = java.getJavaVersion(version); Range<VersionNumber> javaVersionRange = java.getJavaVersionRange(version);
if (java.type == RULE_MANDATORY) { if (java.type == RULE_MANDATORY) {
mandatoryJavaRange = mandatoryJavaRange.intersectionWith(javaVersionRange); mandatoryJavaRange = mandatoryJavaRange.intersectionWith(javaVersionRange);
suggestedJavaRange = suggestedJavaRange.intersectionWith(javaVersionRange); suggestedJavaRange = suggestedJavaRange.intersectionWith(javaVersionRange);
@@ -127,26 +148,27 @@ public enum JavaVersionConstraint {
} }
} }
} }
return new VersionRange(mandatoryJavaRange, suggestedJavaRange); return new VersionRanges(mandatoryJavaRange, suggestedJavaRange);
} }
@Nullable @Nullable
public static JavaVersion findSuitableJavaVersion(VersionNumber gameVersion, Version version) throws InterruptedException { public static JavaVersion findSuitableJavaVersion(VersionNumber gameVersion, Version version) throws InterruptedException {
VersionRange range = findSuitableJavaVersionRange(gameVersion, version); VersionRanges range = findSuitableJavaVersionRange(gameVersion, version);
JavaVersion mandatory = null; JavaVersion mandatory = null;
JavaVersion suggested = null; JavaVersion suggested = null;
for (JavaVersion javaVersion : JavaVersion.getJavas()) { for (JavaVersion javaVersion : JavaVersion.getJavas()) {
// select the latest java version that this version accepts. // 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; if (mandatory == null) mandatory = javaVersion;
else if (javaVersion.getVersionNumber().compareTo(mandatory.getVersionNumber()) > 0) { else if (javaVersionNumber.compareTo(mandatory.getVersionNumber()) > 0) {
mandatory = javaVersion; mandatory = javaVersion;
} }
} }
if (range.getSuggested().contains(javaVersion.getVersionNumber())) { if (range.getSuggested().contains(javaVersionNumber)) {
if (suggested == null) suggested = javaVersion; if (suggested == null) suggested = javaVersion;
else if (javaVersion.getVersionNumber().compareTo(suggested.getVersionNumber()) > 0) { else if (javaVersionNumber.compareTo(suggested.getVersionNumber()) > 0) {
suggested = javaVersion; suggested = javaVersion;
} }
} }
@@ -166,11 +188,11 @@ public enum JavaVersionConstraint {
return Range.between(VersionNumber.asVersion(fromInclusive), VersionNumber.asVersion(toExclusive)); 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> mandatory;
private final Range<VersionNumber> suggested; 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.mandatory = mandatory;
this.suggested = suggested; this.suggested = suggested;
} }

View File

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

View File

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