From 48faeba4dea1d269899a2d26311cc077c2bda56c Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sat, 4 Apr 2026 16:36:54 +0800 Subject: [PATCH 01/10] update --- .../jackhuang/hmcl/game/LauncherHelper.java | 14 ++- .../hmcl/ui/versions/ScriptFormatDialog.java | 88 +++++++++++++++++++ .../jackhuang/hmcl/ui/versions/Versions.java | 49 ++++++++++- .../resources/assets/lang/I18N.properties | 4 + .../resources/assets/lang/I18N_zh.properties | 4 + .../assets/lang/I18N_zh_CN.properties | 4 + .../hmcl/launch/DefaultLauncher.java | 42 ++++++++- .../org/jackhuang/hmcl/launch/Launcher.java | 8 ++ 8 files changed, 206 insertions(+), 7 deletions(-) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java 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 48d7a26a5f..12b94aeb54 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -82,6 +82,7 @@ public final class LauncherHelper { private Account account; private final String selectedVersion; private Path scriptFile; + private String forceFormat; private final VersionSetting setting; private LauncherVisibility launcherVisibility; private boolean showLogs; @@ -136,6 +137,13 @@ public void launch() { public void makeLaunchScript(Path scriptFile) { this.scriptFile = Objects.requireNonNull(scriptFile); + this.forceFormat = null; + launch(); + } + + public void makeLaunchScript(Path scriptFile, String forceFormat) { + this.scriptFile = Objects.requireNonNull(scriptFile); + this.forceFormat = forceFormat; launch(); } @@ -250,7 +258,11 @@ private void launch0() { return Task.supplyAsync(launcher::launch); } else { return Task.supplyAsync(() -> { - launcher.makeLaunchScript(scriptFile); + if (forceFormat != null) { + launcher.makeLaunchScript(scriptFile, forceFormat); + } else { + launcher.makeLaunchScript(scriptFile); + } return null; }); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java new file mode 100644 index 0000000000..74b2d6351d --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java @@ -0,0 +1,88 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2026 huangyuhui 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 . + */ +package org.jackhuang.hmcl.ui.versions; + +import javafx.geometry.Insets; +import javafx.scene.control.Label; +import javafx.scene.layout.VBox; +import org.jackhuang.hmcl.ui.construct.ComponentList; +import org.jackhuang.hmcl.ui.construct.DialogPane; +import org.jackhuang.hmcl.ui.construct.LineSelectButton; +import org.jackhuang.hmcl.ui.construct.LineToggleButton; +import org.jackhuang.hmcl.util.platform.OperatingSystem; + +import java.util.concurrent.CompletableFuture; + +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; + +public class ScriptFormatDialog extends DialogPane { + + public record Result(String format, boolean appendSuffix) {} + + private final CompletableFuture future = new CompletableFuture<>(); + private final LineSelectButton formatSelectButton; + private final LineToggleButton appendSuffixToggle; + + public ScriptFormatDialog(String unsupportedExtension) { + setTitle(i18n("version.launch_script.unsupported.title")); + + Label messageLabel = new Label(i18n("version.launch_script.unsupported.message", unsupportedExtension)); + messageLabel.setWrapText(true); + messageLabel.setPadding(new Insets(0, 0, 10, 0)); + + formatSelectButton = new LineSelectButton<>(); + formatSelectButton.setTitle(i18n("version.launch_script.select_type")); + formatSelectButton.setConverter(item -> item); + formatSelectButton.setItems(getAvailableFormats()); + formatSelectButton.setValue(getAvailableFormats()[0]); + + appendSuffixToggle = new LineToggleButton(); + appendSuffixToggle.setTitle(i18n("version.launch_script.append_suffix")); + appendSuffixToggle.setSelected(true); + + ComponentList content = new ComponentList(); + content.getContent().addAll(formatSelectButton, appendSuffixToggle); + + setBody(new VBox(messageLabel, content)); + } + + @Override + protected void onAccept() { + String format = formatSelectButton.getValue(); + if (format != null) { + future.complete(new Result(format, appendSuffixToggle.isSelected())); + } + super.onAccept(); + } + + @Override + protected void onCancel() { + future.cancel(false); + super.onCancel(); + } + + private String[] getAvailableFormats() { + return OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS + ? new String[]{i18n("extension.bat"), i18n("extension.ps1")} + : new String[]{i18n("extension.sh"), i18n("extension.ps1")}; + } + + public CompletableFuture getCompletableFuture() { + return future; + } +} \ No newline at end of file diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java index 5c4ce50ba7..674b271bcd 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java @@ -264,11 +264,36 @@ public static void generateLaunchScript(Profile profile, String id, Consumer injecter : injecters) { - injecter.accept(launcherHelper); + try { + if (file.getFileName().toString().contains("DEBUG_FORCE_EXT_DIALOG")) { + throw new IllegalArgumentException("The extension of " + file + " is not recognized"); + } + + LauncherHelper launcherHelper = new LauncherHelper(profile, account, id); + for (Consumer injecter : injecters) { + injecter.accept(launcherHelper); + } + launcherHelper.makeLaunchScript(file); + } catch (IllegalArgumentException e) { + String unsupportedExtension = FileUtils.getExtension(file); + ScriptFormatDialog dialog = new ScriptFormatDialog(unsupportedExtension); + Controllers.dialog(dialog); + dialog.getCompletableFuture().whenComplete((result, ex) -> { + if (result != null && (ex == null || !(ex instanceof java.util.concurrent.CancellationException))) { + String forceFormat = getForceFormatFromSelection(result.format()); + Path targetFile = file; + if (result.appendSuffix()) { + String extension = getExtensionFromForceFormat(forceFormat); + targetFile = file.resolveSibling(file.getFileName().toString() + "." + extension); + } + LauncherHelper launcherHelper = new LauncherHelper(profile, account, id); + for (Consumer injecter : injecters) { + injecter.accept(launcherHelper); + } + launcherHelper.makeLaunchScript(targetFile, forceFormat); + } + }); } - launcherHelper.makeLaunchScript(file); } }); } @@ -357,4 +382,20 @@ public static void modifyGameSettings(Profile profile, String version) { // VersionPage.loadVersion will be invoked after navigation Controllers.navigate(Controllers.getVersionPage()); } + + private static String getForceFormatFromSelection(String format) { + if (format == null) return null; + if (format.equals(i18n("extension.ps1"))) return "ps1"; + if (format.equals(i18n("extension.bat"))) return "bat"; + if (format.equals(i18n("extension.sh"))) return "bash"; + return null; + } + + private static String getExtensionFromForceFormat(String forceFormat) { + return switch (forceFormat) { + case "ps1" -> "ps1"; + case "bat" -> "bat"; + default -> "sh"; + }; + } } diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index cc67b62d3a..15dd234f33 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -1650,6 +1650,10 @@ version.launch_script=Export Launch Script version.launch_script.failed=Failed to export launch script. version.launch_script.save=Export Launch Script version.launch_script.success=Exported launch script as %s. +version.launch_script.unsupported.title=Unsupported File Type +version.launch_script.unsupported.message=The file extension "%s" is not recognized. Please select a valid script format: +version.launch_script.select_type=Script Format +version.launch_script.append_suffix=Append file extension version.manage=All Instances version.manage.clean=Delete Log Files version.manage.clean.tooltip=Delete the files in "logs" and "crash-reports" directories. diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index da02e13533..4bf667b176 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -1431,6 +1431,10 @@ version.launch_script=生成啟動指令碼 version.launch_script.failed=生成啟動指令碼失敗 version.launch_script.save=儲存啟動指令碼 version.launch_script.success=啟動指令碼已生成完畢: %s +version.launch_script.unsupported.title=不支援的檔案類型 +version.launch_script.unsupported.message=無法識別檔案副檔名"%s",請選擇有效的指令碼格式: +version.launch_script.select_type=指令碼格式 +version.launch_script.append_suffix=新增檔案副檔名 version.manage=實例清單 version.manage.clean=清理遊戲目錄 version.manage.clean.tooltip=清理「logs」與「crash-reports」目錄 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 c53c6f3aa2..a2f13e37fc 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1436,6 +1436,10 @@ version.launch_script=生成启动脚本 version.launch_script.failed=生成启动脚本失败 version.launch_script.save=保存启动脚本 version.launch_script.success=启动脚本已生成完毕:%s +version.launch_script.unsupported.title=不支持的文件类型 +version.launch_script.unsupported.message=无法识别文件扩展名"%s",请选择有效的脚本格式: +version.launch_script.select_type=脚本格式 +version.launch_script.append_suffix=添加文件扩展名 version.manage=实例列表 version.manage.clean=清理游戏文件夹 version.manage.clean.tooltip=清理“logs”和“crash-reports”文件夹 diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index f5896914cf..06305e5a59 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -646,10 +646,48 @@ public void makeLaunchScript(Path scriptFile) throws IOException { if (!usePowerShell) { if (isWindows && !scriptExtension.equals("bat")) throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'bat' or 'ps1' in Windows"); - else if (!isWindows && !(scriptExtension.equals("sh") || scriptExtension.equals("command"))) - throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'sh', 'ps1' or 'command' in macOS/Linux"); + else if (!isWindows && !(scriptExtension.equals("sh") || scriptExtension.equals("command") || scriptExtension.equals("bash"))) + throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'sh', 'bash', 'ps1' or 'command' in macOS/Linux"); } + generateScriptFile(scriptFile, usePowerShell, nativeFolder, isWindows); + } + + @Override + public void makeLaunchScript(Path scriptFile, String forceFormat) throws IOException { + boolean isWindows = OperatingSystem.WINDOWS == OperatingSystem.CURRENT_OS; + + Path nativeFolder; + if (options.getNativesDirType() == NativesDirectoryType.VERSION_FOLDER) { + nativeFolder = repository.getNativeDirectory(version.getId(), options.getJava().getPlatform()); + } else { + nativeFolder = Path.of(options.getNativesDir()); + } + + if (options.getNativesDirType() == NativesDirectoryType.VERSION_FOLDER) { + decompressNatives(nativeFolder); + } + + if (isUsingLog4j()) + extractLog4jConfigurationFile(); + + boolean usePowerShell = "ps1".equalsIgnoreCase(forceFormat); + + if (!usePowerShell) { + if (isWindows) { + if (forceFormat != null && !forceFormat.equals("bat")) + throw new IllegalArgumentException("The forced format " + forceFormat + " is not valid in Windows, use 'bat'"); + } else { + if (forceFormat != null && !forceFormat.equals("bash") && !forceFormat.equals("sh") && !forceFormat.equals("command")) + throw new IllegalArgumentException("The forced format " + forceFormat + " is not valid in Linux/macOS, use 'bash', 'sh', or 'command'"); + } + } + + generateScriptFile(scriptFile, usePowerShell, nativeFolder, isWindows); + } + + private void generateScriptFile(Path scriptFile, boolean usePowerShell, Path nativeFolder, boolean isWindows) throws IOException { + final Command commandLine = generateCommandLine(nativeFolder); final String command = usePowerShell ? null : commandLine.commandLine.toString(); Map envVars = getEnvVars(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/Launcher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/Launcher.java index e4a97f9f79..c6b23f1a3b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/Launcher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/Launcher.java @@ -61,6 +61,14 @@ public Launcher(GameRepository repository, Version version, AuthInfo authInfo, L */ public abstract void makeLaunchScript(Path file) throws IOException; + /** + * @param file the file path. + * @param forceFormat force the script format - "bat", "ps1", or "bash". If null, uses file extension. + */ + public void makeLaunchScript(Path file, String forceFormat) throws IOException { + makeLaunchScript(file); + } + public abstract ManagedProcess launch() throws IOException, InterruptedException; } From 78f490c15a24dd695068e993c45185eb6346e7dd Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sat, 4 Apr 2026 16:40:31 +0800 Subject: [PATCH 02/10] update --- .../main/java/org/jackhuang/hmcl/ui/versions/Versions.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java index 674b271bcd..8f03f0e82a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java @@ -265,10 +265,6 @@ public static void generateLaunchScript(Profile profile, String id, Consumer injecter : injecters) { injecter.accept(launcherHelper); From 351dd191e7d42d69d15c61b1ee086d445cdfe23f Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sat, 4 Apr 2026 16:54:34 +0800 Subject: [PATCH 03/10] update --- .../java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java index 74b2d6351d..8afe2ee0f7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java @@ -85,4 +85,4 @@ private String[] getAvailableFormats() { public CompletableFuture getCompletableFuture() { return future; } -} \ No newline at end of file +} From eccc1b1b8e46654f0bf5fb9aa4fedf82e31cb0ec Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sat, 4 Apr 2026 17:12:06 +0800 Subject: [PATCH 04/10] update --- .../hmcl/ui/versions/ScriptFormatDialog.java | 12 +++++++++--- HMCL/src/main/resources/assets/lang/I18N.properties | 2 ++ .../main/resources/assets/lang/I18N_zh.properties | 2 ++ .../main/resources/assets/lang/I18N_zh_CN.properties | 2 ++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java index 8afe2ee0f7..a29de56af0 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java @@ -39,9 +39,15 @@ public record Result(String format, boolean appendSuffix) {} private final LineToggleButton appendSuffixToggle; public ScriptFormatDialog(String unsupportedExtension) { - setTitle(i18n("version.launch_script.unsupported.title")); - - Label messageLabel = new Label(i18n("version.launch_script.unsupported.message", unsupportedExtension)); + String title = unsupportedExtension.isEmpty() + ? i18n("version.launch_script.unsupported.title.no_ext") + : i18n("version.launch_script.unsupported.title"); + setTitle(title); + + String message = unsupportedExtension.isEmpty() + ? i18n("version.launch_script.unsupported.message.no_ext") + : i18n("version.launch_script.unsupported.message", unsupportedExtension); + Label messageLabel = new Label(message); messageLabel.setWrapText(true); messageLabel.setPadding(new Insets(0, 0, 10, 0)); diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 15dd234f33..28266b3d8e 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -1651,7 +1651,9 @@ version.launch_script.failed=Failed to export launch script. version.launch_script.save=Export Launch Script version.launch_script.success=Exported launch script as %s. version.launch_script.unsupported.title=Unsupported File Type +version.launch_script.unsupported.title.no_ext=No File Extension version.launch_script.unsupported.message=The file extension "%s" is not recognized. Please select a valid script format: +version.launch_script.unsupported.message.no_ext=The file has no extension. Please select a valid script format: version.launch_script.select_type=Script Format version.launch_script.append_suffix=Append file extension version.manage=All Instances diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 4bf667b176..4589d0990c 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -1432,7 +1432,9 @@ version.launch_script.failed=生成啟動指令碼失敗 version.launch_script.save=儲存啟動指令碼 version.launch_script.success=啟動指令碼已生成完畢: %s version.launch_script.unsupported.title=不支援的檔案類型 +version.launch_script.unsupported.title.no_ext=檔案沒有副檔名 version.launch_script.unsupported.message=無法識別檔案副檔名"%s",請選擇有效的指令碼格式: +version.launch_script.unsupported.message.no_ext=檔案沒有副檔名,請選擇有效的指令碼格式: version.launch_script.select_type=指令碼格式 version.launch_script.append_suffix=新增檔案副檔名 version.manage=實例清單 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 a2f13e37fc..44bac214e2 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1437,7 +1437,9 @@ version.launch_script.failed=生成启动脚本失败 version.launch_script.save=保存启动脚本 version.launch_script.success=启动脚本已生成完毕:%s version.launch_script.unsupported.title=不支持的文件类型 +version.launch_script.unsupported.title.no_ext=文件没有扩展名 version.launch_script.unsupported.message=无法识别文件扩展名"%s",请选择有效的脚本格式: +version.launch_script.unsupported.message.no_ext=文件没有扩展名,请选择有效的脚本格式: version.launch_script.select_type=脚本格式 version.launch_script.append_suffix=添加文件扩展名 version.manage=实例列表 From 5c0edc412aeb514133439fbcd4720f38997cfb88 Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sun, 5 Apr 2026 19:43:03 +0800 Subject: [PATCH 05/10] update --- .../jackhuang/hmcl/ui/versions/Versions.java | 54 ++++++------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java index 8f03f0e82a..507afc9057 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java @@ -264,36 +264,30 @@ public static void generateLaunchScript(Profile profile, String id, Consumer injecter : injecters) { + injecter.accept(launcherHelper); + } try { - LauncherHelper launcherHelper = new LauncherHelper(profile, account, id); - for (Consumer injecter : injecters) { - injecter.accept(launcherHelper); - } launcherHelper.makeLaunchScript(file); } catch (IllegalArgumentException e) { - String unsupportedExtension = FileUtils.getExtension(file); - ScriptFormatDialog dialog = new ScriptFormatDialog(unsupportedExtension); - Controllers.dialog(dialog); - dialog.getCompletableFuture().whenComplete((result, ex) -> { - if (result != null && (ex == null || !(ex instanceof java.util.concurrent.CancellationException))) { - String forceFormat = getForceFormatFromSelection(result.format()); - Path targetFile = file; - if (result.appendSuffix()) { - String extension = getExtensionFromForceFormat(forceFormat); - targetFile = file.resolveSibling(file.getFileName().toString() + "." + extension); - } - LauncherHelper launcherHelper = new LauncherHelper(profile, account, id); - for (Consumer injecter : injecters) { - injecter.accept(launcherHelper); - } - launcherHelper.makeLaunchScript(targetFile, forceFormat); - } - }); + Path withExtFile; + String defaultExt = getDefaultScriptExtension(); + withExtFile = file.resolveSibling(file.getFileName().toString() + "." + defaultExt); + launcherHelper.makeLaunchScript(withExtFile); } } }); } + private static String getDefaultScriptExtension() { + return switch (OperatingSystem.CURRENT_OS) { + case WINDOWS -> "bat"; + case MACOS -> "command"; + default -> "sh"; + }; + } + @SafeVarargs public static void launch(Profile profile, String id, Consumer... injecters) { if (!checkVersionForLaunching(profile, id)) @@ -378,20 +372,4 @@ public static void modifyGameSettings(Profile profile, String version) { // VersionPage.loadVersion will be invoked after navigation Controllers.navigate(Controllers.getVersionPage()); } - - private static String getForceFormatFromSelection(String format) { - if (format == null) return null; - if (format.equals(i18n("extension.ps1"))) return "ps1"; - if (format.equals(i18n("extension.bat"))) return "bat"; - if (format.equals(i18n("extension.sh"))) return "bash"; - return null; - } - - private static String getExtensionFromForceFormat(String forceFormat) { - return switch (forceFormat) { - case "ps1" -> "ps1"; - case "bat" -> "bat"; - default -> "sh"; - }; - } } From 6a8a426404642d6c4cd87b9a80350d32a9c4b612 Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sun, 5 Apr 2026 19:46:35 +0800 Subject: [PATCH 06/10] update --- .../jackhuang/hmcl/game/LauncherHelper.java | 14 +------ .../hmcl/launch/DefaultLauncher.java | 42 +------------------ .../org/jackhuang/hmcl/launch/Launcher.java | 8 ---- 3 files changed, 3 insertions(+), 61 deletions(-) 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 12b94aeb54..48d7a26a5f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -82,7 +82,6 @@ public final class LauncherHelper { private Account account; private final String selectedVersion; private Path scriptFile; - private String forceFormat; private final VersionSetting setting; private LauncherVisibility launcherVisibility; private boolean showLogs; @@ -137,13 +136,6 @@ public void launch() { public void makeLaunchScript(Path scriptFile) { this.scriptFile = Objects.requireNonNull(scriptFile); - this.forceFormat = null; - launch(); - } - - public void makeLaunchScript(Path scriptFile, String forceFormat) { - this.scriptFile = Objects.requireNonNull(scriptFile); - this.forceFormat = forceFormat; launch(); } @@ -258,11 +250,7 @@ private void launch0() { return Task.supplyAsync(launcher::launch); } else { return Task.supplyAsync(() -> { - if (forceFormat != null) { - launcher.makeLaunchScript(scriptFile, forceFormat); - } else { - launcher.makeLaunchScript(scriptFile); - } + launcher.makeLaunchScript(scriptFile); return null; }); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 06305e5a59..f5896914cf 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -646,48 +646,10 @@ public void makeLaunchScript(Path scriptFile) throws IOException { if (!usePowerShell) { if (isWindows && !scriptExtension.equals("bat")) throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'bat' or 'ps1' in Windows"); - else if (!isWindows && !(scriptExtension.equals("sh") || scriptExtension.equals("command") || scriptExtension.equals("bash"))) - throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'sh', 'bash', 'ps1' or 'command' in macOS/Linux"); + else if (!isWindows && !(scriptExtension.equals("sh") || scriptExtension.equals("command"))) + throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'sh', 'ps1' or 'command' in macOS/Linux"); } - generateScriptFile(scriptFile, usePowerShell, nativeFolder, isWindows); - } - - @Override - public void makeLaunchScript(Path scriptFile, String forceFormat) throws IOException { - boolean isWindows = OperatingSystem.WINDOWS == OperatingSystem.CURRENT_OS; - - Path nativeFolder; - if (options.getNativesDirType() == NativesDirectoryType.VERSION_FOLDER) { - nativeFolder = repository.getNativeDirectory(version.getId(), options.getJava().getPlatform()); - } else { - nativeFolder = Path.of(options.getNativesDir()); - } - - if (options.getNativesDirType() == NativesDirectoryType.VERSION_FOLDER) { - decompressNatives(nativeFolder); - } - - if (isUsingLog4j()) - extractLog4jConfigurationFile(); - - boolean usePowerShell = "ps1".equalsIgnoreCase(forceFormat); - - if (!usePowerShell) { - if (isWindows) { - if (forceFormat != null && !forceFormat.equals("bat")) - throw new IllegalArgumentException("The forced format " + forceFormat + " is not valid in Windows, use 'bat'"); - } else { - if (forceFormat != null && !forceFormat.equals("bash") && !forceFormat.equals("sh") && !forceFormat.equals("command")) - throw new IllegalArgumentException("The forced format " + forceFormat + " is not valid in Linux/macOS, use 'bash', 'sh', or 'command'"); - } - } - - generateScriptFile(scriptFile, usePowerShell, nativeFolder, isWindows); - } - - private void generateScriptFile(Path scriptFile, boolean usePowerShell, Path nativeFolder, boolean isWindows) throws IOException { - final Command commandLine = generateCommandLine(nativeFolder); final String command = usePowerShell ? null : commandLine.commandLine.toString(); Map envVars = getEnvVars(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/Launcher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/Launcher.java index c6b23f1a3b..e4a97f9f79 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/Launcher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/Launcher.java @@ -61,14 +61,6 @@ public Launcher(GameRepository repository, Version version, AuthInfo authInfo, L */ public abstract void makeLaunchScript(Path file) throws IOException; - /** - * @param file the file path. - * @param forceFormat force the script format - "bat", "ps1", or "bash". If null, uses file extension. - */ - public void makeLaunchScript(Path file, String forceFormat) throws IOException { - makeLaunchScript(file); - } - public abstract ManagedProcess launch() throws IOException, InterruptedException; } From c243801d4eca3d8dd0c88b431f38585a2ee9dd64 Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sun, 5 Apr 2026 19:53:49 +0800 Subject: [PATCH 07/10] update --- .../hmcl/ui/versions/ScriptFormatDialog.java | 94 ------------------- .../resources/assets/lang/I18N.properties | 6 -- .../resources/assets/lang/I18N_zh.properties | 6 -- .../assets/lang/I18N_zh_CN.properties | 6 -- 4 files changed, 112 deletions(-) delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java deleted file mode 100644 index a29de56af0..0000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ScriptFormatDialog.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2026 huangyuhui 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 . - */ -package org.jackhuang.hmcl.ui.versions; - -import javafx.geometry.Insets; -import javafx.scene.control.Label; -import javafx.scene.layout.VBox; -import org.jackhuang.hmcl.ui.construct.ComponentList; -import org.jackhuang.hmcl.ui.construct.DialogPane; -import org.jackhuang.hmcl.ui.construct.LineSelectButton; -import org.jackhuang.hmcl.ui.construct.LineToggleButton; -import org.jackhuang.hmcl.util.platform.OperatingSystem; - -import java.util.concurrent.CompletableFuture; - -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; - -public class ScriptFormatDialog extends DialogPane { - - public record Result(String format, boolean appendSuffix) {} - - private final CompletableFuture future = new CompletableFuture<>(); - private final LineSelectButton formatSelectButton; - private final LineToggleButton appendSuffixToggle; - - public ScriptFormatDialog(String unsupportedExtension) { - String title = unsupportedExtension.isEmpty() - ? i18n("version.launch_script.unsupported.title.no_ext") - : i18n("version.launch_script.unsupported.title"); - setTitle(title); - - String message = unsupportedExtension.isEmpty() - ? i18n("version.launch_script.unsupported.message.no_ext") - : i18n("version.launch_script.unsupported.message", unsupportedExtension); - Label messageLabel = new Label(message); - messageLabel.setWrapText(true); - messageLabel.setPadding(new Insets(0, 0, 10, 0)); - - formatSelectButton = new LineSelectButton<>(); - formatSelectButton.setTitle(i18n("version.launch_script.select_type")); - formatSelectButton.setConverter(item -> item); - formatSelectButton.setItems(getAvailableFormats()); - formatSelectButton.setValue(getAvailableFormats()[0]); - - appendSuffixToggle = new LineToggleButton(); - appendSuffixToggle.setTitle(i18n("version.launch_script.append_suffix")); - appendSuffixToggle.setSelected(true); - - ComponentList content = new ComponentList(); - content.getContent().addAll(formatSelectButton, appendSuffixToggle); - - setBody(new VBox(messageLabel, content)); - } - - @Override - protected void onAccept() { - String format = formatSelectButton.getValue(); - if (format != null) { - future.complete(new Result(format, appendSuffixToggle.isSelected())); - } - super.onAccept(); - } - - @Override - protected void onCancel() { - future.cancel(false); - super.onCancel(); - } - - private String[] getAvailableFormats() { - return OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS - ? new String[]{i18n("extension.bat"), i18n("extension.ps1")} - : new String[]{i18n("extension.sh"), i18n("extension.ps1")}; - } - - public CompletableFuture getCompletableFuture() { - return future; - } -} diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 28266b3d8e..cc67b62d3a 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -1650,12 +1650,6 @@ version.launch_script=Export Launch Script version.launch_script.failed=Failed to export launch script. version.launch_script.save=Export Launch Script version.launch_script.success=Exported launch script as %s. -version.launch_script.unsupported.title=Unsupported File Type -version.launch_script.unsupported.title.no_ext=No File Extension -version.launch_script.unsupported.message=The file extension "%s" is not recognized. Please select a valid script format: -version.launch_script.unsupported.message.no_ext=The file has no extension. Please select a valid script format: -version.launch_script.select_type=Script Format -version.launch_script.append_suffix=Append file extension version.manage=All Instances version.manage.clean=Delete Log Files version.manage.clean.tooltip=Delete the files in "logs" and "crash-reports" directories. diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 4589d0990c..da02e13533 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -1431,12 +1431,6 @@ version.launch_script=生成啟動指令碼 version.launch_script.failed=生成啟動指令碼失敗 version.launch_script.save=儲存啟動指令碼 version.launch_script.success=啟動指令碼已生成完畢: %s -version.launch_script.unsupported.title=不支援的檔案類型 -version.launch_script.unsupported.title.no_ext=檔案沒有副檔名 -version.launch_script.unsupported.message=無法識別檔案副檔名"%s",請選擇有效的指令碼格式: -version.launch_script.unsupported.message.no_ext=檔案沒有副檔名,請選擇有效的指令碼格式: -version.launch_script.select_type=指令碼格式 -version.launch_script.append_suffix=新增檔案副檔名 version.manage=實例清單 version.manage.clean=清理遊戲目錄 version.manage.clean.tooltip=清理「logs」與「crash-reports」目錄 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 44bac214e2..c53c6f3aa2 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1436,12 +1436,6 @@ version.launch_script=生成启动脚本 version.launch_script.failed=生成启动脚本失败 version.launch_script.save=保存启动脚本 version.launch_script.success=启动脚本已生成完毕:%s -version.launch_script.unsupported.title=不支持的文件类型 -version.launch_script.unsupported.title.no_ext=文件没有扩展名 -version.launch_script.unsupported.message=无法识别文件扩展名"%s",请选择有效的脚本格式: -version.launch_script.unsupported.message.no_ext=文件没有扩展名,请选择有效的脚本格式: -version.launch_script.select_type=脚本格式 -version.launch_script.append_suffix=添加文件扩展名 version.manage=实例列表 version.manage.clean=清理游戏文件夹 version.manage.clean.tooltip=清理“logs”和“crash-reports”文件夹 From 3e915c9b0aedeedc1fa49516a7b1106222dc4eaf Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sun, 5 Apr 2026 20:00:21 +0800 Subject: [PATCH 08/10] update --- .../main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index f5896914cf..66d7d6898d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -646,8 +646,8 @@ public void makeLaunchScript(Path scriptFile) throws IOException { if (!usePowerShell) { if (isWindows && !scriptExtension.equals("bat")) throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'bat' or 'ps1' in Windows"); - else if (!isWindows && !(scriptExtension.equals("sh") || scriptExtension.equals("command"))) - throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'sh', 'ps1' or 'command' in macOS/Linux"); + else if (!isWindows && !(scriptExtension.equals("sh") || scriptExtension.equals("command") || scriptExtension.equals("bash"))) + throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'sh', 'bash', 'ps1' or 'command' in macOS/Linux"); } final Command commandLine = generateCommandLine(nativeFolder); From 43bc45a1c4c1663ddd595d6001dd97001866caec Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sun, 5 Apr 2026 20:55:23 +0800 Subject: [PATCH 09/10] update --- .../jackhuang/hmcl/ui/versions/Versions.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java index 507afc9057..38efc5a0c3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java @@ -264,22 +264,27 @@ public static void generateLaunchScript(Profile profile, String id, Consumer injecter : injecters) { injecter.accept(launcherHelper); } - try { - launcherHelper.makeLaunchScript(file); - } catch (IllegalArgumentException e) { - Path withExtFile; - String defaultExt = getDefaultScriptExtension(); - withExtFile = file.resolveSibling(file.getFileName().toString() + "." + defaultExt); - launcherHelper.makeLaunchScript(withExtFile); - } + launcherHelper.makeLaunchScript(file); } }); } + private static boolean isValidScriptExtension(String ext) { + if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { + return ext.equals("bat") || ext.equals("ps1"); + } + return ext.equals("sh") || ext.equals("bash") || ext.equals("command") || ext.equals("ps1"); + } + private static String getDefaultScriptExtension() { return switch (OperatingSystem.CURRENT_OS) { case WINDOWS -> "bat"; From a448248b04d3d6fab00124d8ac4fb260f3e27335 Mon Sep 17 00:00:00 2001 From: Damon Lu <59256766+WhatDamon@users.noreply.github.com> Date: Sun, 5 Apr 2026 22:43:30 +0800 Subject: [PATCH 10/10] update --- .../main/java/org/jackhuang/hmcl/ui/versions/Versions.java | 4 ++-- .../main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java index 38efc5a0c3..1c9c79a078 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java @@ -280,9 +280,9 @@ public static void generateLaunchScript(Profile profile, String id, Consumer