package io.gitlab.jfronny.inceptum.launcher.system.source; import io.gitlab.jfronny.commons.HashUtils; import io.gitlab.jfronny.commons.cache.MemoryOperationResultCache; 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.ModrinthApi; import io.gitlab.jfronny.inceptum.launcher.model.modrinth.*; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; public final class ModrinthModSource implements ModSource { private static final MemoryOperationResultCache, Optional> UPDATE_CACHE = new MemoryOperationResultCache<>(Utils.CACHE_SIZE); private static final MemoryOperationResultCache> DEPENDENCIES_CACHE = new MemoryOperationResultCache<>(Utils.CACHE_SIZE); private final String versionId; private final ModrinthVersion current; private final ModrinthProject mod; public ModrinthModSource(String versionId) throws IOException { this.versionId = versionId; this.current = ModrinthApi.getVersion(versionId); this.mod = ModrinthApi.getMod(getModId()); } @Override public ModDownload download() throws IOException { ModrinthVersion.File file = current.files().get(0); Path path = getJarPath(); try { Net.downloadFile(file.url(), file.hashes().sha1(), path); } catch (URISyntaxException e) { throw new IOException("Could not download file", e); } return new ModDownload(file.hashes().sha1(), HashUtils.murmur2(Files.readAllBytes(path)), path); } @Override public Set getDependencies(String gameVersion) throws IOException { return DEPENDENCIES_CACHE.get(versionId, () -> { Set deps = new HashSet<>(); for (ModrinthVersion.Dependency dependency : current.dependencies()) { //TODO show optional dependencies if (dependency.dependency_type() == ModrinthVersion.Dependency.DependencyType.required) deps.add(new ModrinthModSource(dependency.version_id())); } return Set.copyOf(deps); }); } @Override public Optional getUpdate(String gameVersion) throws IOException { return UPDATE_CACHE.get(Tuple.of(versionId, gameVersion), () -> { ModrinthVersion next = ModrinthApi.getLatestVersions(getModId(), gameVersion).get(current.version_type()); if (next == null) return Optional.empty(); if (next.version_number().equals(current.version_number())) return Optional.empty(); return Optional.of(new ModrinthModSource(next.id())); }); } @Override public String getVersion() { return current.version_number(); } @Override public String getName() { return "modrinth/" + getShortName() + '/' + current.version_number(); } @Override public String getShortName() { return (mod.slug() == null ? mod.id() : mod.slug()); } @Override public String getFileName() { return current.files().get(0).filename(); } @Override public String getDescription() { return mod.body(); } @Override public String getSummary() { return mod.description(); } @Override public boolean equals(Object obj) { return obj instanceof ModSource ms && equals(ms); } @Override public boolean equals(ModSource other) { return other instanceof ModrinthModSource ms && ms.getModId().equals(getModId()) && ms.versionId.equals(versionId); } @Override public boolean projectMatches(ModSource other) { return other instanceof ModrinthModSource ms && ms.getModId().equals(getModId()); } public String getVersionId() { return versionId; } public String getModId() { return current.project_id(); } public ModrinthModpackManifest.File toManifest() throws IOException { ModrinthVersion.File orig = current.files().get(0); return new ModrinthModpackManifest.File( "mods/" + orig.filename(), new ModrinthHashes( orig.hashes().sha1(), orig.hashes().sha512() ), null, // env List.of(orig.url()), Files.size(getJarPath()) ); } }