Modernize, support CfCore and update for 1.19-rc2

This commit is contained in:
Johannes Frohnmeyer 2022-06-05 17:40:50 +02:00
parent 906a0a4d74
commit f699ab3bf3
Signed by: Johannes
GPG Key ID: E76429612C2929F4
32 changed files with 197 additions and 227 deletions

View File

@ -1,5 +1,6 @@
apply from: "https://jfmods.gitlab.io/scripts/jfmod.gradle" apply from: "https://jfmods.gitlab.io/scripts/jfmod.gradle"
dependencies { dependencies {
modImplementation "com.terraformersmc:modmenu:3.1.0" include modImplementation("io.gitlab.jfronny.libjf:libjf-base:${project.jfapi_version}") // for JfCommons
modImplementation "com.terraformersmc:modmenu:4.0.0-beta.4"
} }

View File

@ -1,10 +1,11 @@
# https://fabricmc.net/develop # https://fabricmc.net/develop
minecraft_version=1.18.2 minecraft_version=1.19-rc2
yarn_mappings=build.1 yarn_mappings=build.1
loader_version=0.13.3 loader_version=0.14.6
maven_group=io.gitlab.jfronny maven_group=io.gitlab.jfronny
archives_base_name=resclone archives_base_name=resclone
fabric_version=0.47.8+1.18.2 fabric_version=0.55.1+1.19
jfapi_version=2.8.1-1654352298
modrinth_id=kVAQyCLX modrinth_id=kVAQyCLX

View File

@ -1,79 +1,69 @@
package io.gitlab.jfronny.resclone; package io.gitlab.jfronny.resclone;
import com.google.gson.Gson; import com.google.gson.*;
import io.gitlab.jfronny.resclone.api.PackFetcher; import io.gitlab.jfronny.commons.log.*;
import io.gitlab.jfronny.resclone.api.RescloneApi; import io.gitlab.jfronny.commons.serialize.gson.api.*;
import io.gitlab.jfronny.resclone.api.RescloneEntry; import io.gitlab.jfronny.resclone.api.*;
import io.gitlab.jfronny.resclone.data.PackMetaLoaded; import io.gitlab.jfronny.resclone.data.*;
import io.gitlab.jfronny.resclone.data.PackMetaUnloaded; import io.gitlab.jfronny.resclone.processors.*;
import io.gitlab.jfronny.resclone.api.PackProcessor; import io.gitlab.jfronny.resclone.util.*;
import io.gitlab.jfronny.resclone.processors.RemoveEmptyProcessor; import net.fabricmc.api.*;
import io.gitlab.jfronny.resclone.processors.RootPathProcessor; import net.fabricmc.loader.api.*;
import io.gitlab.jfronny.resclone.util.PackUrlCache;
import io.gitlab.jfronny.resclone.util.Result;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.*;
import java.net.URI; import java.net.*;
import java.nio.file.FileSystem; import java.nio.file.FileSystem;
import java.nio.file.FileSystems; import java.nio.file.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.concurrent.ExecutorService; import java.util.concurrent.*;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Resclone implements ModInitializer, RescloneApi { public class Resclone implements ModInitializer, RescloneApi {
public static final Set<PackMetaUnloaded> conf = new LinkedHashSet<>(); public static final Set<PackMetaUnloaded> CONF = new LinkedHashSet<>();
public static final Map<String, PackFetcher> fetcherInstances = new LinkedHashMap<>(); public static final Map<String, PackFetcher> FETCHER_INSTANCES = new LinkedHashMap<>();
public static final Set<PackProcessor> processors = new LinkedHashSet<>(); public static final Set<PackProcessor> PROCESSORS = new LinkedHashSet<>();
public static final Set<PackMetaLoaded> downloadedPacks = new LinkedHashSet<>(); public static final Set<PackMetaLoaded> DOWNLOADED_PACKS = new LinkedHashSet<>();
public static final Set<PackMetaLoaded> newPacks = new LinkedHashSet<>(); public static final Set<PackMetaLoaded> NEW_PACKS = new LinkedHashSet<>();
public static final Gson gson = new Gson();
public static final String MOD_ID = "resclone"; public static final String MOD_ID = "resclone";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); public static final Logger LOGGER = Logger.forName(MOD_ID);
public static PackUrlCache urlCache; public static PackUrlCache urlCache;
public static int COUNT = 0; public static int packCount = 0;
@Override @Override
public void onInitialize() { public void onInitialize() {
LOGGER.info("Initialising Resclone."); LOGGER.info("Initialising Resclone.");
GsonHolder.register();
urlCache = new PackUrlCache(getConfigPath().resolve("urlCache.properties")); urlCache = new PackUrlCache(getConfigPath().resolve("urlCache.properties"));
conf.clear(); CONF.clear();
fetcherInstances.clear(); FETCHER_INSTANCES.clear();
processors.clear(); PROCESSORS.clear();
downloadedPacks.clear(); DOWNLOADED_PACKS.clear();
addProcessor(new RootPathProcessor()); //This should be run before any other processor to make sure the path is valid addProcessor(new RootPathProcessor()); //This should be run before any other processor to make sure the path is valid
for (RescloneEntry entry : FabricLoader.getInstance().getEntrypoints(MOD_ID, RescloneEntry.class)) { for (RescloneEntry entry : FabricLoader.getInstance().getEntrypoints(MOD_ID, RescloneEntry.class)) {
try { try {
entry.init(this); entry.init(this);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); Resclone.LOGGER.error("Could not initialize resclone pack supplier", e);
} }
} }
addProcessor(new RemoveEmptyProcessor()); addProcessor(new RemoveEmptyProcessor());
reload(); reload();
LOGGER.info("Installed {} resource pack{}.", COUNT, COUNT == 1 ? "" : "s"); LOGGER.info("Installed {} resource pack{}.", packCount, packCount == 1 ? "" : "s");
} }
@Override @Override
public void addFetcher(PackFetcher fetcher) { public void addFetcher(PackFetcher fetcher) {
fetcherInstances.put(fetcher.getSourceTypeName(), fetcher); FETCHER_INSTANCES.put(fetcher.getSourceTypeName(), fetcher);
} }
@Override @Override
public void addProcessor(PackProcessor processor) { public void addProcessor(PackProcessor processor) {
processors.add(processor); PROCESSORS.add(processor);
} }
@Override @Override
@ -88,19 +78,19 @@ public class Resclone implements ModInitializer, RescloneApi {
@Override @Override
public void addPack(String fetcher, String pack, String name, boolean forceRedownload, boolean forceEnable) { public void addPack(String fetcher, String pack, String name, boolean forceRedownload, boolean forceEnable) {
conf.add(new PackMetaUnloaded(fetcher, pack, name, forceRedownload, forceEnable)); CONF.add(new PackMetaUnloaded(fetcher, pack, name, forceRedownload, forceEnable));
} }
@Override @Override
public void reload() { public void reload() {
Set<PackMetaLoaded> metas = new LinkedHashSet<>(); Set<PackMetaLoaded> metas = new LinkedHashSet<>();
try { try {
if (conf.isEmpty()) { if (CONF.isEmpty()) {
LOGGER.info("No resclone pack was specified, add one"); LOGGER.info("No resclone pack was specified, add one");
} }
else { else {
ExecutorService pool = Executors.newFixedThreadPool(conf.size()); ExecutorService pool = Executors.newFixedThreadPool(CONF.size());
for (PackMetaUnloaded s : conf) { for (PackMetaUnloaded s : CONF) {
pool.submit(generateTask(s, metas)); pool.submit(generateTask(s, metas));
} }
pool.shutdown(); pool.shutdown();
@ -109,40 +99,39 @@ public class Resclone implements ModInitializer, RescloneApi {
} }
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); LOGGER.error("Could not execute pack download task", e);
} }
urlCache.save(); urlCache.save();
downloadedPacks.clear(); DOWNLOADED_PACKS.clear();
downloadedPacks.addAll(metas); DOWNLOADED_PACKS.addAll(metas);
} }
private Runnable generateTask(PackMetaUnloaded meta, Set<PackMetaLoaded> metas) { private Runnable generateTask(PackMetaUnloaded meta, Set<PackMetaLoaded> metas) {
return () -> { return () -> {
try { try {
if (!fetcherInstances.containsKey(meta.fetcher)) if (!FETCHER_INSTANCES.containsKey(meta.fetcher))
throw new Exception("Invalid fetcher: " + meta.fetcher); throw new Exception("Invalid fetcher: " + meta.fetcher);
Path cacheDir = getConfigPath().resolve("cache"); Path cacheDir = getConfigPath().resolve("cache");
PackMetaLoaded p; PackMetaLoaded p;
try { try {
boolean isNew = !urlCache.containsKey(meta.source); boolean isNew = !urlCache.containsKey(meta.source);
//Download //Download
Result fr = fetcherInstances.get(meta.fetcher).get(meta.source, cacheDir, meta.forceDownload); PackFetcher.Result fr = FETCHER_INSTANCES.get(meta.fetcher).get(meta.source, cacheDir, meta.forceDownload);
p = new PackMetaLoaded(fr.downloadPath, meta.name, meta.forceEnable); p = new PackMetaLoaded(fr.downloadPath(), meta.name, meta.forceEnable);
metas.add(p); metas.add(p);
if (isNew) if (isNew)
newPacks.add(p); NEW_PACKS.add(p);
if (fr.freshDownload) { if (fr.freshDownload()) {
//Process //Process
Map<String, String> props = new HashMap<>(); Map<String, String> props = new HashMap<>();
props.put("create", "false"); props.put("create", "false");
URI zipfile = URI.create("jar:" + p.zipPath.toUri()); URI zipfile = URI.create("jar:" + p.zipPath().toUri());
try (FileSystem zipfs = FileSystems.newFileSystem(zipfile, props)) { try (FileSystem zipfs = FileSystems.newFileSystem(zipfile, props)) {
for (PackProcessor processor : processors) { for (PackProcessor processor : PROCESSORS) {
processor.process(zipfs); processor.process(zipfs);
} }
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); LOGGER.error("Could not run pack processors on " + p.zipPath(), e);
} }
} }
} catch (Throwable e) { } catch (Throwable e) {
@ -161,9 +150,9 @@ public class Resclone implements ModInitializer, RescloneApi {
try { try {
Files.createDirectories(configPath.resolve("cache")); Files.createDirectories(configPath.resolve("cache"));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); LOGGER.error("Could not create cache directory", e);
} }
} }
return configPath; return configPath;
} }
} }

View File

@ -20,4 +20,4 @@ public class RescloneEntryDefault implements RescloneEntry {
api.addProcessor(new PruneVanillaProcessor()); api.addProcessor(new PruneVanillaProcessor());
ConfigLoader.load(api); ConfigLoader.load(api);
} }
} }

View File

@ -8,7 +8,7 @@ import net.minecraft.resource.ZipResourcePack;
import java.io.File; import java.io.File;
public class RescloneResourcePack extends ZipResourcePack implements ModResourcePack { public class RescloneResourcePack extends ZipResourcePack implements ModResourcePack {
private static final ModMetadata METADATA = FabricLoader.getInstance().getModContainer(Resclone.MOD_ID).get().getMetadata();
private final String name; private final String name;
public RescloneResourcePack(File file, String name) { public RescloneResourcePack(File file, String name) {
@ -23,7 +23,6 @@ public class RescloneResourcePack extends ZipResourcePack implements ModResource
@Override @Override
public ModMetadata getFabricModMetadata() { public ModMetadata getFabricModMetadata() {
return FabricLoader.getInstance().getModContainer(Resclone.MOD_ID).get().getMetadata(); return METADATA;
} }
}
}

View File

@ -1,10 +1,10 @@
package io.gitlab.jfronny.resclone.api; package io.gitlab.jfronny.resclone.api;
import io.gitlab.jfronny.resclone.util.Result;
import java.nio.file.Path; import java.nio.file.Path;
public interface PackFetcher { public interface PackFetcher {
Result get(String baseUrl, Path targetDir, boolean forceDownload) throws Exception; Result get(String baseUrl, Path targetDir, boolean forceDownload) throws Exception;
String getSourceTypeName(); // The name for users to specify in the config String getSourceTypeName(); // The name for users to specify in the config
record Result(Path downloadPath, boolean freshDownload) { }
} }

View File

@ -4,4 +4,4 @@ import java.nio.file.FileSystem;
public interface PackProcessor { public interface PackProcessor {
void process(FileSystem p) throws Exception; void process(FileSystem p) throws Exception;
} }

View File

@ -3,7 +3,6 @@ package io.gitlab.jfronny.resclone.api;
import java.nio.file.Path; import java.nio.file.Path;
public interface RescloneApi { public interface RescloneApi {
void addFetcher(PackFetcher fetcher); void addFetcher(PackFetcher fetcher);
void addProcessor(PackProcessor processor); void addProcessor(PackProcessor processor);
@ -17,5 +16,4 @@ public interface RescloneApi {
void reload(); void reload();
Path getConfigPath(); Path getConfigPath();
}
}

View File

@ -2,4 +2,4 @@ package io.gitlab.jfronny.resclone.api;
public interface RescloneEntry { public interface RescloneEntry {
void init(RescloneApi api) throws Exception; void init(RescloneApi api) throws Exception;
} }

View File

@ -1,11 +0,0 @@
package io.gitlab.jfronny.resclone.data;
import java.util.Set;
public class CfAddon {
public String downloadUrl;
public String fileDate;
public Set<String> gameVersion;
}

View File

@ -2,14 +2,5 @@ package io.gitlab.jfronny.resclone.data;
import java.nio.file.Path; import java.nio.file.Path;
public class PackMetaLoaded { public record PackMetaLoaded(Path zipPath, String name, boolean forceEnable) {
public final Path zipPath; }
public final String name;
public final boolean forceEnable;
public PackMetaLoaded(Path zipPath, String name, boolean forceEnable) {
this.zipPath = zipPath;
this.name = name;
this.forceEnable = forceEnable;
}
}

View File

@ -1,5 +1,8 @@
package io.gitlab.jfronny.resclone.data; package io.gitlab.jfronny.resclone.data;
// Represents a pack as present in the config
// Can't be a record since it'll need to be parsed by Gson
@SuppressWarnings("ClassCanBeRecord")
public class PackMetaUnloaded { public class PackMetaUnloaded {
public final String fetcher; public final String fetcher;
public final String source; public final String source;

View File

@ -0,0 +1,13 @@
package io.gitlab.jfronny.resclone.data.curseforge;
import java.util.*;
public class GetModFilesResponse {
public List<Data> data;
public static class Data {
public String downloadUrl;
public Date fileDate;
public List<String> gameVersions;
}
}

View File

@ -0,0 +1,9 @@
package io.gitlab.jfronny.resclone.data.curseforge;
public class GetModResponse {
public Data data;
public static class Data {
public Boolean allowModDistribution;
}
}

View File

@ -0,0 +1,14 @@
package io.gitlab.jfronny.resclone.data.github;
import java.util.*;
public class Release {
public List<Asset> assets;
public String zipball_url;
public static class Asset {
public String name;
public String content_type;
public String browser_download_url;
}
}

View File

@ -0,0 +1,5 @@
package io.gitlab.jfronny.resclone.data.github;
public class Repository {
public String default_branch;
}

View File

@ -2,7 +2,6 @@ package io.gitlab.jfronny.resclone.fetchers;
import io.gitlab.jfronny.resclone.Resclone; import io.gitlab.jfronny.resclone.Resclone;
import io.gitlab.jfronny.resclone.api.PackFetcher; import io.gitlab.jfronny.resclone.api.PackFetcher;
import io.gitlab.jfronny.resclone.util.Result;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.InputStream; import java.io.InputStream;
@ -20,7 +19,7 @@ public abstract class BasePackFetcher implements PackFetcher {
Resclone.urlCache.set(baseUrl, url); Resclone.urlCache.set(baseUrl, url);
} catch (Exception e) { } catch (Exception e) {
if (Resclone.urlCache.containsKey(baseUrl)) { if (Resclone.urlCache.containsKey(baseUrl)) {
e.printStackTrace(); Resclone.LOGGER.error("Could not get download URL for " + baseUrl + ", using cached", e);
url = Resclone.urlCache.get(baseUrl); url = Resclone.urlCache.get(baseUrl);
} else { } else {
throw e; throw e;
@ -29,7 +28,7 @@ public abstract class BasePackFetcher implements PackFetcher {
Path p = targetDir.resolve(Integer.toHexString(url.hashCode())); Path p = targetDir.resolve(Integer.toHexString(url.hashCode()));
if (!forceDownload && Files.exists(p)) { if (!forceDownload && Files.exists(p)) {
Resclone.COUNT++; Resclone.packCount++;
return new Result(p, false); return new Result(p, false);
} }
@ -46,7 +45,7 @@ public abstract class BasePackFetcher implements PackFetcher {
} catch (Throwable e) { } catch (Throwable e) {
throw new Exception("Could not download pack", e); throw new Exception("Could not download pack", e);
} }
Resclone.COUNT++; Resclone.packCount++;
return new Result(p, true); return new Result(p, true);
} }
} }

View File

@ -1,7 +1,6 @@
package io.gitlab.jfronny.resclone.fetchers; package io.gitlab.jfronny.resclone.fetchers;
public class BasicFileFetcher extends BasePackFetcher { public class BasicFileFetcher extends BasePackFetcher {
@Override @Override
public String getSourceTypeName() { public String getSourceTypeName() {
return "file"; return "file";
@ -11,5 +10,4 @@ public class BasicFileFetcher extends BasePackFetcher {
public String getDownloadUrl(String baseUrl) { public String getDownloadUrl(String baseUrl) {
return baseUrl; return baseUrl;
} }
}
}

View File

@ -1,14 +1,27 @@
package io.gitlab.jfronny.resclone.fetchers; package io.gitlab.jfronny.resclone.fetchers;
import io.gitlab.jfronny.resclone.Resclone; import io.gitlab.jfronny.commons.*;
import io.gitlab.jfronny.resclone.data.CfAddon; import io.gitlab.jfronny.resclone.*;
import io.gitlab.jfronny.resclone.util.UrlUtils; import io.gitlab.jfronny.resclone.data.curseforge.*;
import net.minecraft.MinecraftVersion; import net.minecraft.*;
import java.text.SimpleDateFormat; import java.io.*;
import java.util.Date; import java.net.*;
import java.util.*;
public class CurseforgeFetcher extends BasePackFetcher { public class CurseforgeFetcher extends BasePackFetcher {
// So you found the API key.
// Please be aware that CurseForge requires you to change this if you make any kind of derivative work
// Creating your own API key is relatively simple, so please don't abuse this
private static final String API_KEY = new String(unsalt(new byte[] {
-30, 50, -60, -121, 62, -31, 35, 17, 16, -53,
-53, -88, 21, -21, 15, -105, -115, -108, 114, -50,
-49, -4, 56, -65, -70, 108, -65, -3, -55, -4,
36, -86, -40, 116, 71, -5, 75, -9, -43, 4,
91, -91, -29, 40, 66, 87, -80, -74, 71, 41,
76, -96, 108, -61, -113, 118, 7, -39, -116, -120
}, 1024));
@Override @Override
public String getSourceTypeName() { public String getSourceTypeName() {
return "curseforge"; return "curseforge";
@ -17,25 +30,26 @@ public class CurseforgeFetcher extends BasePackFetcher {
@Override @Override
public String getDownloadUrl(String baseUrl) throws Exception { public String getDownloadUrl(String baseUrl) throws Exception {
try { try {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'Z'"); GetModResponse response = GET(baseUrl, GetModResponse.class);
if (!response.data.allowModDistribution)
throw new Exception("The author of " + baseUrl + " disabled access to this pack outside of the curseforge launcher");
String version = MinecraftVersion.CURRENT.getName(); String version = MinecraftVersion.CURRENT.getName();
CfAddon latest = null; GetModFilesResponse.Data latest = null;
Date latestDate = null; Date latestDate = null;
boolean foundMatchingVersion = false; boolean foundMatchingVersion = false;
for (CfAddon addon : UrlUtils.readJsonFromURLSet("https://addons-ecs.forgesvc.net/api/v2/addon/" + baseUrl + "/files", CfAddon.class)) { for (GetModFilesResponse.Data addon : GET(baseUrl + "/files", GetModFilesResponse.class).data) {
Date d = df.parse(addon.fileDate); if (foundMatchingVersion && !addon.gameVersions.contains(version))
if (foundMatchingVersion && !addon.gameVersion.contains(version))
continue; continue;
if (!foundMatchingVersion && addon.gameVersion.contains(version)) { if (!foundMatchingVersion && addon.gameVersions.contains(version)) {
foundMatchingVersion = true; foundMatchingVersion = true;
latest = null; latest = null;
} }
if (latest == null || d.after(latestDate)) { if (latest == null || addon.fileDate.after(latestDate)) {
latest = addon; latest = addon;
latestDate = d; latestDate = addon.fileDate;
} }
} }
@ -46,4 +60,17 @@ public class CurseforgeFetcher extends BasePackFetcher {
throw new Exception("Could not get CF download for " + baseUrl, e); throw new Exception("Could not get CF download for " + baseUrl, e);
} }
} }
}
private static <T> T GET(String suffix, Class<T> klazz) throws URISyntaxException, IOException {
return HttpUtils.get("https://api.curseforge.com/v1/mods/" + suffix).header("x-api-key", API_KEY).sendSerialized(klazz);
}
private static byte[] unsalt(byte[] data, int salt) {
byte[] result = new byte[data.length];
new Random(salt).nextBytes(result);
for (int i = 0; i < data.length; i++) {
result[i] ^= data[i];
}
return result;
}
}

View File

@ -1,12 +1,12 @@
package io.gitlab.jfronny.resclone.fetchers; package io.gitlab.jfronny.resclone.fetchers;
import com.google.gson.JsonElement; import io.gitlab.jfronny.commons.*;
import com.google.gson.JsonObject;
import io.gitlab.jfronny.resclone.Resclone; import io.gitlab.jfronny.resclone.Resclone;
import io.gitlab.jfronny.resclone.util.UrlUtils; import io.gitlab.jfronny.resclone.data.github.*;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.net.*;
public class GitHubFetcher extends BasePackFetcher { public class GitHubFetcher extends BasePackFetcher {
@Override @Override
@ -39,20 +39,19 @@ public class GitHubFetcher extends BasePackFetcher {
//"user/repo/release" - Gets from the latest release. //"user/repo/release" - Gets from the latest release.
else if (parts[2].equalsIgnoreCase("release")) { else if (parts[2].equalsIgnoreCase("release")) {
try { try {
JsonObject latestRelease = UrlUtils.readJsonFromURL("https://api.github.com/repos/" + parts[0] + "/" + parts[1] + "/releases/latest", JsonObject.class); Release latestRelease = HttpUtils.get("https://api.github.com/repos/" + parts[0] + "/" + parts[1] + "/releases/latest").sendSerialized(Release.class);
String res = null; String res = null;
for (JsonElement element : latestRelease.get("assets").getAsJsonArray()) { for (Release.Asset asset : latestRelease.assets) {
JsonObject o = element.getAsJsonObject(); if ("application/x-zip-compressed".equals(asset.content_type) || asset.name.endsWith(".zip")) {
if ("application/x-zip-compressed".equals(o.get("content_type").getAsString()) || o.get("name").getAsString().endsWith(".zip")) { res = asset.browser_download_url;
res = o.get("browser_download_url").getAsString();
break; break;
} }
} }
Resclone.LOGGER.info("Getting from latest release."); Resclone.LOGGER.info("Getting from latest release.");
if (res == null) return latestRelease.get("zipball_url").getAsString(); if (res == null) return latestRelease.zipball_url;
else return res; else return res;
} catch (Throwable e) { } catch (Throwable e) {
@ -74,8 +73,8 @@ public class GitHubFetcher extends BasePackFetcher {
private String getFromBranch(String repo, @Nullable String branch) { private String getFromBranch(String repo, @Nullable String branch) {
if (branch == null) { if (branch == null) {
try { try {
branch = UrlUtils.readJsonFromURL("https://api.github.com/repos/" + repo, JsonObject.class).get("default_branch").getAsString(); branch = HttpUtils.get("https://api.github.com/repos/" + repo).<Repository>sendSerialized(Repository.class).default_branch;
} catch (IOException e) { } catch (IOException | URISyntaxException e) {
Resclone.LOGGER.error("Failed to fetch branch for " + repo + ". Choosing \"main\"", e); Resclone.LOGGER.error("Failed to fetch branch for " + repo + ". Choosing \"main\"", e);
branch = "main"; branch = "main";
} }
@ -88,4 +87,4 @@ public class GitHubFetcher extends BasePackFetcher {
Resclone.LOGGER.info("Getting from tag " + tag + "."); Resclone.LOGGER.info("Getting from tag " + tag + ".");
return "https://codeload.github.com/" + repo + "/legacy.zip/refs/tags/" + tag; return "https://codeload.github.com/" + repo + "/legacy.zip/refs/tags/" + tag;
} }
} }

View File

@ -21,11 +21,11 @@ public class FileResourcePackProviderMixin {
@Inject(at = @At("TAIL"), method = "register(Ljava/util/function/Consumer;Lnet/minecraft/resource/ResourcePackProfile$Factory;)V") @Inject(at = @At("TAIL"), method = "register(Ljava/util/function/Consumer;Lnet/minecraft/resource/ResourcePackProfile$Factory;)V")
public void registerExtra(Consumer<ResourcePackProfile> consumer, ResourcePackProfile.Factory factory, CallbackInfo info) { public void registerExtra(Consumer<ResourcePackProfile> consumer, ResourcePackProfile.Factory factory, CallbackInfo info) {
for (PackMetaLoaded meta : Resclone.downloadedPacks) { for (PackMetaLoaded meta : Resclone.DOWNLOADED_PACKS) {
ResourcePackProfile resourcePackProfile = ResourcePackProfile.of( ResourcePackProfile resourcePackProfile = ResourcePackProfile.of(
"resclone/" + meta.name, "resclone/" + meta.name(),
meta.forceEnable, meta.forceEnable(),
() -> new RescloneResourcePack(meta.zipPath.toFile(), meta.name), () -> new RescloneResourcePack(meta.zipPath().toFile(), meta.name()),
factory, factory,
ResourcePackProfile.InsertionPosition.TOP, ResourcePackProfile.InsertionPosition.TOP,
this.source this.source
@ -35,4 +35,4 @@ public class FileResourcePackProviderMixin {
} }
} }
} }
} }

View File

@ -19,12 +19,12 @@ public abstract class GameOptionsMixin {
@Inject(at = @At("TAIL"), method = "load()V") @Inject(at = @At("TAIL"), method = "load()V")
public void load(CallbackInfo ci) { public void load(CallbackInfo ci) {
for (PackMetaLoaded meta : Resclone.newPacks) { for (PackMetaLoaded meta : Resclone.NEW_PACKS) {
Resclone.LOGGER.info(Resclone.MOD_ID + "/" + meta.name); Resclone.LOGGER.info(Resclone.MOD_ID + "/" + meta.name());
resourcePacks.add(Resclone.MOD_ID + "/" + meta.name); resourcePacks.add(Resclone.MOD_ID + "/" + meta.name());
} }
if (!Resclone.newPacks.isEmpty()) if (!Resclone.NEW_PACKS.isEmpty())
write(); write();
Resclone.newPacks.clear(); Resclone.NEW_PACKS.clear();
} }
} }

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.resclone.processors; package io.gitlab.jfronny.resclone.processors;
import io.gitlab.jfronny.resclone.*;
import io.gitlab.jfronny.resclone.api.PackProcessor; import io.gitlab.jfronny.resclone.api.PackProcessor;
import io.gitlab.jfronny.resclone.util.io.PathPruneVisitor; import io.gitlab.jfronny.resclone.util.io.PathPruneVisitor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@ -12,7 +13,6 @@ import java.nio.file.Files;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
public class PruneVanillaProcessor implements PackProcessor { public class PruneVanillaProcessor implements PackProcessor {
@Override @Override
public void process(FileSystem p) throws Exception { public void process(FileSystem p) throws Exception {
ClassLoader cl = MinecraftClient.class.getClassLoader(); ClassLoader cl = MinecraftClient.class.getClassLoader();
@ -29,7 +29,7 @@ public class PruneVanillaProcessor implements PackProcessor {
} }
} }
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); Resclone.LOGGER.error("Could not prune unchanged assets", e);
} }
return false; return false;
})); }));
@ -38,5 +38,4 @@ public class PruneVanillaProcessor implements PackProcessor {
throw new Exception("Could not prune vanilla files", e); throw new Exception("Could not prune vanilla files", e);
} }
} }
}
}

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.resclone.processors; package io.gitlab.jfronny.resclone.processors;
import io.gitlab.jfronny.resclone.*;
import io.gitlab.jfronny.resclone.api.PackProcessor; import io.gitlab.jfronny.resclone.api.PackProcessor;
import io.gitlab.jfronny.resclone.util.io.PathPruneVisitor; import io.gitlab.jfronny.resclone.util.io.PathPruneVisitor;
@ -10,7 +11,6 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
public class RemoveEmptyProcessor implements PackProcessor { public class RemoveEmptyProcessor implements PackProcessor {
@Override @Override
public void process(FileSystem p) throws Exception { public void process(FileSystem p) throws Exception {
if (Files.exists(p.getPath("/assets"))) { if (Files.exists(p.getPath("/assets"))) {
@ -20,7 +20,7 @@ public class RemoveEmptyProcessor implements PackProcessor {
try (DirectoryStream<Path> paths = Files.newDirectoryStream(s)) { try (DirectoryStream<Path> paths = Files.newDirectoryStream(s)) {
return !paths.iterator().hasNext(); return !paths.iterator().hasNext();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); Resclone.LOGGER.error("Could not check whether directory has entries", e);
} }
} }
return false; return false;
@ -30,5 +30,4 @@ public class RemoveEmptyProcessor implements PackProcessor {
} }
} }
} }
}
}

View File

@ -7,7 +7,6 @@ import java.io.IOException;
import java.nio.file.*; import java.nio.file.*;
public class RootPathProcessor implements PackProcessor { public class RootPathProcessor implements PackProcessor {
@Override @Override
public void process(FileSystem p) throws Exception { public void process(FileSystem p) throws Exception {
if (!Files.exists(p.getPath("/pack.mcmeta"))) { if (!Files.exists(p.getPath("/pack.mcmeta"))) {
@ -25,5 +24,4 @@ public class RootPathProcessor implements PackProcessor {
} }
} }
} }
}
}

View File

@ -1,6 +1,7 @@
package io.gitlab.jfronny.resclone.util; package io.gitlab.jfronny.resclone.util;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import io.gitlab.jfronny.commons.serialize.gson.api.*;
import io.gitlab.jfronny.resclone.Resclone; import io.gitlab.jfronny.resclone.Resclone;
import io.gitlab.jfronny.resclone.api.RescloneApi; import io.gitlab.jfronny.resclone.api.RescloneApi;
import io.gitlab.jfronny.resclone.data.PackMetaUnloaded; import io.gitlab.jfronny.resclone.data.PackMetaUnloaded;
@ -23,23 +24,23 @@ public class ConfigLoader {
text.append("\r\n"); text.append("\r\n");
text.append(s); text.append(s);
} }
Set<PackMetaUnloaded> data = Resclone.gson.fromJson(text.toString(), new TypeToken<Set<PackMetaUnloaded>>(){}.getType()); Set<PackMetaUnloaded> data = GsonHolder.getGson().fromJson(text.toString(), new TypeToken<Set<PackMetaUnloaded>>(){}.getType());
for (PackMetaUnloaded meta : data) { for (PackMetaUnloaded meta : data) {
api.addPack(meta.fetcher, meta.source, meta.name, meta.forceDownload, meta.forceEnable); api.addPack(meta.fetcher, meta.source, meta.name, meta.forceDownload, meta.forceEnable);
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); Resclone.LOGGER.error("Could not load config", e);
} }
} }
public static void save(RescloneApi api, Set<PackMetaUnloaded> data) { public static void save(RescloneApi api, Set<PackMetaUnloaded> data) {
Path configPath = api.getConfigPath().resolve("config.json"); Path configPath = api.getConfigPath().resolve("config.json");
Set<String> text = new HashSet<>(); Set<String> text = new HashSet<>();
text.add(Resclone.gson.toJson(data)); text.add(GsonHolder.getGson().toJson(data));
try { try {
Files.write(configPath, text); Files.write(configPath, text);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); Resclone.LOGGER.error("Could not write config", e);
} }
} }
} }

View File

@ -1,5 +1,7 @@
package io.gitlab.jfronny.resclone.util; package io.gitlab.jfronny.resclone.util;
import io.gitlab.jfronny.resclone.*;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
@ -8,7 +10,6 @@ import java.nio.file.Path;
import java.util.Properties; import java.util.Properties;
public class PackUrlCache { public class PackUrlCache {
private final Path file; private final Path file;
Properties properties = new Properties(); Properties properties = new Properties();
@ -18,7 +19,7 @@ public class PackUrlCache {
try (BufferedReader r = Files.newBufferedReader(file)) { try (BufferedReader r = Files.newBufferedReader(file)) {
properties.load(r); properties.load(r);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); Resclone.LOGGER.error("Could not load pack URL cache");
} }
} }
} }
@ -27,7 +28,7 @@ public class PackUrlCache {
try (BufferedWriter w = Files.newBufferedWriter(file)) { try (BufferedWriter w = Files.newBufferedWriter(file)) {
properties.store(w, "This is an internal file used for offline pack loading, do not edit"); properties.store(w, "This is an internal file used for offline pack loading, do not edit");
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); Resclone.LOGGER.error("Could not write pack URL cache");
} }
} }
@ -42,5 +43,4 @@ public class PackUrlCache {
public void set(String key, String value) { public void set(String key, String value) {
properties.setProperty(key, value); properties.setProperty(key, value);
} }
}
}

View File

@ -1,15 +0,0 @@
package io.gitlab.jfronny.resclone.util;
import java.nio.file.Path;
public class Result {
public final Path downloadPath;
public final boolean freshDownload;
public Result(Path downloadPath, boolean freshDownload) {
this.downloadPath = downloadPath;
this.freshDownload = freshDownload;
}
}

View File

@ -1,41 +0,0 @@
package io.gitlab.jfronny.resclone.util;
import com.google.gson.reflect.TypeToken;
import io.gitlab.jfronny.resclone.Resclone;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.Set;
public class UrlUtils {
public static boolean urlValid(String url) {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).toURI().toURL().openConnection();
connection.setRequestMethod("GET");
connection.connect();
return connection.getResponseCode() == 200;
} catch (Throwable e) {
return false;
}
}
public static String readStringFromURL(String requestURL) throws IOException {
try (Scanner scanner = new Scanner(new URL(requestURL).openStream(), StandardCharsets.UTF_8.toString())) {
scanner.useDelimiter("\\A");
return scanner.hasNext() ? scanner.next() : "";
}
}
public static <T> T readJsonFromURL(String requestUrl, Class<T> classOfT) throws IOException {
return Resclone.gson.fromJson(readStringFromURL(requestUrl), classOfT);
}
public static <T> Set<T> readJsonFromURLSet(String requestUrl, Class<T> classOfT) throws IOException {
return Resclone.gson.fromJson(readStringFromURL(requestUrl), TypeToken.getParameterized(Set.class, classOfT).getType());
}
}

View File

@ -5,7 +5,6 @@ import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
public class MoveDirVisitor extends SimpleFileVisitor<Path> { public class MoveDirVisitor extends SimpleFileVisitor<Path> {
private final Path fromPath; private final Path fromPath;
private final Path toPath; private final Path toPath;
private final CopyOption copyOption; private final CopyOption copyOption;
@ -36,5 +35,4 @@ public class MoveDirVisitor extends SimpleFileVisitor<Path> {
Files.delete(dir); Files.delete(dir);
return FileVisitResult.CONTINUE; return FileVisitResult.CONTINUE;
} }
}
}

View File

@ -9,8 +9,7 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.util.function.Predicate; import java.util.function.Predicate;
public class PathPruneVisitor extends SimpleFileVisitor<Path> { public class PathPruneVisitor extends SimpleFileVisitor<Path> {
private final Predicate<Path> removalSelector;
Predicate<Path> removalSelector;
public PathPruneVisitor(Predicate<Path> removalSelector) { public PathPruneVisitor(Predicate<Path> removalSelector) {
this.removalSelector = removalSelector; this.removalSelector = removalSelector;
@ -27,5 +26,4 @@ public class PathPruneVisitor extends SimpleFileVisitor<Path> {
if (removalSelector.test(dir)) Files.walkFileTree(dir, new RemoveDirVisitor()); if (removalSelector.test(dir)) Files.walkFileTree(dir, new RemoveDirVisitor());
return super.postVisitDirectory(dir, exc); return super.postVisitDirectory(dir, exc);
} }
}
}

View File

@ -8,7 +8,6 @@ import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
public class RemoveDirVisitor extends SimpleFileVisitor<Path> { public class RemoveDirVisitor extends SimpleFileVisitor<Path> {
@Override @Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file); Files.delete(file);
@ -20,5 +19,4 @@ public class RemoveDirVisitor extends SimpleFileVisitor<Path> {
Files.delete(dir); Files.delete(dir);
return FileVisitResult.CONTINUE; return FileVisitResult.CONTINUE;
} }
}
}