Update for CFCore API
This commit is contained in:
parent
c205603bae
commit
11679ceb75
|
@ -1,4 +1,4 @@
|
|||
image: gradle:jdk17
|
||||
image: gradle:jdk18
|
||||
|
||||
variables:
|
||||
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
|
||||
|
|
|
@ -38,12 +38,12 @@ allprojects {
|
|||
}
|
||||
|
||||
ext {
|
||||
lwjglVersion = '3.3.0'
|
||||
lwjglVersion = '3.3.1'
|
||||
imguiVersion = '1.86.4'
|
||||
log4jVersion = '2.14.1'
|
||||
slf4jVersion = '1.7.36'
|
||||
logbackVersion = '1.2.11'
|
||||
jfCommonsVersion = '0.1.0.2022.4.28.21.6.56'
|
||||
jfCommonsVersion = '2022.6.5+13-35-53'
|
||||
jgitVersion = '6.1.0.202203080745-r'
|
||||
flavorProp = project.hasProperty('flavor') ? project.getProperty('flavor') : 'custom'
|
||||
flavor = flavorProp
|
||||
isPublic = project.hasProperty('public')
|
||||
|
@ -69,7 +69,7 @@ dependencies {
|
|||
implementation "ch.qos.logback:logback-classic:$logbackVersion"
|
||||
implementation "io.gitlab.jfronny:commons:$jfCommonsVersion"
|
||||
implementation "io.gitlab.jfronny:commons-gson:$jfCommonsVersion"
|
||||
implementation 'org.eclipse.jgit:org.eclipse.jgit:6.1.0.202203080745-r'
|
||||
implementation "org.eclipse.jgit:org.eclipse.jgit:$jgitVersion"
|
||||
implementation project(":wrapper")
|
||||
|
||||
implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.gitlab.jfronny.inceptum;
|
||||
|
||||
import io.gitlab.jfronny.commons.serialize.gson.GsonHolder;
|
||||
import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder;
|
||||
import io.gitlab.jfronny.inceptum.frontend.cli.CommandResolution;
|
||||
import io.gitlab.jfronny.inceptum.frontend.cli.Commands;
|
||||
import io.gitlab.jfronny.inceptum.frontend.gui.window.dialog.AlertWindow;
|
||||
|
|
|
@ -157,7 +157,6 @@ public class InceptumGui {
|
|||
* Main application loop.
|
||||
*/
|
||||
public static void run() {
|
||||
Map<String, Integer> windowCountByName = new HashMap<>();
|
||||
while (!GLFW.glfwWindowShouldClose(handle)) {
|
||||
//frame
|
||||
clearBuffer();
|
||||
|
@ -166,17 +165,9 @@ public class InceptumGui {
|
|||
//render
|
||||
if (WINDOWS.isEmpty()) exit();
|
||||
else {
|
||||
windowCountByName.clear();
|
||||
for (Window window : WINDOWS.toArray(new Window[0])) {
|
||||
if (window.isNew()) window.preFirstDraw();
|
||||
String title = window.getName();
|
||||
if (!windowCountByName.containsKey(title))
|
||||
windowCountByName.put(title, 1);
|
||||
else {
|
||||
int count = windowCountByName.get(title) + 1;
|
||||
windowCountByName.put(title, count);
|
||||
title += "##" + count;
|
||||
}
|
||||
String title = window.getName() + "##" + System.identityHashCode(window);
|
||||
if (ImGui.begin(title, window.getOpenState(), window.getFlags()))
|
||||
window.draw();
|
||||
ImGui.end();
|
||||
|
|
|
@ -188,8 +188,8 @@ public class AddModWindow extends Window {
|
|||
}
|
||||
else {
|
||||
if (ImGui.button("Add##" + mod.id)) {
|
||||
CurseforgeMod.GameVersionLatestFile latest = null;
|
||||
for (CurseforgeMod.GameVersionLatestFile file : mod.gameVersionLatestFiles) {
|
||||
CurseforgeMod.LatestFileIndex latest = null;
|
||||
for (CurseforgeMod.LatestFileIndex file : mod.latestFilesIndexes) {
|
||||
if (file.gameVersion.equals(instance.getMinecraftVersion())) {
|
||||
if (latest == null) latest = file;
|
||||
}
|
||||
|
@ -198,10 +198,10 @@ public class AddModWindow extends Window {
|
|||
Inceptum.showError("No valid version could be identified for this mod", "No version found");
|
||||
}
|
||||
else {
|
||||
CurseforgeMod.GameVersionLatestFile finalLatest = latest;
|
||||
CurseforgeMod.LatestFileIndex finalLatest = latest;
|
||||
new Thread(() -> {
|
||||
try {
|
||||
download(new CurseforgeModSource(mod.id, finalLatest.projectFileId), modsDir.resolve((mod.slug == null ? mod.id : mod.slug) + PathUtil.EXT_IMOD), mds).write();
|
||||
download(new CurseforgeModSource(mod.id, finalLatest.fileId), modsDir.resolve((mod.slug == null ? mod.id : mod.slug) + PathUtil.EXT_IMOD), mds).write();
|
||||
} catch (IOException e) {
|
||||
Inceptum.showError("Could not download mod", e);
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ public class AddModWindow extends Window {
|
|||
}
|
||||
ImGui.sameLine();
|
||||
if (ImGui.button("Web##" + mod.id)) {
|
||||
Utils.openWebBrowser(new URI(mod.websiteUrl));
|
||||
Utils.openWebBrowser(new URI(mod.links.websiteUrl));
|
||||
}
|
||||
}
|
||||
ImGui.endTable();
|
||||
|
@ -236,7 +236,7 @@ public class AddModWindow extends Window {
|
|||
}
|
||||
ModDownload md = ms.download();
|
||||
ModDescription manifest = ModDescription.of(md.sha1(), md.murmur2(), ms, mds.getGameVersion());
|
||||
for (ModSource dependency : ms.getDependencies()) {
|
||||
for (ModSource dependency : ms.getDependencies(mds.getGameVersion())) {
|
||||
DownloadMeta depMan = download(dependency, metaFile.getParent().resolve(dependency.getShortName() + PathUtil.EXT_IMOD), mds);
|
||||
depMan.description.dependents.add(md.file().getFileName().toString());
|
||||
manifest.dependencies.add(depMan.download.file().getFileName().toString());
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
package io.gitlab.jfronny.inceptum.frontend.gui.window;
|
||||
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import imgui.ImGui;
|
||||
import io.gitlab.jfronny.commons.serialize.gson.GsonHolder;
|
||||
import io.gitlab.jfronny.inceptum.Inceptum;
|
||||
import com.sun.net.httpserver.*;
|
||||
import imgui.*;
|
||||
import io.gitlab.jfronny.commons.serialize.gson.api.*;
|
||||
import io.gitlab.jfronny.inceptum.*;
|
||||
import io.gitlab.jfronny.inceptum.model.microsoft.*;
|
||||
import io.gitlab.jfronny.inceptum.util.Utils;
|
||||
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
|
||||
import io.gitlab.jfronny.inceptum.util.api.account.MicrosoftAccount;
|
||||
import io.gitlab.jfronny.inceptum.util.api.account.MicrosoftAuthAPI;
|
||||
import io.gitlab.jfronny.inceptum.util.*;
|
||||
import io.gitlab.jfronny.inceptum.util.api.account.*;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.charset.*;
|
||||
import java.util.*;
|
||||
|
||||
public class MicrosoftLoginWindow extends Window {
|
||||
private static HttpServer server;
|
||||
|
|
|
@ -30,12 +30,14 @@ public class ModSourceTypeAdapter implements JsonSerializer<ModSource>, JsonDese
|
|||
}
|
||||
}
|
||||
case "curseforge" -> {
|
||||
if (!jo.has("projectId"))
|
||||
throw new JsonParseException("Expected a projectId in this curseforge project");
|
||||
if (!jo.has("fileId"))
|
||||
throw new JsonParseException("Expected a fileId in this curseforge project");
|
||||
try {
|
||||
yield new CurseforgeModSource(jo.get("projectId").getAsInt(), jo.get("fileId").getAsInt());
|
||||
if (jo.has("projectId")) {
|
||||
yield new CurseforgeModSource(jo.get("projectId").getAsInt(), jo.get("fileId").getAsInt());
|
||||
} else if (jo.has("project")) {
|
||||
yield new CurseforgeModSource(jo.get("project").getAsString(), jo.get("fileId").getAsInt());
|
||||
} else throw new JsonParseException("Expected a projectId in this curseforge project");
|
||||
} catch (IOException e) {
|
||||
throw new JsonParseException("Could not fetch Curseforge source", e);
|
||||
}
|
||||
|
@ -69,7 +71,11 @@ public class ModSourceTypeAdapter implements JsonSerializer<ModSource>, JsonDese
|
|||
}
|
||||
else if (src instanceof CurseforgeModSource cu) {
|
||||
jo.add("type", new JsonPrimitive("curseforge"));
|
||||
jo.add("projectId", new JsonPrimitive(cu.getProjectId()));
|
||||
if (cu.getShortName().matches("\\d+")) {
|
||||
jo.add("projectId", new JsonPrimitive(cu.getProjectId()));
|
||||
} else {
|
||||
jo.add("project", new JsonPrimitive(cu.getShortName()));
|
||||
}
|
||||
jo.add("fileId", new JsonPrimitive(cu.getFileId()));
|
||||
}
|
||||
else throw new RuntimeException("ModSources with the type " + src.getClass() + " are not supported");
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
package io.gitlab.jfronny.inceptum.model.curseforge;
|
||||
|
||||
public class CurseforgeDependency {
|
||||
public Integer id;
|
||||
public Integer addonId;
|
||||
public Integer type;
|
||||
public Integer fileId;
|
||||
}
|
|
@ -1,24 +1,79 @@
|
|||
package io.gitlab.jfronny.inceptum.model.curseforge;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public class CurseforgeFile {
|
||||
public Integer id;
|
||||
public Integer gameId;
|
||||
public Integer modId;
|
||||
public Boolean isAvailable;
|
||||
public String displayName;
|
||||
public String fileName;
|
||||
public String fileDate;
|
||||
public Integer fileLength;
|
||||
/* Possible values:
|
||||
1=Release
|
||||
2=Beta
|
||||
3=Alpha*/
|
||||
public Integer releaseType;
|
||||
/* Possible values:
|
||||
1=Processing
|
||||
2=ChangesRequired
|
||||
3=UnderReview
|
||||
4=Approved
|
||||
5=Rejected
|
||||
6=MalwareDetected
|
||||
7=Deleted
|
||||
8=Archived
|
||||
9=Testing
|
||||
10=Released
|
||||
11=ReadyForReview
|
||||
12=Deprecated
|
||||
13=Baking
|
||||
14=AwaitingPublishing
|
||||
15=FailedPublishing*/
|
||||
public Integer fileStatus;
|
||||
public List<Hash> hashes;
|
||||
public Date fileDate;
|
||||
public Integer fileLength;
|
||||
public Long downloadCount;
|
||||
public String downloadUrl;
|
||||
public Boolean isAlternate;
|
||||
public List<String> gameVersions;
|
||||
public List<GameVersion> sortableGameVersions;
|
||||
public List<Dependency> dependencies;
|
||||
public Integer alternateFileId;
|
||||
public List<CurseforgeDependency> dependencies;
|
||||
public Boolean isAvailable;
|
||||
public List<CurseforgeModule> modules;
|
||||
public Long packageFingerprint;
|
||||
public List<String> gameVersion;
|
||||
public String gameVersionDateReleased;
|
||||
public Integer serverPackFileId;
|
||||
public Boolean hasInstallScript;
|
||||
public Boolean isServerPack;
|
||||
public Long fileFingerprint; // murmur5 hash
|
||||
public List<Module> modules;
|
||||
|
||||
public static class Hash {
|
||||
public String value;
|
||||
/* Possible values:
|
||||
1=Sha1
|
||||
2=Md5*/
|
||||
public Integer algo;
|
||||
}
|
||||
|
||||
public static class GameVersion {
|
||||
public String gameVersionName;
|
||||
public String gameVersionPadded;
|
||||
public String gameVersion;
|
||||
public Date gameVersionReleaseDate;
|
||||
public Integer gameVersionTypeId;
|
||||
}
|
||||
|
||||
public static class Dependency {
|
||||
public Integer modId;
|
||||
/* Possible values:
|
||||
1=EmbeddedLibrary
|
||||
2=OptionalDependency
|
||||
3=RequiredDependency
|
||||
4=Tool
|
||||
5=Incompatible
|
||||
6=Include*/
|
||||
public Integer relationType;
|
||||
}
|
||||
|
||||
public static class Module {
|
||||
public String name;
|
||||
public Long fingerprint;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package io.gitlab.jfronny.inceptum.model.curseforge;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CurseforgeFingerprint {
|
||||
public Boolean isCacheBuilt;
|
||||
public List<Mod> exactMatches;
|
||||
public List<Long> exactFingerprints;
|
||||
|
||||
public static class Mod {
|
||||
public Integer id;
|
||||
public CurseforgeFile file;
|
||||
public List<CurseforgeMod.File> latestFiles;
|
||||
}
|
||||
}
|
|
@ -1,137 +1,95 @@
|
|||
package io.gitlab.jfronny.inceptum.model.curseforge;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public class CurseforgeMod {
|
||||
public Integer id;
|
||||
public String name;
|
||||
public List<Author> authors;
|
||||
public List<Attachment> attachments;
|
||||
public String issueTrackerUrl;
|
||||
public String wikiUrl;
|
||||
public String sourceUrl;
|
||||
public String websiteUrl;
|
||||
public Integer gameId;
|
||||
public String summary;
|
||||
public Integer downloadFiles;
|
||||
public Long downloadCount;
|
||||
public List<File> latestFiles;
|
||||
public List<Category> categories;
|
||||
public Integer statue;
|
||||
public Integer primaryCategoryId;
|
||||
public CategorySection categorySection;
|
||||
public String name;
|
||||
public String slug;
|
||||
public List<GameVersionLatestFile> gameVersionLatestFiles;
|
||||
public Links links;
|
||||
public String summary;
|
||||
/* Possible values:
|
||||
1=New
|
||||
2=ChangesRequired
|
||||
3=UnderSoftReview
|
||||
4=Approved
|
||||
5=Rejected
|
||||
6=ChangesMade
|
||||
7=Inactive
|
||||
8=Abandoned
|
||||
9=Deleted
|
||||
10=UnderReview*/
|
||||
public Integer status;
|
||||
public Long downloadCount;
|
||||
public Boolean isFeatured;
|
||||
public Float popularityScore;
|
||||
public Integer primaryCategoryId;
|
||||
public List<Category> categories;
|
||||
public Integer classId;
|
||||
public List<Author> authors;
|
||||
public Logo logo;
|
||||
public List<Screenshot> screenshots;
|
||||
public Integer mainFileId;
|
||||
public List<CurseforgeFile> latestFiles;
|
||||
public List<LatestFileIndex> latestFilesIndexes;
|
||||
public Date dateCreated;
|
||||
public Date dateModified;
|
||||
public Date dateReleased;
|
||||
public Boolean allowModDistribution;
|
||||
public Integer gamePopularityRank;
|
||||
public String primaryLanguage;
|
||||
public String gameSlug;
|
||||
public List<String> modLoaders;
|
||||
public String gameName;
|
||||
public String portalName;
|
||||
//public Date dateModified;
|
||||
//public Date dateCreated;
|
||||
//public Date dateReleased;
|
||||
public Boolean isAvailable;
|
||||
public Boolean isExperimental;
|
||||
public Integer thumbsUpCount;
|
||||
|
||||
public static class Author {
|
||||
public String name;
|
||||
public String url;
|
||||
public Integer projectId;
|
||||
public Integer id;
|
||||
public Integer userId;
|
||||
public Integer twitchId;
|
||||
}
|
||||
|
||||
public static class Attachment {
|
||||
public Integer id;
|
||||
public Integer projectId;
|
||||
public String description;
|
||||
public Boolean isDefault;
|
||||
public String thumbnailUrl;
|
||||
public String title;
|
||||
public String url;
|
||||
public Integer status;
|
||||
}
|
||||
|
||||
public static class File {
|
||||
public Integer id;
|
||||
public String displayName;
|
||||
public String fileName;
|
||||
//public Date fileDate;
|
||||
public Integer fileLength;
|
||||
public Integer releaseType;
|
||||
public Integer fileStatus;
|
||||
public String downloadUrl;
|
||||
public Boolean isAlternate;
|
||||
public Integer alternatFileId;
|
||||
public List<CurseforgeDependency> dependencies;
|
||||
public Boolean isAvailable;
|
||||
public List<CurseforgeModule> modules;
|
||||
public Long packageFingerprint;
|
||||
public List<String> gameVersion;
|
||||
public List<SortableGameVersion> sortableGameVersion;
|
||||
public String changelog;
|
||||
public Boolean hasInstallScript;
|
||||
public Boolean isCompatibleWithClient;
|
||||
public Integer categorySectionPackageType;
|
||||
public Integer restrictProjectFileAccess;
|
||||
public Integer projectStatus;
|
||||
public Integer renderCacheId;
|
||||
public Integer projectId;
|
||||
public Long packageFingerprintId;
|
||||
//public Date gameVersionDateReleased;
|
||||
public Long gameVersionMappingId;
|
||||
public Integer gameVersionId;
|
||||
public Integer gameId;
|
||||
public Boolean isServerPack;
|
||||
public List<Hash> hashes;
|
||||
|
||||
public static class SortableGameVersion {
|
||||
public String gameVersionPadded;
|
||||
public String gameVersion;
|
||||
//public Date gameVersionReleaseDate;
|
||||
public String gameVersionName;
|
||||
public Integer gameVersionTypeId;
|
||||
}
|
||||
|
||||
public static class Hash {
|
||||
public Integer algorithm;
|
||||
public String value;
|
||||
}
|
||||
public static class Links {
|
||||
public String websiteUrl;
|
||||
public String wikiUrl;
|
||||
public String issuesUrl;
|
||||
public String sourcesUrl;
|
||||
}
|
||||
|
||||
public static class Category {
|
||||
public Integer categoryId;
|
||||
public String name;
|
||||
public String url;
|
||||
public String avatarUrl;
|
||||
public Integer parentId;
|
||||
public Integer rootId;
|
||||
public Integer projectId;
|
||||
public Integer avatarId;
|
||||
public Integer gameId;
|
||||
public String slug;
|
||||
//public Date dateModified;
|
||||
}
|
||||
|
||||
public static class CategorySection {
|
||||
public Integer id;
|
||||
public Integer gameId;
|
||||
public String name;
|
||||
public Integer packageType;
|
||||
public String path;
|
||||
public String initialInclusionPattern;
|
||||
public Integer gameCategoryId;
|
||||
public String slug;
|
||||
public String url;
|
||||
public String iconUrl;
|
||||
public Date dateModified;
|
||||
public Boolean isClass;
|
||||
public Integer classId;
|
||||
public Integer primaryCategoryId;
|
||||
}
|
||||
|
||||
public static class GameVersionLatestFile {
|
||||
public static class Author {
|
||||
public Integer id;
|
||||
public String name;
|
||||
public String url;
|
||||
}
|
||||
|
||||
public static class Logo {
|
||||
public Integer id;
|
||||
public Integer modId;
|
||||
public String title;
|
||||
public String description;
|
||||
public String thumbnailUrl;
|
||||
public String url;
|
||||
}
|
||||
|
||||
public static class Screenshot {
|
||||
public Integer id;
|
||||
public Integer modId;
|
||||
public String title;
|
||||
public String description;
|
||||
public String thumbnailUrl;
|
||||
public String url;
|
||||
}
|
||||
|
||||
public static class LatestFileIndex {
|
||||
public String gameVersion;
|
||||
public Integer projectFileId;
|
||||
public String projectFileName;
|
||||
public Integer fileType;
|
||||
public Integer fileId;
|
||||
public String filename;
|
||||
public Integer releaseType;
|
||||
public Integer gameVersionTypeId;
|
||||
public Integer modLoader;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package io.gitlab.jfronny.inceptum.model.curseforge;
|
||||
|
||||
public class CurseforgeModule {
|
||||
public String folderName;
|
||||
public Long fingerprint;
|
||||
public Integer type;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package io.gitlab.jfronny.inceptum.model.curseforge.response;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class FingerprintMatchesResponse {
|
||||
public Result data;
|
||||
|
||||
public static class Result {
|
||||
public Boolean isCacheBuilt;
|
||||
public List<Match> exactMatches;
|
||||
public List<Integer> exactFingerprints;
|
||||
public List<Match> partialMatches;
|
||||
public List<Integer> installedFingerprints;
|
||||
public List<Integer> unmatchedFingerprints;
|
||||
|
||||
public static class Match {
|
||||
public Integer id;
|
||||
public CurseforgeFile file;
|
||||
public List<CurseforgeFile> latestFiles;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package io.gitlab.jfronny.inceptum.model.curseforge.response;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.*;
|
||||
|
||||
public class GetModFileResponse {
|
||||
public CurseforgeFile data;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package io.gitlab.jfronny.inceptum.model.curseforge.response;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.*;
|
||||
|
||||
public class GetModResponse {
|
||||
public CurseforgeMod data;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package io.gitlab.jfronny.inceptum.model.curseforge.response;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SearchResponse {
|
||||
public List<CurseforgeMod> data;
|
||||
public Pagination pagination;
|
||||
|
||||
public static class Pagination {
|
||||
public Integer index;
|
||||
public Integer pageSite;
|
||||
public Integer resultCount;
|
||||
public Integer totalCount;
|
||||
}
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
package io.gitlab.jfronny.inceptum.model.inceptum;
|
||||
|
||||
import io.gitlab.jfronny.commons.serialize.gson.GsonIgnore;
|
||||
import io.gitlab.jfronny.commons.serialize.gson.api.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
public class InstanceMeta {
|
||||
@GsonIgnore
|
||||
@Ignore
|
||||
public static final String floaderPrefix = "fabric-loader-";
|
||||
public String version;
|
||||
public String java;
|
||||
|
|
|
@ -1,25 +1,21 @@
|
|||
package io.gitlab.jfronny.inceptum.model.inceptum;
|
||||
|
||||
import io.gitlab.jfronny.commons.HashUtils;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeFingerprint;
|
||||
import io.gitlab.jfronny.inceptum.util.source.CurseforgeModSource;
|
||||
import io.gitlab.jfronny.inceptum.util.source.ModSource;
|
||||
import io.gitlab.jfronny.inceptum.util.source.ModrinthModSource;
|
||||
import io.gitlab.jfronny.inceptum.util.Utils;
|
||||
import io.gitlab.jfronny.inceptum.util.api.CurseforgeApi;
|
||||
import io.gitlab.jfronny.inceptum.util.api.ModrinthApi;
|
||||
import org.eclipse.jgit.annotations.Nullable;
|
||||
import io.gitlab.jfronny.commons.*;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.response.*;
|
||||
import io.gitlab.jfronny.inceptum.util.*;
|
||||
import io.gitlab.jfronny.inceptum.util.api.*;
|
||||
import io.gitlab.jfronny.inceptum.util.source.*;
|
||||
import org.eclipse.jgit.annotations.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
|
||||
public class ModDescription {
|
||||
public Map<ModSource, Optional<ModSource>> sources; //key: source, value: update
|
||||
public String sha1;
|
||||
public String murmur2;
|
||||
public Long murmur2;
|
||||
public List<String> dependents; // by file name
|
||||
public List<String> dependencies; // by file name
|
||||
|
||||
|
@ -43,9 +39,9 @@ public class ModDescription {
|
|||
}
|
||||
if (!curseforge) {
|
||||
try {
|
||||
CurseforgeFingerprint cf = CurseforgeApi.checkFingerprint(murmur2);
|
||||
FingerprintMatchesResponse.Result cf = CurseforgeApi.checkFingerprint(murmur2);
|
||||
if (!cf.exactMatches.isEmpty()) {
|
||||
CurseforgeFingerprint.Mod f = cf.exactMatches.get(0);
|
||||
FingerprintMatchesResponse.Result.Match f = cf.exactMatches.get(0);
|
||||
addSource(new CurseforgeModSource(f.id, f.file.id), gameVersion);
|
||||
changed = true;
|
||||
}
|
||||
|
@ -72,7 +68,7 @@ public class ModDescription {
|
|||
return res;
|
||||
}
|
||||
|
||||
public static ModDescription of(String sha1, String murmur2, @Nullable ModSource knownSource, String gameVersion) {
|
||||
public static ModDescription of(String sha1, Long murmur2, @Nullable ModSource knownSource, String gameVersion) {
|
||||
ModDescription res = new ModDescription();
|
||||
res.sources = new LinkedHashMap<>();
|
||||
res.sha1 = sha1;
|
||||
|
|
|
@ -1,27 +1,21 @@
|
|||
package io.gitlab.jfronny.inceptum.util;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeModpackManifest;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
|
||||
import io.gitlab.jfronny.inceptum.model.multimc.MMCPackMeta;
|
||||
import io.gitlab.jfronny.inceptum.util.mds.IWModDescription;
|
||||
import io.gitlab.jfronny.inceptum.util.mds.ModsDirScanner;
|
||||
import io.gitlab.jfronny.inceptum.util.source.CurseforgeModSource;
|
||||
import io.gitlab.jfronny.inceptum.util.source.ModSource;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.*;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.*;
|
||||
import io.gitlab.jfronny.inceptum.model.multimc.*;
|
||||
import io.gitlab.jfronny.inceptum.util.mds.*;
|
||||
import io.gitlab.jfronny.inceptum.util.source.*;
|
||||
import org.eclipse.jgit.api.*;
|
||||
import org.eclipse.jgit.api.errors.*;
|
||||
import org.eclipse.jgit.treewalk.FileTreeIterator;
|
||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||
import org.eclipse.jgit.treewalk.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.nio.file.*;
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
|
||||
//TODO deduplicate
|
||||
//TODO modrinth export
|
||||
|
|
|
@ -1,46 +1,86 @@
|
|||
package io.gitlab.jfronny.inceptum.util.api;
|
||||
|
||||
import io.gitlab.jfronny.commons.HttpUtils;
|
||||
import io.gitlab.jfronny.gson.reflect.TypeToken;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeFile;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeFingerprint;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeMod;
|
||||
import io.gitlab.jfronny.inceptum.util.Utils;
|
||||
import io.gitlab.jfronny.commons.*;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.*;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.response.*;
|
||||
import io.gitlab.jfronny.inceptum.util.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
public class CurseforgeApi {
|
||||
private static final String API_URL = "https://addons-ecs.forgesvc.net/api/v2/";
|
||||
private static final Type curseforgeModListType = new TypeToken<List<CurseforgeMod>>() {}.getType();
|
||||
// So you found the API key.
|
||||
// Please be aware that CurseForge requires you to change this if you make any kind of derivative work
|
||||
// Creating your own API key is relatively simple, so please don't abuse this
|
||||
private static final String API_KEY = new String(unsalt(new byte[] {
|
||||
-30, 50, -60, -121, 62, -31, 35, 17, 16, -53,
|
||||
-53, -88, 21, -21, 15, -105, -115, -108, 114, -50,
|
||||
-49, -4, 56, -65, -70, 108, -65, -3, -55, -4,
|
||||
36, -86, -40, 116, 71, -5, 75, -9, -43, 4,
|
||||
91, -91, -29, 40, 66, 87, -80, -74, 71, 41,
|
||||
76, -96, 108, -61, -113, 118, 7, -39, -116, -120
|
||||
}, 1024));
|
||||
|
||||
private static final String API_URL = "https://api.curseforge.com/v1/";
|
||||
private static final int pageSize = 20;
|
||||
|
||||
//TODO use gameVersion
|
||||
public static List<CurseforgeMod> search(String gameVersion, String query, int page, String sort) throws IOException {
|
||||
return Utils.downloadObject(Utils.buildUrl(API_URL, "addon/search", Map.of(
|
||||
return Utils.downloadObject(Utils.buildUrl(API_URL, "mods/search", Map.of(
|
||||
"gameId", "432", // minecraft
|
||||
"modLoaderType", "4", // fabric, forge would be 1
|
||||
"sectionId", "6", // mods
|
||||
"modLoaderType", "4", // fabric
|
||||
"classId", "6", // mods
|
||||
// "categoryId", ""
|
||||
"searchFilter", query,
|
||||
"sort", sort,
|
||||
"sortDescending", "true",
|
||||
"sortField", sort,
|
||||
"sortOrder", "desc",
|
||||
"gameVersion", gameVersion,
|
||||
"pageSize", Integer.toString(pageSize),
|
||||
"index", Integer.toString(page * pageSize)
|
||||
)), curseforgeModListType);
|
||||
)), SearchResponse.class, API_KEY);
|
||||
}
|
||||
|
||||
public static CurseforgeMod getMod(String slug) throws IOException {
|
||||
SearchResponse response = Utils.downloadObject(Utils.buildUrl(API_URL, "mods/search", Map.of(
|
||||
"gameId", "432",
|
||||
"classId", "6",
|
||||
"slug", slug
|
||||
)), SearchResponse.class, API_KEY);
|
||||
if (response.pagination.totalCount != 1) {
|
||||
throw new FileNotFoundException("Could not find mod with slug \"" + slug + "\"");
|
||||
}
|
||||
return checkDistribution(response.data.get(0));
|
||||
}
|
||||
|
||||
public static CurseforgeMod getMod(int id) throws IOException {
|
||||
return Utils.downloadObject(API_URL + "addon/" + id, CurseforgeMod.class);
|
||||
GetModResponse response = Utils.downloadObject(API_URL + "mods/" + id, GetModResponse.class, API_KEY);
|
||||
return checkDistribution(response.data);
|
||||
}
|
||||
|
||||
private static CurseforgeMod checkDistribution(CurseforgeMod mod) {
|
||||
if (!mod.allowModDistribution) {
|
||||
throw new IllegalArgumentException("The author of the mod \"" + mod.slug + "\" has chosen to deliberately break your ability of downloading it.\n"
|
||||
+ "Please let them know that disabling third party downloads does nothing but make the users life harder for no reason.");
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
public static CurseforgeFile getFile(int modId, int fileId) throws IOException {
|
||||
return Utils.downloadObject(API_URL + "addon/" + modId + "/file/" + fileId, CurseforgeFile.class);
|
||||
GetModFileResponse response = Utils.downloadObject(API_URL + "mods/" + modId + "/files/" + fileId, GetModFileResponse.class, API_KEY);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public static CurseforgeFingerprint checkFingerprint(String hash) throws IOException, URISyntaxException {
|
||||
return HttpUtils.post(API_URL + "fingerprint").bodyJson("[" + hash + "]").sendSerialized(CurseforgeFingerprint.class);
|
||||
public static FingerprintMatchesResponse.Result checkFingerprint(long hash) throws IOException, URISyntaxException {
|
||||
FingerprintMatchesResponse response = HttpUtils.post(API_URL + "fingerprints").bodyJson("{\"fingerprints\":[" + hash + "]}").sendSerialized(FingerprintMatchesResponse.class);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
private static byte[] unsalt(byte[] data, int salt) {
|
||||
byte[] result = new byte[data.length];
|
||||
new Random(salt).nextBytes(result);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
result[i] ^= data[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package io.gitlab.jfronny.inceptum.util.source;
|
|||
import io.gitlab.jfronny.commons.HashUtils;
|
||||
import io.gitlab.jfronny.commons.tuple.Triple;
|
||||
import io.gitlab.jfronny.commons.tuple.Tuple;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeDependency;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeFile;
|
||||
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeMod;
|
||||
import io.gitlab.jfronny.inceptum.util.Utils;
|
||||
|
@ -34,6 +33,13 @@ public final class CurseforgeModSource implements ModSource {
|
|||
this.mod = CurseforgeApi.getMod(projectId);
|
||||
}
|
||||
|
||||
public CurseforgeModSource(String projectSlug, int fileId) throws IOException {
|
||||
this.mod = CurseforgeApi.getMod(projectSlug);
|
||||
this.projectId = mod.id;
|
||||
this.fileId = fileId;
|
||||
this.current = CurseforgeApi.getFile(projectId, fileId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModDownload download() throws IOException {
|
||||
Path path = getJarPath();
|
||||
|
@ -47,12 +53,18 @@ public final class CurseforgeModSource implements ModSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ModSource> getDependencies() throws IOException {
|
||||
public Set<ModSource> getDependencies(String gameVersion) throws IOException {
|
||||
return DEPENDENCIES_CACHE.get(Tuple.of(projectId, fileId), () -> {
|
||||
Set<ModSource> deps = new HashSet<>();
|
||||
for (CurseforgeDependency dependency : current.dependencies) {
|
||||
if (dependency.type == 3) //TODO support other types (3=required, 2=optional)
|
||||
deps.add(new CurseforgeModSource(dependency.addonId, dependency.fileId));
|
||||
for (CurseforgeFile.Dependency dependency : current.dependencies) {
|
||||
if (dependency.relationType == 3) { //TODO support other types (IDs are documented on field declaration)
|
||||
for (CurseforgeMod.LatestFileIndex index : CurseforgeApi.getMod(dependency.modId).latestFilesIndexes) {
|
||||
if (index.gameVersion.equals(gameVersion)) {
|
||||
deps.add(new CurseforgeModSource(dependency.modId, index.fileId));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
});
|
||||
|
@ -61,11 +73,11 @@ public final class CurseforgeModSource implements ModSource {
|
|||
@Override
|
||||
public Optional<ModSource> getUpdate(String gameVersion) throws IOException {
|
||||
return UPDATE_CACHE.get(Tuple.of(projectId, fileId, gameVersion), () -> {
|
||||
for (CurseforgeMod.GameVersionLatestFile file : mod.gameVersionLatestFiles) {
|
||||
for (CurseforgeMod.LatestFileIndex file : mod.latestFilesIndexes) {
|
||||
if (file.gameVersion.equals(gameVersion)) {
|
||||
return file.projectFileId == fileId
|
||||
return file.fileId == fileId
|
||||
? Optional.empty()
|
||||
: Optional.of(new CurseforgeModSource(projectId, file.projectFileId));
|
||||
: Optional.of(new CurseforgeModSource(projectId, file.fileId));
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
|
|
|
@ -28,7 +28,7 @@ public record DirectModSource(String fileName, String url, Set<ModSource> depend
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ModSource> getDependencies() throws IOException {
|
||||
public Set<ModSource> getDependencies(String gameVersion) throws IOException {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,5 +2,5 @@ package io.gitlab.jfronny.inceptum.util.source;
|
|||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public record ModDownload(String sha1, String murmur2, Path file) {
|
||||
public record ModDownload(String sha1, long murmur2, Path file) {
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.util.Set;
|
|||
|
||||
public interface ModSource {
|
||||
ModDownload download() throws IOException;
|
||||
Set<ModSource> getDependencies() throws IOException;
|
||||
Set<ModSource> getDependencies(String gameVersion) throws IOException;
|
||||
Optional<ModSource> getUpdate(String gameVersion) throws IOException;
|
||||
String getVersion();
|
||||
String getName();
|
||||
|
@ -17,6 +17,11 @@ public interface ModSource {
|
|||
String getFileName();
|
||||
boolean equals(ModSource other);
|
||||
default Path getJarPath() {
|
||||
return MetaHolder.LIBRARIES_DIR.resolve("com").resolve(getName()).resolve(getFileName());
|
||||
try {
|
||||
return MetaHolder.LIBRARIES_DIR.resolve("com").resolve(getName()).resolve(getFileName());
|
||||
} catch (NullPointerException npe) {
|
||||
System.identityHashCode(this);
|
||||
throw npe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public final class ModrinthModSource implements ModSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ModSource> getDependencies() throws IOException {
|
||||
public Set<ModSource> getDependencies(String gameVersion) throws IOException {
|
||||
return DEPENDENCIES_CACHE.get(versionId, () -> {
|
||||
Set<ModSource> deps = new HashSet<>();
|
||||
for (ModrinthVersion.Dependency dependency : current.dependencies) {
|
||||
|
|
|
@ -1,22 +1,16 @@
|
|||
package io.gitlab.jfronny.inceptum;
|
||||
|
||||
import io.gitlab.jfronny.commons.ComparableVersion;
|
||||
import io.gitlab.jfronny.commons.OSUtils;
|
||||
import io.gitlab.jfronny.commons.serialize.gson.GsonHolder;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.UpdateChannel;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.UpdateInfo;
|
||||
import io.gitlab.jfronny.commons.*;
|
||||
import io.gitlab.jfronny.commons.serialize.gson.api.*;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.*;
|
||||
import io.gitlab.jfronny.inceptum.util.*;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
public class Wrapper {
|
||||
private static final Path INCEPTUM_LIB_DIR = MetaHolder.BASE_PATH.resolve("libraries/io/gitlab/jfronny/inceptum/Inceptum");
|
||||
|
|
|
@ -1,20 +1,12 @@
|
|||
package io.gitlab.jfronny.inceptum.util;
|
||||
|
||||
import io.gitlab.jfronny.commons.ComparableVersion;
|
||||
import io.gitlab.jfronny.commons.OSUtils;
|
||||
import io.gitlab.jfronny.commons.serialize.gson.ComparableVersionAdapter;
|
||||
import io.gitlab.jfronny.gson.GsonBuilder;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.InceptumVersion;
|
||||
import io.gitlab.jfronny.commons.*;
|
||||
import io.gitlab.jfronny.commons.serialize.gson.api.*;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.file.*;
|
||||
|
||||
public class MetaHolder {
|
||||
public static final InceptumVersion VERSION;
|
||||
|
@ -23,10 +15,7 @@ public class MetaHolder {
|
|||
static {
|
||||
try (InputStream is = MetaHolder.class.getClassLoader().getResourceAsStream("version.json");
|
||||
InputStreamReader isr = new InputStreamReader(is)) {
|
||||
VERSION = new GsonBuilder()
|
||||
.registerTypeAdapter(ComparableVersion.class, new ComparableVersionAdapter())
|
||||
.create()
|
||||
.fromJson(isr, InceptumVersion.class);
|
||||
VERSION = GsonHolder.getGson().fromJson(isr, InceptumVersion.class);
|
||||
if (System.getProperty("inceptum.base") == null) {
|
||||
Path runDir = getRunDir();
|
||||
BASE_PATH = VERSION.isRelease && !Files.exists(runDir)
|
||||
|
|
|
@ -1,35 +1,25 @@
|
|||
package io.gitlab.jfronny.inceptum.util;
|
||||
|
||||
import io.gitlab.jfronny.commons.HashUtils;
|
||||
import io.gitlab.jfronny.commons.HttpUtils;
|
||||
import io.gitlab.jfronny.commons.OSUtils;
|
||||
import io.gitlab.jfronny.commons.serialize.Serializer;
|
||||
import io.gitlab.jfronny.commons.serialize.SerializerHolder;
|
||||
import io.gitlab.jfronny.commons.serialize.gson.GsonHolder;
|
||||
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
|
||||
import io.gitlab.jfronny.commons.throwable.ThrowingSupplier;
|
||||
import io.gitlab.jfronny.inceptum.WrapperStrap;
|
||||
import io.gitlab.jfronny.inceptum.util.cache.GsonFileCache;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import io.gitlab.jfronny.commons.*;
|
||||
import io.gitlab.jfronny.commons.serialize.gson.api.*;
|
||||
import io.gitlab.jfronny.commons.throwable.*;
|
||||
import io.gitlab.jfronny.inceptum.*;
|
||||
import io.gitlab.jfronny.inceptum.util.cache.*;
|
||||
import org.slf4j.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
import java.nio.charset.*;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.*;
|
||||
import java.util.function.*;
|
||||
import java.util.regex.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
public class Utils {
|
||||
public static final Pattern VALID_FILENAME = Pattern.compile("[a-zA-Z0-9_\\-.][a-zA-Z0-9 _\\-.]*[a-zA-Z0-9_\\-.]");
|
||||
|
@ -61,6 +51,10 @@ public class Utils {
|
|||
return downloadObject(url, type, true);
|
||||
}
|
||||
|
||||
public static <T> T downloadObject(String url, Type type, String apiKey) throws IOException {
|
||||
return downloadObject(url, () -> HttpUtils.get(url).header("x-api-key", apiKey).sendString(), type, true);
|
||||
}
|
||||
|
||||
public static <T> T downloadObject(String url, Type type, boolean cache) throws IOException {
|
||||
return downloadObject(url, () -> HttpUtils.get(url).sendString(), type, cache);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue