diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java index 60acf74bb..6b9e94f94 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java @@ -25,8 +25,9 @@ import org.jackhuang.hmcl.mod.curse.CurseInstallTask; import org.jackhuang.hmcl.mod.curse.CurseManifest; import org.jackhuang.hmcl.mod.multimc.MultiMCInstanceConfiguration; import org.jackhuang.hmcl.mod.multimc.MultiMCModpackInstallTask; -import org.jackhuang.hmcl.mod.server.ServerModpackInstallTask; +import org.jackhuang.hmcl.mod.server.ServerModpackLocalInstallTask; import org.jackhuang.hmcl.mod.server.ServerModpackManifest; +import org.jackhuang.hmcl.mod.server.ServerModpackRemoteInstallTask; import org.jackhuang.hmcl.setting.EnumGameDirectory; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.VersionSetting; @@ -99,6 +100,29 @@ public final class ModpackHelper { throw new UnsupportedModpackException(); } + public static Task getInstallTask(Profile profile, ServerModpackManifest manifest, String name, Modpack modpack) { + profile.getRepository().markVersionAsModpack(name); + + ExceptionalRunnable success = () -> { + HMCLGameRepository repository = profile.getRepository(); + repository.refreshVersions(); + VersionSetting vs = repository.specializeVersionSetting(name); + repository.undoMark(name); + if (vs != null) + vs.setGameDirType(EnumGameDirectory.VERSION_FOLDER); + }; + + ExceptionalConsumer failure = ex -> { + if (ex instanceof CurseCompletionException && !(ex.getCause() instanceof FileNotFoundException)) { + success.run(); + // This is tolerable and we will not delete the game + } + }; + + return new ServerModpackRemoteInstallTask(profile.getDependency(), manifest, name) + .whenComplete(Schedulers.defaultScheduler(), success, failure); + } + public static Task getInstallTask(Profile profile, File zipFile, String name, Modpack modpack) { profile.getRepository().markVersionAsModpack(name); @@ -129,7 +153,7 @@ public final class ModpackHelper { .whenComplete(Schedulers.defaultScheduler(), success, failure) .thenComposeAsync(new MultiMCInstallVersionSettingTask(profile, ((MultiMCInstanceConfiguration) modpack.getManifest()), name)); else if (modpack.getManifest() instanceof ServerModpackManifest) - return new ServerModpackInstallTask(profile.getDependency(), zipFile, modpack, ((ServerModpackManifest) modpack.getManifest()), name) + return new ServerModpackLocalInstallTask(profile.getDependency(), zipFile, modpack, ((ServerModpackManifest) modpack.getManifest()), name) .whenComplete(Schedulers.defaultScheduler(), success, failure); else throw new IllegalArgumentException("Unrecognized modpack: " + modpack.getManifest()); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java similarity index 97% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java index 6f4968ecb..a318dc87c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java @@ -48,7 +48,7 @@ import java.util.Optional; import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public final class ModpackPage extends StackPane implements WizardPage { +public final class LocalModpackPage extends StackPane implements WizardPage { private final WizardController controller; private Modpack manifest = null; @@ -77,7 +77,7 @@ public final class ModpackPage extends StackPane implements WizardPage { @FXML private SpinnerPane spinnerPane; - public ModpackPage(WizardController controller) { + public LocalModpackPage(WizardController controller) { this.controller = controller; FXUtils.loadFXML(this, "/assets/fxml/download/modpack.fxml"); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java index c3c196d46..f4f8a413b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java @@ -23,6 +23,7 @@ import org.jackhuang.hmcl.mod.curse.CurseCompletionException; import org.jackhuang.hmcl.mod.MismatchedModpackTypeException; import org.jackhuang.hmcl.mod.Modpack; import org.jackhuang.hmcl.mod.UnsupportedModpackException; +import org.jackhuang.hmcl.mod.server.ServerModpackManifest; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; @@ -65,22 +66,24 @@ public class ModpackInstallWizardProvider implements WizardProvider { @Override public void start(Map settings) { if (file != null) - settings.put(ModpackPage.MODPACK_FILE, file); + settings.put(LocalModpackPage.MODPACK_FILE, file); if (updateVersion != null) - settings.put(ModpackPage.MODPACK_NAME, updateVersion); + settings.put(LocalModpackPage.MODPACK_NAME, updateVersion); settings.put(PROFILE, profile); } private Task finishModpackInstallingAsync(Map settings) { - if (!settings.containsKey(ModpackPage.MODPACK_FILE)) - return null; - - File selected = tryCast(settings.get(ModpackPage.MODPACK_FILE), File.class).orElse(null); - Modpack modpack = tryCast(settings.get(ModpackPage.MODPACK_MANIFEST), Modpack.class).orElse(null); - String name = tryCast(settings.get(ModpackPage.MODPACK_NAME), String.class).orElse(null); - if (selected == null || modpack == null || name == null) return null; + File selected = tryCast(settings.get(LocalModpackPage.MODPACK_FILE), File.class).orElse(null); + ServerModpackManifest serverModpackManifest = tryCast(settings.get(RemoteModpackPage.MODPACK_SERVER_MANIFEST), ServerModpackManifest.class).orElse(null); + Modpack modpack = tryCast(settings.get(LocalModpackPage.MODPACK_MANIFEST), Modpack.class).orElse(null); + String name = tryCast(settings.get(LocalModpackPage.MODPACK_NAME), String.class).orElse(null); + if ((selected == null && serverModpackManifest == null) || modpack == null || name == null) return null; if (updateVersion != null) { + if (selected == null) { + Controllers.dialog(i18n("modpack.unsupported"), i18n("message.error"), MessageType.ERROR); + return null; + } try { return ModpackHelper.getUpdateTask(profile, selected, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name))); } catch (UnsupportedModpackException e) { @@ -92,8 +95,13 @@ public class ModpackInstallWizardProvider implements WizardProvider { } return null; } else { - return ModpackHelper.getInstallTask(profile, selected, name, modpack) - .thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); + if (serverModpackManifest != null) { + return ModpackHelper.getInstallTask(profile, serverModpackManifest, name, modpack) + .thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); + } else { + return ModpackHelper.getInstallTask(profile, selected, name, modpack) + .thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); + } } } @@ -124,7 +132,12 @@ public class ModpackInstallWizardProvider implements WizardProvider { case 0: return new ModpackSelectionPage(controller); case 1: - return new ModpackPage(controller); + if (controller.getSettings().containsKey(LocalModpackPage.MODPACK_FILE)) + return new LocalModpackPage(controller); + else if (controller.getSettings().containsKey(RemoteModpackPage.MODPACK_SERVER_MANIFEST)) + return new RemoteModpackPage(controller); + else + throw new IllegalArgumentException(); default: throw new IllegalStateException("error step " + step + ", settings: " + settings + ", pages: " + controller.getPages()); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java index 61e67dfca..844d45157 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java @@ -22,12 +22,15 @@ import javafx.application.Platform; import javafx.fxml.FXML; import javafx.scene.layout.StackPane; import javafx.stage.FileChooser; +import org.jackhuang.hmcl.mod.server.ServerModpackManifest; import org.jackhuang.hmcl.task.FileDownloadTask; +import org.jackhuang.hmcl.task.GetTask; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardPage; +import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; import java.io.File; @@ -38,7 +41,8 @@ import java.nio.file.Path; import java.util.Map; import java.util.Optional; -import static org.jackhuang.hmcl.ui.download.ModpackPage.MODPACK_FILE; +import static org.jackhuang.hmcl.ui.download.LocalModpackPage.*; +import static org.jackhuang.hmcl.ui.download.RemoteModpackPage.MODPACK_SERVER_MANIFEST; import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -85,22 +89,40 @@ public final class ModpackSelectionPage extends StackPane implements WizardPage Controllers.inputDialog(i18n("modpack.choose.remote.tooltip"), (urlString, resolve, reject) -> { try { URL url = new URL(urlString); - Path modpack = Files.createTempFile("forge-installer", ".jar"); - resolve.run(); + if (urlString.endsWith("server-manifest.json")) { + // if urlString ends with .json, we assume that the url is server-manifest.json + Controllers.taskDialog(new GetTask(url).whenComplete(Schedulers.javafx(), (result, e) -> { + ServerModpackManifest manifest = JsonUtils.fromMaybeMalformedJson(result, ServerModpackManifest.class); + if (manifest == null) { + reject.accept(i18n("modpack.type.server.malformed")); + } else if (e == null) { + resolve.run(); + controller.getSettings().put(MODPACK_SERVER_MANIFEST, manifest); + controller.onNext(); + } else { + reject.accept(e.getMessage()); + } + }).executor(true), i18n("message.downloading")); + } else { + // otherwise we still consider the file as modpack zip file + // since casually the url may not ends with ".zip" + Path modpack = Files.createTempFile("modpack", ".zip"); + resolve.run(); - Controllers.taskDialog( - new FileDownloadTask(url, modpack.toFile(), null) - .whenComplete(Schedulers.javafx(), e -> { - if (e == null) { - resolve.run(); - controller.getSettings().put(MODPACK_FILE, modpack.toFile()); - controller.onNext(); - } else { - reject.accept(e.getMessage()); - } - }).executor(true), - i18n("message.downloading") - ); + Controllers.taskDialog( + new FileDownloadTask(url, modpack.toFile(), null) + .whenComplete(Schedulers.javafx(), e -> { + if (e == null) { + resolve.run(); + controller.getSettings().put(MODPACK_FILE, modpack.toFile()); + controller.onNext(); + } else { + reject.accept(e.getMessage()); + } + }).executor(true), + i18n("message.downloading") + ); + } } catch (IOException e) { reject.accept(e.getMessage()); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/RemoteModpackPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/RemoteModpackPage.java new file mode 100644 index 000000000..c157b0df7 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/RemoteModpackPage.java @@ -0,0 +1,150 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2019 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.download; + +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXTextField; +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.stage.FileChooser; +import org.jackhuang.hmcl.game.ModpackHelper; +import org.jackhuang.hmcl.mod.Modpack; +import org.jackhuang.hmcl.mod.server.ServerModpackManifest; +import org.jackhuang.hmcl.setting.Profile; +import org.jackhuang.hmcl.task.Schedulers; +import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.ui.Controllers; +import org.jackhuang.hmcl.ui.FXUtils; +import org.jackhuang.hmcl.ui.WebStage; +import org.jackhuang.hmcl.ui.construct.MessageDialogPane; +import org.jackhuang.hmcl.ui.construct.SpinnerPane; +import org.jackhuang.hmcl.ui.construct.Validator; +import org.jackhuang.hmcl.ui.wizard.WizardController; +import org.jackhuang.hmcl.ui.wizard.WizardPage; +import org.jackhuang.hmcl.util.StringUtils; +import org.jackhuang.hmcl.util.gson.JsonUtils; +import org.jackhuang.hmcl.util.io.CompressingUtils; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.Optional; + +import static org.jackhuang.hmcl.util.Lang.tryCast; +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; + +public class RemoteModpackPage extends StackPane implements WizardPage { + private final WizardController controller; + + private final ServerModpackManifest manifest; + + @FXML + private Region borderPane; + + @FXML + private Label lblName; + + @FXML + private Label lblVersion; + + @FXML + private Label lblAuthor; + + @FXML + private Label lblModpackLocation; + + @FXML + private JFXTextField txtModpackName; + + @FXML + private JFXButton btnInstall; + + @FXML + private SpinnerPane spinnerPane; + + public RemoteModpackPage(WizardController controller) { + this.controller = controller; + + FXUtils.loadFXML(this, "/assets/fxml/download/modpack.fxml"); + + Profile profile = (Profile) controller.getSettings().get("PROFILE"); + + Optional name = tryCast(controller.getSettings().get(MODPACK_NAME), String.class); + if (name.isPresent()) { + txtModpackName.setText(name.get()); + txtModpackName.setDisable(true); + } + + manifest = tryCast(controller.getSettings().get(MODPACK_SERVER_MANIFEST), ServerModpackManifest.class) + .orElseThrow(() -> new IllegalStateException("MODPACK_SERVER_MANIFEST should exist")); + lblModpackLocation.setText(manifest.getFileApi()); + + try { + controller.getSettings().put(MODPACK_MANIFEST, manifest.toModpack(null)); + } catch (IOException e) { + Controllers.dialog(i18n("modpack.type.server.malformed"), i18n("message.error"), MessageDialogPane.MessageType.ERROR); + Platform.runLater(controller::onEnd); + return; + } + + lblName.setText(manifest.getName()); + lblVersion.setText(manifest.getVersion()); + lblAuthor.setText(manifest.getAuthor()); + + if (!name.isPresent()) { + txtModpackName.setText(manifest.getName() + (StringUtils.isBlank(manifest.getVersion()) ? "" : "-" + manifest.getVersion())); + txtModpackName.getValidators().addAll( + new Validator(i18n("install.new_game.already_exists"), str -> !profile.getRepository().hasVersion(str) && StringUtils.isNotBlank(str)), + new Validator(i18n("version.forbidden_name"), str -> !profile.getRepository().forbidsVersion(str)) + ); + txtModpackName.textProperty().addListener(e -> btnInstall.setDisable(!txtModpackName.validate())); + } + } + + @Override + public void cleanup(Map settings) { + settings.remove(MODPACK_SERVER_MANIFEST); + } + + @FXML + private void onInstall() { + if (!txtModpackName.validate()) return; + controller.getSettings().put(MODPACK_NAME, txtModpackName.getText()); + controller.onFinish(); + } + + @FXML + private void onDescribe() { + WebStage stage = new WebStage(); + stage.getWebView().getEngine().loadContent(manifest.getDescription()); + stage.setTitle(i18n("modpack.description")); + stage.showAndWait(); + } + + @Override + public String getTitle() { + return i18n("modpack.task.install"); + } + + public static final String MODPACK_SERVER_MANIFEST = "MODPACK_SERVER_MANIFEST"; + public static final String MODPACK_NAME = "MODPACK_NAME"; + public static final String MODPACK_MANIFEST = "MODPACK_MANIFEST"; +} diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 0f2d5ab45..0a1e81f6d 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -264,6 +264,7 @@ modpack.type.multimc=MultiMC modpack.type.multimc.export=Can be imported by Hello Minecraft! Launcher and MultiMC modpack.type.server=Server Auto-Update Modpack modpack.type.server.export=Allow server manager updating game client remotely +modpack.type.server.malformed=Malformed server modpack manifest modpack.unsupported=Unsupported modpack, only HMCL, MultiMC, and Curse modpacks are supported. modpack.update=Game Update modpack.wizard=Exporting modpack wizard diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 7f7c4f096..626e516e2 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -201,6 +201,7 @@ login.enter_password=請輸入您的密碼 logwindow.show_lines=顯示行數 logwindow.terminate_game=結束遊戲執行程序 logwindow.title=記錄 +logwindow.autoscroll=自動滾動 main_page=首頁 @@ -261,6 +262,7 @@ modpack.type.multimc=MultiMC modpack.type.multimc.export=可以被 Hello Minecraft! Launcher (HMCL) 和 MultiMC 導入 modpack.type.server=伺服器自動更新整合包 modpack.type.server.export=允許伺服器管理員遠程更新遊戲用戶端 +modpack.type.server.malformed=伺服器整合包配置格式錯誤,請聯絡伺服器管理員解決此問題 modpack.unsupported=不支援該整合包。僅 HMCL、MultiMC、Curse 整合包受支援。 modpack.update=正在升級整合包 modpack.wizard=匯出整合包引導 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 2c21c6fa8..67ddc7c51 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -202,6 +202,7 @@ login.enter_password=请输入您的密码 logwindow.show_lines=显示行数 logwindow.terminate_game=结束游戏进程 logwindow.title=日志 +logwindow.autoscroll=自动滚动 main_page=主页 @@ -262,6 +263,7 @@ modpack.type.multimc=MultiMC modpack.type.multimc.export=可以被 Hello Minecraft! Launcher (HMCL) 和 MultiMC 导入 modpack.type.server=服务器自动更新整合包 modpack.type.server.export=允许服务器管理员远程更新游戏客户端 +modpack.type.server.malformed=服务器整合包配置格式错误,请联系服务器管理员解决此问题 modpack.unsupported=该整合包不被支持。仅 HMCL、MultiMC、Curse 整合包受支持。 modpack.update=正在升级整合包 modpack.wizard=导出整合包向导 diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackCompletionTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackCompletionTask.java index 8c2d566ea..f11b9bb4f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackCompletionTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackCompletionTask.java @@ -29,6 +29,7 @@ import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; +import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.File; import java.io.IOException; @@ -53,16 +54,25 @@ public class ServerModpackCompletionTask extends Task { private final List> dependencies = new LinkedList<>(); public ServerModpackCompletionTask(DefaultDependencyManager dependencyManager, String version) { + this(dependencyManager, version, null); + } + + public ServerModpackCompletionTask(DefaultDependencyManager dependencyManager, String version, ModpackConfiguration manifest) { this.repository = dependencyManager.getGameRepository(); this.version = version; - try { - File manifestFile = repository.getModpackConfiguration(version); - if (manifestFile.exists()) - this.manifest = JsonUtils.GSON.fromJson(FileUtils.readText(manifestFile), new TypeToken>() { - }.getType()); - } catch (Exception e) { - Logging.LOG.log(Level.WARNING, "Unable to read CurseForge modpack manifest.json", e); + if (manifest == null) { + try { + File manifestFile = repository.getModpackConfiguration(version); + if (manifestFile.exists()) { + this.manifest = JsonUtils.GSON.fromJson(FileUtils.readText(manifestFile), new TypeToken>() { + }.getType()); + } + } catch (Exception e) { + Logging.LOG.log(Level.WARNING, "Unable to read CurseForge modpack manifest.json", e); + } + } else { + this.manifest = manifest; } } @@ -125,7 +135,7 @@ public class ServerModpackCompletionTask extends Task { if (download) { dependencies.add(new FileDownloadTask( - new URL(remoteManifest.getFileApi() + "/overrides/" + file.getPath()), + new URL(remoteManifest.getFileApi() + "/overrides/" + NetworkUtils.encodeLocation(file.getPath())), actualPath.toFile(), new FileDownloadTask.IntegrityCheck("SHA-1", file.getHash()))); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java similarity index 92% rename from HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackInstallTask.java rename to HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java index e6b61897b..0dfa58f20 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java @@ -35,7 +35,7 @@ import java.io.IOException; import java.util.LinkedList; import java.util.List; -public class ServerModpackInstallTask extends Task { +public class ServerModpackLocalInstallTask extends Task { private final File zipFile; private final Modpack modpack; @@ -45,7 +45,7 @@ public class ServerModpackInstallTask extends Task { private final List> dependencies = new LinkedList<>(); private final List> dependents = new LinkedList<>(); - public ServerModpackInstallTask(DefaultDependencyManager dependencyManager, File zipFile, Modpack modpack, ServerModpackManifest manifest, String name) { + public ServerModpackLocalInstallTask(DefaultDependencyManager dependencyManager, File zipFile, Modpack modpack, ServerModpackManifest manifest, String name) { this.zipFile = zipFile; this.modpack = modpack; this.manifest = manifest; @@ -75,7 +75,7 @@ public class ServerModpackInstallTask extends Task { }.getType()); if (!MODPACK_TYPE.equals(config.getType())) - throw new IllegalArgumentException("Version " + name + " is not a Curse modpack. Cannot update this version."); + throw new IllegalArgumentException("Version " + name + " is not a Server modpack. Cannot update this version."); } } catch (JsonParseException | IOException ignore) { } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackManifest.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackManifest.java index 943fe83a5..f1c046062 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackManifest.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackManifest.java @@ -114,6 +114,12 @@ public class ServerModpackManifest implements Validation { } } + public Modpack toModpack(Charset encoding) throws IOException { + String gameVersion = addons.stream().filter(x -> MINECRAFT.getPatchId().equals(x.id)).findAny() + .orElseThrow(() -> new IOException("Cannot find game version")).getVersion(); + return new Modpack(name, author, version, gameVersion, description, encoding, this); + } + /** * @param zip the CurseForge modpack file. * @throws IOException if the file is not a valid zip file. @@ -123,7 +129,6 @@ public class ServerModpackManifest implements Validation { public static Modpack readManifest(Path zip, Charset encoding) throws IOException, JsonParseException { String json = CompressingUtils.readTextZipEntry(zip, "server-manifest.json", encoding); ServerModpackManifest manifest = JsonUtils.fromNonNullJson(json, ServerModpackManifest.class); - String gameVersion = manifest.getAddons().stream().filter(x -> MINECRAFT.getPatchId().equals(x.getId())).findAny().orElseThrow(() -> new IOException("Cannot find game version")).getVersion(); - return new Modpack(manifest.getName(), manifest.getAuthor(), manifest.getVersion(), gameVersion, manifest.getDescription(), encoding, manifest); + return manifest.toModpack(encoding); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackRemoteInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackRemoteInstallTask.java new file mode 100644 index 000000000..b3f7588ed --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackRemoteInstallTask.java @@ -0,0 +1,98 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2019 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.mod.server; + +import com.google.gson.JsonParseException; +import com.google.gson.reflect.TypeToken; +import org.jackhuang.hmcl.download.DefaultDependencyManager; +import org.jackhuang.hmcl.download.GameBuilder; +import org.jackhuang.hmcl.game.DefaultGameRepository; +import org.jackhuang.hmcl.mod.MinecraftInstanceTask; +import org.jackhuang.hmcl.mod.Modpack; +import org.jackhuang.hmcl.mod.ModpackConfiguration; +import org.jackhuang.hmcl.mod.ModpackInstallTask; +import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.gson.JsonUtils; +import org.jackhuang.hmcl.util.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class ServerModpackRemoteInstallTask extends Task { + + private final String name; + private final DefaultDependencyManager dependency; + private final DefaultGameRepository repository; + private final List> dependencies = new LinkedList<>(); + private final List> dependents = new LinkedList<>(); + private final ServerModpackManifest manifest; + + public ServerModpackRemoteInstallTask(DefaultDependencyManager dependencyManager, ServerModpackManifest manifest, String name) { + this.name = name; + this.dependency = dependencyManager; + this.repository = dependencyManager.getGameRepository(); + this.manifest = manifest; + + File json = repository.getModpackConfiguration(name); + if (repository.hasVersion(name) && !json.exists()) + throw new IllegalArgumentException("Version " + name + " already exists."); + + GameBuilder builder = dependencyManager.gameBuilder().name(name); + for (ServerModpackManifest.Addon addon : manifest.getAddons()) { + builder.version(addon.getId(), addon.getVersion()); + } + + dependents.add(builder.buildAsync()); + onDone().register(event -> { + if (event.isFailed()) + repository.removeVersionFromDisk(name); + }); + + ModpackConfiguration config = null; + try { + if (json.exists()) { + config = JsonUtils.GSON.fromJson(FileUtils.readText(json), new TypeToken>() { + }.getType()); + + if (!MODPACK_TYPE.equals(config.getType())) + throw new IllegalArgumentException("Version " + name + " is not a Server modpack. Cannot update this version."); + } + } catch (JsonParseException | IOException ignore) { + } + } + + @Override + public List> getDependents() { + return dependents; + } + + @Override + public List> getDependencies() { + return dependencies; + } + + @Override + public void execute() throws Exception { + dependencies.add(new ServerModpackCompletionTask(dependency, name, new ModpackConfiguration<>(manifest, MODPACK_TYPE, Collections.emptyList()))); + } + + public static final String MODPACK_TYPE = "Server"; +}