From 7c024473d624d47604afc4d2d40366f48503fc31 Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Mon, 15 Sep 2025 23:06:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=96=E7=95=8C=E7=AE=A1=E7=90=86=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=88=A0=E9=99=A4=E4=B8=96=E7=95=8C=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=20(#4263)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com> Co-authored-by: Glavo --- .../hmcl/ui/versions/WorldBackupsPage.java | 2 +- .../hmcl/ui/versions/WorldListItem.java | 27 ++++++++++++++++++- .../hmcl/ui/versions/WorldListItemSkin.java | 1 + .../hmcl/ui/versions/WorldListPage.java | 16 +++++++---- .../resources/assets/lang/I18N.properties | 4 ++- .../resources/assets/lang/I18N_es.properties | 4 ++- .../resources/assets/lang/I18N_ja.properties | 2 ++ .../resources/assets/lang/I18N_lzh.properties | 2 ++ .../resources/assets/lang/I18N_ru.properties | 4 ++- .../resources/assets/lang/I18N_uk.properties | 4 ++- .../resources/assets/lang/I18N_zh.properties | 4 ++- .../assets/lang/I18N_zh_CN.properties | 4 ++- .../java/org/jackhuang/hmcl/game/World.java | 7 +++++ 13 files changed, 68 insertions(+), 13 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldBackupsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldBackupsPage.java index c66d35886..586495d1a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldBackupsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldBackupsPage.java @@ -147,7 +147,7 @@ public final class WorldBackupsPage extends ListPageBase new WorldExportPage(world, file.toPath(), controller::onFinish))); } + public void delete() { + Controllers.confirm( + i18n("button.remove.confirm"), + i18n("world.delete"), + () -> Task.runAsync(world::delete) + .whenComplete(Schedulers.javafx(), (result, exception) -> { + if (exception == null) { + parent.remove(this); + } else if (exception instanceof WorldLockedException) { + Controllers.dialog(i18n("world.locked.failed"), null, MessageType.WARNING); + } else { + Controllers.dialog(i18n("world.delete.failed", StringUtils.getStackTrace(exception)), null, MessageType.WARNING); + } + }).start(), + null + ); + } + public void reveal() { FXUtils.openFolder(world.getFile().toFile()); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListItemSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListItemSkin.java index 3551c5ae4..89b8006b5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListItemSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListItemSkin.java @@ -136,6 +136,7 @@ public final class WorldListItemSkin extends SkinBase { popupMenu.getContent().addAll( new MenuSeparator(), new IconedMenuItem(SVG.OUTPUT, i18n("world.export"), item::export, popup), + new IconedMenuItem(SVG.DELETE, i18n("world.delete"), item::delete, popup), new IconedMenuItem(SVG.FOLDER_OPEN, i18n("folder.world"), item::reveal, popup)); JFXPopup.PopupVPosition vPosition = determineOptimalPopupPosition(root, popup); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListPage.java index fc82b8dde..161107555 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListPage.java @@ -39,8 +39,8 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; public final class WorldListPage extends ListPageBase implements VersionPage.VersionLoadable { private final BooleanProperty showAll = new SimpleBooleanProperty(this, "showAll", false); @@ -61,7 +61,7 @@ public final class WorldListPage extends ListPageBase implements if (worlds != null) itemsProperty().setAll(worlds.stream() .filter(world -> isShowAll() || world.getGameVersion() == null || world.getGameVersion().equals(gameVersion)) - .map(world -> new WorldListItem(world, backupsDir)).collect(Collectors.toList())); + .map(world -> new WorldListItem(this, world, backupsDir)).toList()); }); } @@ -79,6 +79,10 @@ public final class WorldListPage extends ListPageBase implements refresh(); } + public void remove(WorldListItem item) { + itemsProperty().remove(item); + } + public void refresh() { if (profile == null || id == null) return; @@ -94,8 +98,10 @@ public final class WorldListPage extends ListPageBase implements worlds = result; setLoading(false); if (exception == null) { - itemsProperty().setAll(result.stream().filter(world -> isShowAll() || world.getGameVersion() == null || world.getGameVersion().equals(gameVersion)) - .map(world -> new WorldListItem(world, backupsDir)).collect(Collectors.toList())); + itemsProperty().setAll(result.stream() + .filter(world -> isShowAll() || world.getGameVersion() == null || world.getGameVersion().equals(gameVersion)) + .map(world -> new WorldListItem(this, world, backupsDir)) + .collect(Collectors.toList())); } else { LOG.warning("Failed to load world list page", exception); } @@ -125,7 +131,7 @@ public final class WorldListPage extends ListPageBase implements Controllers.prompt(i18n("world.name.enter"), (name, resolve, reject) -> { Task.runAsync(() -> world.install(savesDir, name)) .whenComplete(Schedulers.javafx(), () -> { - itemsProperty().add(new WorldListItem(new World(savesDir.resolve(name)), backupsDir)); + itemsProperty().add(new WorldListItem(this, new World(savesDir.resolve(name)), backupsDir)); resolve.run(); }, e -> { if (e instanceof FileAlreadyExistsException) diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 74b875480..2f2e7ae7d 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -1113,7 +1113,6 @@ world.add=Add World world.backup=World Backup world.backup.create.new_one=Create New Backup world.backup.create.failed=Failed to create backup.\n%s -world.backup.create.locked=The world is currently in use. Please close the game and try again. world.backup.create.success=Successfully created a new backup: %s world.backup.delete=Delete this backup world.backup.processing=Backing up ... @@ -1124,6 +1123,8 @@ world.chunkbase.stronghold=Stronghold world.chunkbase.nether_fortress=Nether Fortress world.datapack=Datapacks world.datetime=Last played on %s +world.delete=Delete the World +world.delete.failed=Failed to delete world.\n%s world.download=Download World world.download.title=Download World - %1s world.export=Export the World @@ -1167,6 +1168,7 @@ world.info.random_seed=Seed world.info.time=Game Time world.info.time.format=%s days world.locked=In use +world.locked.failed=The world is currently in use. Please close the game and try again. world.manage=Worlds world.manage.button=World Management world.manage.title=World - %s diff --git a/HMCL/src/main/resources/assets/lang/I18N_es.properties b/HMCL/src/main/resources/assets/lang/I18N_es.properties index e2b3a4c36..ee0700dc7 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_es.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_es.properties @@ -1113,7 +1113,6 @@ world.add=Añadir mundo world.backup=Copia de seguridad world.backup.create.new_one=Crear uno nuevo world.backup.create.failed=No se ha podido crear la copia de seguridad.\n%s -world.backup.create.locked=El mundo está actualmente en uso. Por favor, cierra el juego e inténtalo de nuevo. world.backup.create.success=Creada con éxito una nueva copia de seguridad: %s world.backup.delete=Eliminar esta copia de seguridad world.backup.processing=Creando nueva copia de seguridad ... @@ -1124,6 +1123,8 @@ world.chunkbase.stronghold=Fortaleza world.chunkbase.nether_fortress=Fortaleza del Nether world.datapack=Paquetes de datos world.datetime=Jugado por última vez en %s +world.delete=Eliminar este mundo +world.delete.failed=No se pudo eliminar el mundo.\n%s world.download=Descargar Mundo world.download.title=Descargar mundo - %1s world.export=Exportar el mundo @@ -1166,6 +1167,7 @@ world.info.random_seed=Semilla world.info.time=Tiempo de juego world.info.time.format=%s días world.locked=En uso +world.locked.failed=El mundo está actualmente en uso. Por favor, cierra el juego e inténtalo de nuevo. world.manage=Mundos world.manage.button=Administrar world.manage.title=Mundo - %s diff --git a/HMCL/src/main/resources/assets/lang/I18N_ja.properties b/HMCL/src/main/resources/assets/lang/I18N_ja.properties index 863c6d2ab..e5c9e5e78 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ja.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ja.properties @@ -705,6 +705,8 @@ world=マップ world.add=マップを追加(.zip) world.datapack=データパックの管理 world.datetime=最終ゲーム時刻:%s +world.delete=このマップを削除 +world.delete.failed=マップの削除に失敗しました\n%s world.download=ダウンロード world.export=このマップをエクスポートする world.export.title=保存する場所を選択してください diff --git a/HMCL/src/main/resources/assets/lang/I18N_lzh.properties b/HMCL/src/main/resources/assets/lang/I18N_lzh.properties index 074580aa7..b117bf296 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_lzh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_lzh.properties @@ -929,6 +929,8 @@ world.chunkbase.stronghold=要塞輿圖 world.chunkbase.nether_fortress=焱界府輿圖 world.datapack=司錄囊 world.datetime=前戲之時辰: %s +world.delete=刪斯生界 +world.delete.failed=刪斯生界未成\n%s world.download=引生界 world.download.title=引生界 - %1s world.export=錄出生界 diff --git a/HMCL/src/main/resources/assets/lang/I18N_ru.properties b/HMCL/src/main/resources/assets/lang/I18N_ru.properties index 7414c65ea..310a52a46 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ru.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ru.properties @@ -1112,7 +1112,6 @@ world.add=Добавить мир world.backup=Резервный мир world.backup.create.new_one=Создать новый world.backup.create.failed=Не удалось создать резервную копию.\n%s -world.backup.create.locked=В настоящее время мир находится в эксплуатации. Закройте игру и попробуйте снова. world.backup.create.success=Успешно создано новое резервное копирование: %s world.backup.delete=Удалить эту резервную копию world.backup.processing=Создание новой резервной копии ... @@ -1121,6 +1120,8 @@ world.chunkbase.end_city=Город Края world.chunkbase.seed_map=Предпросмотр генерации мира world.chunkbase.stronghold=Крепость world.chunkbase.nether_fortress=Крепость Нижнего мира +world.delete=Удалить этот мир +world.delete.failed=Не удалось удалить мир.\n%s world.datapack=Наборы данных world.datetime=Последний запуск игры %s world.download=Скачать мир @@ -1165,6 +1166,7 @@ world.info.random_seed=Ключ генератора мира world.info.time=Время игры world.info.time.format=%s дн. world.locked=В эксплуатации +world.locked.failed=В настоящее время мир находится в эксплуатации. Закройте игру и попробуйте снова. world.manage=Миры world.manage.button=Управлять world.manage.title=Мир - %s diff --git a/HMCL/src/main/resources/assets/lang/I18N_uk.properties b/HMCL/src/main/resources/assets/lang/I18N_uk.properties index 3ac4af45d..bf2a920e3 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_uk.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_uk.properties @@ -1053,7 +1053,6 @@ world.add=Додати світ world.backup=Резервне копіювання світу world.backup.create.new_one=Створити нову резервну копію world.backup.create.failed=Не вдалося створити резервну копію. \n%s -world.backup.create.locked=Світ наразі використовується. Закрийте гру та спробуйте знову. world.backup.create.success=Успішно створено нову резервну копію: %s world.backup.delete=Видалити цю резервну копію world.backup.processing=Резервне копіювання ... @@ -1064,6 +1063,8 @@ world.chunkbase.stronghold=Фортеця world.chunkbase.nether_fortress=Форт Незеру world.datapack=Datapacks world.datetime=Останній раз грали %s +world.delete=Видалити цей світ +world.delete.failed=Не вдалося видалити світ.\n%s world.download=Завантажити світ world.download.title=Завантажити світ - %1s world.export=Експортувати світ @@ -1107,6 +1108,7 @@ world.info.random_seed=Насіння world.info.time=Час гри world.info.time.format=%s днів world.locked=Використовується +world.locked.failed=Світ наразі використовується. Закрийте гру та спробуйте знову. world.manage=Світи world.manage.button=Керування світами world.manage.title=Світ - %s diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index df3bb58a5..215c21257 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -910,7 +910,6 @@ world.add=新增世界 world.backup=世界備份 world.backup.create.new_one=建立新備份 world.backup.create.failed=建立備份失敗。\n%s -world.backup.create.locked=該世界正在使用中,請關閉遊戲後重試。 world.backup.create.success=成功建立新備份:%s world.backup.delete=刪除此備份 world.backup.processing=正在備份中…… @@ -921,6 +920,8 @@ world.chunkbase.stronghold=要塞地圖 world.chunkbase.nether_fortress=地獄要塞地圖 world.datapack=資料包管理 world.datetime=上一次遊戲時間: %s +world.delete=刪除此世界 +world.delete.failed=刪除世界失敗。\n%s world.download=下載世界 world.download.title=世界下載 - %1s world.export=匯出此世界 @@ -963,6 +964,7 @@ world.info.random_seed=種子碼 world.info.time=遊戲內時間 world.info.time.format=%s 天 world.locked=使用中 +world.locked.failed=該世界正在使用中,請關閉遊戲後重試。 world.game_version=遊戲版本 world.manage=世界管理 world.manage.button=世界管理 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 a02189c66..21674164b 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -920,7 +920,6 @@ world.add=添加世界 world.backup=备份管理 world.backup.create.new_one=创建新备份 world.backup.create.failed=创建备份失败。\n%s -world.backup.create.locked=该世界正在使用中,请关闭游戏后重试。 world.backup.create.success=成功创建新备份:%s world.backup.delete=删除此备份 world.backup.processing=正在备份中…… @@ -931,6 +930,8 @@ world.chunkbase.stronghold=要塞地图 world.chunkbase.nether_fortress=下界要塞地图 world.datapack=数据包管理 world.datetime=上一次游戏时间: %s +world.delete=删除此世界 +world.delete.failed=删除世界失败。\n%s world.download=下载世界 world.download.title=世界下载 - %1s world.export=导出此世界 @@ -974,6 +975,7 @@ world.info.random_seed=种子 world.info.time=游戏内时间 world.info.time.format=%s 天 world.locked=使用中 +world.locked.failed=该世界正在使用中,请关闭游戏后重试。 world.manage=世界管理 world.manage.button=世界管理 world.manage.title=世界管理 - %s diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java index 92834744f..ae7fd12d7 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java @@ -275,6 +275,13 @@ public final class World { } } + public void delete() throws IOException { + if (isLocked()) { + throw new WorldLockedException("The world " + getFile() + " has been locked"); + } + FileUtils.deleteDirectory(file); + } + public CompoundTag readLevelDat() throws IOException { if (!Files.isDirectory(file)) throw new IOException("Not a valid world directory");