Separate search pages for mr/cf, filter updatable in instance edit, fix mod adding

This commit is contained in:
Johannes Frohnmeyer 2022-01-02 18:26:49 +01:00
parent ca2ad0306a
commit 66241d5631
Signed by: Johannes
GPG Key ID: E76429612C2929F4
8 changed files with 190 additions and 144 deletions

View File

@ -25,7 +25,6 @@ import java.nio.file.Path;
import java.util.Scanner;
import java.util.function.Consumer;
//TODO allow instance sync through metadata
public class Inceptum {
public static final Path CACHE_DIR = MetaHolder.BASE_PATH.resolve("cache");
public static final Path INSTANCE_DIR = MetaHolder.BASE_PATH.resolve("instances");

View File

@ -31,7 +31,6 @@ public class DownloadClientStep implements Step {
Utils.downloadFile(client.url, client.sha1, clientPath);
}
Inceptum.LOGGER.info(serverPath.toString());
Inceptum.LOGGER.info(Boolean.toString(Files.exists(serverPath)));
if (!Files.exists(serverPath)) {
MojangFileDownload server = info.version().downloads.server;
if (new ComparableVersion(minecraftVersion).compareTo("1.18") >= 0) {

View File

@ -50,13 +50,11 @@ public final class ModrinthModSource implements ModSource {
ModrinthVersion latest = null;
for (ModrinthVersion version : ModrinthApi.getVersions(getModId())) {
if (version.game_versions.contains(gameVersion) && version.loaders.contains("fabric")) {
if (latest == null) latest = version;
if (version.version_type == ModrinthVersion.VersionType.beta || version.version_type == ModrinthVersion.VersionType.release) {
latest = version;
if (version.version_type == ModrinthVersion.VersionType.beta || version.version_type == ModrinthVersion.VersionType.release)
beta = version;
}
if (version.version_type == ModrinthVersion.VersionType.release) {
if (version.version_type == ModrinthVersion.VersionType.release)
stable = version;
}
}
}
ModrinthVersion next = switch (current.version_type) {
@ -91,7 +89,7 @@ public final class ModrinthModSource implements ModSource {
@Override
public boolean equals(ModSource other) {
return other instanceof ModrinthModSource ms && ms.getModId().equals(getModId());
return other instanceof ModrinthModSource ms && ms.getModId().equals(getModId()) && ms.versionId.equals(versionId);
}
public String getVersionId() {

View File

@ -57,6 +57,10 @@ public class ModsDirScanner implements Closeable {
return descriptions.get(path);
}
public void invalidate(Path path) {
descriptions.remove(path);
}
private void scanTaskInternal() {
while (!disposed) {
try {

View File

@ -8,6 +8,7 @@ import io.gitlab.jfronny.inceptum.util.Utils;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
@ -17,6 +18,7 @@ public class ModrinthApi {
private static final Type modrinthVersionListType = new TypeToken<List<ModrinthVersion>>() {}.getType();
//TODO search by categories: facets:[["versions:$ver","versions:$ver"],["categories:$cat","categories:$cat"]]
//TODO filter server/client-only mods
public static ModrinthSearchResult search(String query, int page, String version) throws IOException {
return Utils.downloadObject(Utils.buildUrl(API_HOST, "api/v1/mod", Map.of(
"query", query,
@ -33,7 +35,9 @@ public class ModrinthApi {
}
public static List<ModrinthVersion> getVersions(String mod) throws IOException {
return Utils.downloadObject(API_HOST + "api/v1/mod/" + mod + "/version", modrinthVersionListType);
List<ModrinthVersion> versions = Utils.downloadObject(API_HOST + "api/v1/mod/" + mod + "/version", modrinthVersionListType);
versions.sort(Comparator.comparing(version -> version.date_published));
return versions;
}
public static ModrinthVersion getVersion(String id) throws IOException {

View File

@ -23,14 +23,14 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
public class AddModWindow extends Window {
private final ImString query = new ImString("", 128);
private final Path modsDir;
private final InstanceMeta instance;
private final ModsDirScanner mds;
private int page = 0;
private int cfPage = 0;
private int mrPage = 0;
private ModrinthSearchResult mr = null;
private List<CurseforgeMod> cf = null;
public AddModWindow(Path modsDir, InstanceMeta instance, ModsDirScanner mds) {
@ -40,10 +40,10 @@ public class AddModWindow extends Window {
this.mds = mds;
}
private void refreshMR() throws IOException {
private void reSearch() throws IOException {
//TODO move to thread maybe
mr = ModrinthApi.search(query.get(), page, instance.getMinecraftVersion());
cf = CurseforgeApi.search(instance.getMinecraftVersion(), query.get(), page, "Popularity");
mr = ModrinthApi.search(query.get(), mrPage, instance.getMinecraftVersion());
cf = CurseforgeApi.search(instance.getMinecraftVersion(), query.get(), cfPage, "Popularity");
//if (mr.hits.isEmpty()) page = 0;
}
@ -51,160 +51,178 @@ public class AddModWindow extends Window {
public void draw() {
try {
if (ImGui.inputTextWithHint("Search", "Your search query", query)) {
refreshMR();
reSearch();
}
if (mr != null) {
boolean hasNext = (mr.offset + mr.hits.size() < mr.limit) || cf.size() == 20;
if (page > 0 && ImGui.button("Previous Page")) {
page--;
refreshMR();
if (hasNext)
ImGui.sameLine();
}
if (hasNext && ImGui.button("Next Page")) {
page++;
refreshMR();
}
if (ImGui.beginTabBar("ModsSelect")) {
if (ImGui.beginTabItem("Modrinth")) {
if (ImGui.beginTable("mods" + modsDir, 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
for (ModrinthSearchResult.ModResult mod : mr.hits) {
String modId = (mod.slug != null ? mod.slug : mod.mod_id);
final String idPrefix = "local-";
if (mod.mod_id.startsWith(idPrefix))
mod.mod_id = mod.mod_id.substring(idPrefix.length());
//TODO detail view
ImGui.tableNextColumn();
ImGui.text(mod.title);
ImGui.tableNextColumn();
ImGui.text(mod.description);
ImGui.tableNextColumn();
boolean alreadyPresent = false;
for (ModsDirScanner.IWModDescription mdsMod : mds.getMods()) {
alreadyPresent = mdsMod.mod().isPresent()
&& mdsMod.mod().get().sources.keySet().stream()
.anyMatch(s -> s instanceof ModrinthModSource ms
&& ms.getModId().equals(mod.mod_id));
if (alreadyPresent)
break;
}
if (alreadyPresent) {
ImGui.text("Installed");
}
else {
if (ImGui.button("Add##" + mod.mod_id)) {
ModrinthVersion stable = null;
ModrinthVersion beta = null;
ModrinthVersion latest = null;
for (ModrinthVersion version : ModrinthApi.getVersions(mod.mod_id)) {
if (version.game_versions.contains(instance.getMinecraftVersion()) && version.loaders.contains("fabric")) {
if (latest == null) latest = version;
if (beta == null && (version.version_type == ModrinthVersion.VersionType.beta || version.version_type == ModrinthVersion.VersionType.release)) {
beta = version;
}
if (stable == null && (version.version_type == ModrinthVersion.VersionType.release)) {
stable = version;
}
if (ImGui.beginTabBar("ModsSelect")) {
if (ImGui.beginTabItem("Modrinth")) {
if (mr != null) {
boolean hasNext = (mr.offset + mr.hits.size() < mr.total_hits);
if (mrPage > 0) {
if (ImGui.button("Previous Page")) {
mrPage--;
reSearch();
}
if (hasNext)
ImGui.sameLine();
}
if (hasNext && ImGui.button("Next Page")) {
mrPage++;
reSearch();
}
}
if (mr != null && ImGui.beginTable("mods" + modsDir, 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
for (ModrinthSearchResult.ModResult mod : mr.hits) {
String modId = (mod.slug != null ? mod.slug : mod.mod_id);
final String idPrefix = "local-";
if (mod.mod_id.startsWith(idPrefix))
mod.mod_id = mod.mod_id.substring(idPrefix.length());
//TODO detail view
ImGui.tableNextColumn();
ImGui.text(mod.title);
ImGui.tableNextColumn();
ImGui.text(mod.description);
ImGui.tableNextColumn();
boolean alreadyPresent = false;
for (ModsDirScanner.IWModDescription mdsMod : mds.getMods()) {
alreadyPresent = mdsMod.mod().isPresent()
&& mdsMod.mod().get().sources.keySet().stream()
.anyMatch(s -> s instanceof ModrinthModSource ms
&& ms.getModId().equals(mod.mod_id));
if (alreadyPresent)
break;
}
if (alreadyPresent) {
ImGui.text("Installed");
}
else {
if (ImGui.button("Add##" + mod.mod_id)) {
ModrinthVersion stable = null;
ModrinthVersion beta = null;
ModrinthVersion latest = null;
for (ModrinthVersion version : ModrinthApi.getVersions(mod.mod_id)) {
if (version.game_versions.contains(instance.getMinecraftVersion()) && version.loaders.contains("fabric")) {
latest = version;
if (version.version_type == ModrinthVersion.VersionType.beta || version.version_type == ModrinthVersion.VersionType.release) {
beta = version;
}
if (version.version_type == ModrinthVersion.VersionType.release) {
stable = version;
}
}
if (stable != null) beta = stable;
if (beta != null) latest = beta;
if (latest == null) {
Inceptum.showError("No valid version could be identified for this mod", "No version found");
}
else {
//TODO don't block
download(new ModrinthModSource(latest.id), modsDir, mds).write();
}
}
if (stable != null) beta = stable;
if (beta != null) latest = beta;
if (latest == null) {
Inceptum.showError("No valid version could be identified for this mod", "No version found");
}
else {
//TODO don't block
download(new ModrinthModSource(latest.id), modsDir.resolve((mod.slug == null ? mod.mod_id : mod.slug) + ".imod"), mds).write();
}
}
ImGui.sameLine();
if (ImGui.button("Web##" + mod.mod_id)) {
Utils.openWebBrowser(new URI("https://modrinth.com/mod/" + modId));
}
}
ImGui.endTable();
}
ImGui.endTabItem();
}
if (ImGui.beginTabItem("Curseforge")) {
if (ImGui.beginTable("curseforge" + modsDir, 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
for (CurseforgeMod mod : cf) {
//TODO detail view
ImGui.tableNextColumn();
ImGui.text(mod.name);
ImGui.tableNextColumn();
ImGui.text(mod.summary);
ImGui.tableNextColumn();
boolean alreadyPresent = false;
for (ModsDirScanner.IWModDescription mdsMod : mds.getMods()) {
alreadyPresent = mdsMod.mod().isPresent()
&& mdsMod.mod().get().sources.keySet().stream()
.anyMatch(s -> s instanceof CurseforgeModSource ms
&& ms.getProjectId() == mod.id);
if (alreadyPresent)
break;
}
if (alreadyPresent) {
ImGui.text("Installed");
}
else {
if (ImGui.button("Add##" + mod.id)) {
CurseforgeMod.GameVersionLatestFile latest = null;
for (CurseforgeMod.GameVersionLatestFile file : mod.gameVersionLatestFiles) {
if (file.gameVersion.equals(instance.getMinecraftVersion())) {
if (latest == null) latest = file;
}
}
if (latest == null) {
Inceptum.showError("No valid version could be identified for this mod", "No version found");
}
else {
//TODO don't block
download(new CurseforgeModSource(mod.id, latest.projectFileId), modsDir, mds).write();
}
}
}
ImGui.sameLine();
if (ImGui.button("Web##" + mod.id)) {
Utils.openWebBrowser(new URI(mod.websiteUrl));
}
ImGui.sameLine();
if (ImGui.button("Web##" + mod.mod_id)) {
Utils.openWebBrowser(new URI("https://modrinth.com/mod/" + modId));
}
ImGui.endTable();
}
ImGui.endTabItem();
ImGui.endTable();
}
ImGui.endTabBar();
ImGui.endTabItem();
}
if (ImGui.beginTabItem("Curseforge")) {
if (cf != null) {
boolean hasNext = cf.size() == 20;
if (cfPage > 0) {
if (ImGui.button("Previous Page")) {
cfPage--;
reSearch();
}
if (hasNext)
ImGui.sameLine();
}
if (hasNext && ImGui.button("Next Page")) {
cfPage++;
reSearch();
}
}
if (cf != null && ImGui.beginTable("curseforge" + modsDir, 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
for (CurseforgeMod mod : cf) {
//TODO detail view
ImGui.tableNextColumn();
ImGui.text(mod.name);
ImGui.tableNextColumn();
ImGui.text(mod.summary);
ImGui.tableNextColumn();
boolean alreadyPresent = false;
for (ModsDirScanner.IWModDescription mdsMod : mds.getMods()) {
alreadyPresent = mdsMod.mod().isPresent()
&& mdsMod.mod().get().sources.keySet().stream()
.anyMatch(s -> s instanceof CurseforgeModSource ms
&& ms.getProjectId() == mod.id);
if (alreadyPresent)
break;
}
if (alreadyPresent) {
ImGui.text("Installed");
}
else {
if (ImGui.button("Add##" + mod.id)) {
CurseforgeMod.GameVersionLatestFile latest = null;
for (CurseforgeMod.GameVersionLatestFile file : mod.gameVersionLatestFiles) {
if (file.gameVersion.equals(instance.getMinecraftVersion())) {
if (latest == null) latest = file;
}
}
if (latest == null) {
Inceptum.showError("No valid version could be identified for this mod", "No version found");
}
else {
//TODO don't block
download(new CurseforgeModSource(mod.id, latest.projectFileId), modsDir.resolve((mod.slug == null ? mod.id : mod.slug) + ".imod"), mds).write();
}
}
}
ImGui.sameLine();
if (ImGui.button("Web##" + mod.id)) {
Utils.openWebBrowser(new URI(mod.websiteUrl));
}
}
ImGui.endTable();
}
ImGui.endTabItem();
}
ImGui.endTabBar();
}
} catch (IOException | URISyntaxException e) {
Inceptum.LOGGER.error("Something went wrong while rendering an AddModWindow", e);
}
}
public static DownloadMeta download(ModSource ms, Path modsDir, ModsDirScanner mds) throws IOException {
public static DownloadMeta download(ModSource ms, Path metaFile, ModsDirScanner mds) throws IOException {
for (ModsDirScanner.IWModDescription value : mds.getMods()) {
if (value.mod().isEmpty()) continue;
for (ModSource source : value.mod().get().sources.keySet()) {
if (ms.equals(source)) {
return new DownloadMeta(new ModDownload(value.mod().get().sha1, value.mod().get().murmur2, value.path()), value.mod().get(), source, modsDir);
return new DownloadMeta(new ModDownload(value.mod().get().sha1, value.mod().get().murmur2, value.path()), value.mod().get(), source, metaFile);
}
}
}
ModDownload md = ms.download();
ModDescription manifest = ModDescription.of(md.sha1(), md.murmur2(), ms, mds.getGameVersion());
for (ModSource dependency : ms.getDependencies()) {
DownloadMeta depMan = download(dependency, modsDir, mds);
DownloadMeta depMan = download(dependency, metaFile.getParent().resolve(dependency.getShortName() + ".imod"), mds);
depMan.description.dependents.add(md.file().getFileName().toString());
manifest.dependencies.add(depMan.download.file().getFileName().toString());
depMan.write();
}
return new DownloadMeta(md, manifest, ms, modsDir);
return new DownloadMeta(md, manifest, ms, metaFile);
}
public static record DownloadMeta(ModDownload download, ModDescription description, ModSource source, Path modsDir) {
public record DownloadMeta(ModDownload download, ModDescription description, ModSource source, Path metaFile) {
public void write() throws IOException {
Utils.writeObject(modsDir.resolve(download.file().getFileName().toString() + ".imod"), description);
Utils.writeObject(metaFile, description);
}
}
}

View File

@ -18,12 +18,14 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public class InstanceEditWindow extends Window {
private final Path path;
private final InstanceMeta instance;
private final InstanceManageControls imc;
private final ImBoolean customJava;
private final ImBoolean filterUpdates = new ImBoolean();
private final ImString customJavaPath = new ImString(128);
private final ModsDirScanner mds;
private Path selected = null;
@ -86,8 +88,6 @@ public class InstanceEditWindow extends Window {
ImGui.text("Did you know that every instance in Inceptum is a git repository?");
ImGui.endTabItem();
}
//TODO update all/better updatability indicator
//TODO there is still noticeable lag here
//TODO drag-and-drop mods
if (instance.isFabric() && ImGui.beginTabItem("Mods")) {
if (!Files.exists(path.resolve("mods"))) {
@ -109,9 +109,33 @@ public class InstanceEditWindow extends Window {
if (Files.exists(path.resolve("config")) && ImGui.button("Configs")) {
Utils.openFile(path.resolve("config").toFile());
}
ImGui.separator();
try {
for (ModsDirScanner.IWModDescription mod : mds.getMods()) {
Set<ModsDirScanner.IWModDescription> modSet = mds.getMods();
boolean updatesFound = false;
for (ModsDirScanner.IWModDescription mod : modSet) {
if (mod.mod().isEmpty()) continue;
for (Optional<ModSource> value : mod.mod().get().sources.values()) {
if (value.isPresent()) {
updatesFound = true;
break;
}
if (updatesFound)
break;
}
}
if (updatesFound)
ImGui.checkbox("Updatable", filterUpdates);
else
filterUpdates.set(false);
ImGui.separator();
for (ModsDirScanner.IWModDescription mod : modSet) {
updatesFound = false;
if (mod.mod().isPresent()) {
for (Optional<ModSource> value : mod.mod().get().sources.values()) {
updatesFound |= value.isPresent();
}
}
if (filterUpdates.get() && !updatesFound) continue;
final String disabledSuffix = ".disabled";
final String imodDisabledSuffix = ".disabled.imod";
String fName = mod.path().getFileName().toString();
@ -163,12 +187,14 @@ public class InstanceEditWindow extends Window {
ImGui.sameLine();
if (ImGui.button("Update to " + ms.get().getVersion())) {
try {
AddModWindow.DownloadMeta dm = AddModWindow.download(ms.get(), path.resolve("mods"), mds);
dm.write();
Path imodPath = md.imod().isPresent() ? md.imod().get() : path.resolve("mods").resolve(ms.get().getShortName() + ".imod");
AddModWindow.DownloadMeta dm = AddModWindow.download(ms.get(), imodPath, mds);
Files.delete(md.path());
if (md.imod().isPresent() && Files.exists(md.imod().get()))
Files.delete(md.imod().get());
selected = dm.download().file();
dm.write();
selected = imodPath;
mds.invalidate(imodPath);
} catch (IOException e) {
Inceptum.showError("Update failed", e);
}

View File

@ -3,7 +3,6 @@ package io.gitlab.jfronny.inceptum.windows;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.api.FabricMetaApi;
import io.gitlab.jfronny.inceptum.windows.control.InstanceManageControls;
import java.io.IOException;
@ -19,7 +18,6 @@ public class NewInstanceWindow extends Window {
public void draw() {
imc.snapshotsBox();
imc.versionBox(ver -> {});
//TODO forge
imc.nameBox("OK", name -> {
try {
InceptumGui.open(new InstanceCreateProcessWindow(new SetupStepInfo(imc.getVersionInfo(),