Inceptum/launcher/src/main/java/io/gitlab/jfronny/inceptum/launcher/system/source/CurseforgeModSource.java

147 lines
5.1 KiB
Java

package io.gitlab.jfronny.inceptum.launcher.system.source;
import io.gitlab.jfronny.commons.HashUtils;
import io.gitlab.jfronny.commons.StringFormatter;
import io.gitlab.jfronny.commons.cache.MemoryOperationResultCache;
import io.gitlab.jfronny.commons.tuple.Triple;
import io.gitlab.jfronny.commons.tuple.Tuple;
import io.gitlab.jfronny.inceptum.common.Net;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.api.CurseforgeApi;
import io.gitlab.jfronny.inceptum.launcher.model.curseforge.*;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public final class CurseforgeModSource implements ModSource {
private static final MemoryOperationResultCache<Triple<Integer, Integer, String>, Optional<ModSource>> UPDATE_CACHE = new MemoryOperationResultCache<>(Utils.CACHE_SIZE);
private static final MemoryOperationResultCache<Tuple<Integer, Integer>, Set<ModSource>> DEPENDENCIES_CACHE = new MemoryOperationResultCache<>(Utils.CACHE_SIZE);
private final int projectId;
private final int fileId;
private final CurseforgeFile current;
private final CurseforgeMod mod;
public CurseforgeModSource(int projectId, int fileId) throws IOException {
this.projectId = projectId;
this.fileId = fileId;
this.current = CurseforgeApi.getFile(projectId, fileId);
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();
try {
Net.downloadFile(current.downloadUrl(), path);
} catch (URISyntaxException e) {
throw new IOException("Could not download file", e);
}
byte[] data = Files.readAllBytes(path);
return new ModDownload(HashUtils.sha1(data), HashUtils.murmur2(data), path);
}
@Override
public Set<ModSource> getDependencies(String gameVersion) throws IOException {
return DEPENDENCIES_CACHE.get(Tuple.of(projectId, fileId), () -> {
Set<ModSource> deps = new HashSet<>();
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;
});
}
@Override
public Optional<ModSource> getUpdate(String gameVersion) throws IOException {
return UPDATE_CACHE.get(Tuple.of(projectId, fileId, gameVersion), () -> {
for (CurseforgeMod.LatestFileIndex file : mod.latestFilesIndexes()) {
if (file.gameVersion().equals(gameVersion)) {
return file.fileId() == fileId
? Optional.empty()
: Optional.of(new CurseforgeModSource(projectId, file.fileId()));
}
}
return Optional.empty();
});
}
@Override
public String getVersion() {
return current.displayName();
}
@Override
public String getName() {
return "curseforge/" + getShortName() + '/' + current.id();
}
@Override
public String getShortName() {
return mod.slug() == null ? Integer.toString(mod.id()) : mod.slug();
}
@Override
public String getFileName() {
return current.fileName();
}
@Override
public String getDescription() {
try {
return CurseforgeApi.getDescription(mod.id());
} catch (IOException e) {
return "Could not get description\n\n" + StringFormatter.toString(e);
}
}
@Override
public String getSummary() {
return mod.summary();
}
@Override
public boolean equals(Object obj) {
return obj instanceof ModSource ms && equals(ms);
}
@Override
public boolean equals(ModSource other) {
return other instanceof CurseforgeModSource cu && cu.projectId == projectId && cu.fileId == fileId;
}
@Override
public boolean projectMatches(ModSource other) {
return other instanceof CurseforgeModSource cu && cu.projectId == projectId;
}
public int getFileId() {
return fileId;
}
public int getProjectId() {
return projectId;
}
public CurseforgeModpackManifest.File toManifest() {
return new CurseforgeModpackManifest.File(projectId, fileId, true);
}
}