Skip to content

修复启动游戏补全文件时,任务没有正确归类的问题#5430

Open
CiiLu wants to merge 6 commits intoHMCL-dev:mainfrom
CiiLu:master
Open

修复启动游戏补全文件时,任务没有正确归类的问题#5430
CiiLu wants to merge 6 commits intoHMCL-dev:mainfrom
CiiLu:master

Conversation

@CiiLu
Copy link
Contributor

@CiiLu CiiLu commented Feb 4, 2026

image image 同时包括 assets libraries 补全

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an issue where tasks were not properly categorized during game launch file completion. The changes enable multiple stage names to be grouped together and displayed under a single stage node in the UI.

Changes:

  • Modified the stage hint system to support grouping multiple stage names under a single display stage
  • Updated task counting logic in StageNode to track multiple concurrent tasks per stage
  • Applied the new multi-stage grouping to the game launch flow, grouping assets, libraries, and modpack downloads under the dependencies stage

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskExecutor.java Changed stages field type from List<String> to List<List<String>> to support stage grouping
HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java Added withMultiStagesHint method and converted withStagesHint to use it for backward compatibility
HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java Updated addStages to map multiple stage names to single display nodes, added task counting to track concurrent tasks per stage
HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java Applied multi-stage grouping to game launch, grouping dependencies, assets, libraries, and modpack downloads together

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

stageNodes.computeIfAbsent(stage, s -> {
StageNode node = new StageNode(stage);
private void addStages(@NotNull Collection<List<String>> stageGroups) {
for (List<String> group : stageGroups) {
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

The code calls group.get(0) without checking if the list is empty. If an empty list is passed in the stageGroups collection, this will throw an IndexOutOfBoundsException. Consider adding a check to skip empty groups or validate that all groups contain at least one element.

Suggested change
for (List<String> group : stageGroups) {
for (List<String> group : stageGroups) {
if (group == null || group.isEmpty()) {
continue;
}

Copilot uses AI. Check for mistakes.
Comment on lines +481 to 484
public void fail() {
runningTasksCount = Math.max(0, runningTasksCount - 1);
status.set(Status.FAILED);
}
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

The succeed() method only sets the status to SUCCESS when runningTasksCount reaches 0, which allows multiple tasks in the same stage to complete successfully. However, the fail() method immediately sets the status to FAILED regardless of the remaining task count. This creates an inconsistency: if a stage has multiple running tasks and one fails while others are still running, the stage will be marked as FAILED even though other tasks might still succeed. Consider whether the fail logic should also check the running task count, or document why immediate failure is the desired behavior.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 81 to 89
List<Task.StagesHint> stages = new ArrayList<>();
for (Object value : settings.asStringMap().values()) {
if (value instanceof RemoteVersion remoteVersion) {
ret = ret.thenComposeAsync(version -> dependencyManager.installLibraryAsync(version, remoteVersion));
stages.add(String.format("hmcl.install.%s:%s", remoteVersion.getLibraryId(), remoteVersion.getSelfVersion()));
stages.add(new Task.StagesHint(String.format("hmcl.install.%s:%s", remoteVersion.getLibraryId(), remoteVersion.getSelfVersion())));
if ("game".equals(remoteVersion.getLibraryId())) {
stages.add("hmcl.install.libraries");
stages.add("hmcl.install.assets");
stages.add(new Task.StagesHint("hmcl.install.libraries"));
stages.add(new Task.StagesHint("hmcl.install.assets"));
}
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

This local variable is still named "stages" but now holds Task.StagesHint objects (including aliases). Renaming to "hints" (or similar) would reduce confusion with the new stages-hints API.

Copilot uses AI. Check for mistakes.
int remaining = runningTasksCount - 1;
runningTasksCount = Math.max(0, remaining);

if (runningTasksCount == 0) {
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

StageNode.succeed() can set status to SUCCESS even if a previous task in the same stage already called fail(), which would incorrectly clear the FAILED state when the last remaining task succeeds. Consider preserving FAILED once it happens (e.g., only transition to SUCCESS when status is not FAILED), while still decrementing runningTasksCount.

Suggested change
if (runningTasksCount == 0) {
if (runningTasksCount == 0 && status.get() != Status.FAILED) {

Copilot uses AI. Check for mistakes.
});
}
for (String stage : hint.aliases()) {
stageNodes.put(stage, node);
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

addStagesHints() unconditionally overwrites stageNodes mappings for aliases. If an alias key is already mapped to a different StageNode (because it was previously registered as a primary stage), this can orphan the original StageNode in the list and reroute updates unexpectedly. Consider detecting this case (alias already present and != current node) and skipping/merging explicitly instead of overwriting silently.

Suggested change
stageNodes.put(stage, node);
StageNode existing = stageNodes.get(stage);
if (existing == null) {
stageNodes.put(stage, node);
} else if (existing == node) {
// Alias already correctly mapped to this node; nothing to do.
} else {
// Alias is already mapped to a different StageNode; avoid overwriting silently.
}

Copilot uses AI. Check for mistakes.
Comment on lines 46 to 52
List<Task.StagesHint> stages = new ArrayList<>();

Task<Version> libraryTask = Task.supplyAsync(() -> new Version(name));
libraryTask = libraryTask.thenComposeAsync(libraryTaskHelper(gameVersion, "game", gameVersion));
stages.add("hmcl.install.game:" + gameVersion);
stages.add("hmcl.install.libraries");
stages.add("hmcl.install.assets");
stages.add(new Task.StagesHint("hmcl.install.game:" + gameVersion));
stages.add(new Task.StagesHint("hmcl.install.libraries"));
stages.add(new Task.StagesHint("hmcl.install.assets"));
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

This local variable is still named "stages" but now holds Task.StagesHint objects (including aliases). Renaming to "hints" (or similar) would reduce confusion with the old List stages API.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants