Inceptum/launcher/src/main/java/io/gitlab/jfronny/inceptum/launcher/model/inceptum/ModMeta.java

122 lines
4.3 KiB
Java

package io.gitlab.jfronny.inceptum.launcher.model.inceptum;
import io.gitlab.jfronny.commons.HashUtils;
import io.gitlab.jfronny.commons.data.MutCollection;
import io.gitlab.jfronny.commons.data.delegate.DelegateMap;
import io.gitlab.jfronny.gson.compile.annotations.GPrefer;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.api.CurseforgeApi;
import io.gitlab.jfronny.inceptum.launcher.api.ModrinthApi;
import io.gitlab.jfronny.inceptum.launcher.gson.ModMetaSourcesAdapter;
import io.gitlab.jfronny.inceptum.launcher.model.curseforge.response.FingerprintMatchesResponse;
import io.gitlab.jfronny.inceptum.launcher.system.source.CurseforgeModSource;
import io.gitlab.jfronny.inceptum.launcher.system.source.ModSource;
import io.gitlab.jfronny.inceptum.launcher.system.source.ModrinthModSource;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@GSerializable(configure = GsonPreset.Config.class)
public record ModMeta(
Sources sources, //key: source, value: update
String sha1,
Long murmur2,
List<String> dependents, // by file name
List<String> dependencies, // by file name
boolean explicit
) {
@GSerializable(with = ModMetaSourcesAdapter.class, configure = GsonPreset.Config.class)
public static class Sources extends DelegateMap<ModSource, Optional<ModSource>> {
public Sources() {
super(MutCollection.mapOf());
}
}
@GPrefer
public ModMeta {}
public static ModMeta of(Path mod) {
String sha1 = null;
Long murmur2 = null;
if (!Files.isDirectory(mod)) {
try {
byte[] data = Files.readAllBytes(mod);
sha1 = HashUtils.sha1(data);
murmur2 = HashUtils.murmur2(data);
} catch (IOException e) {
Utils.LOGGER.error("Could not read file hash", e);
}
}
return new ModMeta(
new Sources(),
sha1,
murmur2,
new ArrayList<>(),
new ArrayList<>(),
true
);
}
public static ModMeta of(String sha1, Long murmur2, @Nullable ModSource knownSource, String gameVersion) {
ModMeta res = new ModMeta(
new Sources(),
sha1,
murmur2,
new ArrayList<>(),
new ArrayList<>(),
true
);
if (knownSource != null) res.addSource(knownSource, gameVersion);
res.initialize(gameVersion);
return res;
}
public boolean initialize(String gameVersion) {
boolean modrinth = false;
boolean curseforge = false;
for (ModSource source : sources.keySet().toArray(ModSource[]::new)) {
if (source instanceof ModrinthModSource) modrinth = true;
if (source instanceof CurseforgeModSource) curseforge = true;
addSource(source, gameVersion);
}
boolean changed = false;
if (!modrinth) {
try {
addSource(new ModrinthModSource(ModrinthApi.getVersionByHash(sha1).id), gameVersion);
changed = true;
} catch (IOException e) {
// not found
}
}
if (!curseforge) {
try {
FingerprintMatchesResponse.Result cf = CurseforgeApi.checkFingerprint(murmur2);
if (!cf.exactMatches.isEmpty) {
FingerprintMatchesResponse.Result.Match f = cf.exactMatches[0];
addSource(new CurseforgeModSource(f.id, f.file.id), gameVersion);
changed = true;
}
} catch (IOException | URISyntaxException e) {
// not found
}
}
return changed;
}
public void addSource(ModSource source, String gameVersion) {
try {
sources[source] = source.getUpdate(gameVersion);
} catch (IOException e) {
Utils.LOGGER.error("Could not check " + source.name + " for updates", e);
}
}
}