mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2026-10-29 07:06:49 +08:00
[Chores] 优化 addon 类型推断逻辑 (#6536)
This commit is contained in:
@@ -49,7 +49,7 @@ public abstract class LocalizedRemoteAddonRepository implements RemoteAddonRepos
|
||||
Set<String> englishSearchFiltersSet = new LinkedHashSet<>(INITIAL_CAPACITY);
|
||||
|
||||
int count = 0;
|
||||
for (ModTranslations.Mod mod : ModTranslations.getTranslationsByRepositoryType(getType()).searchMod(searchFilter)) {
|
||||
for (ModTranslations.Mod mod : ModTranslations.getTranslationsByAddonType(getType()).searchMod(searchFilter)) {
|
||||
String englishSearchFilter = String.join(" ", StringUtils.tokenize(StringUtils.isNotBlank(mod.getSubname()) ? mod.getSubname() : mod.getName()));
|
||||
if (StringUtils.isNotBlank(englishSearchFilter)) {
|
||||
englishSearchFiltersSet.add(englishSearchFilter);
|
||||
@@ -82,7 +82,7 @@ public abstract class LocalizedRemoteAddonRepository implements RemoteAddonRepos
|
||||
continue;
|
||||
}
|
||||
|
||||
ModTranslations.Mod chineseTranslation = ModTranslations.getTranslationsByRepositoryType(getType()).getModByCurseForgeId(remoteAddon.slug());
|
||||
ModTranslations.Mod chineseTranslation = ModTranslations.getTranslationsByAddonType(getType()).getModByCurseForgeId(remoteAddon.slug());
|
||||
if (chineseTranslation != null && !StringUtils.isBlank(chineseTranslation.getName()) && StringUtils.containsChinese(chineseTranslation.getName())) {
|
||||
searchResultArray[chineseIndex++] = remoteAddon;
|
||||
} else {
|
||||
@@ -94,7 +94,7 @@ public abstract class LocalizedRemoteAddonRepository implements RemoteAddonRepos
|
||||
|
||||
StringUtils.LevCalculator levCalculator = new StringUtils.LevCalculator();
|
||||
return new SearchResult(Stream.concat(Arrays.stream(searchResultArray, 0, chineseIndex).map(remoteMod -> {
|
||||
ModTranslations.Mod chineseRemoteMod = ModTranslations.getTranslationsByRepositoryType(getType()).getModByCurseForgeId(remoteMod.slug());
|
||||
ModTranslations.Mod chineseRemoteMod = ModTranslations.getTranslationsByAddonType(getType()).getModByCurseForgeId(remoteMod.slug());
|
||||
if (chineseRemoteMod == null || StringUtils.isBlank(chineseRemoteMod.getName()) || !StringUtils.containsChinese(chineseRemoteMod.getName())) {
|
||||
return Pair.pair(remoteMod, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@@ -586,12 +586,12 @@ public class DownloadListPage extends Control implements DecoratorPage, GameInst
|
||||
setGraphic(null);
|
||||
} else {
|
||||
setPadding(
|
||||
getIndex() == getListView().getItems().size() - 1
|
||||
? LAST_PADDING
|
||||
: PADDING
|
||||
getIndex() == getListView().getItems().size() - 1
|
||||
? LAST_PADDING
|
||||
: PADDING
|
||||
);
|
||||
|
||||
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(getSkinnable().repository.getType()).getModByCurseForgeId(item.slug());
|
||||
ModTranslations.Mod mod = ModTranslations.getTranslationsByAddonType(getSkinnable().repository.getType()).getModByCurseForgeId(item.slug());
|
||||
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : item.title());
|
||||
String description = item.description();
|
||||
if (description != null) {
|
||||
|
||||
@@ -70,7 +70,7 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
private final HMCLGameRepository.InstanceReference instanceReference;
|
||||
private final DownloadCallback callback;
|
||||
private final DownloadListPage page;
|
||||
private final RemoteAddonRepository.Type type;
|
||||
private final RemoteAddon.Type type;
|
||||
|
||||
private SimpleMultimap<String, RemoteAddon.Version, List<RemoteAddon.Version>> versions;
|
||||
|
||||
@@ -78,8 +78,8 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
this.page = page;
|
||||
this.repository = page.repository;
|
||||
this.addon = addon;
|
||||
this.type = Objects.requireNonNullElse(addon.repoType(), repository.getType());
|
||||
this.translations = ModTranslations.getTranslationsByRepositoryType(this.type);
|
||||
this.type = Objects.requireNonNullElse(addon.type(), repository.getType());
|
||||
this.translations = ModTranslations.getTranslationsByAddonType(this.type);
|
||||
this.mod = translations.getModByCurseForgeId(addon.slug());
|
||||
this.instanceReference = instanceReference;
|
||||
this.callback = callback;
|
||||
@@ -281,7 +281,7 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
|
||||
resolve:
|
||||
for (RemoteAddon.Version modVersion : modVersions) {
|
||||
if (getSkinnable().type == RemoteAddonRepository.Type.MOD) {
|
||||
if (getSkinnable().type == RemoteAddon.Type.MOD) {
|
||||
for (ModLoaderType loader : modVersion.loaders()) {
|
||||
if (targetLoaders.contains(loader)) {
|
||||
list.getContent().addAll(
|
||||
@@ -386,8 +386,8 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
pane.getChildren().setAll(imageView, content);
|
||||
FXUtils.setLimitHeight(this, 60);
|
||||
|
||||
RemoteAddonRepository.Type type = addon.repoType();
|
||||
DownloadCallback callback = switch (type) {
|
||||
RemoteAddon.Type type = addon.type();
|
||||
DownloadCallback callback = type == null ? null : switch (type) {
|
||||
case MOD -> org.jackhuang.hmcl.ui.download.DownloadPage.FOR_MOD;
|
||||
case RESOURCE_PACK -> org.jackhuang.hmcl.ui.download.DownloadPage.FOR_RESOURCE_PACK;
|
||||
case SHADER_PACK -> org.jackhuang.hmcl.ui.download.DownloadPage.FOR_SHADER;
|
||||
@@ -400,7 +400,7 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
setNode(IDX_LEADING, pane);
|
||||
|
||||
if (addon != RemoteAddon.BROKEN) {
|
||||
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(type).getModByCurseForgeId(addon.slug());
|
||||
ModTranslations.Mod mod = ModTranslations.getTranslationsByAddonType(type).getModByCurseForgeId(addon.slug());
|
||||
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : addon.title());
|
||||
content.setSubtitle(addon.description());
|
||||
for (String category : addon.categories()) {
|
||||
@@ -510,7 +510,7 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
|
||||
private static final class AddonVersion extends JFXDialogLayout {
|
||||
public AddonVersion(RemoteAddon mod, RemoteAddon.Version version, DownloadPage selfPage) {
|
||||
RemoteAddonRepository.Type type = selfPage.type;
|
||||
RemoteAddon.Type type = selfPage.type;
|
||||
|
||||
String title = switch (type) {
|
||||
case WORLD -> "world.download.title";
|
||||
@@ -546,10 +546,10 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
|
||||
JFXButton downloadButton = null;
|
||||
if (selfPage.callback != null) {
|
||||
downloadButton = new JFXButton(type == RemoteAddonRepository.Type.MODPACK ? i18n("install.modpack") : i18n("mods.install"));
|
||||
downloadButton = new JFXButton(type == RemoteAddon.Type.MODPACK ? i18n("install.modpack") : i18n("mods.install"));
|
||||
downloadButton.getStyleClass().add("dialog-accept");
|
||||
downloadButton.setOnAction(e -> {
|
||||
if (type == RemoteAddonRepository.Type.MODPACK || !spinnerPane.isLoading() && spinnerPane.getFailedReason() == null) {
|
||||
if (type == RemoteAddon.Type.MODPACK || !spinnerPane.isLoading() && spinnerPane.getFailedReason() == null) {
|
||||
fireEvent(new DialogCloseEvent());
|
||||
}
|
||||
selfPage.download(mod, version);
|
||||
|
||||
+13
-12
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui.instances;
|
||||
|
||||
import org.jackhuang.hmcl.addon.RemoteAddon;
|
||||
import org.jackhuang.hmcl.game.LocalizedRemoteAddonRepository;
|
||||
import org.jackhuang.hmcl.addon.RemoteAddonRepository;
|
||||
import org.jackhuang.hmcl.addon.repository.CurseForgeRemoteAddonRepository;
|
||||
@@ -31,40 +32,40 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
public final class HMCLLocalizedDownloadListPage extends DownloadListPage {
|
||||
public static DownloadListPage ofMod(DownloadPage.DownloadCallback callback, boolean instanceSelection) {
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddonRepository.Type.MOD, CurseForgeRemoteAddonRepository.MODS, ModrinthRemoteAddonRepository.MODS);
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddon.Type.MOD, CurseForgeRemoteAddonRepository.MODS, ModrinthRemoteAddonRepository.MODS);
|
||||
}
|
||||
|
||||
public static DownloadListPage ofCurseForgeMod(DownloadPage.DownloadCallback callback, boolean instanceSelection) {
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddonRepository.Type.MOD, CurseForgeRemoteAddonRepository.MODS, null);
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddon.Type.MOD, CurseForgeRemoteAddonRepository.MODS, null);
|
||||
}
|
||||
|
||||
public static DownloadListPage ofModrinthMod(DownloadPage.DownloadCallback callback, boolean instanceSelection) {
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddonRepository.Type.MOD, null, ModrinthRemoteAddonRepository.MODS);
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddon.Type.MOD, null, ModrinthRemoteAddonRepository.MODS);
|
||||
}
|
||||
|
||||
public static DownloadListPage ofModPack(DownloadPage.DownloadCallback callback, boolean instanceSelection) {
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddonRepository.Type.MODPACK, CurseForgeRemoteAddonRepository.MODPACKS, ModrinthRemoteAddonRepository.MODPACKS);
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddon.Type.MODPACK, CurseForgeRemoteAddonRepository.MODPACKS, ModrinthRemoteAddonRepository.MODPACKS);
|
||||
}
|
||||
|
||||
public static DownloadListPage ofResourcePack(DownloadPage.DownloadCallback callback, boolean instanceSelection) {
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddonRepository.Type.RESOURCE_PACK, CurseForgeRemoteAddonRepository.RESOURCE_PACKS, ModrinthRemoteAddonRepository.RESOURCE_PACKS);
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddon.Type.RESOURCE_PACK, CurseForgeRemoteAddonRepository.RESOURCE_PACKS, ModrinthRemoteAddonRepository.RESOURCE_PACKS);
|
||||
}
|
||||
|
||||
public static DownloadListPage ofCurseForgeResourcePack(DownloadPage.DownloadCallback callback, boolean instanceSelection) {
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddonRepository.Type.RESOURCE_PACK, CurseForgeRemoteAddonRepository.RESOURCE_PACKS, null);
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddon.Type.RESOURCE_PACK, CurseForgeRemoteAddonRepository.RESOURCE_PACKS, null);
|
||||
}
|
||||
|
||||
public static DownloadListPage ofModrinthResourcePack(DownloadPage.DownloadCallback callback, boolean instanceSelection) {
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddonRepository.Type.RESOURCE_PACK, null, ModrinthRemoteAddonRepository.RESOURCE_PACKS);
|
||||
return new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddon.Type.RESOURCE_PACK, null, ModrinthRemoteAddonRepository.RESOURCE_PACKS);
|
||||
}
|
||||
|
||||
public static DownloadListPage ofShaderPack(DownloadPage.DownloadCallback callback, boolean instanceSelection) {
|
||||
var page = new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddonRepository.Type.SHADER_PACK, CurseForgeRemoteAddonRepository.SHADERS, ModrinthRemoteAddonRepository.SHADER_PACKS);
|
||||
var page = new HMCLLocalizedDownloadListPage(callback, instanceSelection, RemoteAddon.Type.SHADER_PACK, CurseForgeRemoteAddonRepository.SHADERS, ModrinthRemoteAddonRepository.SHADER_PACKS);
|
||||
page.supportChinese.set(false);
|
||||
return page;
|
||||
}
|
||||
|
||||
private HMCLLocalizedDownloadListPage(DownloadPage.DownloadCallback callback, boolean instanceSelection, RemoteAddonRepository.Type type, CurseForgeRemoteAddonRepository curseForge, ModrinthRemoteAddonRepository modrinth) {
|
||||
private HMCLLocalizedDownloadListPage(DownloadPage.DownloadCallback callback, boolean instanceSelection, RemoteAddon.Type type, CurseForgeRemoteAddonRepository curseForge, ModrinthRemoteAddonRepository modrinth) {
|
||||
super(null, callback, instanceSelection);
|
||||
|
||||
repository = new Repository(type, curseForge, modrinth);
|
||||
@@ -98,11 +99,11 @@ public final class HMCLLocalizedDownloadListPage extends DownloadListPage {
|
||||
}
|
||||
|
||||
private class Repository extends LocalizedRemoteAddonRepository {
|
||||
private final RemoteAddonRepository.Type type;
|
||||
private final RemoteAddon.Type type;
|
||||
private final CurseForgeRemoteAddonRepository curseForge;
|
||||
private final ModrinthRemoteAddonRepository modrinth;
|
||||
|
||||
public Repository(Type type, CurseForgeRemoteAddonRepository curseForge, ModrinthRemoteAddonRepository modrinth) {
|
||||
public Repository(RemoteAddon.Type type, CurseForgeRemoteAddonRepository curseForge, ModrinthRemoteAddonRepository modrinth) {
|
||||
this.type = type;
|
||||
this.curseForge = curseForge;
|
||||
this.modrinth = modrinth;
|
||||
@@ -127,7 +128,7 @@ public final class HMCLLocalizedDownloadListPage extends DownloadListPage {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
public RemoteAddon.Type getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui.instances;
|
||||
|
||||
import org.jackhuang.hmcl.addon.RemoteAddonRepository;
|
||||
import org.jackhuang.hmcl.addon.RemoteAddon;
|
||||
import org.jackhuang.hmcl.util.Pair;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -56,7 +56,8 @@ public enum ModTranslations {
|
||||
}
|
||||
};
|
||||
|
||||
public static ModTranslations getTranslationsByRepositoryType(RemoteAddonRepository.Type type) {
|
||||
public static ModTranslations getTranslationsByAddonType(@Nullable RemoteAddon.Type type) {
|
||||
if (type == null) return EMPTY;
|
||||
return switch (type) {
|
||||
case MOD -> MOD;
|
||||
case MODPACK -> MODPACK;
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public record RemoteAddon(String slug, String author, String title, String description, List<String> categories,
|
||||
String pageUrl, String iconUrl, IAddon data, RemoteAddonRepository.Type repoType) {
|
||||
String pageUrl, String iconUrl, IAddon data, @Nullable Type type) {
|
||||
|
||||
public static final RemoteAddon BROKEN = new RemoteAddon("", "", "RemoteAddon.BROKEN", "", Collections.emptyList(), "", "", new IAddon() {
|
||||
@Override
|
||||
@@ -44,7 +44,7 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
public Stream<Version> loadVersions(RemoteAddonRepository repo, DownloadProvider downloadProvider) throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
}, RemoteAddonRepository.Type.MOD);
|
||||
}, Type.MOD);
|
||||
|
||||
public enum VersionType {
|
||||
Release,
|
||||
@@ -67,23 +67,23 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
|
||||
private final DependencyType type;
|
||||
|
||||
private final @Nullable RemoteAddonRepository remoteAddonRepository;
|
||||
private final @Nullable Source source;
|
||||
|
||||
private final @Nullable String id;
|
||||
|
||||
private transient RemoteAddon remoteAddon = null;
|
||||
|
||||
private Dependency(DependencyType type, @Nullable RemoteAddonRepository remoteAddonRepository, @Nullable String id) {
|
||||
private Dependency(DependencyType type, @Nullable Source source, @Nullable String id) {
|
||||
this.type = type;
|
||||
this.remoteAddonRepository = remoteAddonRepository;
|
||||
this.source = source;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static Dependency ofGeneral(DependencyType type, RemoteAddonRepository remoteAddonRepository, String id) {
|
||||
public static Dependency ofGeneral(DependencyType type, Source source, String id) {
|
||||
if (type == DependencyType.BROKEN) {
|
||||
return ofBroken();
|
||||
} else {
|
||||
return new Dependency(type, remoteAddonRepository, id);
|
||||
return new Dependency(type, source, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RemoteAddonRepository getRemoteModRepository() {
|
||||
return this.remoteAddonRepository;
|
||||
public Source getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -113,7 +113,7 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
if (this.type == DependencyType.BROKEN) {
|
||||
this.remoteAddon = RemoteAddon.BROKEN;
|
||||
} else {
|
||||
this.remoteAddon = this.remoteAddonRepository.resolveDependency(downloadProvider, this.id);
|
||||
this.remoteAddon = this.source.getCommonRepo().resolveDependency(downloadProvider, this.id);
|
||||
}
|
||||
}
|
||||
return this.remoteAddon;
|
||||
@@ -127,14 +127,14 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
Dependency that = (Dependency) o;
|
||||
|
||||
if (type != that.type) return false;
|
||||
if (!remoteAddonRepository.equals(that.remoteAddonRepository)) return false;
|
||||
if (source != that.source) return false;
|
||||
return id.equals(that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = type.hashCode();
|
||||
result = 31 * result + remoteAddonRepository.hashCode();
|
||||
result = 31 * result + source.hashCode();
|
||||
result = 31 * result + id.hashCode();
|
||||
return result;
|
||||
}
|
||||
@@ -142,6 +142,7 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
|
||||
public enum Source {
|
||||
CURSEFORGE(
|
||||
CurseForgeRemoteAddonRepository.COMMON,
|
||||
CurseForgeRemoteAddonRepository.MODS,
|
||||
CurseForgeRemoteAddonRepository.RESOURCE_PACKS,
|
||||
CurseForgeRemoteAddonRepository.SHADERS,
|
||||
@@ -150,6 +151,7 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
CurseForgeRemoteAddonRepository.CUSTOMIZATIONS
|
||||
),
|
||||
MODRINTH(
|
||||
ModrinthRemoteAddonRepository.COMMON,
|
||||
ModrinthRemoteAddonRepository.MODS,
|
||||
ModrinthRemoteAddonRepository.RESOURCE_PACKS,
|
||||
ModrinthRemoteAddonRepository.SHADER_PACKS,
|
||||
@@ -158,15 +160,16 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
null
|
||||
);
|
||||
|
||||
public final RemoteAddonRepository modRepo;
|
||||
public final RemoteAddonRepository resourcePackRepo;
|
||||
public final RemoteAddonRepository shaderPackRepo;
|
||||
public final RemoteAddonRepository worldRepo;
|
||||
public final RemoteAddonRepository modpackRepo;
|
||||
public final RemoteAddonRepository customizationRepo;
|
||||
private final RemoteAddonRepository commonRepo;
|
||||
private final RemoteAddonRepository modRepo;
|
||||
private final RemoteAddonRepository resourcePackRepo;
|
||||
private final RemoteAddonRepository shaderPackRepo;
|
||||
private final RemoteAddonRepository worldRepo;
|
||||
private final RemoteAddonRepository modpackRepo;
|
||||
private final RemoteAddonRepository customizationRepo;
|
||||
|
||||
@Nullable
|
||||
public RemoteAddonRepository getRepoForType(RemoteAddonRepository.Type type) {
|
||||
public RemoteAddonRepository getRepoForType(Type type) {
|
||||
return switch (type) {
|
||||
case MOD -> modRepo;
|
||||
case RESOURCE_PACK -> resourcePackRepo;
|
||||
@@ -177,7 +180,12 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
};
|
||||
}
|
||||
|
||||
public RemoteAddonRepository getCommonRepo() {
|
||||
return commonRepo;
|
||||
}
|
||||
|
||||
Source(
|
||||
RemoteAddonRepository commonRepo,
|
||||
RemoteAddonRepository modRepo,
|
||||
RemoteAddonRepository resourcePackRepo,
|
||||
RemoteAddonRepository shaderPackRepo,
|
||||
@@ -185,6 +193,7 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
RemoteAddonRepository modpackRepo,
|
||||
RemoteAddonRepository customizationRepo
|
||||
) {
|
||||
this.commonRepo = commonRepo;
|
||||
this.modRepo = modRepo;
|
||||
this.resourcePackRepo = resourcePackRepo;
|
||||
this.shaderPackRepo = shaderPackRepo;
|
||||
@@ -194,6 +203,15 @@ public record RemoteAddon(String slug, String author, String title, String descr
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
MOD,
|
||||
MODPACK,
|
||||
RESOURCE_PACK,
|
||||
SHADER_PACK,
|
||||
WORLD,
|
||||
CUSTOMIZATION
|
||||
}
|
||||
|
||||
public interface IAddon {
|
||||
List<RemoteAddon> loadDependencies(RemoteAddonRepository repo, DownloadProvider downloadProvider) throws IOException;
|
||||
|
||||
|
||||
@@ -28,16 +28,7 @@ import java.util.stream.Stream;
|
||||
|
||||
public interface RemoteAddonRepository {
|
||||
|
||||
enum Type {
|
||||
MOD,
|
||||
MODPACK,
|
||||
RESOURCE_PACK,
|
||||
SHADER_PACK,
|
||||
WORLD,
|
||||
CUSTOMIZATION
|
||||
}
|
||||
|
||||
Type getType();
|
||||
RemoteAddon.Type getType();
|
||||
|
||||
enum SortType {
|
||||
POPULARITY,
|
||||
|
||||
@@ -196,7 +196,7 @@ public final class LocalModFile extends LocalAddonFile implements Comparable<Loc
|
||||
|
||||
@Override
|
||||
public AddonUpdate checkUpdates(DownloadProvider downloadProvider, String gameVersion, RemoteAddon.Source source) throws IOException {
|
||||
RemoteAddonRepository repository = source.getRepoForType(RemoteAddonRepository.Type.MOD);
|
||||
RemoteAddonRepository repository = source.getRepoForType(RemoteAddon.Type.MOD);
|
||||
if (repository == null) return null;
|
||||
Optional<RemoteAddon.Version> currentVersion = repository.getRemoteVersionByLocalFile(file);
|
||||
if (currentVersion.isEmpty()) return null;
|
||||
|
||||
+40
-17
@@ -70,16 +70,23 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
return !API_KEY.isEmpty();
|
||||
}
|
||||
|
||||
private final Type type;
|
||||
private final @Nullable RemoteAddon.Type type;
|
||||
private final int section;
|
||||
|
||||
public CurseForgeRemoteAddonRepository(Type type, int section) {
|
||||
this.type = type;
|
||||
public CurseForgeRemoteAddonRepository() {
|
||||
this.type = null;
|
||||
this.section = -1;
|
||||
}
|
||||
|
||||
public CurseForgeRemoteAddonRepository(int section) {
|
||||
this.type = toAddonType(section);
|
||||
if (type == null) throw new IllegalArgumentException("Unsupported CurseForge section id: " + section);
|
||||
this.section = section;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
public RemoteAddon.Type getType() {
|
||||
if (type == null) throw new UnsupportedOperationException();
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -110,6 +117,7 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
|
||||
@Override
|
||||
public SearchResult search(DownloadProvider downloadProvider, String gameVersion, @Nullable RemoteAddonRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder) throws IOException {
|
||||
if (type == null) throw new UnsupportedOperationException();
|
||||
SEMAPHORE.acquireUninterruptibly();
|
||||
try {
|
||||
int categoryId = 0;
|
||||
@@ -139,7 +147,7 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
response = withApiKey(HttpRequest.GET(candidate.toString()))
|
||||
.getJson(Response.typeOf(listTypeOf(CurseAddon.class)));
|
||||
if (searchFilter.isEmpty()) {
|
||||
return new SearchResult(response.data().stream().map(addon -> addon.toAddon(type)), calculateTotalPages(response, pageSize));
|
||||
return new SearchResult(response.data().stream().map(CurseAddon::toAddon), calculateTotalPages(response, pageSize));
|
||||
}
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
@@ -168,7 +176,7 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
|
||||
StringUtils.LevCalculator levCalculator = new StringUtils.LevCalculator();
|
||||
|
||||
return new SearchResult(response.data().stream().map(addon -> addon.toAddon(type)).map(remoteAddon -> {
|
||||
return new SearchResult(response.data().stream().map(CurseAddon::toAddon).map(remoteAddon -> {
|
||||
String lowerCaseResult = remoteAddon.title().toLowerCase(Locale.ROOT);
|
||||
int diff = levCalculator.calc(lowerCaseSearchFilter, lowerCaseResult);
|
||||
|
||||
@@ -179,7 +187,7 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
}
|
||||
|
||||
return pair(remoteAddon, diff);
|
||||
}).sorted(Comparator.comparingInt(Pair::getValue)).map(Pair::getKey), response.data().stream().map(addon -> addon.toAddon(type)), calculateTotalPages(response, pageSize));
|
||||
}).sorted(Comparator.comparingInt(Pair::getValue)).map(Pair::getKey), response.data().stream().map(CurseAddon::toAddon), calculateTotalPages(response, pageSize));
|
||||
} finally {
|
||||
SEMAPHORE.release();
|
||||
}
|
||||
@@ -228,7 +236,7 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
try {
|
||||
Response<CurseAddon> response = withApiKey(HttpRequest.GET(PREFIX + "/v1/mods/" + id))
|
||||
.getJson(Response.typeOf(CurseAddon.class));
|
||||
return response.data.toAddon(type);
|
||||
return response.data.toAddon();
|
||||
} finally {
|
||||
SEMAPHORE.release();
|
||||
}
|
||||
@@ -261,6 +269,7 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
|
||||
@Override
|
||||
public Stream<RemoteAddonRepository.Category> getCategories() throws IOException {
|
||||
if (type == null) throw new UnsupportedOperationException();
|
||||
SEMAPHORE.acquireUninterruptibly();
|
||||
try {
|
||||
Response<List<Category>> categories = withApiKey(HttpRequest.GET(PREFIX + "/v1/categories", pair("gameId", "432")))
|
||||
@@ -305,12 +314,26 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
public static final int SECTION_UNKNOWN2 = 4979;
|
||||
public static final int SECTION_UNKNOWN3 = 4984;
|
||||
|
||||
public static final CurseForgeRemoteAddonRepository MODS = new CurseForgeRemoteAddonRepository(RemoteAddonRepository.Type.MOD, SECTION_MOD);
|
||||
public static final CurseForgeRemoteAddonRepository MODPACKS = new CurseForgeRemoteAddonRepository(RemoteAddonRepository.Type.MODPACK, SECTION_MODPACK);
|
||||
public static final CurseForgeRemoteAddonRepository RESOURCE_PACKS = new CurseForgeRemoteAddonRepository(RemoteAddonRepository.Type.RESOURCE_PACK, SECTION_RESOURCE_PACK);
|
||||
public static final CurseForgeRemoteAddonRepository WORLDS = new CurseForgeRemoteAddonRepository(RemoteAddonRepository.Type.WORLD, SECTION_WORLD);
|
||||
public static final CurseForgeRemoteAddonRepository CUSTOMIZATIONS = new CurseForgeRemoteAddonRepository(RemoteAddonRepository.Type.CUSTOMIZATION, SECTION_CUSTOMIZATION);
|
||||
public static final CurseForgeRemoteAddonRepository SHADERS = new CurseForgeRemoteAddonRepository(RemoteAddonRepository.Type.SHADER_PACK, SECTION_SHADER);
|
||||
public static final CurseForgeRemoteAddonRepository COMMON = new CurseForgeRemoteAddonRepository();
|
||||
public static final CurseForgeRemoteAddonRepository MODS = new CurseForgeRemoteAddonRepository(SECTION_MOD);
|
||||
public static final CurseForgeRemoteAddonRepository MODPACKS = new CurseForgeRemoteAddonRepository(SECTION_MODPACK);
|
||||
public static final CurseForgeRemoteAddonRepository RESOURCE_PACKS = new CurseForgeRemoteAddonRepository(SECTION_RESOURCE_PACK);
|
||||
public static final CurseForgeRemoteAddonRepository WORLDS = new CurseForgeRemoteAddonRepository(SECTION_WORLD);
|
||||
public static final CurseForgeRemoteAddonRepository CUSTOMIZATIONS = new CurseForgeRemoteAddonRepository(SECTION_CUSTOMIZATION);
|
||||
public static final CurseForgeRemoteAddonRepository SHADERS = new CurseForgeRemoteAddonRepository(SECTION_SHADER);
|
||||
|
||||
@Nullable
|
||||
private static RemoteAddon.Type toAddonType(int classId) {
|
||||
return switch (classId) {
|
||||
case SECTION_MODPACK -> RemoteAddon.Type.MODPACK;
|
||||
case SECTION_RESOURCE_PACK -> RemoteAddon.Type.RESOURCE_PACK;
|
||||
case SECTION_WORLD -> RemoteAddon.Type.WORLD;
|
||||
case SECTION_CUSTOMIZATION -> RemoteAddon.Type.CUSTOMIZATION;
|
||||
case SECTION_SHADER -> RemoteAddon.Type.SHADER_PACK;
|
||||
case SECTION_MOD -> RemoteAddon.Type.MOD;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
public record Pagination(int index, int pageSize, int resultCount, int totalCount) {
|
||||
}
|
||||
@@ -380,7 +403,7 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
return repo.getRemoteVersionsById(downloadProvider, Integer.toString(id));
|
||||
}
|
||||
|
||||
public RemoteAddon toAddon(Type type) {
|
||||
public RemoteAddon toAddon() {
|
||||
String iconUrl = "";
|
||||
if (logo != null) {
|
||||
if (StringUtils.isNotBlank(logo.thumbnailUrl()))
|
||||
@@ -398,7 +421,7 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
links.websiteUrl,
|
||||
iconUrl,
|
||||
this,
|
||||
type
|
||||
toAddonType(classId)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -480,7 +503,7 @@ public final class CurseForgeRemoteAddonRepository implements RemoteAddonReposit
|
||||
if (!RELATION_TYPE.containsKey(dependency.relationType())) {
|
||||
throw new IllegalStateException("Broken datas.");
|
||||
}
|
||||
return RemoteAddon.Dependency.ofGeneral(RELATION_TYPE.get(dependency.relationType()), MODS, Integer.toString(dependency.modId()));
|
||||
return RemoteAddon.Dependency.ofGeneral(RELATION_TYPE.get(dependency.relationType()), RemoteAddon.Source.CURSEFORGE, Integer.toString(dependency.modId()));
|
||||
}).distinct().filter(Objects::nonNull).collect(Collectors.toList()),
|
||||
gameVersions.stream().filter(GameVersionNumber::isKnown).toList(),
|
||||
gameVersions.stream().flatMap(version -> {
|
||||
|
||||
+32
-25
@@ -24,10 +24,12 @@ import org.jackhuang.hmcl.addon.RemoteAddonRepository;
|
||||
import org.jackhuang.hmcl.addon.mod.ModLoaderType;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.util.*;
|
||||
import org.jackhuang.hmcl.util.gson.JsonSerializable;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.HttpRequest;
|
||||
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.io.ResponseCodeException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
|
||||
@@ -49,6 +51,7 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
/// @see <a href="https://docs.modrinth.com/api">Modrinth API Doc</a>
|
||||
public final class ModrinthRemoteAddonRepository implements RemoteAddonRepository {
|
||||
public static final ModrinthRemoteAddonRepository COMMON = new ModrinthRemoteAddonRepository();
|
||||
public static final ModrinthRemoteAddonRepository MODS = new ModrinthRemoteAddonRepository("mod");
|
||||
public static final ModrinthRemoteAddonRepository MODPACKS = new ModrinthRemoteAddonRepository("modpack");
|
||||
public static final ModrinthRemoteAddonRepository RESOURCE_PACKS = new ModrinthRemoteAddonRepository("resourcepack");
|
||||
@@ -89,26 +92,39 @@ public final class ModrinthRemoteAddonRepository implements RemoteAddonRepositor
|
||||
false
|
||||
);
|
||||
|
||||
@Nullable
|
||||
private static RemoteAddon.Type toAddonType(String projectType) {
|
||||
return switch (projectType) {
|
||||
case "modpack" -> RemoteAddon.Type.MODPACK;
|
||||
case "resourcepack" -> RemoteAddon.Type.RESOURCE_PACK;
|
||||
case "shader" -> RemoteAddon.Type.SHADER_PACK;
|
||||
case "mod" -> RemoteAddon.Type.MOD;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private static final Semaphore SEMAPHORE = new Semaphore(16);
|
||||
|
||||
private static final String PREFIX = "https://api.modrinth.com";
|
||||
|
||||
private final String projectType;
|
||||
private final @Nullable String projectType;
|
||||
|
||||
private final RemoteAddonRepository.Type type;
|
||||
private final @Nullable RemoteAddon.Type type;
|
||||
|
||||
private ModrinthRemoteAddonRepository(String projectType) {
|
||||
private ModrinthRemoteAddonRepository() {
|
||||
this.projectType = null;
|
||||
this.type = null;
|
||||
}
|
||||
|
||||
private ModrinthRemoteAddonRepository(@NotNull String projectType) {
|
||||
this.projectType = projectType;
|
||||
this.type = switch (projectType) {
|
||||
case "modpack" -> Type.MODPACK;
|
||||
case "resourcepack" -> Type.RESOURCE_PACK;
|
||||
case "shader" -> Type.SHADER_PACK;
|
||||
default -> Type.MOD;
|
||||
};
|
||||
this.type = toAddonType(projectType);
|
||||
if (type == null) throw new IllegalArgumentException("Unsupported Modrinth project type: " + projectType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
public RemoteAddon.Type getType() {
|
||||
if (type == null) throw new UnsupportedOperationException();
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@@ -131,6 +147,7 @@ public final class ModrinthRemoteAddonRepository implements RemoteAddonRepositor
|
||||
|
||||
@Override
|
||||
public SearchResult search(DownloadProvider downloadProvider, String gameVersion, @Nullable RemoteAddonRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sort, SortOrder sortOrder) throws IOException {
|
||||
if (projectType == null) throw new UnsupportedOperationException();
|
||||
SEMAPHORE.acquireUninterruptibly();
|
||||
try {
|
||||
List<List<String>> facets = new ArrayList<>();
|
||||
@@ -286,6 +303,7 @@ public final class ModrinthRemoteAddonRepository implements RemoteAddonRepositor
|
||||
|
||||
@Override
|
||||
public Stream<RemoteAddonRepository.Category> getCategories() throws IOException {
|
||||
if (projectType == null) throw new UnsupportedOperationException();
|
||||
SEMAPHORE.acquireUninterruptibly();
|
||||
try {
|
||||
List<Category> categories = HttpRequest.GET(PREFIX + "/v2/tag/category").getJson(listTypeOf(Category.class));
|
||||
@@ -297,6 +315,7 @@ public final class ModrinthRemoteAddonRepository implements RemoteAddonRepositor
|
||||
}
|
||||
}
|
||||
|
||||
@JsonSerializable
|
||||
public record Category(String icon, String name, @SerializedName("project_type") String projectType) {
|
||||
public Category() {
|
||||
this("", "", "");
|
||||
@@ -336,12 +355,6 @@ public final class ModrinthRemoteAddonRepository implements RemoteAddonRepositor
|
||||
}
|
||||
|
||||
public RemoteAddon toAddon() {
|
||||
Type type = switch (projectType) {
|
||||
case "modpack" -> Type.MODPACK;
|
||||
case "resourcepack" -> Type.RESOURCE_PACK;
|
||||
case "shader" -> Type.SHADER_PACK;
|
||||
default -> Type.MOD;
|
||||
};
|
||||
return new RemoteAddon(
|
||||
slug,
|
||||
"",
|
||||
@@ -351,7 +364,7 @@ public final class ModrinthRemoteAddonRepository implements RemoteAddonRepositor
|
||||
String.format("https://modrinth.com/%s/%s", projectType, id),
|
||||
iconUrl,
|
||||
this,
|
||||
type
|
||||
toAddonType(projectType)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -417,7 +430,7 @@ public final class ModrinthRemoteAddonRepository implements RemoteAddonRepositor
|
||||
throw new IllegalStateException("Broken datas");
|
||||
}
|
||||
|
||||
return RemoteAddon.Dependency.ofGeneral(DEPENDENCY_TYPE.get(dependency.dependencyType), MODS, dependency.projectId);
|
||||
return RemoteAddon.Dependency.ofGeneral(DEPENDENCY_TYPE.get(dependency.dependencyType), RemoteAddon.Source.MODRINTH, dependency.projectId);
|
||||
}).filter(Objects::nonNull).collect(Collectors.toList()),
|
||||
gameVersions,
|
||||
loaders.stream().flatMap(loader -> {
|
||||
@@ -468,12 +481,6 @@ public final class ModrinthRemoteAddonRepository implements RemoteAddonRepositor
|
||||
}
|
||||
|
||||
public RemoteAddon toAddon() {
|
||||
Type type = switch (projectType) {
|
||||
case "modpack" -> Type.MODPACK;
|
||||
case "resourcepack" -> Type.RESOURCE_PACK;
|
||||
case "shader" -> Type.SHADER_PACK;
|
||||
default -> Type.MOD;
|
||||
};
|
||||
return new RemoteAddon(
|
||||
slug,
|
||||
author,
|
||||
@@ -483,7 +490,7 @@ public final class ModrinthRemoteAddonRepository implements RemoteAddonRepositor
|
||||
String.format("https://modrinth.com/%s/%s", projectType, projectId),
|
||||
iconUrl,
|
||||
this,
|
||||
type
|
||||
toAddonType(projectType)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ final class ResourcePackZipFile extends ResourcePackFile {
|
||||
|
||||
@Override
|
||||
public AddonUpdate checkUpdates(DownloadProvider downloadProvider, String gameVersion, RemoteAddon.Source source) throws IOException {
|
||||
RemoteAddonRepository repository = source.getRepoForType(RemoteAddonRepository.Type.RESOURCE_PACK);
|
||||
RemoteAddonRepository repository = source.getRepoForType(RemoteAddon.Type.RESOURCE_PACK);
|
||||
if (repository == null) return null;
|
||||
Optional<RemoteAddon.Version> currentVersion = repository.getRemoteVersionByLocalFile(file);
|
||||
if (currentVersion.isEmpty()) return null;
|
||||
|
||||
Reference in New Issue
Block a user