diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index 5ff5f0d1d..fb777e4f1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -92,7 +92,8 @@ public final class LauncherHelper { this.launchingStepsPane.setTitle(i18n("version.launch")); } - private final TaskExecutorDialogPane launchingStepsPane = new TaskExecutorDialogPane(it -> {}); + private final TaskExecutorDialogPane launchingStepsPane = new TaskExecutorDialogPane(it -> { + }); public void setTestMode() { launcherVisibility = LauncherVisibility.KEEP; @@ -342,9 +343,9 @@ public final class LauncherHelper { JavaVersionConstraint violatedMandatoryConstraint = null; JavaVersionConstraint violatedSuggestedConstraint = null; - for (JavaVersionConstraint constraint : JavaVersionConstraint.values()) { - if (constraint.getGameVersion().contains(gameVersion) && constraint.appliesToVersion(gameVersion, version)) { - if (!constraint.getJavaVersion(version).contains(javaVersion.getVersionNumber())) { + for (JavaVersionConstraint constraint : JavaVersionConstraint.ALL) { + if (constraint.appliesToVersion(gameVersion, version, javaVersion)) { + if (!constraint.checkJava(gameVersion, version, javaVersion)) { if (constraint.getType() == JavaVersionConstraint.RULE_MANDATORY) { violatedMandatoryConstraint = constraint; } 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); return null; case VANILLA_LINUX_JAVA_8: - Controllers.dialog(i18n("launch.advice.vanilla_linux_java_8"), i18n("message.error"), MessageType.ERROR, breakAction); - return null; + if (setting.getNativesDirType() == NativesDirectoryType.VERSION_FOLDER) { + Controllers.dialog(i18n("launch.advice.vanilla_linux_java_8"), i18n("message.error"), MessageType.ERROR, breakAction); + return null; + } else { + break; + } case LAUNCH_WRAPPER: Controllers.dialog(i18n("launch.advice.java9") + "\n" + i18n("launch.advice.uncorrected"), i18n("message.error"), MessageType.ERROR, breakAction); return null; @@ -696,6 +701,7 @@ public final class LauncherHelper { } public static final Queue PROCESSES = new ConcurrentLinkedQueue<>(); + public static void stopManagedProcesses() { while (!PROCESSES.isEmpty()) Optional.ofNullable(PROCESSES.poll()).ifPresent(ManagedProcess::stop); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/JavaVersionConstraint.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/JavaVersionConstraint.java index b8945569f..fcb654467 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/JavaVersionConstraint.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/JavaVersionConstraint.java @@ -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 getJavaVersion(Version version) { + public Range 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 gameVersion; - private final Range javaVersion; + private final Range gameVersionRange; + private final Range javaVersionRange; - JavaVersionConstraint(int type, Range gameVersion, Range javaVersion) { + JavaVersionConstraint(int type, Range gameVersionRange, Range javaVersionRange) { this.type = type; - this.gameVersion = gameVersion; - this.javaVersion = javaVersion; + this.gameVersionRange = gameVersionRange; + this.javaVersionRange = javaVersionRange; } public int getType() { return type; } - public Range getGameVersion() { - return gameVersion; + public Range getGameVersionRange() { + return gameVersionRange; } - public Range getJavaVersion(Version version) { - return javaVersion; + public Range 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 ALL = Lang.immutableListOf(values()); + + public static VersionRanges findSuitableJavaVersionRange(VersionNumber gameVersion, Version version) { Range mandatoryJavaRange = versionRange(MIN, MAX); Range suggestedJavaRange = versionRange(MIN, MAX); - for (JavaVersionConstraint java : values()) { - if (java.gameVersion.contains(gameVersion) && java.appliesToVersion(gameVersion, version)) { - Range javaVersionRange = java.getJavaVersion(version); + for (JavaVersionConstraint java : ALL) { + if (java.appliesToVersion(gameVersion, version, null)) { + Range 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 mandatory; private final Range suggested; - public VersionRange(Range mandatory, Range suggested) { + public VersionRanges(Range mandatory, Range suggested) { this.mandatory = mandatory; this.suggested = suggested; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/JavaVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/JavaVersion.java index dd7ee6dca..daefd20e6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/JavaVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/JavaVersion.java @@ -68,6 +68,10 @@ public final class JavaVersion { return platform; } + public Architecture getArchitecture() { + return platform.getArchitecture(); + } + public Bits getBits() { return platform.getBits(); } diff --git a/HMCLCore/src/test/java/org/jackhuang/hmcl/game/JavaVersionConstraintTest.java b/HMCLCore/src/test/java/org/jackhuang/hmcl/game/JavaVersionConstraintTest.java index 06e95ad76..94e56e025 100644 --- a/HMCLCore/src/test/java/org/jackhuang/hmcl/game/JavaVersionConstraintTest.java +++ b/HMCLCore/src/test/java/org/jackhuang/hmcl/game/JavaVersionConstraintTest.java @@ -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 );