Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
import javafx.scene.layout.HBox;
import org.jackhuang.hmcl.game.HMCLGameRepository;
import org.jackhuang.hmcl.modpack.ModAdviser;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.NoneMultipleSelectionModel;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage;
import org.jackhuang.hmcl.util.Pair;
Expand All @@ -44,6 +46,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.Lang.mapOf;
Expand All @@ -58,27 +61,33 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
private final WizardController controller;
private final String version;
private final ModAdviser adviser;
private final ModpackFileTreeItem rootNode;
private ModpackFileTreeItem rootNode;

public ModpackFileSelectionPage(WizardController controller, HMCLGameRepository repository, String version, ModAdviser adviser) {
this.controller = controller;
this.version = version;
this.adviser = adviser;

JFXTreeView<String> treeView = new JFXTreeView<>();
rootNode = getTreeItem(repository.getRunDirectory(version), "minecraft", 0);
treeView.setRoot(rootNode);
treeView.setSelectionModel(new NoneMultipleSelectionModel<>());
onEscPressed(treeView, () -> controller.onPrev(true));
setMargin(treeView, new Insets(10, 10, 5, 10));
this.setCenter(treeView);

SpinnerPane spinnerPane = new SpinnerPane();
spinnerPane.setContent(treeView);
setMargin(spinnerPane, new Insets(10, 10, 5, 10));
this.setCenter(spinnerPane);

spinnerPane.setLoading(true);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当遍历期间出现 UncheckedIOException 等异常时,CompletableFuture 会异常完成,导致 thenAcceptAsync 完全不执行;此时 spinnerPane 永远保持加载状态,“下一步”也始终禁用,且异常不会被记录或展示。应添加异常完成处理,在 JavaFX 线程中结束加载状态并向用户报告或允许重试。

loadRoot(repository, treeView, spinnerPane);
spinnerPane.setOnFailedAction((__) -> loadRoot(repository, treeView, spinnerPane));

HBox nextPane = new HBox();
nextPane.setPadding(new Insets(16, 16, 16, 0));
nextPane.setAlignment(Pos.CENTER_RIGHT);
{
JFXButton btnNext = FXUtils.newRaisedButton(i18n("wizard.next"));
btnNext.setPrefSize(100, 40);
btnNext.disableProperty().bind(spinnerPane.loadingProperty());
btnNext.setOnAction(e -> onNext());

nextPane.getChildren().setAll(btnNext);
Expand All @@ -87,6 +96,21 @@ public ModpackFileSelectionPage(WizardController controller, HMCLGameRepository
this.setBottom(nextPane);
}

private void loadRoot(HMCLGameRepository repository, JFXTreeView<String> treeView, SpinnerPane spinnerPane) {
CompletableFuture
.supplyAsync(() -> getTreeItem(repository.getRunDirectory(version), "minecraft", 0), Schedulers.io())
.whenCompleteAsync((modpackFileTreeItem, throwable) -> {
if (throwable != null) {
treeView.setRoot(rootNode = modpackFileTreeItem);
spinnerPane.setFailedReason(null);
} else {
LOG.warning("Failed to load modpack file tree. Please click here to retry.");
spinnerPane.setFailedReason(i18n("modpack.files.load_failed"));
}
spinnerPane.setLoading(false);
}, Schedulers.javafx());
}

private ModpackFileTreeItem getTreeItem(Path file, String basePath, int level) {
if (Files.notExists(file))
return null;
Expand Down Expand Up @@ -176,6 +200,7 @@ public void cleanup(SettingsMap settings) {
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当游戏目录不存在、为空或所有内容均被过滤时,getTreeItem 会返回 null;加载结束后按钮会重新启用,但此处直接返回,使用户点击“下一步”没有任何反应。修改前 getFilesNeeded(null, ...) 会生成空列表并继续调用 controller.onFinish(),因此这是空目录场景下的新回归。

private void onNext() {
if (rootNode == null) return;
ArrayList<String> list = new ArrayList<>();
getFilesNeeded(rootNode, "minecraft", list);
controller.getSettings().put(MODPACK_FILE_SELECTION, list);
Expand Down
1 change: 1 addition & 0 deletions HMCL/src/main/resources/assets/lang/I18N.properties
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,7 @@ modpack.files.config=Mod Configuration Files
modpack.files.dumps=NEI Debug Output Files
modpack.files.hmclversion_cfg=Launcher Configuration File
modpack.files.liteconfig=LiteLoader Related Files
modpack.files.load_failed=Failed to load modpack file tree. Please click here to retry.
modpack.files.mods=Mods
modpack.files.mods.voxelmods=VoxelMods Options
modpack.files.options_txt=Minecraft Option File
Expand Down
1 change: 1 addition & 0 deletions HMCL/src/main/resources/assets/lang/I18N_zh.properties
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,7 @@ modpack.files.config=模組設定檔案
modpack.files.dumps=NEI 除錯輸出檔案
modpack.files.hmclversion_cfg=啟動器設定檔案
modpack.files.liteconfig=LiteLoader 相關檔案
modpack.files.load_failed=載入整合包檔案樹失敗,點選此處重試
modpack.files.mods=模組
modpack.files.mods.voxelmods=VoxelMods 設定,如小地圖
modpack.files.options_txt=遊戲設定
Expand Down
1 change: 1 addition & 0 deletions HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,7 @@ modpack.files.config=模组配置文件
modpack.files.dumps=NEI 调试输出文件
modpack.files.hmclversion_cfg=启动器配置文件
modpack.files.liteconfig=LiteLoader 相关文件
modpack.files.load_failed=加载整合包文件树失败,点击此处重试
modpack.files.mods=模组
modpack.files.mods.voxelmods=VoxelMods 配置,如小地图
modpack.files.options_txt=游戏设置
Expand Down