From 5be81d63c20e81009d60bf25fe5a33f8f69e4009 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Sun, 18 Jan 2026 15:59:54 +0800 Subject: [PATCH 01/22] Prompt user to switch working directory if unexpected content found Added a confirmation dialog when unexpected folders (resourcepacks, saves, mods, shaderpacks, crash-report) are detected in the version root, prompting the user to switch to 'Isolated' mode. Updated I18N.properties with new dialog strings for this feature. --- .../hmcl/game/HMCLGameRepository.java | 18 ++++++++++++++++++ .../main/resources/assets/lang/I18N.properties | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index f77a236a42..707c6042ed 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -20,6 +20,10 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonBar; +import javafx.scene.control.ButtonType; import javafx.scene.image.Image; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.download.LibraryAnalyzer; @@ -45,6 +49,7 @@ import org.jackhuang.hmcl.util.versioning.VersionNumber; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.InvalidPathException; @@ -56,6 +61,7 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.util.Pair.pair; +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.logging.Logger.LOG; public final class HMCLGameRepository extends DefaultGameRepository { @@ -91,6 +97,18 @@ public Path getRunDirectory(String id) { case VERSION_FOLDER: return getVersionRoot(id); case ROOT_FOLDER: + if (Files.exists(Path.of(getVersionRoot(id).toString() + File.separator + "resourcepacks")) || + Files.exists(Path.of(getVersionRoot(id).toString() + File.separator + "saves")) || + Files.exists(Path.of(getVersionRoot(id).toString() + File.separator + "mods")) || + Files.exists(Path.of(getVersionRoot(id).toString() + File.separator + "shaderpacks")) || + Files.exists(Path.of(getVersionRoot(id).toString() + File.separator + "crash-report")) + ) { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION, + i18n("launcher.info.switch_working_directory.content"), + ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) + ); + alert.showAndWait().orElse(null); + } return super.getRunDirectory(id); case CUSTOM: try { diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index e34ee60f2d..162e710230 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -376,6 +376,8 @@ download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s +Dialog.this_launch_only.button=This Launch only + exception.access_denied=HMCL is unable to access the file "%s". It may be locked by another process.\n\ \n\ For Windows users, you can open "Resource Monitor" to check if another process is currently using it. If so, you can try again after terminating that process.\n\ @@ -827,6 +829,7 @@ launch.state.modpack=Downloading required files launch.state.waiting_launching=Waiting for the game to launch launch.invalid_java=Invalid Java path. Please reset the Java path. + launcher=Launcher launcher.agreement=ToS and EULA launcher.agreement.accept=Accept @@ -850,6 +853,9 @@ launcher.crash=Hello Minecraft! Launcher has encountered a fatal error! Please c launcher.crash.java_internal_error=Hello Minecraft! Launcher has encountered a fatal error because your Java is corrupted. Please uninstall your Java and download a suitable Java here. launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher has encountered a fatal error! Your launcher is outdated. Please update your launcher! launcher.update_java=Please update your Java version. +launcher.info.switch_working_directory.title=Would you like to switch the Working Directory? +# %1$s = .minecraft Directory (Don't ends with java.io.File.separator), %2$s = java.io.File.separator, %3$s = version root (Don't ends with java.io.File.separator) +launcher.info.switch_working_directory.content=We detected unexpected content in %1$s%2$sversions%2$s%3$s. It's likely you selected "Isolated" mode, but it was switched to "Default" mode automatically or manually. The choice to readjust to "Isolated" mode is available to you.\nRe-adjust to 'Isolated' mode and make it effective for this launch, press "Yes". if you want to retain current version settings, press "No". if you want make it effective for this launch only, press "This launch only". libraries.download=Downloading Libraries From 92ea64ef98a9962a35d8c137625aeb52b6dbb341 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Sun, 18 Jan 2026 16:20:07 +0800 Subject: [PATCH 02/22] Refactor path construction in ROOT_FOLDER check Replaces manual string concatenation with Path.of() using varargs for directory checks in the ROOT_FOLDER case, improving code readability and reliability. --- .../org/jackhuang/hmcl/game/HMCLGameRepository.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index 707c6042ed..d4d82a402d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -97,11 +97,11 @@ public Path getRunDirectory(String id) { case VERSION_FOLDER: return getVersionRoot(id); case ROOT_FOLDER: - if (Files.exists(Path.of(getVersionRoot(id).toString() + File.separator + "resourcepacks")) || - Files.exists(Path.of(getVersionRoot(id).toString() + File.separator + "saves")) || - Files.exists(Path.of(getVersionRoot(id).toString() + File.separator + "mods")) || - Files.exists(Path.of(getVersionRoot(id).toString() + File.separator + "shaderpacks")) || - Files.exists(Path.of(getVersionRoot(id).toString() + File.separator + "crash-report")) + if (Files.exists(Path.of(getVersionRoot(id).toString(), "resourcepacks")) || + Files.exists(Path.of(getVersionRoot(id).toString(), "saves")) || + Files.exists(Path.of(getVersionRoot(id).toString(), "mods")) || + Files.exists(Path.of(getVersionRoot(id).toString(), "shaderpacks")) || + Files.exists(Path.of(getVersionRoot(id).toString(), "crash-report")) ) { Alert alert = new Alert(Alert.AlertType.CONFIRMATION, i18n("launcher.info.switch_working_directory.content"), From 00bf5a26d8a1d1ef8ccbb67486443447e637eff3 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Sun, 18 Jan 2026 18:13:06 +0800 Subject: [PATCH 03/22] Handle user response in working directory switch alert Added logic to process the user's selection from the working directory switch alert dialog, updating the game directory type or returning the appropriate directory based on the chosen button. --- .../jackhuang/hmcl/game/HMCLGameRepository.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index d4d82a402d..a0cc267831 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -107,7 +107,19 @@ public Path getRunDirectory(String id) { i18n("launcher.info.switch_working_directory.content"), ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) ); - alert.showAndWait().orElse(null); + alert.setTitle(i18n("launcher.info.switch_working_directory.title")); + switch (alert.showAndWait().orElse(ButtonType.YES).getButtonData()){ + case YES -> { + getVersionSetting(id).setGameDirType(GameDirectoryType.VERSION_FOLDER); + return getVersionRoot(id); + } + case NO -> { + return super.getRunDirectory(id); + } + case APPLY -> { + return getVersionRoot(id); + } + } } return super.getRunDirectory(id); case CUSTOM: From a4e66d7f58eff43e9c96b7e1a8df240d56782516 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Mon, 19 Jan 2026 10:47:25 +0800 Subject: [PATCH 04/22] =?UTF-8?q?fix(ui):=20=E4=BF=AE=E5=A4=8DAlert?= =?UTF-8?q?=E5=9C=A8=E9=9D=9EJavaFX=E7=BA=BF=E7=A8=8B=E4=B8=AD=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E7=BA=BF=E7=A8=8B=E5=AE=89=E5=85=A8=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 问题描述 在后台线程中直接调用JavaFX的Alert组件会导致`IllegalStateException: Not on FX application thread`异常,影响程序稳定性。 ## 修改内容 - 将原有的直接Alert调用包装在`Platform.runLater()`中,确保UI操作在JavaFX应用程序线程执行 - 使用`CompletableFuture`在JavaFX线程和非JavaFX线程之间传递用户选择结果 - 保持原有的业务逻辑和对话框选项不变 - 添加异常处理,在对话框异常时使用默认值继续执行 ## 技术细节 1. 创建`CompletableFuture`用于接收用户选择 2. 在`Platform.runLater()`中: - 创建Confirmation类型的Alert对话框 - 设置三个按钮选项:是、否、仅本次启动 - 使用`showAndWait()`等待用户响应 - 将用户选择的按钮数据传递给CompletableFuture 3. 在后台线程中使用`future.get()`阻塞等待用户选择 4. 根据按钮数据执行相应的目录设置逻辑 ## 影响范围 - 修复启动器在非JavaFX线程中询问工作目录切换的问题 - 确保线程安全的同时保持原有功能不变 - 提升程序在多线程环境下的稳定性 ## 测试要点 ✅ 在后台线程中调用此代码段能正常显示对话框 ✅ 对话框的三个按钮功能与之前一致 ✅ 异常情况下能使用默认值继续执行 ✅ 不会出现线程阻塞或死锁问题 ## 关联问题 修复了在多线程环境下可能导致的UI崩溃问题 --- .../hmcl/game/HMCLGameRepository.java | 57 ++++++++++++++----- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index a0cc267831..2200eac58c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -56,6 +56,8 @@ import java.nio.file.Path; import java.time.Instant; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -103,21 +105,50 @@ public Path getRunDirectory(String id) { Files.exists(Path.of(getVersionRoot(id).toString(), "shaderpacks")) || Files.exists(Path.of(getVersionRoot(id).toString(), "crash-report")) ) { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION, - i18n("launcher.info.switch_working_directory.content"), - ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) - ); - alert.setTitle(i18n("launcher.info.switch_working_directory.title")); - switch (alert.showAndWait().orElse(ButtonType.YES).getButtonData()){ - case YES -> { - getVersionSetting(id).setGameDirType(GameDirectoryType.VERSION_FOLDER); - return getVersionRoot(id); + if (Platform.isFxApplicationThread()) { + // 在JavaFX线程中直接使用原代码 + Alert alert = new Alert(Alert.AlertType.CONFIRMATION, + i18n("launcher.info.switch_working_directory.content"), + ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) + ); + alert.setTitle(i18n("launcher.info.switch_working_directory.title")); + switch (alert.showAndWait().orElse(ButtonType.YES).getButtonData()) { + case YES -> { + getVersionSetting(id).setGameDirType(GameDirectoryType.VERSION_FOLDER); + return getVersionRoot(id); + } + case NO -> super.getRunDirectory(id); + case APPLY -> getVersionRoot(id); + default -> super.getRunDirectory(id); } - case NO -> { - return super.getRunDirectory(id); + } else { + // 在非JavaFX线程中使用上面的代码 + CompletableFuture buttonDataFuture = new CompletableFuture<>(); + + Platform.runLater(() -> { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION, + i18n("launcher.info.switch_working_directory.content"), + ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) + ); + alert.setTitle(i18n("launcher.info.switch_working_directory.title")); + buttonDataFuture.complete(alert.showAndWait().orElse(ButtonType.YES).getButtonData()); + }); + + ButtonBar.ButtonData result; + try { + result = buttonDataFuture.get(); + } catch (InterruptedException | ExecutionException e) { + result = ButtonBar.ButtonData.YES; } - case APPLY -> { - return getVersionRoot(id); + + switch (result) { + case YES -> { + getVersionSetting(id).setGameDirType(GameDirectoryType.VERSION_FOLDER); + return getVersionRoot(id); + } + case NO -> super.getRunDirectory(id); + case APPLY -> getVersionRoot(id); + default -> super.getRunDirectory(id); } } } From 37a03fcc0d6c2cf7142da584c457163c1d1dacab Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Mon, 19 Jan 2026 10:51:16 +0800 Subject: [PATCH 05/22] =?UTF-8?q?fix(JavaDoc):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BA=86=E4=B8=80=E4=BA=9B=E6=96=87=E6=A1=A3=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=E9=94=99=E8=AF=AF=E5=92=8C=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=BA=94=E5=BD=93=E4=BF=9D=E6=8C=81=E5=A4=A7?= =?UTF-8?q?=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index 2200eac58c..6328b536a7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -262,7 +262,7 @@ private void loadLocalVersionSetting(String id) { VersionSetting versionSetting = JsonUtils.fromJsonFile(file, VersionSetting.class); initLocalVersionSetting(id, versionSetting); } catch (Exception ex) { - // If [JsonParseException], [IOException] or [NullPointerException] happens, the json file is malformed and needed to be recreated. + // If [JsonParseException], [IOException] or [NullPointerException] happens, the JSON file is malformed and needed to be recreated. initLocalVersionSetting(id, new VersionSetting()); } } @@ -292,7 +292,7 @@ private VersionSetting initLocalVersionSetting(String id, VersionSetting vs) { * Get the version setting for version id. * * @param id version id - * @return corresponding version setting, null if the version has no its own version setting. + * @return corresponding version setting, null if the version does not have its own version setting. */ @Nullable public VersionSetting getLocalVersionSetting(String id) { From bcd4a87054151cdb15848139e895fe3708b1ffc1 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Mon, 19 Jan 2026 16:04:36 +0800 Subject: [PATCH 06/22] Moved "Switch Working Directory". --- .../jackhuang/hmcl/game/HMCLGameLauncher.java | 71 ++++++++++++++++++- .../hmcl/game/HMCLGameRepository.java | 65 +---------------- .../resources/assets/lang/I18N.properties | 4 +- 3 files changed, 74 insertions(+), 66 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java index 434b739b6f..6ae7f9676f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java @@ -17,6 +17,10 @@ */ package org.jackhuang.hmcl.game; +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonBar; +import javafx.scene.control.ButtonType; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.auth.AuthInfo; import org.jackhuang.hmcl.launch.DefaultLauncher; @@ -26,12 +30,16 @@ import org.jackhuang.hmcl.util.platform.ManagedProcess; import org.jackhuang.hmcl.util.versioning.GameVersionNumber; +import java.io.File; import java.io.IOException; import java.nio.file.*; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.stream.Stream; import static org.jackhuang.hmcl.setting.ConfigHolder.config; +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.logging.Logger.LOG; /** @@ -62,8 +70,19 @@ protected Map getConfigurations() { private void generateOptionsTxt() { if (config().isDisableAutoGameOptions()) return; - Path runDir = repository.getRunDirectory(version.getId()); + if (repository instanceof HMCLGameRepository HMCLRepository) { + if (HMCLRepository.getVersionSetting(version.getId()).getGameDirType() == GameDirectoryType.ROOT_FOLDER) { + if (Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "resourcepacks")) || + Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "saves")) || + Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "mods")) || + Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "shaderpacks")) || + Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "crash-report")) + ) { + runDir = switchWorkingDirectory(HMCLRepository, version); + + } + } Path optionsFile = runDir.resolve("options.txt"); Path configFolder = runDir.resolve("config"); @@ -107,6 +126,56 @@ private void generateOptionsTxt() { } } + private Path switchWorkingDirectory(HMCLGameRepository HMCLRepository, Version version) { + if (Platform.isFxApplicationThread()) { + // 在JavaFX线程中直接使用原代码 + Alert alert = new Alert(Alert.AlertType.CONFIRMATION, + String.format(i18n("launcher.info.switch_working_directory.content"), File.separatorChar, version.getId()), + ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) + ); + alert.setTitle(i18n("launcher.info.switch_working_directory.title")); + switch (alert.showAndWait().orElse(ButtonType.YES).getButtonData()) { + case YES -> { + HMCLRepository.getVersionSetting(version.getId()).setGameDirType(GameDirectoryType.VERSION_FOLDER); + return HMCLRepository.getVersionRoot(version.getId()); + } + case NO -> {return HMCLRepository.getBaseDirectory();} + case APPLY -> HMCLRepository.getVersionRoot(version.getId()); + default -> {return HMCLRepository.getBaseDirectory();} + } + } else { + // 在非JavaFX线程中使用上面的代码 + CompletableFuture buttonDataFuture = new CompletableFuture<>(); + + Platform.runLater(() -> { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION, + String.format(i18n("launcher.info.switch_working_directory.content"), File.separatorChar, version.getId()), + ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) + ); + alert.setTitle(i18n("launcher.info.switch_working_directory.title")); + buttonDataFuture.complete(alert.showAndWait().orElse(ButtonType.YES).getButtonData()); + }); + + ButtonBar.ButtonData result; + try { + result = buttonDataFuture.get(); + } catch (InterruptedException | ExecutionException e) { + result = ButtonBar.ButtonData.YES; + } + + switch (result) { + case YES -> { + HMCLRepository.getVersionSetting(version.getId()).setGameDirType(GameDirectoryType.VERSION_FOLDER); + return HMCLRepository.getVersionRoot(version.getId()); + } + case NO -> {return HMCLRepository.getBaseDirectory();} + case APPLY -> HMCLRepository.getVersionRoot(version.getId()); + default -> {return HMCLRepository.getBaseDirectory();} + } + } + return HMCLRepository.getVersionRoot(version.getId()); + } + private static String normalizedLanguageTag(Locale locale, GameVersionNumber gameVersion) { String region = locale.getCountry(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index 6328b536a7..cbe66a4607 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -20,10 +20,6 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; -import javafx.application.Platform; -import javafx.scene.control.Alert; -import javafx.scene.control.ButtonBar; -import javafx.scene.control.ButtonType; import javafx.scene.image.Image; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.download.LibraryAnalyzer; @@ -49,21 +45,17 @@ import org.jackhuang.hmcl.util.versioning.VersionNumber; import org.jetbrains.annotations.Nullable; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.time.Instant; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.stream.Stream; import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.util.Pair.pair; -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.logging.Logger.LOG; public final class HMCLGameRepository extends DefaultGameRepository { @@ -92,71 +84,18 @@ public GameDirectoryType getGameDirectoryType(String id) { return getVersionSetting(id).getGameDirType(); } } - @Override public Path getRunDirectory(String id) { switch (getGameDirectoryType(id)) { case VERSION_FOLDER: return getVersionRoot(id); case ROOT_FOLDER: - if (Files.exists(Path.of(getVersionRoot(id).toString(), "resourcepacks")) || - Files.exists(Path.of(getVersionRoot(id).toString(), "saves")) || - Files.exists(Path.of(getVersionRoot(id).toString(), "mods")) || - Files.exists(Path.of(getVersionRoot(id).toString(), "shaderpacks")) || - Files.exists(Path.of(getVersionRoot(id).toString(), "crash-report")) - ) { - if (Platform.isFxApplicationThread()) { - // 在JavaFX线程中直接使用原代码 - Alert alert = new Alert(Alert.AlertType.CONFIRMATION, - i18n("launcher.info.switch_working_directory.content"), - ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) - ); - alert.setTitle(i18n("launcher.info.switch_working_directory.title")); - switch (alert.showAndWait().orElse(ButtonType.YES).getButtonData()) { - case YES -> { - getVersionSetting(id).setGameDirType(GameDirectoryType.VERSION_FOLDER); - return getVersionRoot(id); - } - case NO -> super.getRunDirectory(id); - case APPLY -> getVersionRoot(id); - default -> super.getRunDirectory(id); - } - } else { - // 在非JavaFX线程中使用上面的代码 - CompletableFuture buttonDataFuture = new CompletableFuture<>(); - - Platform.runLater(() -> { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION, - i18n("launcher.info.switch_working_directory.content"), - ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) - ); - alert.setTitle(i18n("launcher.info.switch_working_directory.title")); - buttonDataFuture.complete(alert.showAndWait().orElse(ButtonType.YES).getButtonData()); - }); - - ButtonBar.ButtonData result; - try { - result = buttonDataFuture.get(); - } catch (InterruptedException | ExecutionException e) { - result = ButtonBar.ButtonData.YES; - } - - switch (result) { - case YES -> { - getVersionSetting(id).setGameDirType(GameDirectoryType.VERSION_FOLDER); - return getVersionRoot(id); - } - case NO -> super.getRunDirectory(id); - case APPLY -> getVersionRoot(id); - default -> super.getRunDirectory(id); - } - } - } - return super.getRunDirectory(id); + return getBaseDirectory(); case CUSTOM: try { return Path.of(getVersionSetting(id).getGameDir()); } catch (InvalidPathException ignored) { + getBaseDirectory(); return getVersionRoot(id); } default: diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 162e710230..8fabe5f89b 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -854,8 +854,8 @@ launcher.crash.java_internal_error=Hello Minecraft! Launcher has encountered a f launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher has encountered a fatal error! Your launcher is outdated. Please update your launcher! launcher.update_java=Please update your Java version. launcher.info.switch_working_directory.title=Would you like to switch the Working Directory? -# %1$s = .minecraft Directory (Don't ends with java.io.File.separator), %2$s = java.io.File.separator, %3$s = version root (Don't ends with java.io.File.separator) -launcher.info.switch_working_directory.content=We detected unexpected content in %1$s%2$sversions%2$s%3$s. It's likely you selected "Isolated" mode, but it was switched to "Default" mode automatically or manually. The choice to readjust to "Isolated" mode is available to you.\nRe-adjust to 'Isolated' mode and make it effective for this launch, press "Yes". if you want to retain current version settings, press "No". if you want make it effective for this launch only, press "This launch only". +# %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) +launcher.info.switch_working_directory.content=We detected unexpected content in .minecraft%1$sversions%1$s%2$s. It's likely you selected "Isolated" mode, but it was switched to "Default" mode automatically or manually. The choice to readjust to "Isolated" mode is available to you.\nRe-adjust to 'Isolated' mode and make it effective for this launch, press "Yes". if you want to retain current version settings, press "No". if you want make it effective for this launch only, press "This launch only". libraries.download=Downloading Libraries From e238c117aaed294517252494310aa53df0153f28 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Mon, 19 Jan 2026 16:15:14 +0800 Subject: [PATCH 07/22] =?UTF-8?q?fix(bug)=EF=BC=9A=E5=A1=AB=E8=A1=A5?= =?UTF-8?q?=E4=BA=86=E6=9C=AA=E5=A1=AB=E5=85=85=E7=9A=84=E5=A4=A7=E6=8B=AC?= =?UTF-8?q?=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jackhuang/hmcl/game/HMCLGameLauncher.java | 77 ++++++++++--------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java index 6ae7f9676f..2445291d9d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java @@ -29,6 +29,7 @@ import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.ManagedProcess; import org.jackhuang.hmcl.util.versioning.GameVersionNumber; +import org.jackhuang.hmcl.game.HMCLGameRepository; import java.io.File; import java.io.IOException; @@ -80,53 +81,53 @@ private void generateOptionsTxt() { Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "crash-report")) ) { runDir = switchWorkingDirectory(HMCLRepository, version); - + } } - } - Path optionsFile = runDir.resolve("options.txt"); - Path configFolder = runDir.resolve("config"); - - if (Files.exists(optionsFile)) - return; - - if (Files.isDirectory(configFolder)) { - try (Stream stream = Files.walk(configFolder, 2, FileVisitOption.FOLLOW_LINKS)) { - if (stream.anyMatch(file -> "options.txt".equals(FileUtils.getName(file)))) - return; - } catch (IOException e) { - LOG.warning("Failed to visit config folder", e); + Path optionsFile = runDir.resolve("options.txt"); + Path configFolder = runDir.resolve("config"); + + if (Files.exists(optionsFile)) + return; + + if (Files.isDirectory(configFolder)) { + try (Stream stream = Files.walk(configFolder, 2, FileVisitOption.FOLLOW_LINKS)) { + if (stream.anyMatch(file -> "options.txt".equals(FileUtils.getName(file)))) + return; + } catch (IOException e) { + LOG.warning("Failed to visit config folder", e); + } } - } - Locale locale = Locale.getDefault(); - - /* - * 1.0 : No language option, do not set for these versions - * 1.1 ~ 1.5 : zh_CN works fine, zh_cn will crash (the last two letters must be uppercase, otherwise it will cause an NPE crash) - * 1.6 ~ 1.10 : zh_CN works fine, zh_cn will automatically switch to English - * 1.11 ~ 1.12 : zh_cn works fine, zh_CN will display Chinese but the language setting will incorrectly show English as selected - * 1.13+ : zh_cn works fine, zh_CN will automatically switch to English - */ - GameVersionNumber gameVersion = GameVersionNumber.asGameVersion(repository.getGameVersion(version)); - if (gameVersion.compareTo("1.1") < 0) - return; + Locale locale = Locale.getDefault(); - String lang = normalizedLanguageTag(locale, gameVersion); - if (lang.isEmpty()) - return; + /* + * 1.0 : No language option, do not set for these versions + * 1.1 ~ 1.5 : zh_CN works fine, zh_cn will crash (the last two letters must be uppercase, otherwise it will cause an NPE crash) + * 1.6 ~ 1.10 : zh_CN works fine, zh_cn will automatically switch to English + * 1.11 ~ 1.12 : zh_cn works fine, zh_CN will display Chinese but the language setting will incorrectly show English as selected + * 1.13+ : zh_cn works fine, zh_CN will automatically switch to English + */ + GameVersionNumber gameVersion = GameVersionNumber.asGameVersion(repository.getGameVersion(version)); + if (gameVersion.compareTo("1.1") < 0) + return; + + String lang = normalizedLanguageTag(locale, gameVersion); + if (lang.isEmpty()) + return; - if (gameVersion.compareTo("1.11") >= 0) - lang = lang.toLowerCase(Locale.ROOT); + if (gameVersion.compareTo("1.11") >= 0) + lang = lang.toLowerCase(Locale.ROOT); - try { - Files.createDirectories(optionsFile.getParent()); - Files.writeString(optionsFile, String.format("lang:%s\n", lang)); - } catch (IOException e) { - LOG.warning("Unable to generate options.txt", e); + try { + Files.createDirectories(optionsFile.getParent()); + Files.writeString(optionsFile, String.format("lang:%s\n", lang)); + } catch (IOException e) { + LOG.warning("Unable to generate options.txt", e); + } } } - private Path switchWorkingDirectory(HMCLGameRepository HMCLRepository, Version version) { + protected Path switchWorkingDirectory(HMCLGameRepository HMCLRepository, Version version) { if (Platform.isFxApplicationThread()) { // 在JavaFX线程中直接使用原代码 Alert alert = new Alert(Alert.AlertType.CONFIRMATION, From f0329a38b91b954017d6bdcf57770cb4e70d5bdc Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Mon, 19 Jan 2026 17:32:28 +0800 Subject: [PATCH 08/22] =?UTF-8?q?fix=EF=BC=9A=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/jackhuang/hmcl/game/HMCLGameLauncher.java | 8 ++++---- .../java/org/jackhuang/hmcl/game/HMCLGameRepository.java | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java index 2445291d9d..9610b9ff5f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java @@ -140,9 +140,9 @@ ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.butt HMCLRepository.getVersionSetting(version.getId()).setGameDirType(GameDirectoryType.VERSION_FOLDER); return HMCLRepository.getVersionRoot(version.getId()); } - case NO -> {return HMCLRepository.getBaseDirectory();} + case NO -> { return HMCLRepository.getBaseDirectory(); } case APPLY -> HMCLRepository.getVersionRoot(version.getId()); - default -> {return HMCLRepository.getBaseDirectory();} + default -> { return HMCLRepository.getBaseDirectory(); } } } else { // 在非JavaFX线程中使用上面的代码 @@ -169,9 +169,9 @@ ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.butt HMCLRepository.getVersionSetting(version.getId()).setGameDirType(GameDirectoryType.VERSION_FOLDER); return HMCLRepository.getVersionRoot(version.getId()); } - case NO -> {return HMCLRepository.getBaseDirectory();} + case NO -> { return HMCLRepository.getBaseDirectory(); } case APPLY -> HMCLRepository.getVersionRoot(version.getId()); - default -> {return HMCLRepository.getBaseDirectory();} + default -> { return HMCLRepository.getBaseDirectory(); } } } return HMCLRepository.getVersionRoot(version.getId()); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index cbe66a4607..0e9b876633 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -84,6 +84,7 @@ public GameDirectoryType getGameDirectoryType(String id) { return getVersionSetting(id).getGameDirType(); } } + @Override public Path getRunDirectory(String id) { switch (getGameDirectoryType(id)) { From 5becbaf737d28a00575c56a3fc9a6341aedec415 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Mon, 19 Jan 2026 17:39:34 +0800 Subject: [PATCH 09/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E9=A2=9D?= =?UTF-8?q?=E5=A4=96=E5=AF=BC=E5=85=A5=E7=9A=84=E5=90=8C=E5=8C=85=E4=B8=8B?= =?UTF-8?q?=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java | 1 - .../main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java index 9610b9ff5f..e442da0beb 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java @@ -29,7 +29,6 @@ import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.ManagedProcess; import org.jackhuang.hmcl.util.versioning.GameVersionNumber; -import org.jackhuang.hmcl.game.HMCLGameRepository; import java.io.File; import java.io.IOException; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index 0e9b876633..99b10456a3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -84,7 +84,7 @@ public GameDirectoryType getGameDirectoryType(String id) { return getVersionSetting(id).getGameDirType(); } } - + @Override public Path getRunDirectory(String id) { switch (getGameDirectoryType(id)) { From 612aa8f0cf033b84e8152893003f85a330862992 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Mon, 19 Jan 2026 19:13:55 +0800 Subject: [PATCH 10/22] =?UTF-8?q?fix=EF=BC=9A=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E6=9C=AC=E4=BA=BA=E5=8F=91=E7=8E=B0=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E5=8F=8APR#5260=E6=89=80=E6=8F=90=E5=88=B0=E7=9A=84=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E6=89=B9=E5=88=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jackhuang/hmcl/game/HMCLGameLauncher.java | 82 +++++++++---------- .../hmcl/game/HMCLGameRepository.java | 3 +- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java index e442da0beb..7df51fb99c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java @@ -25,6 +25,7 @@ import org.jackhuang.hmcl.auth.AuthInfo; import org.jackhuang.hmcl.launch.DefaultLauncher; import org.jackhuang.hmcl.launch.ProcessListener; +import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.util.i18n.LocaleUtils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.ManagedProcess; @@ -71,64 +72,62 @@ private void generateOptionsTxt() { if (config().isDisableAutoGameOptions()) return; Path runDir = repository.getRunDirectory(version.getId()); - if (repository instanceof HMCLGameRepository HMCLRepository) { - if (HMCLRepository.getVersionSetting(version.getId()).getGameDirType() == GameDirectoryType.ROOT_FOLDER) { - if (Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "resourcepacks")) || - Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "saves")) || - Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "mods")) || - Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "shaderpacks")) || - Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "crash-report")) - ) { - runDir = switchWorkingDirectory(HMCLRepository, version); - } + HMCLGameRepository HMCLRepository = (HMCLGameRepository) repository; + if (HMCLRepository.getGameDirectoryType(version.getId()) == GameDirectoryType.ROOT_FOLDER) { + if (Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "resourcepacks")) || + Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "saves")) || + Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "mods")) || + Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "shaderpacks")) || + Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "crash-report")) + ) { + runDir = switchWorkingDirectory(HMCLRepository, version); } - Path optionsFile = runDir.resolve("options.txt"); - Path configFolder = runDir.resolve("config"); - - if (Files.exists(optionsFile)) - return; - - if (Files.isDirectory(configFolder)) { - try (Stream stream = Files.walk(configFolder, 2, FileVisitOption.FOLLOW_LINKS)) { - if (stream.anyMatch(file -> "options.txt".equals(FileUtils.getName(file)))) - return; - } catch (IOException e) { - LOG.warning("Failed to visit config folder", e); - } + } + Path optionsFile = runDir.resolve("options.txt"); + Path configFolder = runDir.resolve("config"); + + if (Files.exists(optionsFile)) + return; + + if (Files.isDirectory(configFolder)) { + try (Stream stream = Files.walk(configFolder, 2, FileVisitOption.FOLLOW_LINKS)) { + if (stream.anyMatch(file -> "options.txt".equals(FileUtils.getName(file)))) + return; + } catch (IOException e) { + LOG.warning("Failed to visit config folder", e); } + } - Locale locale = Locale.getDefault(); + Locale locale = Locale.getDefault(); - /* + /* * 1.0 : No language option, do not set for these versions * 1.1 ~ 1.5 : zh_CN works fine, zh_cn will crash (the last two letters must be uppercase, otherwise it will cause an NPE crash) * 1.6 ~ 1.10 : zh_CN works fine, zh_cn will automatically switch to English * 1.11 ~ 1.12 : zh_cn works fine, zh_CN will display Chinese but the language setting will incorrectly show English as selected * 1.13+ : zh_cn works fine, zh_CN will automatically switch to English */ - GameVersionNumber gameVersion = GameVersionNumber.asGameVersion(repository.getGameVersion(version)); - if (gameVersion.compareTo("1.1") < 0) - return; + GameVersionNumber gameVersion = GameVersionNumber.asGameVersion(repository.getGameVersion(version)); + if (gameVersion.compareTo("1.1") < 0) + return; - String lang = normalizedLanguageTag(locale, gameVersion); - if (lang.isEmpty()) - return; + String lang = normalizedLanguageTag(locale, gameVersion); + if (lang.isEmpty()) + return; - if (gameVersion.compareTo("1.11") >= 0) - lang = lang.toLowerCase(Locale.ROOT); + if (gameVersion.compareTo("1.11") >= 0) + lang = lang.toLowerCase(Locale.ROOT); - try { - Files.createDirectories(optionsFile.getParent()); - Files.writeString(optionsFile, String.format("lang:%s\n", lang)); - } catch (IOException e) { - LOG.warning("Unable to generate options.txt", e); - } + try { + Files.createDirectories(optionsFile.getParent()); + Files.writeString(optionsFile, String.format("lang:%s\n", lang)); + } catch (IOException e) { + LOG.warning("Unable to generate options.txt", e); } } - protected Path switchWorkingDirectory(HMCLGameRepository HMCLRepository, Version version) { + private Path switchWorkingDirectory(HMCLGameRepository HMCLRepository, Version version) { if (Platform.isFxApplicationThread()) { - // 在JavaFX线程中直接使用原代码 Alert alert = new Alert(Alert.AlertType.CONFIRMATION, String.format(i18n("launcher.info.switch_working_directory.content"), File.separatorChar, version.getId()), ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) @@ -144,7 +143,6 @@ ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.butt default -> { return HMCLRepository.getBaseDirectory(); } } } else { - // 在非JavaFX线程中使用上面的代码 CompletableFuture buttonDataFuture = new CompletableFuture<>(); Platform.runLater(() -> { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index 99b10456a3..b6e258ddfc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -91,12 +91,11 @@ public Path getRunDirectory(String id) { case VERSION_FOLDER: return getVersionRoot(id); case ROOT_FOLDER: - return getBaseDirectory(); + return super.getRunDirectory(id); case CUSTOM: try { return Path.of(getVersionSetting(id).getGameDir()); } catch (InvalidPathException ignored) { - getBaseDirectory(); return getVersionRoot(id); } default: From 1d52a583e05019d8590e34d1310a5d6bfebcb423 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Mon, 19 Jan 2026 19:42:01 +0800 Subject: [PATCH 11/22] =?UTF-8?q?add+fix:=20=E4=BF=AE=E6=AD=A3=E4=BA=86?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=EF=BC=8C=E5=B9=B6=E6=B7=BB=E5=8A=A0=E4=BA=9A?= =?UTF-8?q?=E6=B4=B2=E8=AF=AD=E8=A8=80=EF=BC=88zh-Hant=E3=80=81zh-CN?= =?UTF-8?q?=E3=80=81ja-JP=EF=BC=89=E7=9A=84=E7=BF=BB=E8=AF=91=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java | 1 - HMCL/src/main/resources/assets/lang/I18N_ja.properties | 5 +++++ HMCL/src/main/resources/assets/lang/I18N_zh.properties | 5 +++++ HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | 5 +++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java index 7df51fb99c..4083ba77d1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java @@ -25,7 +25,6 @@ import org.jackhuang.hmcl.auth.AuthInfo; import org.jackhuang.hmcl.launch.DefaultLauncher; import org.jackhuang.hmcl.launch.ProcessListener; -import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.util.i18n.LocaleUtils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.ManagedProcess; diff --git a/HMCL/src/main/resources/assets/lang/I18N_ja.properties b/HMCL/src/main/resources/assets/lang/I18N_ja.properties index 187db50375..46d308e148 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ja.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ja.properties @@ -305,6 +305,8 @@ download.javafx.notes=ネットワークを介したHMCLに必要なコンポー download.javafx.component=ダウンロード中のモジュール %s download.javafx.prepare=ダウンロードする準備ができました +Dialog.this_launch_only.button=今回のみ + exception.access_denied=ファイル %s にアクセスできないので、HMCL がファイルにアクセスできないか、ファイルが他のプログラムによって開かれています。\n\ 例えば、管理者でないユーザーは、他のアカウントの個人フォルダーにあるファイルにアクセスできない場合があります。\n\ Windowsユーザーの場合、リソースモニターでプログラムがファイルを占有しているかどうかを確認し、もしそうなら、このファイルを占有している関連プログラムを閉じるか、コンピュータを再起動して、もう一度試してみることも可能です。 @@ -539,6 +541,9 @@ launcher.contact=お問い合わせ launcher.crash=Hello Minecraft!ランチャーがクラッシュしました!次のコンテンツをコピーして、MCBBS、Baidu Tieba、GitHub、またはMinecraftForumを介してフィードバックを送信してください。 launcher.crash.hmcl_out_dated=Hello Minecraft!ランチャーがクラッシュしました!ランチャーが古くなっています。ランチャーを更新してください! launcher.update_java=Javaを更新してください。 +launcher.info.switch_working_directory.title=作業ディレクトリを切り替えますか? +# %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) +launcher.info.switch_working_directory.content=.minecraft%1$sversions%1$s%2$s で予期しないコンテンツを検出しました。「隔離」モードを選択していた可能性がありますが、自動または手動で「デフォルト」モードに切り替えられています。今から「隔離」モードに再調整できます。\n「隔離」モードに再調整し、今回の起動で有効にするには「はい」を、現在のバージョン設定を維持するには「いいえ」を、今回の起動のみに有効にするには「今回のみ」を押してください。 login.empty_username=ユーザー名を設定していません! login.enter_password=パスワードを入力してください。 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 27be6ce69e..b3fa1907f6 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -367,6 +367,8 @@ download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s +Dialog.this_launch_only.button=僅限本次啟動 + exception.access_denied=無法存取檔案「%s」。因為 HMCL 沒有對該檔案的訪問權限,或者該檔案已被其他程式開啟。\n\ 請你檢查目前作業系統帳戶是否能訪存取檔案,比如非管理員使用者可能不能訪問其他帳戶的個人目錄內的檔案。\n\ 對於 Windows 使用者,你還可以嘗試透過資源監視器查看是否有程式占用了該檔案。如果是,你可以關閉占用此檔案的程式,或者重啟電腦再試。 @@ -649,6 +651,9 @@ launcher.crash=Hello Minecraft! Launcher 遇到了無法處理的錯誤。請複 launcher.crash.java_internal_error=Hello Minecraft! Launcher 由於目前 Java 損壞而無法繼續執行。請移除目前 Java,點擊 此處 安裝合適的 Java 版本。 launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher 遇到了無法處理的錯誤。已偵測到你的啟動器不是最新版本,請更新後重試! launcher.update_java=請更新你的 Java +launcher.info.switch_working_directory.title=是否要切換工作目錄? +# %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) +launcher.info.switch_working_directory.content=我們在 .minecraft%1$sversions%1$s%2$s 中偵測到意外的內容。您可能選擇了「隔離」模式,但該模式已被自動或手動切換為「預設」模式。您現在可以重新調整為「隔離」模式。\n若想重新調整為「隔離」模式並在本次啟動中生效,請按「是」;若想保留目前版本設定,請按「否」;若想僅對本次啟動生效,請按「僅本次啟動」。 libraries.download=下載依賴庫 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 c3a5549d31..1ab0505371 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -369,6 +369,8 @@ download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s +Dialog.this_launch_only.button=仅本次启动 + exception.access_denied=无法访问文件“%s”。HMCL 没有对该文件的访问权限,或者该文件已被其他程序打开。\n\ 请你检查当前操作系统账户是否能访问该文件,比如非管理员用户可能无法访问其他账户的个人文件夹内的文件。\n\ 对于 Windows 用户,你还可以尝试通过资源监视器查看是否有程序占用了该文件。如果是,请关闭占用该文件的程序,或者重启电脑再试。\n\ @@ -653,6 +655,9 @@ launcher.crash=Hello Minecraft! Launcher 遇到了无法处理的错误。请复 launcher.crash.java_internal_error=Hello Minecraft! Launcher 由于当前 Java 损坏而无法继续运行。请卸载当前 Java,点击 此处 安装合适的 Java 版本。 launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher 遇到了无法处理的错误。已检测到你的启动器不是最新版本,请更新后再试。 launcher.update_java=请更新你的 Java。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。 +launcher.info.switch_working_directory.title=是否要切换工作目录? +# %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) +launcher.info.switch_working_directory.content=我们在 .minecraft%1$sversions%1$s%2$s 中检测到意外的内容。您可能选择了“隔离”模式,但该模式已被自动或手动切换为“默认”模式。您现在可以重新调整为“隔离”模式。\n若想重新调整为“隔离”模式并在本次启动中生效,请按“是”;若想保留当前版本设置,请按“否”;若想仅对本次启动生效,请按“仅本次启动”。 libraries.download=下载依赖库 From 95d287682b365a26fa90b4b32a699fe2b3c011a5 Mon Sep 17 00:00:00 2001 From: Ciilu <109708109+Ciilu@users.noreply.github.com> Date: Mon, 19 Jan 2026 22:04:27 +0800 Subject: [PATCH 12/22] UPDATE --- .../jackhuang/hmcl/game/HMCLGameLauncher.java | 109 +++++++----------- 1 file changed, 42 insertions(+), 67 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java index 4083ba77d1..50514f1516 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java @@ -17,14 +17,13 @@ */ package org.jackhuang.hmcl.game; -import javafx.application.Platform; -import javafx.scene.control.Alert; -import javafx.scene.control.ButtonBar; -import javafx.scene.control.ButtonType; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.auth.AuthInfo; import org.jackhuang.hmcl.launch.DefaultLauncher; import org.jackhuang.hmcl.launch.ProcessListener; +import org.jackhuang.hmcl.ui.Controllers; +import org.jackhuang.hmcl.ui.FXUtils; +import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.util.i18n.LocaleUtils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.ManagedProcess; @@ -32,10 +31,13 @@ import java.io.File; import java.io.IOException; -import java.nio.file.*; -import java.util.*; +import java.nio.file.FileVisitOption; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Locale; +import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.stream.Stream; import static org.jackhuang.hmcl.setting.ConfigHolder.config; @@ -71,15 +73,13 @@ private void generateOptionsTxt() { if (config().isDisableAutoGameOptions()) return; Path runDir = repository.getRunDirectory(version.getId()); - HMCLGameRepository HMCLRepository = (HMCLGameRepository) repository; - if (HMCLRepository.getGameDirectoryType(version.getId()) == GameDirectoryType.ROOT_FOLDER) { - if (Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "resourcepacks")) || - Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "saves")) || - Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "mods")) || - Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "shaderpacks")) || - Files.exists(Path.of(HMCLRepository.getVersionRoot(version.getId()).toString(), "crash-report")) - ) { - runDir = switchWorkingDirectory(HMCLRepository, version); + HMCLGameRepository repository = (HMCLGameRepository) this.repository; + if (repository.getGameDirectoryType(version.getId()) == GameDirectoryType.ROOT_FOLDER) { + Path versionRoot = repository.getVersionRoot(version.getId()); + String[] subdirs = {"resourcepacks", "saves", "mods", "shaderpacks", "crash-report"}; + + if (Arrays.stream(subdirs).anyMatch(dir -> Files.exists(versionRoot.resolve(dir)))) { + runDir = switchWorkingDirectory(repository, version); } } Path optionsFile = runDir.resolve("options.txt"); @@ -100,13 +100,13 @@ private void generateOptionsTxt() { Locale locale = Locale.getDefault(); /* - * 1.0 : No language option, do not set for these versions - * 1.1 ~ 1.5 : zh_CN works fine, zh_cn will crash (the last two letters must be uppercase, otherwise it will cause an NPE crash) - * 1.6 ~ 1.10 : zh_CN works fine, zh_cn will automatically switch to English - * 1.11 ~ 1.12 : zh_cn works fine, zh_CN will display Chinese but the language setting will incorrectly show English as selected - * 1.13+ : zh_cn works fine, zh_CN will automatically switch to English - */ - GameVersionNumber gameVersion = GameVersionNumber.asGameVersion(repository.getGameVersion(version)); + * 1.0 : No language option, do not set for these versions + * 1.1 ~ 1.5 : zh_CN works fine, zh_cn will crash (the last two letters must be uppercase, otherwise it will cause an NPE crash) + * 1.6 ~ 1.10 : zh_CN works fine, zh_cn will automatically switch to English + * 1.11 ~ 1.12 : zh_cn works fine, zh_CN will display Chinese but the language setting will incorrectly show English as selected + * 1.13+ : zh_cn works fine, zh_CN will automatically switch to English + */ + GameVersionNumber gameVersion = GameVersionNumber.asGameVersion(this.repository.getGameVersion(version)); if (gameVersion.compareTo("1.1") < 0) return; @@ -125,52 +125,27 @@ private void generateOptionsTxt() { } } - private Path switchWorkingDirectory(HMCLGameRepository HMCLRepository, Version version) { - if (Platform.isFxApplicationThread()) { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION, - String.format(i18n("launcher.info.switch_working_directory.content"), File.separatorChar, version.getId()), - ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) - ); - alert.setTitle(i18n("launcher.info.switch_working_directory.title")); - switch (alert.showAndWait().orElse(ButtonType.YES).getButtonData()) { - case YES -> { - HMCLRepository.getVersionSetting(version.getId()).setGameDirType(GameDirectoryType.VERSION_FOLDER); - return HMCLRepository.getVersionRoot(version.getId()); - } - case NO -> { return HMCLRepository.getBaseDirectory(); } - case APPLY -> HMCLRepository.getVersionRoot(version.getId()); - default -> { return HMCLRepository.getBaseDirectory(); } - } - } else { - CompletableFuture buttonDataFuture = new CompletableFuture<>(); - - Platform.runLater(() -> { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION, - String.format(i18n("launcher.info.switch_working_directory.content"), File.separatorChar, version.getId()), - ButtonType.YES, ButtonType.NO, new ButtonType(i18n("Dialog.this_launch_only.button"), ButtonBar.ButtonData.APPLY) - ); - alert.setTitle(i18n("launcher.info.switch_working_directory.title")); - buttonDataFuture.complete(alert.showAndWait().orElse(ButtonType.YES).getButtonData()); - }); - - ButtonBar.ButtonData result; - try { - result = buttonDataFuture.get(); - } catch (InterruptedException | ExecutionException e) { - result = ButtonBar.ButtonData.YES; - } + private Path switchWorkingDirectory(HMCLGameRepository repository, Version version) { + CompletableFuture future = new CompletableFuture<>(); + + var dialog = new MessageDialogPane.Builder( + i18n("launcher.info.switch_working_directory.content", File.separatorChar, version.getId()), + i18n("launcher.info.switch_working_directory.title"), MessageDialogPane.MessageType.QUESTION) + .ok(() -> { + repository.getVersionSetting(version.getId()).setGameDirType(GameDirectoryType.VERSION_FOLDER); + future.complete(repository.getVersionRoot(version.getId())); + }).addCancel(() -> { + future.complete(repository.getBaseDirectory()); + }).addCancel(i18n("Dialog.this_launch_only.button"), () -> { + future.complete(repository.getVersionRoot(version.getId())); + }).build(); + FXUtils.runInFX(()-> Controllers.dialog(dialog)); - switch (result) { - case YES -> { - HMCLRepository.getVersionSetting(version.getId()).setGameDirType(GameDirectoryType.VERSION_FOLDER); - return HMCLRepository.getVersionRoot(version.getId()); - } - case NO -> { return HMCLRepository.getBaseDirectory(); } - case APPLY -> HMCLRepository.getVersionRoot(version.getId()); - default -> { return HMCLRepository.getBaseDirectory(); } - } + try { + return future.get(); + } catch (Exception e) { + throw new RuntimeException(e); } - return HMCLRepository.getVersionRoot(version.getId()); } private static String normalizedLanguageTag(Locale locale, GameVersionNumber gameVersion) { From cd090e73acef5c58c0e24ca0230f304b2fb5562c Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Tue, 20 Jan 2026 08:06:03 +0800 Subject: [PATCH 13/22] Update HMCL/src/main/resources/assets/lang/I18N.properties Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com> --- HMCL/src/main/resources/assets/lang/I18N.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 8fabe5f89b..b28f806acc 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -376,7 +376,7 @@ download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s -Dialog.this_launch_only.button=This Launch only +Dialog.this_launch_only.button=This launch only exception.access_denied=HMCL is unable to access the file "%s". It may be locked by another process.\n\ \n\ From 5d2ff487bd36f4956ca24151bfea60d4af597569 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Tue, 20 Jan 2026 08:06:35 +0800 Subject: [PATCH 14/22] Update HMCL/src/main/resources/assets/lang/I18N.properties Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com> --- HMCL/src/main/resources/assets/lang/I18N.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index b28f806acc..9b0d46d6c8 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -853,7 +853,7 @@ launcher.crash=Hello Minecraft! Launcher has encountered a fatal error! Please c launcher.crash.java_internal_error=Hello Minecraft! Launcher has encountered a fatal error because your Java is corrupted. Please uninstall your Java and download a suitable Java here. launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher has encountered a fatal error! Your launcher is outdated. Please update your launcher! launcher.update_java=Please update your Java version. -launcher.info.switch_working_directory.title=Would you like to switch the Working Directory? +launcher.info.switch_working_directory.title=Instance files detected # %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) launcher.info.switch_working_directory.content=We detected unexpected content in .minecraft%1$sversions%1$s%2$s. It's likely you selected "Isolated" mode, but it was switched to "Default" mode automatically or manually. The choice to readjust to "Isolated" mode is available to you.\nRe-adjust to 'Isolated' mode and make it effective for this launch, press "Yes". if you want to retain current version settings, press "No". if you want make it effective for this launch only, press "This launch only". From 9c5df2f558226418a384dd8e49239c83127215c5 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Tue, 20 Jan 2026 08:10:46 +0800 Subject: [PATCH 15/22] Update HMCL/src/main/resources/assets/lang/I18N.properties Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com> --- HMCL/src/main/resources/assets/lang/I18N.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 9b0d46d6c8..7eea42b298 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -855,7 +855,7 @@ launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher has encountered a fatal launcher.update_java=Please update your Java version. launcher.info.switch_working_directory.title=Instance files detected # %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) -launcher.info.switch_working_directory.content=We detected unexpected content in .minecraft%1$sversions%1$s%2$s. It's likely you selected "Isolated" mode, but it was switched to "Default" mode automatically or manually. The choice to readjust to "Isolated" mode is available to you.\nRe-adjust to 'Isolated' mode and make it effective for this launch, press "Yes". if you want to retain current version settings, press "No". if you want make it effective for this launch only, press "This launch only". +launcher.info.switch_working_directory.content=Existing game files were detected in ".minecraft%1$sversions%1$s%2$s", but the Working Directory is currently set to "Default".\n\nTo use these files, the setting in "Game Settings → Working Directory" should be "Isolated". Would you like to switch to Isolated mode? libraries.download=Downloading Libraries From 161948095d42e9516420dd1a083500c3e658f82a Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Tue, 20 Jan 2026 08:10:59 +0800 Subject: [PATCH 16/22] Update HMCL/src/main/resources/assets/lang/I18N_zh.properties Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com> --- HMCL/src/main/resources/assets/lang/I18N_zh.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index b3fa1907f6..3a352a2969 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -651,7 +651,7 @@ launcher.crash=Hello Minecraft! Launcher 遇到了無法處理的錯誤。請複 launcher.crash.java_internal_error=Hello Minecraft! Launcher 由於目前 Java 損壞而無法繼續執行。請移除目前 Java,點擊 此處 安裝合適的 Java 版本。 launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher 遇到了無法處理的錯誤。已偵測到你的啟動器不是最新版本,請更新後重試! launcher.update_java=請更新你的 Java -launcher.info.switch_working_directory.title=是否要切換工作目錄? +launcher.info.switch_working_directory.title=偵測到實例檔案 # %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) launcher.info.switch_working_directory.content=我們在 .minecraft%1$sversions%1$s%2$s 中偵測到意外的內容。您可能選擇了「隔離」模式,但該模式已被自動或手動切換為「預設」模式。您現在可以重新調整為「隔離」模式。\n若想重新調整為「隔離」模式並在本次啟動中生效,請按「是」;若想保留目前版本設定,請按「否」;若想僅對本次啟動生效,請按「僅本次啟動」。 From 84b1969985d7221a05af4f1578a9e28a3c94e1ea Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Tue, 20 Jan 2026 08:11:10 +0800 Subject: [PATCH 17/22] Update HMCL/src/main/resources/assets/lang/I18N_zh.properties Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com> --- HMCL/src/main/resources/assets/lang/I18N_zh.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 3a352a2969..6e82219a56 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -653,7 +653,7 @@ launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher 遇到了無法處理的 launcher.update_java=請更新你的 Java launcher.info.switch_working_directory.title=偵測到實例檔案 # %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) -launcher.info.switch_working_directory.content=我們在 .minecraft%1$sversions%1$s%2$s 中偵測到意外的內容。您可能選擇了「隔離」模式,但該模式已被自動或手動切換為「預設」模式。您現在可以重新調整為「隔離」模式。\n若想重新調整為「隔離」模式並在本次啟動中生效,請按「是」;若想保留目前版本設定,請按「否」;若想僅對本次啟動生效,請按「僅本次啟動」。 +launcher.info.switch_working_directory.content=在「.minecraft%1$sversions%1$s%2$s」中偵測到既有遊戲檔案,但目前執行路徑設定為「預設」。\n\n要使用這些檔案,請在「(全域/實例特定) 遊戲設定 → 執行路徑」中選取「各實例獨立」。你是否要切換到「各實例獨立」模式? libraries.download=下載依賴庫 From e35dc8295ae5eca8705540102d605c3b7beb7c2f Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Tue, 20 Jan 2026 08:11:25 +0800 Subject: [PATCH 18/22] Update HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com> --- HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1ab0505371..2c3402504d 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -655,7 +655,7 @@ launcher.crash=Hello Minecraft! Launcher 遇到了无法处理的错误。请复 launcher.crash.java_internal_error=Hello Minecraft! Launcher 由于当前 Java 损坏而无法继续运行。请卸载当前 Java,点击 此处 安装合适的 Java 版本。 launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher 遇到了无法处理的错误。已检测到你的启动器不是最新版本,请更新后再试。 launcher.update_java=请更新你的 Java。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。 -launcher.info.switch_working_directory.title=是否要切换工作目录? +launcher.info.switch_working_directory.title=检测到实例文件 # %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) launcher.info.switch_working_directory.content=我们在 .minecraft%1$sversions%1$s%2$s 中检测到意外的内容。您可能选择了“隔离”模式,但该模式已被自动或手动切换为“默认”模式。您现在可以重新调整为“隔离”模式。\n若想重新调整为“隔离”模式并在本次启动中生效,请按“是”;若想保留当前版本设置,请按“否”;若想仅对本次启动生效,请按“仅本次启动”。 From 31cc0c40845ba7974ec209c72cd378281befe4b2 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Tue, 20 Jan 2026 08:11:44 +0800 Subject: [PATCH 19/22] Update HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com> --- HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2c3402504d..c1330de4e4 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -657,7 +657,7 @@ launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher 遇到了无法处理的 launcher.update_java=请更新你的 Java。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。 launcher.info.switch_working_directory.title=检测到实例文件 # %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) -launcher.info.switch_working_directory.content=我们在 .minecraft%1$sversions%1$s%2$s 中检测到意外的内容。您可能选择了“隔离”模式,但该模式已被自动或手动切换为“默认”模式。您现在可以重新调整为“隔离”模式。\n若想重新调整为“隔离”模式并在本次启动中生效,请按“是”;若想保留当前版本设置,请按“否”;若想仅对本次启动生效,请按“仅本次启动”。 +launcher.info.switch_working_directory.content=在“.minecraft%1$sversions%1$s%2$s”中检测到既有游戏文件,但目前“版本隔离”设置为“默认”。\n\n要使用这些文件,请在“(全局/实例特定) 游戏设置 → 版本隔离”中选择“各实例独立”。\n\n你是否要切换到“各实例独立”模式? libraries.download=下载依赖库 From c6e33a9c777e8a139e50469e3533347746dbf452 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Tue, 20 Jan 2026 10:26:40 +0800 Subject: [PATCH 20/22] fallback ja_JP --- HMCL/src/main/resources/assets/lang/I18N_ja.properties | 5 ----- 1 file changed, 5 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_ja.properties b/HMCL/src/main/resources/assets/lang/I18N_ja.properties index 46d308e148..187db50375 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ja.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ja.properties @@ -305,8 +305,6 @@ download.javafx.notes=ネットワークを介したHMCLに必要なコンポー download.javafx.component=ダウンロード中のモジュール %s download.javafx.prepare=ダウンロードする準備ができました -Dialog.this_launch_only.button=今回のみ - exception.access_denied=ファイル %s にアクセスできないので、HMCL がファイルにアクセスできないか、ファイルが他のプログラムによって開かれています。\n\ 例えば、管理者でないユーザーは、他のアカウントの個人フォルダーにあるファイルにアクセスできない場合があります。\n\ Windowsユーザーの場合、リソースモニターでプログラムがファイルを占有しているかどうかを確認し、もしそうなら、このファイルを占有している関連プログラムを閉じるか、コンピュータを再起動して、もう一度試してみることも可能です。 @@ -541,9 +539,6 @@ launcher.contact=お問い合わせ launcher.crash=Hello Minecraft!ランチャーがクラッシュしました!次のコンテンツをコピーして、MCBBS、Baidu Tieba、GitHub、またはMinecraftForumを介してフィードバックを送信してください。 launcher.crash.hmcl_out_dated=Hello Minecraft!ランチャーがクラッシュしました!ランチャーが古くなっています。ランチャーを更新してください! launcher.update_java=Javaを更新してください。 -launcher.info.switch_working_directory.title=作業ディレクトリを切り替えますか? -# %1$s = java.io.File.separator, %2$s = version root (Don't ends with java.io.File.separator) -launcher.info.switch_working_directory.content=.minecraft%1$sversions%1$s%2$s で予期しないコンテンツを検出しました。「隔離」モードを選択していた可能性がありますが、自動または手動で「デフォルト」モードに切り替えられています。今から「隔離」モードに再調整できます。\n「隔離」モードに再調整し、今回の起動で有効にするには「はい」を、現在のバージョン設定を維持するには「いいえ」を、今回の起動のみに有効にするには「今回のみ」を押してください。 login.empty_username=ユーザー名を設定していません! login.enter_password=パスワードを入力してください。 From d69676ba796e59cc7a6fdf5ea4d79b9b88495521 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Tue, 20 Jan 2026 10:56:09 +0800 Subject: [PATCH 21/22] fixed format --- .../src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java index 50514f1516..f1c67f7902 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java @@ -139,7 +139,7 @@ private Path switchWorkingDirectory(HMCLGameRepository repository, Version versi }).addCancel(i18n("Dialog.this_launch_only.button"), () -> { future.complete(repository.getVersionRoot(version.getId())); }).build(); - FXUtils.runInFX(()-> Controllers.dialog(dialog)); + FXUtils.runInFX(() -> Controllers.dialog(dialog)); try { return future.get(); From 9fea525431e382e01a4c24dc486206c9c8354d59 Mon Sep 17 00:00:00 2001 From: deepsleep-v3 Date: Tue, 20 Jan 2026 21:07:06 +0800 Subject: [PATCH 22/22] =?UTF-8?q?=E4=B8=80=E4=BA=9B=E8=AF=AD=E6=B3=95?= =?UTF-8?q?=E9=94=99=E8=AF=AF=EF=BC=88Part=20=E2=85=A0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/jackhuang/hmcl/game/LaunchOptions.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java index dacf26181b..6f5e6f9a1e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java @@ -82,15 +82,15 @@ public JavaRuntime getJava() { } /** - * Will shown in the left bottom corner of the main menu of Minecraft. - * null if use the id of launch version. + * Will be shown in the left bottom corner of the main menu of Minecraft. + * null if the id of launch version. */ public String getVersionName() { return versionName; } /** - * Will shown in the left bottom corner of the main menu of Minecraft. + * Will be shown in the left bottom corner of the main menu of Minecraft. * null if use Version.versionType. */ public String getVersionType() { @@ -208,7 +208,7 @@ public int getProxyPort() { } /** - * The user name of the proxy, optional. + * The username of the proxy, optional. */ public String getProxyUser() { return proxyUser;