Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion HMCL/src/main/java/org/jackhuang/hmcl/EntryPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.JarUtils;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.WineDetector;

import javax.swing.*;
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
Expand All @@ -46,9 +48,11 @@ public static void main(String[] args) {
System.getProperties().putIfAbsent("javafx.autoproxy.disable", "true");
System.getProperties().putIfAbsent("http.agent", "HMCL/" + Metadata.VERSION);

createHMCLDirectories();
LOG.start(Metadata.HMCL_CURRENT_DIRECTORY.resolve("logs"));

checkWine();

createHMCLDirectories();
setupJavaFXVMOptions();

if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS) {
Expand Down Expand Up @@ -223,6 +227,20 @@ private static void verifyJavaFX() {
}
}

private static void checkWine() {
if (WineDetector.IN_WINE) {
SwingUtils.initLookAndFeel();
LOG.warning("HMCL is running under Wine or its distributions!");

int result = JOptionPane.showOptionDialog(null, i18n("fatal.wine_warning"), i18n("message.warning"), JOptionPane.OK_CANCEL_OPTION,
JOptionPane.WARNING_MESSAGE, null, null, null);

if (result == JOptionPane.CANCEL_OPTION) {
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JOptionPane.showOptionDialog can return JOptionPane.CLOSED_OPTION when the user closes the window (X). Currently only CANCEL_OPTION exits, so closing the dialog will continue launching despite the warning. Handle CLOSED_OPTION the same as cancel (or explicitly document the intended behavior).

Suggested change
if (result == JOptionPane.CANCEL_OPTION) {
if (result == JOptionPane.CANCEL_OPTION || result == JOptionPane.CLOSED_OPTION) {

Copilot uses AI. Check for mistakes.
exit(1);
}
}
}

private static void addEnableNativeAccess() {
if (JavaRuntime.CURRENT_VERSION > 21) {
try {
Expand Down
1 change: 1 addition & 0 deletions HMCL/src/main/resources/assets/lang/I18N.properties
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ fatal.unsupported_platform.windows_arm64=Hello Minecraft! Launcher has provided
\n\
If you are using the <b>Qualcomm</b> platform, you may need to install the <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL Compatibility Pack</a> before playing games.\n\
Click the link to navigate to the Microsoft Store and install the compatibility pack.
fatal.wine_warning=HMCL is running under Wine or one of its distributions.\nAs a cross-platform application, HMCL is best experienced natively on your host OS.\nPress "OK" to continue, but please note that some issues may arise.

file=File

Expand Down
1 change: 1 addition & 0 deletions HMCL/src/main/resources/assets/lang/I18N_zh.properties
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ fatal.unsupported_platform=Minecraft 尚未對您的平臺提供完善支援,
fatal.unsupported_platform.loongarch=Hello Minecraft! Launcher 已為龍芯提供支援。\n如果遇到問題,你可以點擊右上角幫助按鈕進行求助。
fatal.unsupported_platform.macos_arm64=Hello Minecraft! Launcher 已為 Apple Silicon 平臺提供支援。使用 ARM 原生 Java 啟動遊戲以獲得更流暢的遊戲體驗。\n如果你在遊戲中遭遇問題,使用 x86-64 架構的 Java 啟動遊戲可能有更好的相容性。
fatal.unsupported_platform.windows_arm64=Hello Minecraft! Launcher 已為 Windows on Arm 平臺提供原生支援。如果你在遊戲中遭遇問題,請嘗試使用 x86 架構的 Java 啟動遊戲。\n\n如果你正在使用<b>高通</b>平臺,你可能需要安裝 <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL 相容包</a>後才能進行遊戲。點擊連結前往 Microsoft Store 安裝相容包。
fatal.wine_warning=HMCL is running under Wine or one of its distributions.\nAs a cross-platform application, HMCL is best experienced natively on your host OS.\nPress "OK" to continue, but please note that some issues may arise.\n\n您目前正在使用 Wine 或其衍生版本執行 HMCL。\nHMCL 是跨平臺的,我們建議您直接在主機系統上執行。\n按下「確定」以繼續,但請注意,此操作可能會引發一些問題。

file=檔案

Expand Down
1 change: 1 addition & 0 deletions HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ fatal.unsupported_platform=Minecraft 尚未对你的平台提供完善支持,
fatal.unsupported_platform.loongarch=Hello Minecraft! Launcher 已为龙芯提供支持。\n如果遇到问题,你可以点击右上角帮助按钮进行求助。
fatal.unsupported_platform.macos_arm64=Hello Minecraft! Launcher 已为 Apple Silicon 平台提供支持。使用 ARM 原生 Java 启动游戏以获得更流畅的游戏体验。\n如果你在游戏中遇到问题,使用 x86-64 架构的 Java 启动游戏可能有更好的兼容性。\n如遇到问题,你可以点击右上角帮助按钮进行求助。
fatal.unsupported_platform.windows_arm64=Hello Minecraft! Launcher 已为 Windows on Arm 平台提供原生支持。如果你在游戏中遇到问题,请尝试使用 x86 架构的 Java 启动游戏。\n如果你正在使用 <b>高通</b> 平台,你可能需要安装 <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL 兼容包</a> 后才能进行游戏。点击链接前往 Microsoft Store 安装兼容包。\n如遇到问题,你可以点击右上角帮助按钮进行求助。
fatal.wine_warning=HMCL is running under Wine or one of its distributions.\nAs a cross-platform application, HMCL is best experienced natively on your host OS.\nPress "OK" to continue, but please note that some issues may arise.\n\n您目前正在使用 Wine 或其发行版运行 HMCL。\nHMCL 是跨平台的,我们建议您直接在宿主系统上运行。\n按下“确定”以继续,但请注意,此操作可能会引发一些问题。

file=文件

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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.util.platform;

public final class WineDetector {
public static final boolean IN_WINE = isRunningUnderWine();

private static boolean isRunningUnderWine() {
if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS) {
return false;
}

return checkWineRegistryKey() && checkWineEnv();
}

private static boolean checkWineRegistryKey() {
Process process = null;
try {
process = Runtime.getRuntime().exec(
new String[]{"reg", "query", "HKLM\\Software\\Wine"}
);
if (!process.waitFor(800, java.util.concurrent.TimeUnit.MILLISECONDS)) {
process.destroyForcibly();
return false;
}
return process.exitValue() == 0;
Comment on lines +35 to +42
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wine detection spawns an external reg process and relies on PATH resolution. This is brittle (can hang/slow startup, and can be affected by PATH/app-dir hijacking). Since the codebase already has WinReg JNA access, prefer querying Software\\Wine directly via WinReg (and close/consume any process streams if a process-based approach is kept) to avoid startup and security issues.

Copilot uses AI. Check for mistakes.
} catch (Exception e) {
return false;
} finally {
if (process != null && process.isAlive()) {
process.destroyForcibly();
}
}
}

private static boolean checkWineEnv() {
return System.getenv("WINEPREFIX") != null;
Comment on lines +29 to +53
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isRunningUnderWine() requires both the registry key check and WINEPREFIX to be present. WINEPREFIX is not set in many Wine launches (default prefix), so this will often return false even when running under Wine. Consider loosening the detection (e.g., registry key OR one of several common Wine env vars, and/or checking both HKLM and HKCU) so the warning actually triggers in typical Wine environments.

Suggested change
return checkWineRegistryKey() && checkWineEnv();
}
private static boolean checkWineRegistryKey() {
Process process = null;
try {
process = Runtime.getRuntime().exec(
new String[]{"reg", "query", "HKLM\\Software\\Wine"}
);
if (!process.waitFor(800, java.util.concurrent.TimeUnit.MILLISECONDS)) {
process.destroyForcibly();
return false;
}
return process.exitValue() == 0;
} catch (Exception e) {
return false;
} finally {
if (process != null && process.isAlive()) {
process.destroyForcibly();
}
}
}
private static boolean checkWineEnv() {
return System.getenv("WINEPREFIX") != null;
// Detect Wine if either the registry indicates Wine or common Wine env vars are present.
return checkWineRegistryKey() || checkWineEnv();
}
private static boolean checkWineRegistryKey() {
// Check both machine-wide and per-user Wine registry keys.
String[] keysToCheck = {
"HKLM\\Software\\Wine",
"HKCU\\Software\\Wine"
};
for (String key : keysToCheck) {
Process process = null;
try {
process = Runtime.getRuntime().exec(
new String[]{"reg", "query", key}
);
if (!process.waitFor(800, java.util.concurrent.TimeUnit.MILLISECONDS)) {
process.destroyForcibly();
continue;
}
if (process.exitValue() == 0) {
return true;
}
} catch (Exception e) {
// Ignore and fall through to try the next key.
} finally {
if (process != null && process.isAlive()) {
process.destroyForcibly();
}
}
}
return false;
}
private static boolean checkWineEnv() {
// Check a set of common environment variables that are typically set under Wine.
String[] wineEnvVars = {
"WINEPREFIX",
"WINELOADER",
"WINEDEBUG",
"WINEDLLPATH"
};
for (String var : wineEnvVars) {
if (System.getenv(var) != null) {
return true;
}
}
return false;

Copilot uses AI. Check for mistakes.
}

private WineDetector() {
}
}