From a8b40c4ba05102a5f198514a19baace2b6a62729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+Ciilu@users.noreply.github.com> Date: Fri, 20 Mar 2026 23:28:59 +0800 Subject: [PATCH 01/10] update --- .../main/java/org/jackhuang/hmcl/ui/SVG.java | 1 + .../hmcl/ui/construct/MessageDialogPane.java | 15 +- .../hmcl/ui/versions/GameListPage.java | 11 +- .../jackhuang/hmcl/ui/versions/Versions.java | 151 ++++++++++++++++-- .../org/jackhuang/hmcl/util/i18n/I18n.java | 4 + .../hmcl/util/i18n/translator/Translator.java | 10 ++ .../resources/assets/lang/I18N.properties | 3 + .../resources/assets/lang/I18N_zh.properties | 3 + .../assets/lang/I18N_zh_CN.properties | 5 + 9 files changed, 182 insertions(+), 21 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java index c7a99881db..0f3ce1915a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java @@ -44,6 +44,7 @@ public enum SVG { CHECK("M9.55 18 3.85 12.3 5.275 10.875 9.55 15.15 18.725 5.975 20.15 7.4 9.55 18Z"), CHECKROOM("M3 20Q2.575 20 2.2875 19.7125T2 19Q2 18.75 2.1 18.5375T2.4 18.2L11 11.75V10Q11 9.575 11.3 9.2875T12.025 9Q12.65 9 13.075 8.55T13.5 7.475Q13.5 6.85 13.0625 6.425T12 6Q11.375 6 10.9375 6.4375T10.5 7.5H8.5Q8.5 6.05 9.525 5.025T12 4Q13.45 4 14.475 5.0125T15.5 7.475Q15.5 8.65 14.8125 9.575T13 10.85V11.75L21.6 18.2Q21.8 18.325 21.9 18.5375T22 19Q22 19.425 21.7125 19.7125T21 20H3ZM6 18H18L12 13.5 6 18Z"), CHECK_CIRCLE("M10.6 16.6 17.65 9.55 16.25 8.15 10.6 13.8 7.75 10.95 6.35 12.35 10.6 16.6ZM12 22Q9.925 22 8.1 21.2125T4.925 19.075Q3.575 17.725 2.7875 15.9T2 12Q2 9.925 2.7875 8.1T4.925 4.925Q6.275 3.575 8.1 2.7875T12 2Q14.075 2 15.9 2.7875T19.075 4.925Q20.425 6.275 21.2125 8.1T22 12Q22 14.075 21.2125 15.9T19.075 19.075Q17.725 20.425 15.9 21.2125T12 22ZM12 20Q15.35 20 17.675 17.675T20 12Q20 8.65 17.675 6.325T12 4Q8.65 4 6.325 6.325T4 12Q4 15.35 6.325 17.675T12 20ZM12 12Z"), + CLEAN("M3 23v-7q0-2.075 1.463-3.537T8 11h1V3q0-.825.588-1.412T11 1h2q.825 0 1.413.588T15 3v8h1q2.075 0 3.538 1.463T21 16v7zm2-2h2v-3q0-.425.288-.712T8 17t.713.288T9 18v3h2v-3q0-.425.288-.712T12 17t.713.288T13 18v3h2v-3q0-.425.288-.712T16 17t.713.288T17 18v3h2v-5q0-1.25-.875-2.125T16 13H8q-1.25 0-2.125.875T5 16zm8-10V3h-2v8zm0 0h-2z"), CLOSE("M6.4 19 5 17.6 10.6 12 5 6.4 6.4 5 12 10.6 17.6 5 19 6.4 13.4 12 19 17.6 17.6 19 12 13.4 6.4 19Z"), CONTENT_CUT("M19 21l-7-7-2.35 2.35q.2.375.275.8T10 18q0 1.65-1.175 2.825T6 22q-1.65 0-2.825-1.175T2 18t1.175-2.825T6 14q.425 0 .85.075t.8.275L10 12 7.65 9.65q-.375.2-.8.275T6 10q-1.65 0-2.825-1.175T2 6q0-1.65 1.175-2.825T6 2q1.65 0 2.825 1.175T10 6q0 .425-.075.85t-.275.8L22 20v1H19Zm-4-10-2-2 6-6h3v1l-7 7ZM7.4125 7.4125Q8 6.825 8 6t-.5875-1.4125Q6.825 4 6 4t-1.4125.5875Q4 5.175 4 6t.5875 1.4125T6 8t1.4125-.5875ZM12.35 12.35q.15-.15.15-.35t-.15-.35-.35-.15-.35.15-.15.35.15.35.35.15.35-.15ZM7.4125 19.4125Q8 18.825 8 18t-.5875-1.4125Q6.825 16 6 16t-1.4125.5875Q4 17.175 4 18t.5875 1.4125Q5.175 20 6 20t1.4125-.5875Z"), CONTENT_COPY("M9 18Q8.175 18 7.5875 17.4125T7 16V4Q7 3.175 7.5875 2.5875T9 2H18Q18.825 2 19.4125 2.5875T20 4V16Q20 16.825 19.4125 17.4125T18 18H9ZM9 16H18V4H9V16ZM5 22Q4.175 22 3.5875 21.4125T3 20V6H5V20H16V22H5ZM9 16V4 16Z"), diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageDialogPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageDialogPane.java index 2bed442a5f..7cd2c51692 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageDialogPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageDialogPane.java @@ -64,6 +64,7 @@ public String getDisplayName() { } private final HBox actions; + private final EnhancedTextFlow textFlow; private @Nullable ButtonBase cancelButton; @@ -87,7 +88,7 @@ public MessageDialogPane(@NotNull String text, @Nullable String title, @NotNull StackPane content = new StackPane(); content.getStyleClass().add("jfx-layout-body"); - EnhancedTextFlow textFlow = new EnhancedTextFlow(text); + textFlow = new EnhancedTextFlow(text); textFlow.setStyle("-fx-font-size: 14px;"); if (textFlow.computePrefHeight(400.0) <= 350.0) content.getChildren().setAll(textFlow); @@ -115,6 +116,10 @@ public MessageDialogPane(@NotNull String text, @Nullable String title, @NotNull }); } + public void setText(String text) { + textFlow.setText(text); + } + public void addButton(Node btn) { btn.addEventHandler(ActionEvent.ACTION, e -> fireEvent(new DialogCloseEvent())); actions.getChildren().add(btn); @@ -130,7 +135,13 @@ public ButtonBase getCancelButton() { private static final class EnhancedTextFlow extends TextFlow { EnhancedTextFlow(String text) { - this.getChildren().setAll(FXUtils.parseSegment(text, Controllers::onHyperlinkAction)); + setText(text); + } + + public void setText(String newText) { + this.getChildren().setAll( + FXUtils.parseSegment(newText, Controllers::onHyperlinkAction) + ); } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java index cd8aede005..5eab5b0128 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java @@ -34,7 +34,10 @@ import javafx.scene.control.SkinBase; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; -import javafx.scene.layout.*; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; import javafx.util.Duration; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profiles; @@ -187,6 +190,10 @@ public void refreshList() { Profiles.getSelectedProfile().getRepository().refreshVersionsAsync().start(); } + public void clean() { + Versions.cleanGameFiles(Profiles.getSelectedProfile()); + } + @Override protected Skin createDefaultSkin() { return new GameListSkin(this); @@ -237,7 +244,7 @@ public GameListSkin(GameList skinnable) { searchBar.getChildren().setAll(searchField, closeSearchBar); - toolbarNormal.getChildren().setAll(createToolbarButton2(i18n("button.refresh"), SVG.REFRESH, skinnable::refreshList), createToolbarButton2(i18n("search"), SVG.SEARCH, () -> changeToolbar(searchBar))); + toolbarNormal.getChildren().setAll(createToolbarButton2(i18n("button.refresh"), SVG.REFRESH, skinnable::refreshList), createToolbarButton2(i18n("search"), SVG.SEARCH, () -> changeToolbar(searchBar)), createToolbarButton2(i18n("game.clean"), SVG.CLEAN, skinnable::clean)); toolbarPane.setContent(toolbarNormal, ContainerAnimations.FADE); 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 ae72ab4854..b3614a41c8 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 @@ -18,7 +18,9 @@ package org.jackhuang.hmcl.ui.versions; import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXSpinner; import javafx.application.Platform; +import javafx.scene.layout.StackPane; import javafx.stage.FileChooser; import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount; @@ -42,6 +44,7 @@ import org.jackhuang.hmcl.ui.export.ExportWizardProvider; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.TaskCancellationAction; +import org.jackhuang.hmcl.util.i18n.I18n; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.OperatingSystem; @@ -49,10 +52,14 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.logging.Logger.LOG; @@ -131,23 +138,23 @@ public static void deleteVersion(Profile profile, String version) { public static CompletableFuture renameVersion(Profile profile, String version) { return Controllers.prompt(i18n("version.manage.rename.message"), (newName, handler) -> { - if (newName.equals(version)) { - handler.resolve(); - return; - } - if (profile.getRepository().renameVersion(version, newName)) { - handler.resolve(); - profile.getRepository().refreshVersionsAsync() - .thenRunAsync(Schedulers.javafx(), () -> { - if (profile.getRepository().hasVersion(newName)) { - profile.setSelectedVersion(newName); - } - }).start(); - } else { - handler.reject(i18n("version.manage.rename.fail")); - } - }, version, new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId), - new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName) || newVersionName.equals(version))); + if (newName.equals(version)) { + handler.resolve(); + return; + } + if (profile.getRepository().renameVersion(version, newName)) { + handler.resolve(); + profile.getRepository().refreshVersionsAsync() + .thenRunAsync(Schedulers.javafx(), () -> { + if (profile.getRepository().hasVersion(newName)) { + profile.setSelectedVersion(newName); + } + }).start(); + } else { + handler.reject(i18n("version.manage.rename.fail")); + } + }, version, new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId), + new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName) || newVersionName.equals(version))); } public static void exportVersion(Profile profile, String version) { @@ -194,6 +201,116 @@ public static void updateGameAssets(Profile profile, String version) { executor.start(); } + public static void cleanGameFiles(Profile profile) { + var dialogBuilder = new MessageDialogPane.Builder(i18n("game.clean.content", "..."), i18n("message.question"), MessageDialogPane.MessageType.QUESTION); + var spinner = new JFXSpinner(); + spinner.getStyleClass().add("small-spinner"); + + StackPane buttonPane = new StackPane(); + + JFXButton okButton = new JFXButton(i18n("button.yes")); + okButton.getStyleClass().add("dialog-accept"); + + dialogBuilder.addAction(buttonPane); + dialogBuilder.addCancel(null); + + var dialog = dialogBuilder.build(); + + Task.supplyAsync(() -> { + var repository = profile.getRepository(); + var versions = repository.getVersions(); + + Set activeAssets = versions.parallelStream() + .flatMap(version -> { + try { + var index = repository.getAssetIndex(version.getId(), version.getAssetIndex().getId()); + return index.getObjects().values().stream().map(AssetObject::getLocation); + } catch (IOException ignored) { + return Stream.empty(); + } + }) + .collect(Collectors.toSet()); + + Set activeLibraries = versions.parallelStream() + .flatMap(version -> version.getLibraries().stream()) + .map(Library::getPath) + .collect(Collectors.toSet()); + List junkFiles = new ArrayList<>(); + + Path assetsDir = repository.getBaseDirectory().resolve("assets").resolve("objects"); + + junkFiles.addAll(findUnlistedFiles(assetsDir, activeAssets)); + + Path libsDir = repository.getBaseDirectory().resolve("libraries"); + junkFiles.addAll(findUnlistedFiles(libsDir, activeLibraries)); + + List logsAndCrashes = new ArrayList<>(); + logsAndCrashes.add(repository.getBaseDirectory().resolve("logs")); + logsAndCrashes.add(repository.getBaseDirectory().resolve("crash-reports")); + versions.forEach(v -> { + logsAndCrashes.add(repository.getVersionRoot(v.getId()).resolve("logs")); + logsAndCrashes.add(repository.getVersionRoot(v.getId()).resolve("crash-reports")); + }); + + for (Path dir : logsAndCrashes) { + if (Files.exists(dir)) { + try (var s = Files.walk(dir)) { + s.filter(Files::isRegularFile).forEach(junkFiles::add); + } catch (IOException ignored) { + } + } + } + + return junkFiles; + }).thenApplyAsync((list) -> { + long totalSize = list.stream() + .mapToLong(path -> { + try { + return Files.size(path); + } catch (IOException e) { + return 0L; + } + }) + .sum(); + + FXUtils.runInFX(() -> { + dialog.setText(i18n("game.clean.content", I18n.formatSize(totalSize))); + buttonPane.getChildren().setAll(okButton); + okButton.setOnAction(event -> { + buttonPane.getChildren().setAll(spinner); + Task.runAsync(() -> list.forEach(path -> { + try { + Files.deleteIfExists(path); + } catch (IOException ignored) { + } + })).thenRunAsync(Schedulers.javafx(), () -> { + dialog.fireEvent(new DialogCloseEvent()); + }).start(); + }); + }); + return null; + }).start(); + + buttonPane.getChildren().setAll(spinner); + + Controllers.dialog(dialog); + } + + private static List findUnlistedFiles(Path root, Set activePaths) { + if (!Files.exists(root)) return List.of(); + try (var stream = Files.walk(root)) { + return stream + .filter(Files::isRegularFile) + .filter(path -> { + String relative = root.relativize(path).toString(); + return !activePaths.contains(relative); + }) + .toList(); + } catch (IOException e) { + return List.of(); + } + } + public static void cleanVersion(Profile profile, String id) { try { profile.getRepository().clean(id); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/I18n.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/I18n.java index 286910be07..5c4db97ffc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/I18n.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/I18n.java @@ -77,6 +77,10 @@ public static String formatSpeed(long bytes) { return getTranslator().formatSpeed(bytes); } + public static String formatSize(long bytes) { + return getTranslator().formatSize(bytes); + } + public static String getDisplayVersion(RemoteVersion version) { return getTranslator().getDisplayVersion(version); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java index 7bdcfc8038..a55a5fc24a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java @@ -73,4 +73,14 @@ public String formatSpeed(long bytes) { return supportedLocale.i18n("download.speed.megabyte_per_second", (double) bytes / (1024 * 1024)); } } + + public String formatSize(long bytes) { + if (bytes < 1024) { + return supportedLocale.i18n("download.size.byte", bytes); + } else if (bytes < 1024 * 1024) { + return supportedLocale.i18n("download.size.kibibyte", (double) bytes / 1024); + } else { + return supportedLocale.i18n("download.size.megabyte", (double) bytes / (1024 * 1024)); + } + } } diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 174b7a1f41..49274d1921 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -379,6 +379,9 @@ download.javafx.notes=We are currently downloading dependencies for HMCL from th Note: If your download speed is too slow, you can try switching to another mirror. download.javafx.component=Downloading module "%s" download.javafx.prepare=Preparing to download +download.size.byte=%d B +download.speed.kibibyte=%.1f KiB +download.speed.megabyte=%.1f MiB download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 96f7df20b1..0d9bf3793d 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -372,6 +372,9 @@ download.javafx=正在下載必要的執行時元件 download.javafx.notes=正在透過網路下載 HMCL 必要的執行時元件。\n點擊「切換下載源」按鈕查看詳情以及選取下載源。點擊「取消」按鈕停止並退出。\n注意:如果下載速度過慢,請嘗試切換下載源。 download.javafx.component=正在下載元件「%s」 download.javafx.prepare=準備開始下載 +download.size.byte=%d B +download.speed.kibibyte=%.1f KiB +download.speed.megabyte=%.1f MiB download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s 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 2d306511af..98e89d2706 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -374,6 +374,9 @@ download.javafx=正在下载必要的运行时组件…… download.javafx.notes=正在通过网络下载 HMCL 必要的运行时组件。\n点击“切换下载源”按钮查看详情以及选择下载源。点击“取消”按钮停止并退出。\n注意:若下载速度过慢,请尝试切换下载源。 download.javafx.component=正在下载模块“%s” download.javafx.prepare=准备开始下载 +download.size.byte=%d B +download.size.kibibyte=%.1f KiB +download.size.megabyte=%.1f MiB download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s @@ -437,6 +440,8 @@ folder.screenshots=截图文件夹 folder.world=世界文件夹 game=游戏 +game.clean=清理游戏文件 +game.clean.content=本操作将会清理游戏的日志、冗余库、冗余资源等文件,预计释放 %s 空间。\n你的模组、存档等游戏数据不会受到影响。是否继续操作? game.crash.feedback=请不要将本界面截图或拍照给他人!如果你要向他人求助,请你点击左下角“导出游戏崩溃信息”后将导出的文件发送给他人以供分析。\n你可以点击下方的“帮助”前往交流群寻求帮助。 game.crash.info=游戏信息 game.crash.reason=崩溃原因 From d60bb2efc3d3609948f8d0a3995e127e9d5aec09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+Ciilu@users.noreply.github.com> Date: Fri, 20 Mar 2026 23:34:34 +0800 Subject: [PATCH 02/10] update --- .../jackhuang/hmcl/ui/versions/Versions.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 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 b3614a41c8..af339fcb92 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 @@ -138,23 +138,23 @@ public static void deleteVersion(Profile profile, String version) { public static CompletableFuture renameVersion(Profile profile, String version) { return Controllers.prompt(i18n("version.manage.rename.message"), (newName, handler) -> { - if (newName.equals(version)) { - handler.resolve(); - return; - } - if (profile.getRepository().renameVersion(version, newName)) { - handler.resolve(); - profile.getRepository().refreshVersionsAsync() - .thenRunAsync(Schedulers.javafx(), () -> { - if (profile.getRepository().hasVersion(newName)) { - profile.setSelectedVersion(newName); - } - }).start(); - } else { - handler.reject(i18n("version.manage.rename.fail")); - } - }, version, new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId), - new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName) || newVersionName.equals(version))); + if (newName.equals(version)) { + handler.resolve(); + return; + } + if (profile.getRepository().renameVersion(version, newName)) { + handler.resolve(); + profile.getRepository().refreshVersionsAsync() + .thenRunAsync(Schedulers.javafx(), () -> { + if (profile.getRepository().hasVersion(newName)) { + profile.setSelectedVersion(newName); + } + }).start(); + } else { + handler.reject(i18n("version.manage.rename.fail")); + } + }, version, new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId), + new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName) || newVersionName.equals(version))); } public static void exportVersion(Profile profile, String version) { From a29d193f63dbf485d01a9919ce0ea709d1970e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+Ciilu@users.noreply.github.com> Date: Fri, 20 Mar 2026 23:37:05 +0800 Subject: [PATCH 03/10] update --- HMCL/src/main/resources/assets/lang/I18N.properties | 4 ++-- HMCL/src/main/resources/assets/lang/I18N_zh.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 49274d1921..d0dc585bf0 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -380,8 +380,8 @@ download.javafx.notes=We are currently downloading dependencies for HMCL from th download.javafx.component=Downloading module "%s" download.javafx.prepare=Preparing to download download.size.byte=%d B -download.speed.kibibyte=%.1f KiB -download.speed.megabyte=%.1f MiB +download.size.kibibyte=%.1f KiB +download.size.megabyte=%.1f MiB download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 0d9bf3793d..df540ed798 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -373,8 +373,8 @@ download.javafx.notes=正在透過網路下載 HMCL 必要的執行時元件。\ download.javafx.component=正在下載元件「%s」 download.javafx.prepare=準備開始下載 download.size.byte=%d B -download.speed.kibibyte=%.1f KiB -download.speed.megabyte=%.1f MiB +download.size.kibibyte=%.1f KiB +download.size.megabyte=%.1f MiB download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s From dbdd6ff82f20c9512867a0316d0a196695d240aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+Ciilu@users.noreply.github.com> Date: Fri, 20 Mar 2026 23:40:56 +0800 Subject: [PATCH 04/10] update --- HMCL/src/main/resources/assets/lang/I18N.properties | 2 ++ HMCL/src/main/resources/assets/lang/I18N_zh.properties | 2 ++ 2 files changed, 4 insertions(+) diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index d0dc585bf0..70cfa44932 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -473,6 +473,8 @@ folder.screenshots=Screenshots folder.world=World Directory game=Games +game.clean=Clean Game Files +game.clean.content=This operation will clean up game logs, redundant libraries, redundant resource files, etc., freeing up approximately %s of space.\nYour mods, save files, and other game data will not be affected. Do you want to continue? game.crash.feedback=Please do not share screenshots or photos of this interface with others! If you ask for help from others, please click "Export Crash Logs" and send the exported file to others for analysis. game.crash.info=Crash Info game.crash.reason=Crash Cause diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index df540ed798..b2b190fd1e 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -436,6 +436,8 @@ folder.screenshots=截圖目錄 folder.world=世界目錄 game=遊戲 +game.clean=清理遊戲文件 +game.clean.content=本操作將會清理遊戲的日誌、冗餘庫、冗餘資源等文件,預計釋放 %s 空間。\n你的模組、存檔等遊戲數據不會受到影響。是否繼續操作? game.crash.feedback=請不要將本介面截圖或拍照給他人!如果你要求助他人,請你點擊左下角「匯出遊戲崩潰資訊」後將匯出的檔案發送給他人以供分析。\n你可以點擊下方的「幫助」前往社群尋求幫助。 game.crash.info=遊戲訊息 game.crash.reason=崩潰原因 From bca62ef8e84fe86c094db3fc6934447643179a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+Ciilu@users.noreply.github.com> Date: Sat, 21 Mar 2026 10:50:04 +0800 Subject: [PATCH 05/10] update --- .../jackhuang/hmcl/ui/versions/Versions.java | 27 +++++++++---------- .../hmcl/util/i18n/translator/Translator.java | 4 ++- .../resources/assets/lang/I18N.properties | 2 ++ .../resources/assets/lang/I18N_zh.properties | 2 ++ .../assets/lang/I18N_zh_CN.properties | 2 ++ 5 files changed, 21 insertions(+), 16 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 af339fcb92..abcb923e92 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 @@ -202,7 +202,7 @@ public static void updateGameAssets(Profile profile, String version) { } public static void cleanGameFiles(Profile profile) { - var dialogBuilder = new MessageDialogPane.Builder(i18n("game.clean.content", "..."), i18n("message.question"), MessageDialogPane.MessageType.QUESTION); + var dialogBuilder = new MessageDialogPane.Builder(i18n("game.clean.content", i18n("game.clean.loading")), i18n("message.question"), MessageDialogPane.MessageType.QUESTION); var spinner = new JFXSpinner(); spinner.getStyleClass().add("small-spinner"); @@ -235,33 +235,30 @@ public static void cleanGameFiles(Profile profile) { .flatMap(version -> version.getLibraries().stream()) .map(Library::getPath) .collect(Collectors.toSet()); - List junkFiles = new ArrayList<>(); - Path assetsDir = repository.getBaseDirectory().resolve("assets").resolve("objects"); + List unusedFiles = new ArrayList<>(); - junkFiles.addAll(findUnlistedFiles(assetsDir, activeAssets)); + unusedFiles.addAll(findUnlistedFiles(repository.getBaseDirectory().resolve("assets").resolve("objects"), activeAssets)); + unusedFiles.addAll(findUnlistedFiles(repository.getBaseDirectory().resolve("libraries"), activeLibraries)); - Path libsDir = repository.getBaseDirectory().resolve("libraries"); - junkFiles.addAll(findUnlistedFiles(libsDir, activeLibraries)); - - List logsAndCrashes = new ArrayList<>(); - logsAndCrashes.add(repository.getBaseDirectory().resolve("logs")); - logsAndCrashes.add(repository.getBaseDirectory().resolve("crash-reports")); + List unusedLogs = new ArrayList<>(); + unusedLogs.add(repository.getBaseDirectory().resolve("logs")); + unusedLogs.add(repository.getBaseDirectory().resolve("crash-reports")); versions.forEach(v -> { - logsAndCrashes.add(repository.getVersionRoot(v.getId()).resolve("logs")); - logsAndCrashes.add(repository.getVersionRoot(v.getId()).resolve("crash-reports")); + unusedLogs.add(repository.getVersionRoot(v.getId()).resolve("logs")); + unusedLogs.add(repository.getVersionRoot(v.getId()).resolve("crash-reports")); }); - for (Path dir : logsAndCrashes) { + for (Path dir : unusedLogs) { if (Files.exists(dir)) { try (var s = Files.walk(dir)) { - s.filter(Files::isRegularFile).forEach(junkFiles::add); + s.filter(Files::isRegularFile).forEach(unusedFiles::add); } catch (IOException ignored) { } } } - return junkFiles; + return unusedFiles; }).thenApplyAsync((list) -> { long totalSize = list.stream() .mapToLong(path -> { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java index a55a5fc24a..4299c9fb89 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java @@ -79,8 +79,10 @@ public String formatSize(long bytes) { return supportedLocale.i18n("download.size.byte", bytes); } else if (bytes < 1024 * 1024) { return supportedLocale.i18n("download.size.kibibyte", (double) bytes / 1024); - } else { + } else if (bytes < 1024 * 1024 * 1024){ return supportedLocale.i18n("download.size.megabyte", (double) bytes / (1024 * 1024)); + } else { + return supportedLocale.i18n("download.size.gibabyte", (double) bytes / (1024 * 1024 * 1024)); } } } diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 70cfa44932..0cbb51a14d 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -382,6 +382,7 @@ download.javafx.prepare=Preparing to download download.size.byte=%d B download.size.kibibyte=%.1f KiB download.size.megabyte=%.1f MiB +download.size.gibabyte=%.1f GiB download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s @@ -474,6 +475,7 @@ folder.world=World Directory game=Games game.clean=Clean Game Files +game.clean.loading=Loading... game.clean.content=This operation will clean up game logs, redundant libraries, redundant resource files, etc., freeing up approximately %s of space.\nYour mods, save files, and other game data will not be affected. Do you want to continue? game.crash.feedback=Please do not share screenshots or photos of this interface with others! If you ask for help from others, please click "Export Crash Logs" and send the exported file to others for analysis. game.crash.info=Crash Info diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index b2b190fd1e..ccc03792fd 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -375,6 +375,7 @@ download.javafx.prepare=準備開始下載 download.size.byte=%d B download.size.kibibyte=%.1f KiB download.size.megabyte=%.1f MiB +download.size.gibabyte=%.1f GiB download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s @@ -437,6 +438,7 @@ folder.world=世界目錄 game=遊戲 game.clean=清理遊戲文件 +game.clean.loading=统计中... game.clean.content=本操作將會清理遊戲的日誌、冗餘庫、冗餘資源等文件,預計釋放 %s 空間。\n你的模組、存檔等遊戲數據不會受到影響。是否繼續操作? game.crash.feedback=請不要將本介面截圖或拍照給他人!如果你要求助他人,請你點擊左下角「匯出遊戲崩潰資訊」後將匯出的檔案發送給他人以供分析。\n你可以點擊下方的「幫助」前往社群尋求幫助。 game.crash.info=遊戲訊息 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 98e89d2706..ca2eebdf12 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -377,6 +377,7 @@ download.javafx.prepare=准备开始下载 download.size.byte=%d B download.size.kibibyte=%.1f KiB download.size.megabyte=%.1f MiB +download.size.gibabyte=%.1f GiB download.speed.byte_per_second=%d B/s download.speed.kibibyte_per_second=%.1f KiB/s download.speed.megabyte_per_second=%.1f MiB/s @@ -441,6 +442,7 @@ folder.world=世界文件夹 game=游戏 game.clean=清理游戏文件 +game.clean.loading=统计中... game.clean.content=本操作将会清理游戏的日志、冗余库、冗余资源等文件,预计释放 %s 空间。\n你的模组、存档等游戏数据不会受到影响。是否继续操作? game.crash.feedback=请不要将本界面截图或拍照给他人!如果你要向他人求助,请你点击左下角“导出游戏崩溃信息”后将导出的文件发送给他人以供分析。\n你可以点击下方的“帮助”前往交流群寻求帮助。 game.crash.info=游戏信息 From 007a10325a299ad808684524bd658ee1e90d8649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+Ciilu@users.noreply.github.com> Date: Sat, 21 Mar 2026 10:51:34 +0800 Subject: [PATCH 06/10] update --- .../org/jackhuang/hmcl/util/i18n/translator/Translator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java index 4299c9fb89..82a7c201eb 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/translator/Translator.java @@ -79,7 +79,7 @@ public String formatSize(long bytes) { return supportedLocale.i18n("download.size.byte", bytes); } else if (bytes < 1024 * 1024) { return supportedLocale.i18n("download.size.kibibyte", (double) bytes / 1024); - } else if (bytes < 1024 * 1024 * 1024){ + } else if (bytes < 1024 * 1024 * 1024) { return supportedLocale.i18n("download.size.megabyte", (double) bytes / (1024 * 1024)); } else { return supportedLocale.i18n("download.size.gibabyte", (double) bytes / (1024 * 1024 * 1024)); From 7ed8f521da509d3a0c4898797c8f17bb38cc5cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+Ciilu@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:17:13 +0800 Subject: [PATCH 07/10] update --- .../jackhuang/hmcl/ui/versions/Versions.java | 62 ++++++++++++------- 1 file changed, 38 insertions(+), 24 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 abcb923e92..a0e4422250 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 @@ -138,23 +138,23 @@ public static void deleteVersion(Profile profile, String version) { public static CompletableFuture renameVersion(Profile profile, String version) { return Controllers.prompt(i18n("version.manage.rename.message"), (newName, handler) -> { - if (newName.equals(version)) { - handler.resolve(); - return; - } - if (profile.getRepository().renameVersion(version, newName)) { - handler.resolve(); - profile.getRepository().refreshVersionsAsync() - .thenRunAsync(Schedulers.javafx(), () -> { - if (profile.getRepository().hasVersion(newName)) { - profile.setSelectedVersion(newName); - } - }).start(); - } else { - handler.reject(i18n("version.manage.rename.fail")); - } - }, version, new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId), - new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName) || newVersionName.equals(version))); + if (newName.equals(version)) { + handler.resolve(); + return; + } + if (profile.getRepository().renameVersion(version, newName)) { + handler.resolve(); + profile.getRepository().refreshVersionsAsync() + .thenRunAsync(Schedulers.javafx(), () -> { + if (profile.getRepository().hasVersion(newName)) { + profile.setSelectedVersion(newName); + } + }).start(); + } else { + handler.reject(i18n("version.manage.rename.fail")); + } + }, version, new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId), + new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName) || newVersionName.equals(version))); } public static void exportVersion(Profile profile, String version) { @@ -241,15 +241,29 @@ public static void cleanGameFiles(Profile profile) { unusedFiles.addAll(findUnlistedFiles(repository.getBaseDirectory().resolve("assets").resolve("objects"), activeAssets)); unusedFiles.addAll(findUnlistedFiles(repository.getBaseDirectory().resolve("libraries"), activeLibraries)); - List unusedLogs = new ArrayList<>(); - unusedLogs.add(repository.getBaseDirectory().resolve("logs")); - unusedLogs.add(repository.getBaseDirectory().resolve("crash-reports")); + List unusedFolders = new ArrayList<>(); + + for (String path : List.of("logs", "crash-reports", "modernfix", "mods/.connector")) { + unusedFolders.add(repository.getBaseDirectory().resolve(path)); + versions.forEach(v -> { + unusedFolders.add(repository.getVersionRoot(v.getId()).resolve(path)); + }); + } + versions.forEach(v -> { - unusedLogs.add(repository.getVersionRoot(v.getId()).resolve("logs")); - unusedLogs.add(repository.getVersionRoot(v.getId()).resolve("crash-reports")); + try (var walker = Files.walk(repository.getVersionRoot(v.getId()), 1)) { + unusedFolders.addAll(walker + .filter(it -> { + var name = it.getFileName().toString(); + System.out.println(name); + System.out.println(Files.isDirectory(it) && (name.startsWith("natives-")) || name.endsWith("-natives")); + return Files.isDirectory(it) && (name.startsWith("natives-")) || name.endsWith("-natives"); + }).toList()); + } catch (IOException ignored) { + } }); - for (Path dir : unusedLogs) { + for (Path dir : unusedFolders) { if (Files.exists(dir)) { try (var s = Files.walk(dir)) { s.filter(Files::isRegularFile).forEach(unusedFiles::add); @@ -299,7 +313,7 @@ private static List findUnlistedFiles(Path root, Set activePaths) return stream .filter(Files::isRegularFile) .filter(path -> { - String relative = root.relativize(path).toString(); + String relative = root.relativize(path).toString().replace("\\", "/"); return !activePaths.contains(relative); }) .toList(); From 06dd28e2b14f0fd11f7a7a5479dc786d7b1211d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+Ciilu@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:18:28 +0800 Subject: [PATCH 08/10] update --- HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java | 2 -- 1 file changed, 2 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 a0e4422250..549d032261 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 @@ -255,8 +255,6 @@ public static void cleanGameFiles(Profile profile) { unusedFolders.addAll(walker .filter(it -> { var name = it.getFileName().toString(); - System.out.println(name); - System.out.println(Files.isDirectory(it) && (name.startsWith("natives-")) || name.endsWith("-natives")); return Files.isDirectory(it) && (name.startsWith("natives-")) || name.endsWith("-natives"); }).toList()); } catch (IOException ignored) { From 9cc49fb95d31c03d574f0762721d196b9ec6ab34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+Ciilu@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:24:15 +0800 Subject: [PATCH 09/10] update --- .../main/java/org/jackhuang/hmcl/ui/versions/Versions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 549d032261..95215bb4c5 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 @@ -243,7 +243,7 @@ public static void cleanGameFiles(Profile profile) { List unusedFolders = new ArrayList<>(); - for (String path : List.of("logs", "crash-reports", "modernfix", "mods/.connector")) { + for (String path : List.of("logs", "crash-reports", "modernfix", "mods/.connector", "CustomSkinLoader/caches", ".fabric")) { unusedFolders.add(repository.getBaseDirectory().resolve(path)); versions.forEach(v -> { unusedFolders.add(repository.getVersionRoot(v.getId()).resolve(path)); @@ -255,7 +255,7 @@ public static void cleanGameFiles(Profile profile) { unusedFolders.addAll(walker .filter(it -> { var name = it.getFileName().toString(); - return Files.isDirectory(it) && (name.startsWith("natives-")) || name.endsWith("-natives"); + return Files.isDirectory(it) && (name.startsWith("natives-") || name.endsWith("-natives")); }).toList()); } catch (IOException ignored) { } From 4bb530544ebe7bc5641005734af3dce4aea79a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+Ciilu@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:26:44 +0800 Subject: [PATCH 10/10] update --- .../jackhuang/hmcl/ui/versions/Versions.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 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 95215bb4c5..e19e90616d 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 @@ -138,23 +138,23 @@ public static void deleteVersion(Profile profile, String version) { public static CompletableFuture renameVersion(Profile profile, String version) { return Controllers.prompt(i18n("version.manage.rename.message"), (newName, handler) -> { - if (newName.equals(version)) { - handler.resolve(); - return; - } - if (profile.getRepository().renameVersion(version, newName)) { - handler.resolve(); - profile.getRepository().refreshVersionsAsync() - .thenRunAsync(Schedulers.javafx(), () -> { - if (profile.getRepository().hasVersion(newName)) { - profile.setSelectedVersion(newName); - } - }).start(); - } else { - handler.reject(i18n("version.manage.rename.fail")); - } - }, version, new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId), - new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName) || newVersionName.equals(version))); + if (newName.equals(version)) { + handler.resolve(); + return; + } + if (profile.getRepository().renameVersion(version, newName)) { + handler.resolve(); + profile.getRepository().refreshVersionsAsync() + .thenRunAsync(Schedulers.javafx(), () -> { + if (profile.getRepository().hasVersion(newName)) { + profile.setSelectedVersion(newName); + } + }).start(); + } else { + handler.reject(i18n("version.manage.rename.fail")); + } + }, version, new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId), + new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName) || newVersionName.equals(version))); } public static void exportVersion(Profile profile, String version) {