This commit is contained in:
huanghongxun
2019-12-14 12:50:22 +08:00
parent 61abed04f3
commit 71131dadb7
12 changed files with 372 additions and 45 deletions

View File

@@ -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<Void> 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<Exception, ?> 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<Void> 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());
}

View File

@@ -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");

View File

@@ -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<String, Object> 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<Void> finishModpackInstallingAsync(Map<String, Object> 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());
}

View File

@@ -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());
}

View File

@@ -0,0 +1,150 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2019 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
*/
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<String> 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<String, Object> 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";
}

View File

@@ -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

View File

@@ -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=匯出整合包引導

View File

@@ -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=导出整合包向导