diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java index 4993bb7019..8b493eb3a0 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -99,9 +99,14 @@ public final class Controllers { GameListPage gameListPage = new GameListPage(); gameListPage.selectedProfileProperty().bindBidirectional(Profiles.selectedProfileProperty()); gameListPage.profilesProperty().bindContent(Profiles.profilesProperty()); - FXUtils.applyDragListener(gameListPage, ModpackHelper::isFileModpackByExtension, modpacks -> { - Path modpack = modpacks.get(0); - Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), modpack), i18n("install.modpack")); + FXUtils.applyDragListener(gameListPage, file -> ModpackHelper.isFileModpackByExtension(file) || "json".equalsIgnoreCase(FileUtils.getNameWithoutExtension(file)), files -> { + Path file = files.get(0); + + if (ModpackHelper.isFileModpackByExtension(file)) { + Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), file), i18n("install.modpack")); + } else if ("json".equalsIgnoreCase(FileUtils.getExtension(file))) { + Versions.installFromJson(Profiles.getSelectedProfile(), file); + } }); return gameListPage; }); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java index 32e7b24ca8..4875e75bd8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java @@ -54,6 +54,7 @@ import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.TaskCancellationAction; import org.jackhuang.hmcl.util.io.CompressingUtils; +import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.*; import org.jackhuang.hmcl.util.versioning.VersionNumber; @@ -98,7 +99,7 @@ public MainPage getMainPage() { if (mainPage == null) { MainPage mainPage = new MainPage(); FXUtils.applyDragListener(mainPage, - file -> ModpackHelper.isFileModpackByExtension(file) || NBTFileType.isNBTFileByExtension(file), + file -> ModpackHelper.isFileModpackByExtension(file) || NBTFileType.isNBTFileByExtension(file) || "json".equalsIgnoreCase(FileUtils.getExtension(file)), modpacks -> { Path file = modpacks.get(0); if (ModpackHelper.isFileModpackByExtension(file)) { @@ -113,6 +114,8 @@ public MainPage getMainPage() { Controllers.dialog(i18n("nbt.open.failed") + "\n\n" + StringUtils.getStackTrace(e), i18n("message.error"), MessageDialogPane.MessageType.ERROR); } + } else if ("json".equalsIgnoreCase(FileUtils.getExtension(file))) { + Versions.installFromJson(Profiles.getSelectedProfile(), 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 d3b561fa9c..7c126dd690 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 @@ -23,6 +23,7 @@ import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount; import org.jackhuang.hmcl.download.game.GameAssetDownloadTask; +import org.jackhuang.hmcl.download.game.GameDownloadTask; import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.mod.RemoteMod; import org.jackhuang.hmcl.setting.*; @@ -41,6 +42,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.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.platform.OperatingSystem; @@ -157,6 +159,41 @@ public static void openFolder(Profile profile, String version) { FXUtils.openFolder(profile.getRepository().getRunDirectory(version)); } + public static void installFromJson(Profile profile, Path file) { + Version version; + try { + version = profile.getRepository().readVersionJson(file); + } catch (Exception e) { + Controllers.dialog(i18n("install.new_game.malformed_json"), i18n("message.error"), MessageDialogPane.MessageType.ERROR); + return; + } + + Controllers.prompt(i18n("version.manage.duplicate.prompt"), (result, handler) -> { + var unnamedVersion = version.setId(result).setJar(result); + var gameDownloadTask = new GameDownloadTask(profile.getDependency(), null, unnamedVersion).whenComplete(Schedulers.javafx(), (exception) -> { + if (exception != null) { + handler.reject(StringUtils.getStackTrace(exception)); + } else { + profile.getRepository().refreshVersions(); + profile.setSelectedVersion(result); + handler.resolve(); + } + }); + Task.runAsync(() -> { + var dir = profile.getGameDir().resolve("versions"); + var versionDir = Files.createDirectory(dir.resolve(result)); + var jsonPath = versionDir.resolve(result + ".json"); + + JsonUtils.writeToJsonFile(jsonPath, unnamedVersion); + }).thenRunAsync(() -> profile.getRepository().refreshVersions()).whenComplete(Schedulers.javafx(), (exception) -> { + if (exception != null) { + handler.reject(StringUtils.getStackTrace(exception)); + } else + Controllers.taskDialog(gameDownloadTask, i18n("install.new_game"), TaskCancellationAction.NORMAL); + }).start(); + }, FileUtils.getNameWithoutExtension(file), new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId), new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName))); + } + public static void duplicateVersion(Profile profile, String version) { Controllers.prompt( new PromptDialogPane.Builder(i18n("version.manage.duplicate.prompt"), (res, handler) -> { diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 4ac702239d..c15b68cb18 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -753,6 +753,7 @@ install.new_game.already_exists=This instance name already exists. Please use an install.new_game.current_game_version=Current Instance Version install.new_game.installation=Instance Installation install.new_game.malformed=Invalid name. +install.new_game.malformed_json=Invalid Minecraft instance JSON file。 install.select=Choose operation install.success=Successfully installed. diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index a7846dacf1..d148f8ca86 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -557,6 +557,7 @@ install.new_game.already_exists=此實例已經存在,請重新命名 install.new_game.current_game_version=目前遊戲實例 install.new_game.installation=安裝新實例 install.new_game.malformed=名稱無效 +install.new_game.malformed_json=無效的 Minecraft 實例 JSON 文件。 install.select=請選取安裝方式 install.success=安裝成功 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 b4e00451ab..353fcfff90 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -562,6 +562,7 @@ install.new_game.already_exists=此实例已经存在,请换一个名字 install.new_game.current_game_version=当前游戏实例 install.new_game.installation=安装新游戏 install.new_game.malformed=名字不合法 +install.new_game.malformed_json=不是有效的 Minecraft 实例 JSON 文件。 install.select=请选择安装方式 install.success=安装成功