Merge dbeb69856162eba045cc3ce822563ac60697ab8b into 9969dc60c5278340b6b9a4d7facdde620e99d1f5

This commit is contained in:
辞庐 2025-08-02 23:00:10 +08:00 committed by GitHub
commit 17600cae47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 96 additions and 24 deletions

View File

@ -41,9 +41,9 @@ public abstract class LocalizedRemoteModRepository implements RemoteModRepositor
protected abstract SortType getBackedRemoteModRepositorySortOrder();
@Override
public SearchResult search(String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, SortType sort, SortOrder sortOrder) throws IOException {
public SearchResult search(String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, SortType sort, SortOrder sortOrder, LoaderType loaderType) throws IOException {
if (!StringUtils.containsChinese(searchFilter)) {
return getBackedRemoteModRepository().search(gameVersion, category, pageOffset, pageSize, searchFilter, sort, sortOrder);
return getBackedRemoteModRepository().search(gameVersion, category, pageOffset, pageSize, searchFilter, sort, sortOrder, loaderType);
}
Set<String> englishSearchFiltersSet = new HashSet<>(INITIAL_CAPACITY);
@ -65,7 +65,7 @@ public abstract class LocalizedRemoteModRepository implements RemoteModRepositor
RemoteMod[] searchResultArray = new RemoteMod[pageSize];
int totalPages, chineseIndex = 0, englishIndex = pageSize - 1;
{
SearchResult searchResult = getBackedRemoteModRepository().search(gameVersion, category, pageOffset, pageSize, String.join(" ", englishSearchFiltersSet), getBackedRemoteModRepositorySortOrder(), sortOrder);
SearchResult searchResult = getBackedRemoteModRepository().search(gameVersion, category, pageOffset, pageSize, String.join(" ", englishSearchFiltersSet), getBackedRemoteModRepositorySortOrder(), sortOrder, loaderType);
for (Iterator<RemoteMod> iterator = searchResult.getUnsortedResults().iterator(); iterator.hasNext(); ) {
if (chineseIndex > englishIndex) {
LOG.warning("Too many search results! Are the backed remote mod repository broken? Or are the API broken?");

View File

@ -116,7 +116,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
if (!searchInitialized) {
searchInitialized = true;
search("", null, 0, "", RemoteModRepository.SortType.POPULARITY);
search("", null, 0, "", RemoteModRepository.SortType.POPULARITY, RemoteModRepository.LoaderType.ALL);
}
if (versionSelection) {
@ -155,7 +155,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
FXUtils.runInFX(() -> selectedVersion.set(versionID));
}
private void search(String userGameVersion, RemoteModRepository.Category category, int pageOffset, String searchFilter, RemoteModRepository.SortType sort) {
private void search(String userGameVersion, RemoteModRepository.Category category, int pageOffset, String searchFilter, RemoteModRepository.SortType sort, RemoteModRepository.LoaderType loader) {
retrySearch = null;
setLoading(true);
setFailed(false);
@ -171,7 +171,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
: "";
}
}).thenApplyAsync(
gameVersion -> repository.search(gameVersion, category, pageOffset, 50, searchFilter, sort, RemoteModRepository.SortOrder.DESC)
gameVersion -> repository.search(gameVersion, category, pageOffset, 50, searchFilter, sort, RemoteModRepository.SortOrder.DESC, loader)
).whenComplete(Schedulers.javafx(), (result, exception) -> {
if (searchID != currentSearchID) {
return;
@ -185,7 +185,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
} else {
failed.set(true);
pageCount.set(-1);
retrySearch = () -> search(userGameVersion, category, pageOffset, searchFilter, sort);
retrySearch = () -> search(userGameVersion, category, pageOffset, searchFilter, sort, loader);
}
}).executor(true);
}
@ -357,6 +357,16 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
sortComboBox.getSelectionModel().select(0);
searchPane.addRow(rowIndex++, new Label(i18n("mods.category")), categoryStackPane, new Label(i18n("search.sort")), sortStackPane);
StackPane loaderStackPane = new StackPane();
JFXComboBox<RemoteModRepository.LoaderType> loaderComboBox = new JFXComboBox<>();
loaderStackPane.getChildren().setAll(loaderComboBox);
loaderComboBox.prefWidthProperty().bind(loaderStackPane.widthProperty());
loaderComboBox.getStyleClass().add("fit-width");
loaderComboBox.setConverter(stringConverter(loaderType -> i18n("mods.loader." + loaderType.name().toLowerCase(Locale.ROOT))));
loaderComboBox.getItems().setAll(RemoteModRepository.LoaderType.values());
loaderComboBox.getSelectionModel().select(0);
searchPane.addRow(rowIndex++, new Label(i18n("mods.loader")), loaderStackPane);
IntegerProperty filterID = new SimpleIntegerProperty(this, "Filter ID", 0);
IntegerProperty currentFilterID = new SimpleIntegerProperty(this, "Current Filter ID", -1);
EventHandler<ActionEvent> searchAction = e -> {
@ -372,7 +382,8 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
.orElse(null),
pageOffset == -1 ? 0 : pageOffset,
nameField.getText(),
sortComboBox.getSelectionModel().getSelectedItem());
sortComboBox.getSelectionModel().getSelectedItem(),
loaderComboBox.getSelectionModel().getSelectedItem());
};
control.listenerHolder.add(FXUtils.observeWeak(
@ -382,7 +393,8 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
gameVersionField.getSelectionModel().selectedItemProperty(),
categoryComboBox.getSelectionModel().selectedItemProperty(),
nameField.textProperty(),
sortComboBox.getSelectionModel().selectedItemProperty()
sortComboBox.getSelectionModel().selectedItemProperty(),
loaderComboBox.getSelectionModel().selectedItemProperty()
));
HBox actionsBox = new HBox(8);
@ -489,6 +501,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
gameVersionField.setOnAction(searchAction);
categoryComboBox.setOnAction(searchAction);
sortComboBox.setOnAction(searchAction);
loaderComboBox.setOnAction(searchAction);
}
SpinnerPane spinnerPane = new SpinnerPane();

View File

@ -1069,6 +1069,12 @@ mods.url=Official Page
mods.update_modpack_mod.warning=Updating mods in a modpack can lead to irreparable results, possibly corrupting the modpack so that it cannot launch. Are you sure you want to update?
mods.install=Install
mods.save_as=Save As
mods.loader=Loader
mods.loader.all=All
mods.loader.fabric=Fabric
mods.loader.forge=Forge
mods.loader.neoforge=NeoForge
mods.loader.quilt=Quilt
nbt.entries=%s entries
nbt.open.failed=Failed to open file

View File

@ -875,6 +875,12 @@ mods.url=官方頁面
mods.update_modpack_mod.warning=更新模組包中的模組可能導致模組包損壞,使模組包無法正常啟動。該操作不可逆,確定要更新嗎?
mods.install=安裝到目前實例
mods.save_as=下載到本機目錄
mods.loader=加載器
mods.loader.all=全部
mods.loader.fabric=Fabric
mods.loader.forge=Forge
mods.loader.neoforge=NeoForge
mods.loader.quilt=Quilt
nbt.entries=%s 個條目
nbt.open.failed=開啟檔案失敗

View File

@ -885,6 +885,12 @@ mods.url=官方页面
mods.update_modpack_mod.warning=更新整合包中的模组可能导致整合包损坏,使整合包无法正常启动。该操作不可逆,确定要更新吗?
mods.install=安装到当前版本
mods.save_as=下载到本地文件夹
mods.loader=加载器
mods.loader.all=全部
mods.loader.fabric=Fabric
mods.loader.forge=Forge
mods.loader.neoforge=NeoForge
mods.loader.quilt=Quilt
nbt.entries=%s 个条目
nbt.open.failed=打开文件失败

View File

@ -46,6 +46,14 @@ public interface RemoteModRepository {
TOTAL_DOWNLOADS
}
enum LoaderType {
ALL,
FORGE,
NEOFORGE,
FABRIC,
QUILT
}
enum SortOrder {
ASC,
DESC
@ -83,8 +91,7 @@ public interface RemoteModRepository {
}
}
SearchResult search(String gameVersion, @Nullable Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder)
throws IOException;
SearchResult search(String gameVersion, @Nullable Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder, LoaderType loaderType) throws IOException;
Optional<RemoteMod.Version> getRemoteVersionByLocalFile(LocalModFile localModFile, Path file) throws IOException;

View File

@ -84,6 +84,22 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
}
}
private int toModsSearchModloaderField(LoaderType sort) {
https://docs.curseforge.com/rest-api/#tocS_MinecraftModLoaderIndex
switch (sort) {
case FORGE:
return 1;
case FABRIC:
return 4;
case QUILT:
return 5;
case NEOFORGE:
return 6;
default:
return 0;
}
}
private String toSortOrder(SortOrder sortOrder) {
// https://docs.curseforge.com/#tocS_SortOrder
switch (sortOrder) {
@ -100,21 +116,29 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
}
@Override
public SearchResult search(String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder) throws IOException {
public SearchResult search(String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder, LoaderType loaderType) throws IOException {
int categoryId = 0;
if (category != null && category.getSelf() instanceof CurseAddon.Category) {
categoryId = ((CurseAddon.Category) category.getSelf()).getId();
}
Response<List<CurseAddon>> response = HttpRequest.GET(PREFIX + "/v1/mods/search",
pair("gameId", "432"),
pair("classId", Integer.toString(section)),
pair("categoryId", Integer.toString(categoryId)),
pair("gameVersion", gameVersion),
pair("searchFilter", searchFilter),
pair("sortField", Integer.toString(toModsSearchSortField(sortType))),
pair("sortOrder", toSortOrder(sortOrder)),
pair("index", Integer.toString(pageOffset * pageSize)),
pair("pageSize", Integer.toString(pageSize)))
List<Pair<String, String>> params = new ArrayList<>();
params.add(pair("gameId", "432"));
params.add(pair("classId", Integer.toString(section)));
params.add(pair("categoryId", Integer.toString(categoryId)));
params.add(pair("gameVersion", gameVersion));
if (loaderType != LoaderType.ALL) {
params.add(pair("modLoaderTypes", String.format("[%s]", toModsSearchModloaderField(loaderType))));
}
params.add(pair("searchFilter", searchFilter));
params.add(pair("sortField", Integer.toString(toModsSearchSortField(sortType))));
params.add(pair("sortOrder", toSortOrder(sortOrder)));
params.add(pair("index", Integer.toString(pageOffset * pageSize)));
params.add(pair("pageSize", Integer.toString(pageSize)));
Response<List<CurseAddon>> response = HttpRequest.GET(PREFIX + "/v1/mods/search", params.toArray(new Pair[0]))
.header("X-API-KEY", apiKey)
.getJson(Response.typeOf(listTypeOf(CurseAddon.class)));
if (searchFilter.isEmpty()) {

View File

@ -79,15 +79,25 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
}
@Override
public SearchResult search(String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sort, SortOrder sortOrder) throws IOException {
public SearchResult search(String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sort, SortOrder sortOrder, LoaderType loaderType) throws IOException {
List<List<String>> facets = new ArrayList<>();
facets.add(Collections.singletonList("project_type:" + projectType));
if (StringUtils.isNotBlank(gameVersion)) {
facets.add(Collections.singletonList("versions:" + gameVersion));
}
List<String> categorys = new ArrayList<>();
if (category != null && StringUtils.isNotBlank(category.getId())) {
facets.add(Collections.singletonList("categories:" + category.getId()));
categorys.add(category.getId());
}
if (loaderType != null && loaderType != LoaderType.ALL) {
categorys.add(loaderType.name());
}
if (!categorys.isEmpty()) {
facets.add(Collections.singletonList("categories:" + String.join(",", categorys)));
}
Map<String, String> query = mapOf(
pair("query", searchFilter),
pair("facets", JsonUtils.UGLY_GSON.toJson(facets)),