refactor(mod): ModInfo -> LocalMod

This commit is contained in:
huanghongxun
2021-10-04 16:48:50 +08:00
parent bb6bd86e71
commit 31327d685b
21 changed files with 343 additions and 285 deletions

View File

@@ -24,7 +24,7 @@ import javafx.scene.Node;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import org.jackhuang.hmcl.download.*; import org.jackhuang.hmcl.download.*;
import org.jackhuang.hmcl.download.game.GameRemoteVersion; import org.jackhuang.hmcl.download.game.GameRemoteVersion;
import org.jackhuang.hmcl.mod.RemoteModRepository; import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.mod.curse.CurseForgeRemoteModRepository; import org.jackhuang.hmcl.mod.curse.CurseForgeRemoteModRepository;
import org.jackhuang.hmcl.setting.DownloadProviders; import org.jackhuang.hmcl.setting.DownloadProviders;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
@@ -154,7 +154,7 @@ public class DownloadPage extends BorderPane implements DecoratorPage {
setCenter(transitionPane); setCenter(transitionPane);
} }
private void download(Profile profile, @Nullable String version, RemoteModRepository.Version file, String subdirectoryName) { private void download(Profile profile, @Nullable String version, RemoteMod.Version file, String subdirectoryName) {
if (version == null) version = profile.getSelectedVersion(); if (version == null) version = profile.getSelectedVersion();
Path runDirectory = profile.getRepository().hasVersion(version) ? profile.getRepository().getRunDirectory(version).toPath() : profile.getRepository().getBaseDirectory().toPath(); Path runDirectory = profile.getRepository().hasVersion(version) ? profile.getRepository().getRunDirectory(version).toPath() : profile.getRepository().getBaseDirectory().toPath();

View File

@@ -40,6 +40,7 @@ import javafx.scene.image.ImageView;
import javafx.scene.layout.*; import javafx.scene.layout.*;
import org.jackhuang.hmcl.game.GameVersion; import org.jackhuang.hmcl.game.GameVersion;
import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.mod.RemoteModRepository; import org.jackhuang.hmcl.mod.RemoteModRepository;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Schedulers;
@@ -74,7 +75,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
private final BooleanProperty failed = new SimpleBooleanProperty(false); private final BooleanProperty failed = new SimpleBooleanProperty(false);
private final boolean versionSelection; private final boolean versionSelection;
private final ObjectProperty<Profile.ProfileVersion> version = new SimpleObjectProperty<>(); private final ObjectProperty<Profile.ProfileVersion> version = new SimpleObjectProperty<>();
private final ListProperty<RemoteModRepository.Mod> items = new SimpleListProperty<>(this, "items", FXCollections.observableArrayList()); private final ListProperty<RemoteMod> items = new SimpleListProperty<>(this, "items", FXCollections.observableArrayList());
private final ObservableList<String> versions = FXCollections.observableArrayList(); private final ObservableList<String> versions = FXCollections.observableArrayList();
private final StringProperty selectedVersion = new SimpleStringProperty(); private final StringProperty selectedVersion = new SimpleStringProperty();
private final DownloadPage.DownloadCallback callback; private final DownloadPage.DownloadCallback callback;
@@ -351,16 +352,16 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
} }
}, getSkinnable().failedProperty())); }, getSkinnable().failedProperty()));
JFXListView<RemoteModRepository.Mod> listView = new JFXListView<>(); JFXListView<RemoteMod> listView = new JFXListView<>();
spinnerPane.setContent(listView); spinnerPane.setContent(listView);
Bindings.bindContent(listView.getItems(), getSkinnable().items); Bindings.bindContent(listView.getItems(), getSkinnable().items);
listView.setOnMouseClicked(e -> { listView.setOnMouseClicked(e -> {
if (listView.getSelectionModel().getSelectedIndex() < 0) if (listView.getSelectionModel().getSelectedIndex() < 0)
return; return;
RemoteModRepository.Mod selectedItem = listView.getSelectionModel().getSelectedItem(); RemoteMod selectedItem = listView.getSelectionModel().getSelectedItem();
Controllers.navigate(new DownloadPage(getSkinnable(), selectedItem, getSkinnable().getProfileVersion(), getSkinnable().callback)); Controllers.navigate(new DownloadPage(getSkinnable(), selectedItem, getSkinnable().getProfileVersion(), getSkinnable().callback));
}); });
listView.setCellFactory(x -> new FloatListCell<RemoteModRepository.Mod>(listView) { listView.setCellFactory(x -> new FloatListCell<RemoteMod>(listView) {
TwoLineListItem content = new TwoLineListItem(); TwoLineListItem content = new TwoLineListItem();
ImageView imageView = new ImageView(); ImageView imageView = new ImageView();
@@ -373,7 +374,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
} }
@Override @Override
protected void updateControl(RemoteModRepository.Mod dataItem, boolean empty) { protected void updateControl(RemoteMod dataItem, boolean empty) {
if (empty) return; if (empty) return;
ModTranslations.Mod mod = ModTranslations.getModByCurseForgeId(dataItem.getSlug()); ModTranslations.Mod mod = ModTranslations.getModByCurseForgeId(dataItem.getSlug());
content.setTitle(mod != null ? mod.getDisplayName() : dataItem.getTitle()); content.setTitle(mod != null ? mod.getDisplayName() : dataItem.getTitle());

View File

@@ -37,7 +37,7 @@ import javafx.scene.image.ImageView;
import javafx.scene.layout.*; import javafx.scene.layout.*;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import org.jackhuang.hmcl.mod.ModManager; import org.jackhuang.hmcl.mod.ModManager;
import org.jackhuang.hmcl.mod.RemoteModRepository; import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.FileDownloadTask;
@@ -69,16 +69,16 @@ public class DownloadPage extends Control implements DecoratorPage {
private final BooleanProperty loaded = new SimpleBooleanProperty(false); private final BooleanProperty loaded = new SimpleBooleanProperty(false);
private final BooleanProperty loading = new SimpleBooleanProperty(false); private final BooleanProperty loading = new SimpleBooleanProperty(false);
private final BooleanProperty failed = new SimpleBooleanProperty(false); private final BooleanProperty failed = new SimpleBooleanProperty(false);
private final RemoteModRepository.Mod addon; private final RemoteMod addon;
private final ModTranslations.Mod mod; private final ModTranslations.Mod mod;
private final Profile.ProfileVersion version; private final Profile.ProfileVersion version;
private final DownloadCallback callback; private final DownloadCallback callback;
private final DownloadListPage page; private final DownloadListPage page;
private List<RemoteModRepository.Mod> dependencies; private List<RemoteMod> dependencies;
private SimpleMultimap<String, RemoteModRepository.Version> versions; private SimpleMultimap<String, RemoteMod.Version> versions;
public DownloadPage(DownloadListPage page, RemoteModRepository.Mod addon, Profile.ProfileVersion version, @Nullable DownloadCallback callback) { public DownloadPage(DownloadListPage page, RemoteMod addon, Profile.ProfileVersion version, @Nullable DownloadCallback callback) {
this.page = page; this.page = page;
this.addon = addon; this.addon = addon;
this.mod = ModTranslations.getModByCurseForgeId(addon.getSlug()); this.mod = ModTranslations.getModByCurseForgeId(addon.getSlug());
@@ -95,7 +95,7 @@ public class DownloadPage extends Control implements DecoratorPage {
Task.allOf( Task.allOf(
Task.supplyAsync(() -> addon.getData().loadDependencies()), Task.supplyAsync(() -> addon.getData().loadDependencies()),
Task.supplyAsync(() -> { Task.supplyAsync(() -> {
Stream<RemoteModRepository.Version> versions = addon.getData().loadVersions(); Stream<RemoteMod.Version> versions = addon.getData().loadVersions();
// if (StringUtils.isNotBlank(version.getVersion())) { // if (StringUtils.isNotBlank(version.getVersion())) {
// Optional<String> gameVersion = GameVersion.minecraftVersion(versionJar); // Optional<String> gameVersion = GameVersion.minecraftVersion(versionJar);
// if (gameVersion.isPresent()) { // if (gameVersion.isPresent()) {
@@ -108,9 +108,9 @@ public class DownloadPage extends Control implements DecoratorPage {
.whenComplete(Schedulers.javafx(), (result, exception) -> { .whenComplete(Schedulers.javafx(), (result, exception) -> {
if (exception == null) { if (exception == null) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<RemoteModRepository.Mod> dependencies = (List<RemoteModRepository.Mod>) result.get(0); List<RemoteMod> dependencies = (List<RemoteMod>) result.get(0);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
SimpleMultimap<String, RemoteModRepository.Version> versions = (SimpleMultimap<String, RemoteModRepository.Version>) result.get(1); SimpleMultimap<String, RemoteMod.Version> versions = (SimpleMultimap<String, RemoteMod.Version>) result.get(1);
this.dependencies = dependencies; this.dependencies = dependencies;
this.versions = versions; this.versions = versions;
@@ -126,9 +126,9 @@ public class DownloadPage extends Control implements DecoratorPage {
this.state.set(State.fromTitle(addon.getTitle())); this.state.set(State.fromTitle(addon.getTitle()));
} }
private SimpleMultimap<String, RemoteModRepository.Version> sortVersions(Stream<RemoteModRepository.Version> versions) { private SimpleMultimap<String, RemoteMod.Version> sortVersions(Stream<RemoteMod.Version> versions) {
SimpleMultimap<String, RemoteModRepository.Version> classifiedVersions SimpleMultimap<String, RemoteMod.Version> classifiedVersions
= new SimpleMultimap<String, RemoteModRepository.Version>(HashMap::new, ArrayList::new); = new SimpleMultimap<String, RemoteMod.Version>(HashMap::new, ArrayList::new);
versions.forEach(version -> { versions.forEach(version -> {
for (String gameVersion : version.getGameVersions()) { for (String gameVersion : version.getGameVersions()) {
classifiedVersions.put(gameVersion, version); classifiedVersions.put(gameVersion, version);
@@ -136,13 +136,13 @@ public class DownloadPage extends Control implements DecoratorPage {
}); });
for (String gameVersion : classifiedVersions.keys()) { for (String gameVersion : classifiedVersions.keys()) {
List<RemoteModRepository.Version> versionList = (List<RemoteModRepository.Version>) classifiedVersions.get(gameVersion); List<RemoteMod.Version> versionList = (List<RemoteMod.Version>) classifiedVersions.get(gameVersion);
versionList.sort(Comparator.comparing(RemoteModRepository.Version::getDatePublished).reversed()); versionList.sort(Comparator.comparing(RemoteMod.Version::getDatePublished).reversed());
} }
return classifiedVersions; return classifiedVersions;
} }
public RemoteModRepository.Mod getAddon() { public RemoteMod getAddon() {
return addon; return addon;
} }
@@ -174,7 +174,7 @@ public class DownloadPage extends Control implements DecoratorPage {
this.failed.set(failed); this.failed.set(failed);
} }
public void download(RemoteModRepository.Version file) { public void download(RemoteMod.Version file) {
if (this.callback == null) { if (this.callback == null) {
saveAs(file); saveAs(file);
} else { } else {
@@ -182,7 +182,7 @@ public class DownloadPage extends Control implements DecoratorPage {
} }
} }
public void saveAs(RemoteModRepository.Version file) { public void saveAs(RemoteMod.Version file) {
String extension = StringUtils.substringAfterLast(file.getFile().getFilename(), '.'); String extension = StringUtils.substringAfterLast(file.getFile().getFilename(), '.');
FileChooser fileChooser = new FileChooser(); FileChooser fileChooser = new FileChooser();
@@ -328,7 +328,7 @@ public class DownloadPage extends Control implements DecoratorPage {
private static final class DependencyModItem extends StackPane { private static final class DependencyModItem extends StackPane {
DependencyModItem(DownloadListPage page, RemoteModRepository.Mod addon, Profile.ProfileVersion version, DownloadCallback callback) { DependencyModItem(DownloadListPage page, RemoteMod addon, Profile.ProfileVersion version, DownloadCallback callback) {
HBox pane = new HBox(8); HBox pane = new HBox(8);
pane.setPadding(new Insets(8)); pane.setPadding(new Insets(8));
pane.setAlignment(Pos.CENTER_LEFT); pane.setAlignment(Pos.CENTER_LEFT);
@@ -355,7 +355,7 @@ public class DownloadPage extends Control implements DecoratorPage {
} }
private static final class ModItem extends StackPane { private static final class ModItem extends StackPane {
ModItem(RemoteModRepository.Version dataItem, DownloadPage selfPage) { ModItem(RemoteMod.Version dataItem, DownloadPage selfPage) {
HBox pane = new HBox(8); HBox pane = new HBox(8);
pane.setPadding(new Insets(8)); pane.setPadding(new Insets(8));
pane.setAlignment(Pos.CENTER_LEFT); pane.setAlignment(Pos.CENTER_LEFT);
@@ -399,6 +399,6 @@ public class DownloadPage extends Control implements DecoratorPage {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withLocale(Locale.getDefault()).withZone(ZoneId.systemDefault()); private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withLocale(Locale.getDefault()).withZone(ZoneId.systemDefault());
public interface DownloadCallback { public interface DownloadCallback {
void download(Profile profile, @Nullable String version, RemoteModRepository.Version file); void download(Profile profile, @Nullable String version, RemoteMod.Version file);
} }
} }

View File

@@ -17,6 +17,7 @@
*/ */
package org.jackhuang.hmcl.ui.versions; package org.jackhuang.hmcl.ui.versions;
import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.mod.RemoteModRepository; import org.jackhuang.hmcl.mod.RemoteModRepository;
import org.jackhuang.hmcl.mod.curse.CurseForgeRemoteModRepository; import org.jackhuang.hmcl.mod.curse.CurseForgeRemoteModRepository;
import org.jackhuang.hmcl.mod.modrinth.ModrinthRemoteModRepository; import org.jackhuang.hmcl.mod.modrinth.ModrinthRemoteModRepository;
@@ -46,7 +47,7 @@ public class ModDownloadListPage extends DownloadListPage {
private class Repository implements RemoteModRepository { private class Repository implements RemoteModRepository {
@Override @Override
public Stream<Mod> search(String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, int sort) throws IOException { public Stream<RemoteMod> search(String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, int sort) throws IOException {
String newSearchFilter; String newSearchFilter;
if (StringUtils.CHINESE_PATTERN.matcher(searchFilter).find()) { if (StringUtils.CHINESE_PATTERN.matcher(searchFilter).find()) {
List<ModTranslations.Mod> mods = ModTranslations.searchMod(searchFilter); List<ModTranslations.Mod> mods = ModTranslations.searchMod(searchFilter);
@@ -76,7 +77,7 @@ public class ModDownloadListPage extends DownloadListPage {
} }
@Override @Override
public Optional<Version> getRemoteVersionByLocalFile(Path file) { public Optional<RemoteMod.Version> getRemoteVersionByLocalFile(Path file) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@@ -24,7 +24,7 @@ import javafx.collections.ObservableList;
import javafx.scene.control.Skin; import javafx.scene.control.Skin;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.mod.ModInfo; import org.jackhuang.hmcl.mod.LocalMod;
import org.jackhuang.hmcl.mod.ModManager; import org.jackhuang.hmcl.mod.ModManager;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Schedulers;
@@ -151,7 +151,7 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
modManager.removeMods(selectedItems.stream() modManager.removeMods(selectedItems.stream()
.filter(Objects::nonNull) .filter(Objects::nonNull)
.map(ModListPageSkin.ModInfoObject::getModInfo) .map(ModListPageSkin.ModInfoObject::getModInfo)
.toArray(ModInfo[]::new)); .toArray(LocalMod[]::new));
loadMods(modManager); loadMods(modManager);
} catch (IOException ignore) { } catch (IOException ignore) {
// Fail to remove mods if the game is running or the mod is absent. // Fail to remove mods if the game is running or the mod is absent.

View File

@@ -34,7 +34,7 @@ import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.mod.ModInfo; import org.jackhuang.hmcl.mod.LocalMod;
import org.jackhuang.hmcl.mod.ModManager; import org.jackhuang.hmcl.mod.ModManager;
import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Schedulers;
@@ -124,34 +124,34 @@ class ModListPageSkin extends SkinBase<ModListPage> {
static class ModInfoObject extends RecursiveTreeObject<ModInfoObject> implements Comparable<ModInfoObject> { static class ModInfoObject extends RecursiveTreeObject<ModInfoObject> implements Comparable<ModInfoObject> {
private final BooleanProperty active; private final BooleanProperty active;
private final ModInfo modInfo; private final LocalMod localMod;
private final String message; private final String message;
private final ModTranslations.Mod mod; private final ModTranslations.Mod mod;
ModInfoObject(ModInfo modInfo) { ModInfoObject(LocalMod localMod) {
this.modInfo = modInfo; this.localMod = localMod;
this.active = modInfo.activeProperty(); this.active = localMod.activeProperty();
StringBuilder message = new StringBuilder(modInfo.getName()); StringBuilder message = new StringBuilder(localMod.getName());
if (isNotBlank(modInfo.getVersion())) if (isNotBlank(localMod.getVersion()))
message.append(", ").append(i18n("archive.version")).append(": ").append(modInfo.getVersion()); message.append(", ").append(i18n("archive.version")).append(": ").append(localMod.getVersion());
if (isNotBlank(modInfo.getGameVersion())) if (isNotBlank(localMod.getGameVersion()))
message.append(", ").append(i18n("archive.game_version")).append(": ").append(modInfo.getGameVersion()); message.append(", ").append(i18n("archive.game_version")).append(": ").append(localMod.getGameVersion());
if (isNotBlank(modInfo.getAuthors())) if (isNotBlank(localMod.getAuthors()))
message.append(", ").append(i18n("archive.author")).append(": ").append(modInfo.getAuthors()); message.append(", ").append(i18n("archive.author")).append(": ").append(localMod.getAuthors());
this.message = message.toString(); this.message = message.toString();
this.mod = ModTranslations.getModById(modInfo.getId()); this.mod = ModTranslations.getModById(localMod.getId());
} }
String getTitle() { String getTitle() {
return modInfo.getFileName(); return localMod.getFileName();
} }
String getSubtitle() { String getSubtitle() {
return message; return message;
} }
ModInfo getModInfo() { LocalMod getModInfo() {
return modInfo; return localMod;
} }
public ModTranslations.Mod getMod() { public ModTranslations.Mod getMod() {
@@ -160,7 +160,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
@Override @Override
public int compareTo(@NotNull ModListPageSkin.ModInfoObject o) { public int compareTo(@NotNull ModListPageSkin.ModInfoObject o) {
return modInfo.getFileName().toLowerCase().compareTo(o.modInfo.getFileName().toLowerCase()); return localMod.getFileName().toLowerCase().compareTo(o.localMod.getFileName().toLowerCase());
} }
} }

View File

@@ -25,7 +25,7 @@ import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
import org.jackhuang.hmcl.game.GameDirectoryType; import org.jackhuang.hmcl.game.GameDirectoryType;
import org.jackhuang.hmcl.game.GameRepository; import org.jackhuang.hmcl.game.GameRepository;
import org.jackhuang.hmcl.game.LauncherHelper; import org.jackhuang.hmcl.game.LauncherHelper;
import org.jackhuang.hmcl.mod.RemoteModRepository; import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.setting.Accounts; import org.jackhuang.hmcl.setting.Accounts;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.setting.Profiles;
@@ -77,7 +77,7 @@ public final class Versions {
} }
} }
public static void downloadModpackImpl(Profile profile, String version, RemoteModRepository.Version file) { public static void downloadModpackImpl(Profile profile, String version, RemoteMod.Version file) {
Path modpack; Path modpack;
URL downloadURL; URL downloadURL;
try { try {

View File

@@ -202,10 +202,10 @@ public class Datapack {
private Path file; private Path file;
private final BooleanProperty active; private final BooleanProperty active;
private final String id; private final String id;
private final ModInfo.Description description; private final LocalMod.Description description;
private final Datapack datapack; private final Datapack datapack;
public Pack(Path file, String id, ModInfo.Description description, Datapack datapack) { public Pack(Path file, String id, LocalMod.Description description, Datapack datapack) {
this.file = file; this.file = file;
this.id = id; this.id = id;
this.description = description; this.description = description;
@@ -235,7 +235,7 @@ public class Datapack {
return id; return id;
} }
public ModInfo.Description getDescription() { public LocalMod.Description getDescription() {
return description; return description;
} }

View File

@@ -64,14 +64,14 @@ public final class FabricModMetadata {
this.contact = contact; this.contact = contact;
} }
public static ModInfo fromFile(File modFile) throws IOException, JsonParseException { public static LocalMod fromFile(File modFile) throws IOException, JsonParseException {
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) { try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) {
Path mcmod = fs.getPath("fabric.mod.json"); Path mcmod = fs.getPath("fabric.mod.json");
if (Files.notExists(mcmod)) if (Files.notExists(mcmod))
throw new IOException("File " + modFile + " is not a Fabric mod."); throw new IOException("File " + modFile + " is not a Fabric mod.");
FabricModMetadata metadata = JsonUtils.fromNonNullJson(FileUtils.readText(mcmod), FabricModMetadata.class); FabricModMetadata metadata = JsonUtils.fromNonNullJson(FileUtils.readText(mcmod), FabricModMetadata.class);
String authors = metadata.authors == null ? "" : metadata.authors.stream().map(author -> author.name).collect(Collectors.joining(", ")); String authors = metadata.authors == null ? "" : metadata.authors.stream().map(author -> author.name).collect(Collectors.joining(", "));
return new ModInfo(modFile, metadata.id, metadata.name, new ModInfo.Description(metadata.description), return new LocalMod(modFile, ModLoaderType.FABRIC, metadata.id, metadata.name, new LocalMod.Description(metadata.description),
authors, metadata.version, "", metadata.contact != null ? metadata.contact.getOrDefault("homepage", "") : "", metadata.icon); authors, metadata.version, "", metadata.contact != null ? metadata.contact.getOrDefault("homepage", "") : "", metadata.icon);
} }
} }

View File

@@ -116,7 +116,7 @@ public final class ForgeNewModMetadata {
} }
} }
public static ModInfo fromFile(File modFile) throws IOException, JsonParseException { public static LocalMod fromFile(File modFile) throws IOException, JsonParseException {
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) { try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) {
Path modstoml = fs.getPath("META-INF/mods.toml"); Path modstoml = fs.getPath("META-INF/mods.toml");
if (Files.notExists(modstoml)) if (Files.notExists(modstoml))
@@ -135,7 +135,7 @@ public final class ForgeNewModMetadata {
LOG.log(Level.WARNING, "Failed to parse MANIFEST.MF in file " + modFile.getPath()); LOG.log(Level.WARNING, "Failed to parse MANIFEST.MF in file " + modFile.getPath());
} }
} }
return new ModInfo(modFile, mod.getModId(), mod.getDisplayName(), new ModInfo.Description(mod.getDescription()), return new LocalMod(modFile, ModLoaderType.FORGE, mod.getModId(), mod.getDisplayName(), new LocalMod.Description(mod.getDescription()),
mod.getAuthors(), mod.getVersion().replace("${file.jarVersion}", jarVersion), "", mod.getAuthors(), mod.getVersion().replace("${file.jarVersion}", jarVersion), "",
mod.getDisplayURL(), mod.getDisplayURL(),
metadata.getLogoFile()); metadata.getLogoFile());

View File

@@ -120,7 +120,7 @@ public final class ForgeOldModMetadata {
return authors; return authors;
} }
public static ModInfo fromFile(File modFile) throws IOException, JsonParseException { public static LocalMod fromFile(File modFile) throws IOException, JsonParseException {
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) { try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) {
Path mcmod = fs.getPath("mcmod.info"); Path mcmod = fs.getPath("mcmod.info");
if (Files.notExists(mcmod)) if (Files.notExists(mcmod))
@@ -138,7 +138,7 @@ public final class ForgeOldModMetadata {
authors = String.join(", ", metadata.getAuthorList()); authors = String.join(", ", metadata.getAuthorList());
if (StringUtils.isBlank(authors)) if (StringUtils.isBlank(authors))
authors = metadata.getCredits(); authors = metadata.getCredits();
return new ModInfo(modFile, metadata.getModId(), metadata.getName(), new ModInfo.Description(metadata.getDescription()), return new LocalMod(modFile, ModLoaderType.FORGE, metadata.getModId(), metadata.getName(), new LocalMod.Description(metadata.getDescription()),
authors, metadata.getVersion(), metadata.getGameVersion(), authors, metadata.getVersion(), metadata.getGameVersion(),
StringUtils.isBlank(metadata.getUrl()) ? metadata.getUpdateUrl() : metadata.url, StringUtils.isBlank(metadata.getUrl()) ? metadata.getUpdateUrl() : metadata.url,
metadata.getLogoFile()); metadata.getLogoFile());

View File

@@ -108,7 +108,7 @@ public final class LiteModMetadata {
return updateURI; return updateURI;
} }
public static ModInfo fromFile(File modFile) throws IOException, JsonParseException { public static LocalMod fromFile(File modFile) throws IOException, JsonParseException {
try (ZipFile zipFile = new ZipFile(modFile)) { try (ZipFile zipFile = new ZipFile(modFile)) {
ZipEntry entry = zipFile.getEntry("litemod.json"); ZipEntry entry = zipFile.getEntry("litemod.json");
if (entry == null) if (entry == null)
@@ -116,7 +116,7 @@ public final class LiteModMetadata {
LiteModMetadata metadata = JsonUtils.GSON.fromJson(IOUtils.readFullyAsString(zipFile.getInputStream(entry)), LiteModMetadata.class); LiteModMetadata metadata = JsonUtils.GSON.fromJson(IOUtils.readFullyAsString(zipFile.getInputStream(entry)), LiteModMetadata.class);
if (metadata == null) if (metadata == null)
throw new IOException("Mod " + modFile + " `litemod.json` is malformed."); throw new IOException("Mod " + modFile + " `litemod.json` is malformed.");
return new ModInfo(modFile, null, metadata.getName(), new ModInfo.Description(metadata.getDescription()), metadata.getAuthor(), return new LocalMod(modFile, ModLoaderType.FORGE, null, metadata.getName(), new LocalMod.Description(metadata.getDescription()), metadata.getAuthor(),
metadata.getVersion(), metadata.getGameVersion(), metadata.getUpdateURI(), ""); metadata.getVersion(), metadata.getGameVersion(), metadata.getUpdateURI(), "");
} }
} }

View File

@@ -35,9 +35,10 @@ import java.util.logging.Level;
* *
* @author huangyuhui * @author huangyuhui
*/ */
public final class ModInfo implements Comparable<ModInfo> { public final class LocalMod implements Comparable<LocalMod> {
private Path file; private Path file;
private final ModLoaderType modLoaderType;
private final String id; private final String id;
private final String name; private final String name;
private final Description description; private final Description description;
@@ -49,12 +50,13 @@ public final class ModInfo implements Comparable<ModInfo> {
private final String logoPath; private final String logoPath;
private final BooleanProperty activeProperty; private final BooleanProperty activeProperty;
public ModInfo(File file, String id, String name, Description description) { public LocalMod(File file, ModLoaderType modLoaderType, String id, String name, Description description) {
this(file, id, name, description, "", "", "", "", ""); this(file, modLoaderType, id, name, description, "", "", "", "", "");
} }
public ModInfo(File file, String id, String name, Description description, String authors, String version, String gameVersion, String url, String logoPath) { public LocalMod(File file, ModLoaderType modLoaderType, String id, String name, Description description, String authors, String version, String gameVersion, String url, String logoPath) {
this.file = file.toPath(); this.file = file.toPath();
this.modLoaderType = modLoaderType;
this.id = id; this.id = id;
this.name = name; this.name = name;
this.description = description; this.description = description;
@@ -67,13 +69,13 @@ public final class ModInfo implements Comparable<ModInfo> {
activeProperty = new SimpleBooleanProperty(this, "active", !ModManager.isDisabled(file)) { activeProperty = new SimpleBooleanProperty(this, "active", !ModManager.isDisabled(file)) {
@Override @Override
protected void invalidated() { protected void invalidated() {
Path path = ModInfo.this.file.toAbsolutePath(); Path path = LocalMod.this.file.toAbsolutePath();
try { try {
if (get()) if (get())
ModInfo.this.file = ModManager.enableMod(path); LocalMod.this.file = ModManager.enableMod(path);
else else
ModInfo.this.file = ModManager.disableMod(path); LocalMod.this.file = ModManager.disableMod(path);
} catch (IOException e) { } catch (IOException e) {
Logging.LOG.log(Level.SEVERE, "Unable to invert state of mod file " + path, e); Logging.LOG.log(Level.SEVERE, "Unable to invert state of mod file " + path, e);
} }
@@ -87,6 +89,10 @@ public final class ModInfo implements Comparable<ModInfo> {
return file; return file;
} }
public ModLoaderType getModLoaderType() {
return modLoaderType;
}
public String getId() { public String getId() {
return id; return id;
} }
@@ -136,13 +142,13 @@ public final class ModInfo implements Comparable<ModInfo> {
} }
@Override @Override
public int compareTo(ModInfo o) { public int compareTo(LocalMod o) {
return getFileName().compareTo(o.getFileName()); return getFileName().compareTo(o.getFileName());
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
return obj instanceof ModInfo && Objects.equals(getFileName(), ((ModInfo) obj).getFileName()); return obj instanceof LocalMod && Objects.equals(getFileName(), ((LocalMod) obj).getFileName());
} }
@Override @Override

View File

@@ -0,0 +1,26 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.mod;
public enum ModLoaderType {
UNKNOWN,
FORGE,
FABRIC,
LITE_LOADER,
PACK
}

View File

@@ -32,7 +32,7 @@ import java.util.TreeSet;
public final class ModManager { public final class ModManager {
private final GameRepository repository; private final GameRepository repository;
private final String id; private final String id;
private final TreeSet<ModInfo> modInfos = new TreeSet<>(); private final TreeSet<LocalMod> localMods = new TreeSet<>();
private boolean loaded = false; private boolean loaded = false;
@@ -55,12 +55,12 @@ public final class ModManager {
private void addModInfo(File file) { private void addModInfo(File file) {
try { try {
modInfos.add(getModInfo(file)); localMods.add(getModInfo(file));
} catch (IllegalArgumentException ignore) { } catch (IllegalArgumentException ignore) {
} }
} }
public static ModInfo getModInfo(File modFile) { public static LocalMod getModInfo(File modFile) {
File file = isDisabled(modFile) ? new File(modFile.getAbsoluteFile().getParentFile(), FileUtils.getNameWithoutExtension(modFile)) : modFile; File file = isDisabled(modFile) ? new File(modFile.getAbsoluteFile().getParentFile(), FileUtils.getNameWithoutExtension(modFile)) : modFile;
String description, extension = FileUtils.getExtension(file); String description, extension = FileUtils.getExtension(file);
switch (extension) { switch (extension) {
@@ -98,11 +98,11 @@ public final class ModManager {
default: default:
throw new IllegalArgumentException("File " + modFile + " is not a mod file."); throw new IllegalArgumentException("File " + modFile + " is not a mod file.");
} }
return new ModInfo(modFile, null, FileUtils.getNameWithoutExtension(modFile), new ModInfo.Description(description)); return new LocalMod(modFile, ModLoaderType.UNKNOWN, null, FileUtils.getNameWithoutExtension(modFile), new LocalMod.Description(description));
} }
public void refreshMods() throws IOException { public void refreshMods() throws IOException {
modInfos.clear(); localMods.clear();
if (Files.isDirectory(getModsDirectory())) { if (Files.isDirectory(getModsDirectory())) {
try (DirectoryStream<Path> modsDirectoryStream = Files.newDirectoryStream(getModsDirectory())) { try (DirectoryStream<Path> modsDirectoryStream = Files.newDirectoryStream(getModsDirectory())) {
for (Path subitem : modsDirectoryStream) { for (Path subitem : modsDirectoryStream) {
@@ -122,10 +122,10 @@ public final class ModManager {
loaded = true; loaded = true;
} }
public Collection<ModInfo> getMods() throws IOException { public Collection<LocalMod> getMods() throws IOException {
if (!loaded) if (!loaded)
refreshMods(); refreshMods();
return modInfos; return localMods;
} }
public void addMod(File file) throws IOException { public void addMod(File file) throws IOException {
@@ -145,9 +145,9 @@ public final class ModManager {
addModInfo(newFile); addModInfo(newFile);
} }
public void removeMods(ModInfo... modInfos) throws IOException { public void removeMods(LocalMod... localMods) throws IOException {
for (ModInfo modInfo : modInfos) { for (LocalMod localMod : localMods) {
Files.deleteIfExists(modInfo.getFile()); Files.deleteIfExists(localMod.getFile());
} }
} }

View File

@@ -66,13 +66,13 @@ public class PackMcMeta implements Validation {
private final int packFormat; private final int packFormat;
@SerializedName("description") @SerializedName("description")
private final ModInfo.Description description; private final LocalMod.Description description;
public PackInfo() { public PackInfo() {
this(0, new ModInfo.Description(Collections.emptyList())); this(0, new LocalMod.Description(Collections.emptyList()));
} }
public PackInfo(int packFormat, ModInfo.Description description) { public PackInfo(int packFormat, LocalMod.Description description) {
this.packFormat = packFormat; this.packFormat = packFormat;
this.description = description; this.description = description;
} }
@@ -81,7 +81,7 @@ public class PackMcMeta implements Validation {
return packFormat; return packFormat;
} }
public ModInfo.Description getDescription() { public LocalMod.Description getDescription() {
return description; return description;
} }
} }
@@ -112,13 +112,13 @@ public class PackMcMeta implements Validation {
} }
} }
public ModInfo.Description.Part deserialize(JsonElement json, JsonDeserializationContext context) throws JsonParseException { public LocalMod.Description.Part deserialize(JsonElement json, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonPrimitive()) { if (json.isJsonPrimitive()) {
return new ModInfo.Description.Part(parseText(json)); return new LocalMod.Description.Part(parseText(json));
} else if (json.isJsonObject()) { } else if (json.isJsonObject()) {
JsonObject obj = json.getAsJsonObject(); JsonObject obj = json.getAsJsonObject();
String text = parseText(obj.get("text")); String text = parseText(obj.get("text"));
return new ModInfo.Description.Part(text); return new LocalMod.Description.Part(text);
} else { } else {
throw new JsonParseException("pack.mcmeta Raw JSON text should be string or an object"); throw new JsonParseException("pack.mcmeta Raw JSON text should be string or an object");
} }
@@ -126,31 +126,31 @@ public class PackMcMeta implements Validation {
@Override @Override
public PackInfo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { public PackInfo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
List<ModInfo.Description.Part> parts = new ArrayList<>(); List<LocalMod.Description.Part> parts = new ArrayList<>();
JsonObject packInfo = json.getAsJsonObject(); JsonObject packInfo = json.getAsJsonObject();
int packFormat = packInfo.get("pack_format").getAsInt(); int packFormat = packInfo.get("pack_format").getAsInt();
JsonElement description = packInfo.get("description"); JsonElement description = packInfo.get("description");
if (description.isJsonPrimitive()) { if (description.isJsonPrimitive()) {
parts.add(new ModInfo.Description.Part(parseText(description))); parts.add(new LocalMod.Description.Part(parseText(description)));
} else if (description.isJsonArray()) { } else if (description.isJsonArray()) {
for (JsonElement element : description.getAsJsonArray()) { for (JsonElement element : description.getAsJsonArray()) {
JsonObject descriptionPart = element.getAsJsonObject(); JsonObject descriptionPart = element.getAsJsonObject();
parts.add(new ModInfo.Description.Part(descriptionPart.get("text").getAsString(), descriptionPart.get("color").getAsString())); parts.add(new LocalMod.Description.Part(descriptionPart.get("text").getAsString(), descriptionPart.get("color").getAsString()));
} }
} else { } else {
throw new JsonParseException("pack.mcmeta::pack::description should be String or array of text objects with text and color fields"); throw new JsonParseException("pack.mcmeta::pack::description should be String or array of text objects with text and color fields");
} }
return new PackInfo(packFormat, new ModInfo.Description(parts)); return new PackInfo(packFormat, new LocalMod.Description(parts));
} }
} }
public static ModInfo fromFile(File modFile) throws IOException, JsonParseException { public static LocalMod fromFile(File modFile) throws IOException, JsonParseException {
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) { try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) {
Path mcmod = fs.getPath("pack.mcmeta"); Path mcmod = fs.getPath("pack.mcmeta");
if (Files.notExists(mcmod)) if (Files.notExists(mcmod))
throw new IOException("File " + modFile + " is not a resource pack."); throw new IOException("File " + modFile + " is not a resource pack.");
PackMcMeta metadata = JsonUtils.fromNonNullJson(FileUtils.readText(mcmod), PackMcMeta.class); PackMcMeta metadata = JsonUtils.fromNonNullJson(FileUtils.readText(mcmod), PackMcMeta.class);
return new ModInfo(modFile, null, FileUtils.getNameWithoutExtension(modFile), metadata.pack.description, "", "", "", "", ""); return new LocalMod(modFile, ModLoaderType.PACK, null, FileUtils.getNameWithoutExtension(modFile), metadata.pack.description, "", "", "", "", "");
} }
} }
} }

View File

@@ -0,0 +1,180 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.mod;
import java.io.IOException;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
public class RemoteMod {
private final String slug;
private final String author;
private final String title;
private final String description;
private final List<String> categories;
private final String pageUrl;
private final String iconUrl;
private final IMod data;
public RemoteMod(String slug, String author, String title, String description, List<String> categories, String pageUrl, String iconUrl, IMod data) {
this.slug = slug;
this.author = author;
this.title = title;
this.description = description;
this.categories = categories;
this.pageUrl = pageUrl;
this.iconUrl = iconUrl;
this.data = data;
}
public String getSlug() {
return slug;
}
public String getAuthor() {
return author;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public List<String> getCategories() {
return categories;
}
public String getPageUrl() {
return pageUrl;
}
public String getIconUrl() {
return iconUrl;
}
public IMod getData() {
return data;
}
public enum VersionType {
Release,
Beta,
Alpha
}
public interface IMod {
List<RemoteMod> loadDependencies() throws IOException;
Stream<Version> loadVersions() throws IOException;
}
public static class Version {
private final Object self;
private final String name;
private final String version;
private final String changelog;
private final Instant datePublished;
private final VersionType versionType;
private final File file;
private final List<String> dependencies;
private final List<String> gameVersions;
private final List<String> loaders;
public Version(Object self, String name, String version, String changelog, Instant datePublished, VersionType versionType, File file, List<String> dependencies, List<String> gameVersions, List<String> loaders) {
this.self = self;
this.name = name;
this.version = version;
this.changelog = changelog;
this.datePublished = datePublished;
this.versionType = versionType;
this.file = file;
this.dependencies = dependencies;
this.gameVersions = gameVersions;
this.loaders = loaders;
}
public Object getSelf() {
return self;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
public String getChangelog() {
return changelog;
}
public Instant getDatePublished() {
return datePublished;
}
public VersionType getVersionType() {
return versionType;
}
public File getFile() {
return file;
}
public List<String> getDependencies() {
return dependencies;
}
public List<String> getGameVersions() {
return gameVersions;
}
public List<String> getLoaders() {
return loaders;
}
}
public static class File {
private final Map<String, String> hashes;
private final String url;
private final String filename;
public File(Map<String, String> hashes, String url, String filename) {
this.hashes = hashes;
this.url = url;
this.filename = filename;
}
public Map<String, String> getHashes() {
return hashes;
}
public String getUrl() {
return url;
}
public String getFilename() {
return filename;
}
}
}

View File

@@ -19,27 +19,19 @@ package org.jackhuang.hmcl.mod;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
public interface RemoteModRepository { public interface RemoteModRepository {
Stream<Mod> search(String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, int sort) Stream<RemoteMod> search(String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, int sort)
throws IOException; throws IOException;
Optional<Version> getRemoteVersionByLocalFile(Path file) throws IOException; Optional<RemoteMod.Version> getRemoteVersionByLocalFile(Path file) throws IOException;
Stream<Category> getCategories() throws IOException; Stream<Category> getCategories() throws IOException;
interface IMod {
List<Mod> loadDependencies() throws IOException;
Stream<Version> loadVersions() throws IOException;
}
class Category { class Category {
private final Object self; private final Object self;
private final String id; private final String id;
@@ -64,156 +56,6 @@ public interface RemoteModRepository {
} }
} }
class Mod {
private final String slug;
private final String author;
private final String title;
private final String description;
private final List<String> categories;
private final String pageUrl;
private final String iconUrl;
private final IMod data;
public Mod(String slug, String author, String title, String description, List<String> categories, String pageUrl, String iconUrl, IMod data) {
this.slug = slug;
this.author = author;
this.title = title;
this.description = description;
this.categories = categories;
this.pageUrl = pageUrl;
this.iconUrl = iconUrl;
this.data = data;
}
public String getSlug() {
return slug;
}
public String getAuthor() {
return author;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public List<String> getCategories() {
return categories;
}
public String getPageUrl() {
return pageUrl;
}
public String getIconUrl() {
return iconUrl;
}
public IMod getData() {
return data;
}
}
enum VersionType {
Release,
Beta,
Alpha
}
class Version {
private final Object self;
private final String name;
private final String version;
private final String changelog;
private final Instant datePublished;
private final VersionType versionType;
private final File file;
private final List<String> dependencies;
private final List<String> gameVersions;
private final List<String> loaders;
public Version(Object self, String name, String version, String changelog, Instant datePublished, VersionType versionType, File file, List<String> dependencies, List<String> gameVersions, List<String> loaders) {
this.self = self;
this.name = name;
this.version = version;
this.changelog = changelog;
this.datePublished = datePublished;
this.versionType = versionType;
this.file = file;
this.dependencies = dependencies;
this.gameVersions = gameVersions;
this.loaders = loaders;
}
public Object getSelf() {
return self;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
public String getChangelog() {
return changelog;
}
public Instant getDatePublished() {
return datePublished;
}
public VersionType getVersionType() {
return versionType;
}
public File getFile() {
return file;
}
public List<String> getDependencies() {
return dependencies;
}
public List<String> getGameVersions() {
return gameVersions;
}
public List<String> getLoaders() {
return loaders;
}
}
class File {
private final Map<String, String> hashes;
private final String url;
private final String filename;
public File(Map<String, String> hashes, String url, String filename) {
this.hashes = hashes;
this.url = url;
this.filename = filename;
}
public Map<String, String> getHashes() {
return hashes;
}
public String getUrl() {
return url;
}
public String getFilename() {
return filename;
}
}
String[] DEFAULT_GAME_VERSIONS = new String[]{ String[] DEFAULT_GAME_VERSIONS = new String[]{
"1.17.1", "1.17", "1.17.1", "1.17",
"1.16.5", "1.16.4", "1.16.3", "1.16.2", "1.16.1", "1.16", "1.16.5", "1.16.4", "1.16.3", "1.16.2", "1.16.1", "1.16",

View File

@@ -17,7 +17,7 @@
*/ */
package org.jackhuang.hmcl.mod.curse; package org.jackhuang.hmcl.mod.curse;
import org.jackhuang.hmcl.mod.RemoteModRepository; import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.Immutable;
import java.io.IOException; import java.io.IOException;
@@ -30,7 +30,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@Immutable @Immutable
public class CurseAddon implements RemoteModRepository.IMod { public class CurseAddon implements RemoteMod.IMod {
private final int id; private final int id;
private final String name; private final String name;
private final List<Author> authors; private final List<Author> authors;
@@ -168,13 +168,13 @@ public class CurseAddon implements RemoteModRepository.IMod {
} }
@Override @Override
public List<RemoteModRepository.Mod> loadDependencies() throws IOException { public List<RemoteMod> loadDependencies() throws IOException {
Set<Integer> dependencies = latestFiles.stream() Set<Integer> dependencies = latestFiles.stream()
.flatMap(latestFile -> latestFile.getDependencies().stream()) .flatMap(latestFile -> latestFile.getDependencies().stream())
.filter(dep -> dep.getType() == 3) .filter(dep -> dep.getType() == 3)
.map(Dependency::getAddonId) .map(Dependency::getAddonId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
List<RemoteModRepository.Mod> mods = new ArrayList<>(); List<RemoteMod> mods = new ArrayList<>();
for (int dependencyId : dependencies) { for (int dependencyId : dependencies) {
mods.add(CurseForgeRemoteModRepository.MODS.getAddon(dependencyId).toMod()); mods.add(CurseForgeRemoteModRepository.MODS.getAddon(dependencyId).toMod());
} }
@@ -182,12 +182,12 @@ public class CurseAddon implements RemoteModRepository.IMod {
} }
@Override @Override
public Stream<RemoteModRepository.Version> loadVersions() throws IOException { public Stream<RemoteMod.Version> loadVersions() throws IOException {
return CurseForgeRemoteModRepository.MODS.getFiles(this).stream() return CurseForgeRemoteModRepository.MODS.getFiles(this).stream()
.map(CurseAddon.LatestFile::toVersion); .map(CurseAddon.LatestFile::toVersion);
} }
public RemoteModRepository.Mod toMod() { public RemoteMod toMod() {
String iconUrl = null; String iconUrl = null;
for (CurseAddon.Attachment attachment : attachments) { for (CurseAddon.Attachment attachment : attachments) {
if (attachment.isDefault()) { if (attachment.isDefault()) {
@@ -195,7 +195,7 @@ public class CurseAddon implements RemoteModRepository.IMod {
} }
} }
return new RemoteModRepository.Mod( return new RemoteMod(
slug, slug,
"", "",
name, name,
@@ -481,31 +481,31 @@ public class CurseAddon implements RemoteModRepository.IMod {
return fileDataInstant; return fileDataInstant;
} }
public RemoteModRepository.Version toVersion() { public RemoteMod.Version toVersion() {
RemoteModRepository.VersionType versionType; RemoteMod.VersionType versionType;
switch (getReleaseType()) { switch (getReleaseType()) {
case 1: case 1:
versionType = RemoteModRepository.VersionType.Release; versionType = RemoteMod.VersionType.Release;
break; break;
case 2: case 2:
versionType = RemoteModRepository.VersionType.Beta; versionType = RemoteMod.VersionType.Beta;
break; break;
case 3: case 3:
versionType = RemoteModRepository.VersionType.Alpha; versionType = RemoteMod.VersionType.Alpha;
break; break;
default: default:
versionType = RemoteModRepository.VersionType.Release; versionType = RemoteMod.VersionType.Release;
break; break;
} }
return new RemoteModRepository.Version( return new RemoteMod.Version(
this, this,
getDisplayName(), getDisplayName(),
null, null,
null, null,
getParsedFileDate(), getParsedFileDate(),
versionType, versionType,
new RemoteModRepository.File(Collections.emptyMap(), getDownloadUrl(), getFileName()), new RemoteMod.File(Collections.emptyMap(), getDownloadUrl(), getFileName()),
Collections.emptyList(), Collections.emptyList(),
gameVersion.stream().filter(ver -> ver.startsWith("1.") || ver.contains("w")).collect(Collectors.toList()), gameVersion.stream().filter(ver -> ver.startsWith("1.") || ver.contains("w")).collect(Collectors.toList()),
Collections.emptyList() Collections.emptyList()

View File

@@ -18,6 +18,7 @@
package org.jackhuang.hmcl.mod.curse; package org.jackhuang.hmcl.mod.curse;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.mod.RemoteModRepository; import org.jackhuang.hmcl.mod.RemoteModRepository;
import org.jackhuang.hmcl.util.MurmurHash; import org.jackhuang.hmcl.util.MurmurHash;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
@@ -64,7 +65,7 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
} }
@Override @Override
public Stream<RemoteModRepository.Mod> search(String gameVersion, RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, int sort) throws IOException { public Stream<RemoteMod> search(String gameVersion, RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, int sort) throws IOException {
int categoryId = 0; int categoryId = 0;
if (category != null) categoryId = ((Category) category.getSelf()).getId(); if (category != null) categoryId = ((Category) category.getSelf()).getId();
return searchPaginated(gameVersion, categoryId, pageOffset, pageSize, searchFilter, sort).stream() return searchPaginated(gameVersion, categoryId, pageOffset, pageSize, searchFilter, sort).stream()
@@ -72,7 +73,7 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
} }
@Override @Override
public Optional<RemoteModRepository.Version> getRemoteVersionByLocalFile(Path file) throws IOException { public Optional<RemoteMod.Version> getRemoteVersionByLocalFile(Path file) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(file)))) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(file)))) {
int b; int b;

View File

@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.mod.modrinth;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.mod.RemoteModRepository; import org.jackhuang.hmcl.mod.RemoteModRepository;
import org.jackhuang.hmcl.util.DigestUtils; import org.jackhuang.hmcl.util.DigestUtils;
import org.jackhuang.hmcl.util.Hex; import org.jackhuang.hmcl.util.Hex;
@@ -64,13 +65,13 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
} }
@Override @Override
public Stream<RemoteModRepository.Mod> search(String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, int sort) throws IOException { public Stream<RemoteMod> search(String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, int sort) throws IOException {
return searchPaginated(gameVersion, pageOffset, pageSize, searchFilter).stream() return searchPaginated(gameVersion, pageOffset, pageSize, searchFilter).stream()
.map(ModResult::toMod); .map(ModResult::toMod);
} }
@Override @Override
public Optional<RemoteModRepository.Version> getRemoteVersionByLocalFile(Path file) throws IOException { public Optional<RemoteMod.Version> getRemoteVersionByLocalFile(Path file) throws IOException {
String sha1 = Hex.encodeHex(DigestUtils.digest("SHA-1", file)); String sha1 = Hex.encodeHex(DigestUtils.digest("SHA-1", file));
try { try {
@@ -288,23 +289,23 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
return loaders; return loaders;
} }
public Optional<RemoteModRepository.Version> toVersion() { public Optional<RemoteMod.Version> toVersion() {
RemoteModRepository.VersionType type; RemoteMod.VersionType type;
if ("release".equals(versionType)) { if ("release".equals(versionType)) {
type = RemoteModRepository.VersionType.Release; type = RemoteMod.VersionType.Release;
} else if ("beta".equals(versionType)) { } else if ("beta".equals(versionType)) {
type = RemoteModRepository.VersionType.Beta; type = RemoteMod.VersionType.Beta;
} else if ("alpha".equals(versionType)) { } else if ("alpha".equals(versionType)) {
type = RemoteModRepository.VersionType.Alpha; type = RemoteMod.VersionType.Alpha;
} else { } else {
type = RemoteModRepository.VersionType.Release; type = RemoteMod.VersionType.Release;
} }
if (files.size() == 0) { if (files.size() == 0) {
return Optional.empty(); return Optional.empty();
} }
return Optional.of(new RemoteModRepository.Version( return Optional.of(new RemoteMod.Version(
this, this,
name, name,
versionNumber, versionNumber,
@@ -342,12 +343,12 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
return filename; return filename;
} }
public RemoteModRepository.File toFile() { public RemoteMod.File toFile() {
return new RemoteModRepository.File(hashes, url, filename); return new RemoteMod.File(hashes, url, filename);
} }
} }
public static class ModResult implements RemoteModRepository.IMod { public static class ModResult implements RemoteMod.IMod {
@SerializedName("mod_id") @SerializedName("mod_id")
private final String modId; private final String modId;
@@ -457,19 +458,19 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
} }
@Override @Override
public List<RemoteModRepository.Mod> loadDependencies() throws IOException { public List<RemoteMod> loadDependencies() throws IOException {
return Collections.emptyList(); return Collections.emptyList();
} }
@Override @Override
public Stream<RemoteModRepository.Version> loadVersions() throws IOException { public Stream<RemoteMod.Version> loadVersions() throws IOException {
return ModrinthRemoteModRepository.INSTANCE.getFiles(this).stream() return ModrinthRemoteModRepository.INSTANCE.getFiles(this).stream()
.map(ModVersion::toVersion) .map(ModVersion::toVersion)
.flatMap(Lang::toStream); .flatMap(Lang::toStream);
} }
public RemoteModRepository.Mod toMod() { public RemoteMod toMod() {
return new RemoteModRepository.Mod( return new RemoteMod(
slug, slug,
author, author,
title, title,