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, Optional> UPDATE_CACHE = new MemoryOperationResultCache<>(Utils.CACHE_SIZE); private static final MemoryOperationResultCache, Set> 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 getDependencies(String gameVersion) throws IOException { return DEPENDENCIES_CACHE.get(Tuple.of(projectId, fileId), () -> { Set 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 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); } }