144 lines
5.2 KiB
Java
144 lines
5.2 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.commons.serialize.gson.api.v1.Ignore;
|
|
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.instance.Mod;
|
|
import io.gitlab.jfronny.inceptum.launcher.system.source.*;
|
|
import org.jetbrains.annotations.NotNull;
|
|
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.*;
|
|
|
|
@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());
|
|
}
|
|
|
|
private Optional<ModSource> getPreferredMetadataSource() {
|
|
return keySet().stream().max((left, right) -> {
|
|
if (left.equals(right)) return 0;
|
|
if (left instanceof ModrinthModSource) return 1;
|
|
if (right instanceof ModrinthModSource) return -1;
|
|
if (left instanceof CurseforgeModSource) return 1;
|
|
if (right instanceof CurseforgeModSource) return -1;
|
|
return 1;
|
|
});
|
|
}
|
|
|
|
public @NotNull String getBestSummary() {
|
|
return getPreferredMetadataSource()
|
|
.map(ModSource::getSummary)
|
|
.orElse("Local Mod");
|
|
}
|
|
|
|
public @Nullable String getBestDescription() {
|
|
return getPreferredMetadataSource()
|
|
.map(ModSource::getDescription)
|
|
.orElse(null);
|
|
}
|
|
}
|
|
|
|
@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().get(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.put(source, source.getUpdate(gameVersion));
|
|
} catch (IOException e) {
|
|
Utils.LOGGER.error("Could not check " + source.getName() + " for updates", e);
|
|
}
|
|
}
|
|
}
|