Fix #4977 Modrinth 依赖可以指向已经被删除的项目 (#5012)

This commit is contained in:
Burning_TNT
2026-02-06 22:56:44 +08:00
committed by GitHub
parent 570e1e2029
commit 5d57052ea2
4 changed files with 61 additions and 9 deletions

View File

@@ -27,9 +27,18 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.*; import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Skin;
import javafx.scene.control.SkinBase;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.*; import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.game.HMCLGameRepository; import org.jackhuang.hmcl.game.HMCLGameRepository;
@@ -46,7 +55,11 @@ import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.construct.*; import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.SimpleMultimap;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.TaskCancellationAction;
import org.jackhuang.hmcl.util.i18n.I18n; import org.jackhuang.hmcl.util.i18n.I18n;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.javafx.BindingMapping; import org.jackhuang.hmcl.util.javafx.BindingMapping;
@@ -54,7 +67,14 @@ import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -518,8 +538,10 @@ public class DownloadPage extends Control implements DecoratorPage {
private void loadDependencies(RemoteMod.Version version, DownloadPage selfPage, SpinnerPane spinnerPane, ComponentList dependenciesList) { private void loadDependencies(RemoteMod.Version version, DownloadPage selfPage, SpinnerPane spinnerPane, ComponentList dependenciesList) {
spinnerPane.setLoading(true); spinnerPane.setLoading(true);
Task.supplyAsync(() -> { Task.composeAsync(() -> {
// TODO: Massive tasks may cause OOM.
EnumMap<RemoteMod.DependencyType, List<Node>> dependencies = new EnumMap<>(RemoteMod.DependencyType.class); EnumMap<RemoteMod.DependencyType, List<Node>> dependencies = new EnumMap<>(RemoteMod.DependencyType.class);
List<Task<?>> queue = new ArrayList<>(version.getDependencies().size());
for (RemoteMod.Dependency dependency : version.getDependencies()) { for (RemoteMod.Dependency dependency : version.getDependencies()) {
if (dependency.getType() == RemoteMod.DependencyType.INCOMPATIBLE || dependency.getType() == RemoteMod.DependencyType.BROKEN) { if (dependency.getType() == RemoteMod.DependencyType.INCOMPATIBLE || dependency.getType() == RemoteMod.DependencyType.BROKEN) {
continue; continue;
@@ -532,11 +554,22 @@ public class DownloadPage extends Control implements DecoratorPage {
list.add(title); list.add(title);
dependencies.put(dependency.getType(), list); dependencies.put(dependency.getType(), list);
} }
DependencyModItem dependencyModItem = new DependencyModItem(selfPage.page, dependency.load(), selfPage.version, selfPage.callback);
queue.add(Task.supplyAsync(Schedulers.io(), dependency::load)
.setSignificance(Task.TaskSignificance.MINOR)
.thenAcceptAsync(Schedulers.javafx(), dep -> {
if (dep == RemoteMod.BROKEN) {
return;
}
DependencyModItem dependencyModItem = new DependencyModItem(selfPage.page, dep, selfPage.version, selfPage.callback);
dependencies.get(dependency.getType()).add(dependencyModItem); dependencies.get(dependency.getType()).add(dependencyModItem);
})
.setSignificance(Task.TaskSignificance.MINOR));
} }
return dependencies.values().stream().flatMap(Collection::stream).collect(Collectors.toList()); return Task.allOf(queue).thenSupplyAsync(() ->
dependencies.values().stream().flatMap(Collection::stream).collect(Collectors.toList())
);
}).whenComplete(Schedulers.javafx(), (result, exception) -> { }).whenComplete(Schedulers.javafx(), (result, exception) -> {
spinnerPane.setLoading(false); spinnerPane.setLoading(false);
if (exception == null) { if (exception == null) {

View File

@@ -159,7 +159,7 @@ public final class RemoteMod {
if (this.type == DependencyType.BROKEN) { if (this.type == DependencyType.BROKEN) {
this.remoteMod = RemoteMod.BROKEN; this.remoteMod = RemoteMod.BROKEN;
} else { } else {
this.remoteMod = this.remoteModRepository.getModById(this.id); this.remoteMod = this.remoteModRepository.resolveDependency(this.id);
} }
} }
return this.remoteMod; return this.remoteMod;

View File

@@ -92,6 +92,10 @@ public interface RemoteModRepository {
RemoteMod getModById(String id) throws IOException; RemoteMod getModById(String id) throws IOException;
default RemoteMod resolveDependency(String id) throws IOException {
return getModById(id);
}
RemoteMod.File getModFile(String modId, String fileId) throws IOException; RemoteMod.File getModFile(String modId, String fileId) throws IOException;
Stream<RemoteMod.Version> getRemoteVersionsById(String id) throws IOException; Stream<RemoteMod.Version> getRemoteVersionsById(String id) throws IOException;

View File

@@ -35,6 +35,7 @@ import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jackhuang.hmcl.util.io.ResponseCodeException; import org.jackhuang.hmcl.util.io.ResponseCodeException;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.nio.file.NoSuchFileException; import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
@@ -154,6 +155,20 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
} }
} }
@Override
public RemoteMod resolveDependency(String id) throws IOException {
try {
return getModById(id);
} catch (ResponseCodeException e) {
if (e.getResponseCode() == 502 || e.getResponseCode() == 404) {
return RemoteMod.BROKEN;
}
throw e;
} catch (FileNotFoundException e) {
return RemoteMod.BROKEN;
}
}
@Override @Override
public RemoteMod.File getModFile(String modId, String fileId) throws IOException { public RemoteMod.File getModFile(String modId, String fileId) throws IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();