From cd7c515097bae4fbc9e08cb865efa2513337b7fc Mon Sep 17 00:00:00 2001 From: Glavo Date: Thu, 14 Oct 2021 02:40:36 +0800 Subject: [PATCH] Accurately obtain the Windows version number; Report error when users try to run minecraft using java for other platforms --- .../java/org/jackhuang/hmcl/Launcher.java | 2 +- .../jackhuang/hmcl/game/LauncherHelper.java | 15 +++++ .../jackhuang/hmcl/ui/GameCrashWindow.java | 2 +- .../jackhuang/hmcl/util/CrashReporter.java | 2 +- .../resources/assets/lang/I18N.properties | 2 + .../resources/assets/lang/I18N_zh.properties | 2 + .../assets/lang/I18N_zh_CN.properties | 4 +- .../hmcl/game/JavaVersionConstraint.java | 15 +++++ .../hmcl/util/platform/OperatingSystem.java | 62 +++++++++++++++++-- .../hmcl/util/platform/Platform.java | 9 ++- 10 files changed, 105 insertions(+), 10 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java b/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java index f7710acc5..97876e994 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java @@ -106,7 +106,7 @@ public final class Launcher extends Application { try { LOG.info("*** " + Metadata.TITLE + " ***"); - LOG.info("Operating System: " + System.getProperty("os.name") + ' ' + OperatingSystem.SYSTEM_VERSION); + LOG.info("Operating System: " + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION); LOG.info("Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor")); LOG.info("Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor")); LOG.info("Java Home: " + System.getProperty("java.home")); 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 fb777e4f1..fbf5dbe26 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -430,6 +430,21 @@ public final class LauncherHelper { } else { break; } + case VANILLA_X86: + if (setting.getNativesDirType() == NativesDirectoryType.VERSION_FOLDER) { + if (Architecture.SYSTEM_ARCH == Architecture.ARM64) { + if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX + // Windows on ARM introduced translation support for x86-64 after 10.0.21277. + || (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS && OperatingSystem.SYSTEM_BUILD_NUMBER >= 21277)) { + Controllers.dialog(i18n("launch.advice.vanilla_x86.translation"), i18n("message.error"), MessageType.ERROR, breakAction); + return null; + } + } + Controllers.dialog(i18n("launch.advice.vanilla_x86"), 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; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java index 63a6d5385..a787b8529 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -69,7 +69,7 @@ public class GameCrashWindow extends Stage { private final String memory; private final String java; private final LibraryAnalyzer analyzer; - private final StringProperty os = new SimpleStringProperty(System.getProperty("os.name")); + private final StringProperty os = new SimpleStringProperty(OperatingSystem.SYSTEM_NAME); private final StringProperty arch = new SimpleStringProperty(Architecture.CURRENT_ARCH_NAME); private final StringProperty reason = new SimpleStringProperty(i18n("game.crash.reason.unknown")); private final BooleanProperty loading = new SimpleBooleanProperty(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java index d78d5e3ed..6761dc561 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java @@ -113,7 +113,7 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler { "\n Content: \n " + stackTrace + "\n\n" + "-- System Details --\n" + - " Operating System: " + System.getProperty("os.name") + ' ' + OperatingSystem.SYSTEM_VERSION + "\n" + + " Operating System: " + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + "\n" + " Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n" + " Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n" + " JVM Max Memory: " + Runtime.getRuntime().maxMemory() + "\n" + diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 90eaf265a..ee74cb028 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -449,6 +449,8 @@ launch.advice.not_enough_space=You have allocated too much memory, because the p launch.advice.require_newer_java_version=Minecraft %1$s requires Java %2$s or later, are you willing to download one now? launch.advice.too_large_memory_for_32bit=You have allocated too much memory, because of your 32-Bit Java Runtime Environment, your game may crash. The maximum memory capacity for 32 bit systems is is 1024MB. Shall we continue launching? launch.advice.vanilla_linux_java_8=For Linux x86-64, Minecraft 1.12.2 and below can only run on Java 8.\nJava 9 and above versions cannot load 32-bit native libraries like liblwjgl.so. +launch.advice.vanilla_x86=Minecraft currently does not provide official support for architectures other than x86 and x86-64.\nYou can try to download the corresponding native library of the platform and specify its placement path. +launch.advice.vanilla_x86.translation=Minecraft currently does not provide official support for architectures other than x86 and x86-64.\nPlease use Java for x86-64 to run minecraft through translator, or download the corresponding native library of the platform and specify its placement path. launch.failed=Unable to launch launch.failed.cannot_create_jvm=Java virtual machine could not be created. Java arguments may cause issues. Please restart without JVM arguments. launch.failed.creating_process=Failed to create process. Check your Java path. diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 3542b4a37..df8fa3e11 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -449,6 +449,8 @@ launch.advice.not_enough_space=您設定的記憶體大小過大,由於超過 launch.advice.require_newer_java_version=Minecraft %1$s 僅能運行在 Java %2$s 或更高版本上,是否下載? launch.advice.too_large_memory_for_32bit=您設定的記憶體大小過大,由於可能超過了 32 位元 Java 的記憶體分配限制,所以可能無法啟動遊戲,請將記憶體調至低於 1024MB 的值。是否繼續啟動? launch.advice.vanilla_linux_java_8=對於 Linux x86-64 平台,Minecraft 1.12.2 及以下版本僅支持 Java 8。\nJava 9+ 版本會無法載入 32 位的 liblwjgl.so。 +launch.advice.vanilla_x86=Minecraft 官方尚未提供對非 x86-64 平臺的支持。\n您可以嘗試下載您所用平臺對應的本機庫,在遊戲設定的調試選項中指定其路徑後再嘗試運行。 +launch.advice.vanilla_x86.translation=Minecraft 官方尚未提供對非 x86-64 平臺的支持。\n請使用 x86-64 平臺的 Java 通過轉譯執行,或者嘗試下載您所用平臺對應的本機庫,在遊戲設定的調試選項中指定其路徑後再嘗試運行。 launch.failed=啟動失敗 launch.failed.cannot_create_jvm=偵測到無法建立 Java 虛擬機,可能是 Java 參數有問題。可以在設定中開啟無參數模式啟動。 launch.failed.creating_process=啟動失敗,在建立新處理程式時發生錯誤。可能是 Java 路徑錯誤。 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index ff73ca8c1..f1ab20bf7 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -448,7 +448,9 @@ launch.advice.newer_java=检测到您未使用 Java 8 及更新版本,Java 8 launch.advice.not_enough_space=您设置的内存大小过大,由于超过了系统内存大小 %dMB,所以可能影响游戏体验或无法启动游戏。是否继续启动? launch.advice.require_newer_java_version=Minecraft %1$s 仅能运行在 Java %2$s 或更高版本上,是否下载? launch.advice.too_large_memory_for_32bit=您设置的内存大小过大,由于可能超过了 32 位 Java 的内存分配限制,所以可能无法启动游戏,请将内存调至 1024MB 或更小。是否继续启动? -launch.advice.vanilla_linux_java_8=对于 Linux x86-64 平台,Minecraft 1.12.2 及以下版本仅支持 Java 8。\nJava 9+ 版本会无法加载 32 位的 liblwjgl.so。 +launch.advice.vanilla_linux_java_8=对于 Linux x86-64 平台,Minecraft 1.12.2 及以下版本仅支持 Java 8。\nJava 9+ 版本会无法加载 32 位的 liblwjgl.so。 +launch.advice.vanilla_x86=Minecraft 官方尚未提供对非 x86-64 平台的支持。\n您可以尝试下载您所用平台对应的本机库,在游戏设置的调试选项中指定其路径后再尝试运行。 +launch.advice.vanilla_x86.translation=Minecraft 官方尚未提供对非 x86-64 平台的支持。\n请使用 x86-64 平台的 Java 通过转译执行,或者尝试下载您所用平台对应的本机库,在游戏设置的调试选项中指定其路径后再尝试运行。 launch.failed=启动失败 launch.failed.cannot_create_jvm=截获到无法创建 Java 虚拟机,可能是 Java 参数有问题,可以在设置中开启无参数模式启动。 launch.failed.creating_process=启动失败,在创建新进程时发生错误,可能是 Java 路径错误。 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 fcb654467..d177ef0ce 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/JavaVersionConstraint.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/JavaVersionConstraint.java @@ -98,6 +98,21 @@ public enum JavaVersionConstraint { public boolean checkJava(VersionNumber gameVersionNumber, Version version, JavaVersion javaVersion) { return javaVersion.getArchitecture() != Architecture.X86_64 || super.checkJava(gameVersionNumber, version, javaVersion); } + }, + // Minecraft currently does not provide official support for architectures other than x86 and x86-64. + VANILLA_X86(JavaVersionConstraint.RULE_MANDATORY, versionRange(JavaVersionConstraint.MIN, JavaVersionConstraint.MAX), versionRange(JavaVersionConstraint.MIN, JavaVersionConstraint.MAX)) { + @Override + public boolean appliesToVersion(@Nullable VersionNumber gameVersionNumber, @Nullable Version version, + @Nullable JavaVersion javaVersion) { + return getGameVersionRange().contains(gameVersionNumber) + && Architecture.SYSTEM_ARCH != Architecture.X86 && Architecture.SYSTEM_ARCH != Architecture.X86_64 + && (javaVersion == null || (javaVersion.getArchitecture() != Architecture.X86 && javaVersion.getArchitecture() != Architecture.X86_64)); + } + + @Override + public boolean checkJava(VersionNumber gameVersionNumber, Version version, JavaVersion javaVersion) { + return javaVersion.getArchitecture() == Architecture.X86 || javaVersion.getArchitecture() == Architecture.X86_64; + } }; private final int type; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/OperatingSystem.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/OperatingSystem.java index f6ed724c8..dab7a9dc3 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/OperatingSystem.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/OperatingSystem.java @@ -17,8 +17,13 @@ */ package org.jackhuang.hmcl.util.platform; +import org.jackhuang.hmcl.util.versioning.VersionNumber; +import org.jetbrains.annotations.Nullable; + +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; @@ -26,6 +31,7 @@ import java.nio.file.Paths; import java.util.Arrays; import java.util.Locale; import java.util.Optional; +import java.util.OptionalInt; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -65,7 +71,7 @@ public enum OperatingSystem { /** * The current operating system. */ - public static final OperatingSystem CURRENT_OS; + public static final OperatingSystem CURRENT_OS = parseOSName(System.getProperty("os.name")); /** * The total memory/MB this computer have. @@ -86,19 +92,67 @@ public enum OperatingSystem { */ public static final String ENCODING = System.getProperty("sun.jnu.encoding", Charset.defaultCharset().name()); + /** + * Windows system build number. + * When the version number is not recognized or on another system, the value will be -1. + */ + public static final int SYSTEM_BUILD_NUMBER; + + /** + * The name of current operating system. + */ + public static final String SYSTEM_NAME; + /** * The version of current operating system. */ - public static final String SYSTEM_VERSION = System.getProperty("os.version"); + public static final String SYSTEM_VERSION; public static final Pattern INVALID_RESOURCE_CHARACTERS; private static final String[] INVALID_RESOURCE_BASENAMES; private static final String[] INVALID_RESOURCE_FULLNAMES; private static final Pattern MEMINFO_PATTERN = Pattern.compile("^(?.*?):\\s+(?\\d+) kB?$"); - + static { - CURRENT_OS = parseOSName(System.getProperty("os.name")); + if (CURRENT_OS == WINDOWS) { + String versionNumber = null; + int buildNumber = -1; + + try { + Process process = Runtime.getRuntime().exec(new String[]{"cmd", "ver"}); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + Matcher matcher = Pattern.compile("(?[0-9]+\\.[0-9]+\\.(?[0-9]+)(\\.[0-9]+)?)]$") + .matcher(reader.readLine().trim()); + + if (matcher.find()) { + versionNumber = matcher.group("version"); + buildNumber = Integer.parseInt(matcher.group("build")); + } + } + process.destroy(); + } catch (Throwable ignored) { + } + + if (versionNumber == null) { + versionNumber = System.getProperty("os.version"); + } + + String osName = System.getProperty("os.name"); + + // Java 17 or earlier recognizes Windows 11 as Windows 10 + if (osName.equals("Windows 10") && buildNumber >= 22000) { + osName = "Windows 11"; + } + + SYSTEM_NAME = osName; + SYSTEM_VERSION = versionNumber; + SYSTEM_BUILD_NUMBER = buildNumber; + } else { + SYSTEM_NAME = System.getProperty("os.name"); + SYSTEM_VERSION = System.getProperty("os.version"); + SYSTEM_BUILD_NUMBER = -1; + } TOTAL_MEMORY = getPhysicalMemoryStatus() .map(PhysicalMemoryStatus::getTotal) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Platform.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Platform.java index f2cba1441..3fc8b872d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Platform.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Platform.java @@ -4,13 +4,16 @@ import java.util.Objects; public final class Platform { public static final Platform UNKNOWN = new Platform(OperatingSystem.UNKNOWN, Architecture.UNKNOWN); - public static final Platform CURRENT_PLATFORM = new Platform(OperatingSystem.CURRENT_OS, Architecture.CURRENT_ARCH); - public static final Platform SYSTEM_PLATFORM = new Platform(OperatingSystem.CURRENT_OS, Architecture.SYSTEM_ARCH); public static final Platform WINDOWS_X86_64 = new Platform(OperatingSystem.WINDOWS, Architecture.X86_64); public static final Platform OSX_X86_64 = new Platform(OperatingSystem.OSX, Architecture.X86_64); public static final Platform LINUX_X86_64 = new Platform(OperatingSystem.LINUX, Architecture.X86_64); + public static final Platform OSX_ARM64 = new Platform(OperatingSystem.OSX, Architecture.ARM64); + + public static final Platform CURRENT_PLATFORM = Platform.getPlatform(OperatingSystem.CURRENT_OS, Architecture.CURRENT_ARCH); + public static final Platform SYSTEM_PLATFORM = Platform.getPlatform(OperatingSystem.CURRENT_OS, Architecture.SYSTEM_ARCH); + private final OperatingSystem os; private final Architecture arch; @@ -37,6 +40,8 @@ public final class Platform { case LINUX: return LINUX_X86_64; } + } else if (arch == Architecture.ARM64 && OperatingSystem.CURRENT_OS == OperatingSystem.OSX) { + return OSX_ARM64; } return new Platform(os, arch);