修复 Java 管理页面无法添加 IKVM 的问题 (#3968)

This commit is contained in:
Glavo 2025-06-08 09:45:23 +08:00 committed by GitHub
parent d9d32eab1d
commit d317844b28
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 124 additions and 110 deletions

View File

@ -41,6 +41,7 @@ dependencies {
implementation(project(":HMCLCore"))
implementation("libs:JFoenix")
implementation(libs.twelvemonkeys.imageio.webp)
implementation(libs.java.info)
if (launcherExe == null) {
implementation("org.glavo.hmcl:HMCLauncher:3.6.0.2")

View File

@ -168,7 +168,7 @@ public final class HMCLJavaRepository implements JavaRepository {
JavaInfo info;
if (JavaManager.isCompatible(platform))
info = JavaInfo.fromExecutable(executable, false);
info = JavaInfoUtils.fromExecutable(executable, false);
else
info = new JavaInfo(platform, result.download.getVersion().getName(), null);

View File

@ -0,0 +1,116 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.java;
import com.google.gson.annotations.SerializedName;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.JarUtils;
import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.Platform;
import org.jackhuang.hmcl.util.platform.SystemUtils;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* @author Glavo
* @see <a href="https://github.com/Glavo/java-info">Glavo/java-info</a>
*/
public final class JavaInfoUtils {
private JavaInfoUtils() {
}
private static Path tryFindReleaseFile(Path executable) {
Path parent = executable.getParent();
if (parent != null && parent.getFileName() != null && parent.getFileName().toString().equals("bin")) {
Path javaHome = parent.getParent();
if (javaHome != null && javaHome.getFileName() != null) {
Path releaseFile = javaHome.resolve("release");
String javaHomeName = javaHome.getFileName().toString();
if ((javaHomeName.contains("jre") || javaHomeName.contains("jdk") || javaHomeName.contains("openj9"))
&& Files.isRegularFile(releaseFile)) {
return releaseFile;
}
}
}
return null;
}
public static @NotNull JavaInfo fromExecutable(Path executable, boolean tryFindReleaseFile) throws IOException {
assert executable.isAbsolute();
Path releaseFile;
if (tryFindReleaseFile && (releaseFile = tryFindReleaseFile(executable)) != null) {
try {
return JavaInfo.fromReleaseFile(releaseFile);
} catch (IOException ignored) {
}
}
Path thisPath = JarUtils.thisJarPath();
if (thisPath == null) {
throw new IOException("Failed to find current HMCL location");
}
try {
Result result = JsonUtils.GSON.fromJson(SystemUtils.run(
executable.toString(),
"-classpath",
thisPath.toString(),
org.glavo.info.Main.class.getName()
), Result.class);
if (result == null) {
throw new IOException("Failed to get Java info from " + executable);
}
if (result.javaVersion == null) {
throw new IOException("Failed to get Java version from " + executable);
}
Architecture architecture = Architecture.parseArchName(result.osArch);
Platform platform = Platform.getPlatform(OperatingSystem.CURRENT_OS,
architecture != Architecture.UNKNOWN
? architecture
: Architecture.SYSTEM_ARCH);
return new JavaInfo(platform, result.javaVersion, result.javaVendor);
} catch (IOException e) {
throw e;
} catch (Throwable e) {
throw new IOException(e);
}
}
private static final class Result {
@SerializedName("os.name")
public String osName;
@SerializedName("os.arch")
public String osArch;
@SerializedName("java.version")
public String javaVersion;
@SerializedName("java.vendor")
public String javaVendor;
}
}

View File

@ -32,10 +32,7 @@ import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.util.CacheRepository;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.Platform;
import org.jackhuang.hmcl.util.platform.UnsupportedPlatformException;
import org.jackhuang.hmcl.util.platform.*;
import org.jackhuang.hmcl.util.platform.windows.WinReg;
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import org.jetbrains.annotations.Nullable;
@ -162,7 +159,7 @@ public final class JavaManager {
return javaRuntime;
}
JavaInfo info = JavaInfo.fromExecutable(executable);
JavaInfo info = JavaInfoUtils.fromExecutable(executable, true);
return JavaRuntime.of(executable, info, false);
}
@ -484,7 +481,7 @@ public final class JavaManager {
info = JavaInfo.fromReleaseFile(releaseFile);
} catch (IOException e) {
try {
info = JavaInfo.fromExecutable(executable, false);
info = JavaInfoUtils.fromExecutable(executable, false);
} catch (IOException e2) {
e2.addSuppressed(e);
LOG.warning("Failed to lookup Java executable at " + executable, e2);
@ -509,7 +506,7 @@ public final class JavaManager {
JavaInfo info = null;
try {
info = JavaInfo.fromExecutable(executable);
info = JavaInfoUtils.fromExecutable(executable, true);
} catch (IOException e) {
LOG.warning("Failed to lookup Java executable at " + executable, e);
}

View File

@ -136,108 +136,6 @@ public final class JavaInfo {
}
}
private static final String OS_ARCH = "os.arch = ";
private static final String JAVA_VERSION = "java.version = ";
private static final String JAVA_VENDOR = "java.vendor = ";
private static final String VERSION_PREFIX = "version \"";
public static JavaInfo fromExecutable(Path executable) throws IOException {
return fromExecutable(executable, true);
}
public static JavaInfo fromExecutable(Path executable, boolean tryFindReleaseFile) throws IOException {
assert executable.isAbsolute();
Path parent = executable.getParent();
if (tryFindReleaseFile && parent != null && parent.getFileName() != null && parent.getFileName().toString().equals("bin")) {
Path javaHome = parent.getParent();
if (javaHome != null && javaHome.getFileName() != null) {
Path releaseFile = javaHome.resolve("release");
String javaHomeName = javaHome.getFileName().toString();
if ((javaHomeName.contains("jre") || javaHomeName.contains("jdk") || javaHomeName.contains("openj9")) && Files.isRegularFile(releaseFile)) {
try {
return fromReleaseFile(releaseFile);
} catch (IOException ignored) {
}
}
}
}
String osArch = null;
String version = null;
String vendor = null;
Platform platform = null;
String executablePath = executable.toString();
Process process = new ProcessBuilder(executablePath, "-XshowSettings:properties", "-version").start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), OperatingSystem.NATIVE_CHARSET))) {
for (String line; (line = reader.readLine()) != null; ) {
int idx = line.indexOf(OS_ARCH);
if (idx >= 0) {
osArch = line.substring(idx + OS_ARCH.length()).trim();
if (version != null && vendor != null)
break;
else
continue;
}
idx = line.indexOf(JAVA_VERSION);
if (idx >= 0) {
version = line.substring(idx + JAVA_VERSION.length()).trim();
if (osArch != null && vendor != null)
break;
else
continue;
}
idx = line.indexOf(JAVA_VENDOR);
if (idx >= 0) {
vendor = line.substring(idx + JAVA_VENDOR.length()).trim();
if (osArch != null && version != null)
break;
else
//noinspection UnnecessaryContinue
continue;
}
}
}
if (osArch != null)
platform = Platform.getPlatform(OperatingSystem.CURRENT_OS, Architecture.parseArchName(osArch));
// Java 6
if (version == null) {
boolean is64Bit = false;
process = new ProcessBuilder(executablePath, "-version").start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), OperatingSystem.NATIVE_CHARSET))) {
for (String line; (line = reader.readLine()) != null; ) {
if (version == null) {
int idx = line.indexOf(VERSION_PREFIX);
if (idx >= 0) {
int begin = idx + VERSION_PREFIX.length();
int end = line.indexOf('"', begin);
if (end >= 0) {
version = line.substring(begin, end);
}
}
}
if (line.contains("64-Bit"))
is64Bit = true;
}
}
if (platform == null)
platform = Platform.getPlatform(OperatingSystem.CURRENT_OS, is64Bit ? Architecture.X86_64 : Architecture.X86);
if (version == null)
throw new IOException("Cannot determine version");
}
return new JavaInfo(platform, version, vendor);
}
public static final JavaInfo CURRENT_ENVIRONMENT = new JavaInfo(Platform.CURRENT_PLATFORM, System.getProperty("java.version"), System.getProperty("java.vendor"));
private final Platform platform;

View File

@ -14,6 +14,7 @@ chardet = "2.5.0"
twelvemonkeys = "3.12.0"
jna = "5.17.0"
pci-ids = "0.4.0"
java-info = "1.0"
# plugins
shadow = "8.3.6"
@ -36,6 +37,7 @@ twelvemonkeys-imageio-webp = { module = "com.twelvemonkeys.imageio:imageio-webp"
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" }
pci-ids = { module = "org.glavo:pci-ids", version.ref = "pci-ids" }
java-info = { module = "org.glavo:java-info", version.ref = "java-info" }
[plugins]
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }