From f699ab3bf33a87551776804ee6b1bbf27afc8128 Mon Sep 17 00:00:00 2001 From: JFronny Date: Sun, 5 Jun 2022 17:40:50 +0200 Subject: [PATCH] Modernize, support CfCore and update for 1.19-rc2 --- build.gradle | 3 +- gradle.properties | 7 +- .../io/gitlab/jfronny/resclone/Resclone.java | 103 ++++++++---------- .../resclone/RescloneEntryDefault.java | 2 +- .../resclone/RescloneResourcePack.java | 7 +- .../jfronny/resclone/api/PackFetcher.java | 4 +- .../jfronny/resclone/api/PackProcessor.java | 2 +- .../jfronny/resclone/api/RescloneApi.java | 4 +- .../jfronny/resclone/api/RescloneEntry.java | 2 +- .../gitlab/jfronny/resclone/data/CfAddon.java | 11 -- .../jfronny/resclone/data/PackMetaLoaded.java | 13 +-- .../resclone/data/PackMetaUnloaded.java | 3 + .../data/curseforge/GetModFilesResponse.java | 13 +++ .../data/curseforge/GetModResponse.java | 9 ++ .../jfronny/resclone/data/github/Release.java | 14 +++ .../resclone/data/github/Repository.java | 5 + .../resclone/fetchers/BasePackFetcher.java | 9 +- .../resclone/fetchers/BasicFileFetcher.java | 4 +- .../resclone/fetchers/CurseforgeFetcher.java | 57 +++++++--- .../resclone/fetchers/GitHubFetcher.java | 23 ++-- .../mixin/FileResourcePackProviderMixin.java | 10 +- .../resclone/mixin/GameOptionsMixin.java | 10 +- .../processors/PruneVanillaProcessor.java | 7 +- .../processors/RemoveEmptyProcessor.java | 7 +- .../processors/RootPathProcessor.java | 4 +- .../jfronny/resclone/util/ConfigLoader.java | 11 +- .../jfronny/resclone/util/PackUrlCache.java | 10 +- .../gitlab/jfronny/resclone/util/Result.java | 15 --- .../jfronny/resclone/util/UrlUtils.java | 41 ------- .../resclone/util/io/MoveDirVisitor.java | 4 +- .../resclone/util/io/PathPruneVisitor.java | 6 +- .../resclone/util/io/RemoveDirVisitor.java | 4 +- 32 files changed, 197 insertions(+), 227 deletions(-) delete mode 100644 src/main/java/io/gitlab/jfronny/resclone/data/CfAddon.java create mode 100644 src/main/java/io/gitlab/jfronny/resclone/data/curseforge/GetModFilesResponse.java create mode 100644 src/main/java/io/gitlab/jfronny/resclone/data/curseforge/GetModResponse.java create mode 100644 src/main/java/io/gitlab/jfronny/resclone/data/github/Release.java create mode 100644 src/main/java/io/gitlab/jfronny/resclone/data/github/Repository.java delete mode 100644 src/main/java/io/gitlab/jfronny/resclone/util/Result.java delete mode 100644 src/main/java/io/gitlab/jfronny/resclone/util/UrlUtils.java diff --git a/build.gradle b/build.gradle index 269c14a..bf5b99e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ apply from: "https://jfmods.gitlab.io/scripts/jfmod.gradle" 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" } diff --git a/gradle.properties b/gradle.properties index 6bf839e..7524eb6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,11 @@ # https://fabricmc.net/develop -minecraft_version=1.18.2 +minecraft_version=1.19-rc2 yarn_mappings=build.1 -loader_version=0.13.3 +loader_version=0.14.6 maven_group=io.gitlab.jfronny 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 \ No newline at end of file diff --git a/src/main/java/io/gitlab/jfronny/resclone/Resclone.java b/src/main/java/io/gitlab/jfronny/resclone/Resclone.java index 89d3a34..d34a0a7 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/Resclone.java +++ b/src/main/java/io/gitlab/jfronny/resclone/Resclone.java @@ -1,79 +1,69 @@ package io.gitlab.jfronny.resclone; -import com.google.gson.Gson; -import io.gitlab.jfronny.resclone.api.PackFetcher; -import io.gitlab.jfronny.resclone.api.RescloneApi; -import io.gitlab.jfronny.resclone.api.RescloneEntry; -import io.gitlab.jfronny.resclone.data.PackMetaLoaded; -import io.gitlab.jfronny.resclone.data.PackMetaUnloaded; -import io.gitlab.jfronny.resclone.api.PackProcessor; -import io.gitlab.jfronny.resclone.processors.RemoveEmptyProcessor; -import io.gitlab.jfronny.resclone.processors.RootPathProcessor; -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 com.google.gson.*; +import io.gitlab.jfronny.commons.log.*; +import io.gitlab.jfronny.commons.serialize.gson.api.*; +import io.gitlab.jfronny.resclone.api.*; +import io.gitlab.jfronny.resclone.data.*; +import io.gitlab.jfronny.resclone.processors.*; +import io.gitlab.jfronny.resclone.util.*; +import net.fabricmc.api.*; +import net.fabricmc.loader.api.*; -import java.io.IOException; -import java.net.URI; +import java.io.*; +import java.net.*; import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; +import java.nio.file.*; import java.util.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; public class Resclone implements ModInitializer, RescloneApi { - public static final Set conf = new LinkedHashSet<>(); - public static final Map fetcherInstances = new LinkedHashMap<>(); - public static final Set processors = new LinkedHashSet<>(); - public static final Set downloadedPacks = new LinkedHashSet<>(); - public static final Set newPacks = new LinkedHashSet<>(); - public static final Gson gson = new Gson(); + public static final Set CONF = new LinkedHashSet<>(); + public static final Map FETCHER_INSTANCES = new LinkedHashMap<>(); + public static final Set PROCESSORS = new LinkedHashSet<>(); + public static final Set DOWNLOADED_PACKS = new LinkedHashSet<>(); + public static final Set NEW_PACKS = new LinkedHashSet<>(); 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 int COUNT = 0; + public static int packCount = 0; @Override public void onInitialize() { LOGGER.info("Initialising Resclone."); + GsonHolder.register(); urlCache = new PackUrlCache(getConfigPath().resolve("urlCache.properties")); - conf.clear(); - fetcherInstances.clear(); - processors.clear(); - downloadedPacks.clear(); + CONF.clear(); + FETCHER_INSTANCES.clear(); + PROCESSORS.clear(); + DOWNLOADED_PACKS.clear(); 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)) { try { entry.init(this); } catch (Exception e) { - e.printStackTrace(); + Resclone.LOGGER.error("Could not initialize resclone pack supplier", e); } } addProcessor(new RemoveEmptyProcessor()); reload(); - LOGGER.info("Installed {} resource pack{}.", COUNT, COUNT == 1 ? "" : "s"); + LOGGER.info("Installed {} resource pack{}.", packCount, packCount == 1 ? "" : "s"); } @Override public void addFetcher(PackFetcher fetcher) { - fetcherInstances.put(fetcher.getSourceTypeName(), fetcher); + FETCHER_INSTANCES.put(fetcher.getSourceTypeName(), fetcher); } @Override public void addProcessor(PackProcessor processor) { - processors.add(processor); + PROCESSORS.add(processor); } @Override @@ -88,19 +78,19 @@ public class Resclone implements ModInitializer, RescloneApi { @Override 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 public void reload() { Set metas = new LinkedHashSet<>(); try { - if (conf.isEmpty()) { + if (CONF.isEmpty()) { LOGGER.info("No resclone pack was specified, add one"); } else { - ExecutorService pool = Executors.newFixedThreadPool(conf.size()); - for (PackMetaUnloaded s : conf) { + ExecutorService pool = Executors.newFixedThreadPool(CONF.size()); + for (PackMetaUnloaded s : CONF) { pool.submit(generateTask(s, metas)); } pool.shutdown(); @@ -109,40 +99,39 @@ public class Resclone implements ModInitializer, RescloneApi { } } } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error("Could not execute pack download task", e); } urlCache.save(); - downloadedPacks.clear(); - downloadedPacks.addAll(metas); + DOWNLOADED_PACKS.clear(); + DOWNLOADED_PACKS.addAll(metas); } private Runnable generateTask(PackMetaUnloaded meta, Set metas) { return () -> { try { - if (!fetcherInstances.containsKey(meta.fetcher)) + if (!FETCHER_INSTANCES.containsKey(meta.fetcher)) throw new Exception("Invalid fetcher: " + meta.fetcher); Path cacheDir = getConfigPath().resolve("cache"); PackMetaLoaded p; try { boolean isNew = !urlCache.containsKey(meta.source); //Download - Result fr = fetcherInstances.get(meta.fetcher).get(meta.source, cacheDir, meta.forceDownload); - p = new PackMetaLoaded(fr.downloadPath, meta.name, meta.forceEnable); + PackFetcher.Result fr = FETCHER_INSTANCES.get(meta.fetcher).get(meta.source, cacheDir, meta.forceDownload); + p = new PackMetaLoaded(fr.downloadPath(), meta.name, meta.forceEnable); metas.add(p); if (isNew) - newPacks.add(p); - if (fr.freshDownload) { + NEW_PACKS.add(p); + if (fr.freshDownload()) { //Process Map props = new HashMap<>(); 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)) { - for (PackProcessor processor : processors) { + for (PackProcessor processor : PROCESSORS) { processor.process(zipfs); } - } catch (Throwable e) { - e.printStackTrace(); + LOGGER.error("Could not run pack processors on " + p.zipPath(), e); } } } catch (Throwable e) { @@ -161,9 +150,9 @@ public class Resclone implements ModInitializer, RescloneApi { try { Files.createDirectories(configPath.resolve("cache")); } catch (IOException e) { - e.printStackTrace(); + LOGGER.error("Could not create cache directory", e); } } return configPath; } -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/RescloneEntryDefault.java b/src/main/java/io/gitlab/jfronny/resclone/RescloneEntryDefault.java index 06f9d2d..4c6916f 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/RescloneEntryDefault.java +++ b/src/main/java/io/gitlab/jfronny/resclone/RescloneEntryDefault.java @@ -20,4 +20,4 @@ public class RescloneEntryDefault implements RescloneEntry { api.addProcessor(new PruneVanillaProcessor()); ConfigLoader.load(api); } -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/RescloneResourcePack.java b/src/main/java/io/gitlab/jfronny/resclone/RescloneResourcePack.java index 284e42e..cddf716 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/RescloneResourcePack.java +++ b/src/main/java/io/gitlab/jfronny/resclone/RescloneResourcePack.java @@ -8,7 +8,7 @@ import net.minecraft.resource.ZipResourcePack; import java.io.File; public class RescloneResourcePack extends ZipResourcePack implements ModResourcePack { - + private static final ModMetadata METADATA = FabricLoader.getInstance().getModContainer(Resclone.MOD_ID).get().getMetadata(); private final String name; public RescloneResourcePack(File file, String name) { @@ -23,7 +23,6 @@ public class RescloneResourcePack extends ZipResourcePack implements ModResource @Override public ModMetadata getFabricModMetadata() { - return FabricLoader.getInstance().getModContainer(Resclone.MOD_ID).get().getMetadata(); + return METADATA; } - -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/api/PackFetcher.java b/src/main/java/io/gitlab/jfronny/resclone/api/PackFetcher.java index 683441c..b7e3c3f 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/api/PackFetcher.java +++ b/src/main/java/io/gitlab/jfronny/resclone/api/PackFetcher.java @@ -1,10 +1,10 @@ package io.gitlab.jfronny.resclone.api; -import io.gitlab.jfronny.resclone.util.Result; - import java.nio.file.Path; public interface PackFetcher { Result get(String baseUrl, Path targetDir, boolean forceDownload) throws Exception; String getSourceTypeName(); // The name for users to specify in the config + + record Result(Path downloadPath, boolean freshDownload) { } } diff --git a/src/main/java/io/gitlab/jfronny/resclone/api/PackProcessor.java b/src/main/java/io/gitlab/jfronny/resclone/api/PackProcessor.java index 85e2cd4..a859dcb 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/api/PackProcessor.java +++ b/src/main/java/io/gitlab/jfronny/resclone/api/PackProcessor.java @@ -4,4 +4,4 @@ import java.nio.file.FileSystem; public interface PackProcessor { void process(FileSystem p) throws Exception; -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/api/RescloneApi.java b/src/main/java/io/gitlab/jfronny/resclone/api/RescloneApi.java index 69b269c..4f956e4 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/api/RescloneApi.java +++ b/src/main/java/io/gitlab/jfronny/resclone/api/RescloneApi.java @@ -3,7 +3,6 @@ package io.gitlab.jfronny.resclone.api; import java.nio.file.Path; public interface RescloneApi { - void addFetcher(PackFetcher fetcher); void addProcessor(PackProcessor processor); @@ -17,5 +16,4 @@ public interface RescloneApi { void reload(); Path getConfigPath(); - -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/api/RescloneEntry.java b/src/main/java/io/gitlab/jfronny/resclone/api/RescloneEntry.java index 9be4593..1c14397 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/api/RescloneEntry.java +++ b/src/main/java/io/gitlab/jfronny/resclone/api/RescloneEntry.java @@ -2,4 +2,4 @@ package io.gitlab.jfronny.resclone.api; public interface RescloneEntry { void init(RescloneApi api) throws Exception; -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/data/CfAddon.java b/src/main/java/io/gitlab/jfronny/resclone/data/CfAddon.java deleted file mode 100644 index 9be88f5..0000000 --- a/src/main/java/io/gitlab/jfronny/resclone/data/CfAddon.java +++ /dev/null @@ -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 gameVersion; - -} \ No newline at end of file diff --git a/src/main/java/io/gitlab/jfronny/resclone/data/PackMetaLoaded.java b/src/main/java/io/gitlab/jfronny/resclone/data/PackMetaLoaded.java index ce6756e..3b87dac 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/data/PackMetaLoaded.java +++ b/src/main/java/io/gitlab/jfronny/resclone/data/PackMetaLoaded.java @@ -2,14 +2,5 @@ package io.gitlab.jfronny.resclone.data; import java.nio.file.Path; -public class PackMetaLoaded { - 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; - } -} \ No newline at end of file +public record PackMetaLoaded(Path zipPath, String name, boolean forceEnable) { +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/data/PackMetaUnloaded.java b/src/main/java/io/gitlab/jfronny/resclone/data/PackMetaUnloaded.java index 1ab0cc7..c7a2915 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/data/PackMetaUnloaded.java +++ b/src/main/java/io/gitlab/jfronny/resclone/data/PackMetaUnloaded.java @@ -1,5 +1,8 @@ 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 final String fetcher; public final String source; diff --git a/src/main/java/io/gitlab/jfronny/resclone/data/curseforge/GetModFilesResponse.java b/src/main/java/io/gitlab/jfronny/resclone/data/curseforge/GetModFilesResponse.java new file mode 100644 index 0000000..64bc5f7 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/resclone/data/curseforge/GetModFilesResponse.java @@ -0,0 +1,13 @@ +package io.gitlab.jfronny.resclone.data.curseforge; + +import java.util.*; + +public class GetModFilesResponse { + public List data; + + public static class Data { + public String downloadUrl; + public Date fileDate; + public List gameVersions; + } +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/data/curseforge/GetModResponse.java b/src/main/java/io/gitlab/jfronny/resclone/data/curseforge/GetModResponse.java new file mode 100644 index 0000000..63207e6 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/resclone/data/curseforge/GetModResponse.java @@ -0,0 +1,9 @@ +package io.gitlab.jfronny.resclone.data.curseforge; + +public class GetModResponse { + public Data data; + + public static class Data { + public Boolean allowModDistribution; + } +} \ No newline at end of file diff --git a/src/main/java/io/gitlab/jfronny/resclone/data/github/Release.java b/src/main/java/io/gitlab/jfronny/resclone/data/github/Release.java new file mode 100644 index 0000000..3700c69 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/resclone/data/github/Release.java @@ -0,0 +1,14 @@ +package io.gitlab.jfronny.resclone.data.github; + +import java.util.*; + +public class Release { + public List assets; + public String zipball_url; + + public static class Asset { + public String name; + public String content_type; + public String browser_download_url; + } +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/data/github/Repository.java b/src/main/java/io/gitlab/jfronny/resclone/data/github/Repository.java new file mode 100644 index 0000000..5c4961b --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/resclone/data/github/Repository.java @@ -0,0 +1,5 @@ +package io.gitlab.jfronny.resclone.data.github; + +public class Repository { + public String default_branch; +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/fetchers/BasePackFetcher.java b/src/main/java/io/gitlab/jfronny/resclone/fetchers/BasePackFetcher.java index a3e8712..07cf7f7 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/fetchers/BasePackFetcher.java +++ b/src/main/java/io/gitlab/jfronny/resclone/fetchers/BasePackFetcher.java @@ -2,7 +2,6 @@ package io.gitlab.jfronny.resclone.fetchers; import io.gitlab.jfronny.resclone.Resclone; import io.gitlab.jfronny.resclone.api.PackFetcher; -import io.gitlab.jfronny.resclone.util.Result; import java.io.FileOutputStream; import java.io.InputStream; @@ -20,7 +19,7 @@ public abstract class BasePackFetcher implements PackFetcher { Resclone.urlCache.set(baseUrl, url); } catch (Exception e) { 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); } else { throw e; @@ -29,7 +28,7 @@ public abstract class BasePackFetcher implements PackFetcher { Path p = targetDir.resolve(Integer.toHexString(url.hashCode())); if (!forceDownload && Files.exists(p)) { - Resclone.COUNT++; + Resclone.packCount++; return new Result(p, false); } @@ -46,7 +45,7 @@ public abstract class BasePackFetcher implements PackFetcher { } catch (Throwable e) { throw new Exception("Could not download pack", e); } - Resclone.COUNT++; + Resclone.packCount++; return new Result(p, true); } -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/fetchers/BasicFileFetcher.java b/src/main/java/io/gitlab/jfronny/resclone/fetchers/BasicFileFetcher.java index 6beccff..c00b3dd 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/fetchers/BasicFileFetcher.java +++ b/src/main/java/io/gitlab/jfronny/resclone/fetchers/BasicFileFetcher.java @@ -1,7 +1,6 @@ package io.gitlab.jfronny.resclone.fetchers; public class BasicFileFetcher extends BasePackFetcher { - @Override public String getSourceTypeName() { return "file"; @@ -11,5 +10,4 @@ public class BasicFileFetcher extends BasePackFetcher { public String getDownloadUrl(String baseUrl) { return baseUrl; } - -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/fetchers/CurseforgeFetcher.java b/src/main/java/io/gitlab/jfronny/resclone/fetchers/CurseforgeFetcher.java index 8791bf4..4a2a71d 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/fetchers/CurseforgeFetcher.java +++ b/src/main/java/io/gitlab/jfronny/resclone/fetchers/CurseforgeFetcher.java @@ -1,14 +1,27 @@ package io.gitlab.jfronny.resclone.fetchers; -import io.gitlab.jfronny.resclone.Resclone; -import io.gitlab.jfronny.resclone.data.CfAddon; -import io.gitlab.jfronny.resclone.util.UrlUtils; -import net.minecraft.MinecraftVersion; +import io.gitlab.jfronny.commons.*; +import io.gitlab.jfronny.resclone.*; +import io.gitlab.jfronny.resclone.data.curseforge.*; +import net.minecraft.*; -import java.text.SimpleDateFormat; -import java.util.Date; +import java.io.*; +import java.net.*; +import java.util.*; 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 public String getSourceTypeName() { return "curseforge"; @@ -17,25 +30,26 @@ public class CurseforgeFetcher extends BasePackFetcher { @Override public String getDownloadUrl(String baseUrl) throws Exception { 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(); - CfAddon latest = null; + GetModFilesResponse.Data latest = null; Date latestDate = null; boolean foundMatchingVersion = false; - for (CfAddon addon : UrlUtils.readJsonFromURLSet("https://addons-ecs.forgesvc.net/api/v2/addon/" + baseUrl + "/files", CfAddon.class)) { - Date d = df.parse(addon.fileDate); - if (foundMatchingVersion && !addon.gameVersion.contains(version)) + for (GetModFilesResponse.Data addon : GET(baseUrl + "/files", GetModFilesResponse.class).data) { + if (foundMatchingVersion && !addon.gameVersions.contains(version)) continue; - if (!foundMatchingVersion && addon.gameVersion.contains(version)) { + if (!foundMatchingVersion && addon.gameVersions.contains(version)) { foundMatchingVersion = true; latest = null; } - if (latest == null || d.after(latestDate)) { + if (latest == null || addon.fileDate.after(latestDate)) { 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); } } -} \ No newline at end of file + + private static T GET(String suffix, Class 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; + } +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/fetchers/GitHubFetcher.java b/src/main/java/io/gitlab/jfronny/resclone/fetchers/GitHubFetcher.java index 27e1f1f..52d7ad9 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/fetchers/GitHubFetcher.java +++ b/src/main/java/io/gitlab/jfronny/resclone/fetchers/GitHubFetcher.java @@ -1,12 +1,12 @@ package io.gitlab.jfronny.resclone.fetchers; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +import io.gitlab.jfronny.commons.*; 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 java.io.IOException; +import java.net.*; public class GitHubFetcher extends BasePackFetcher { @Override @@ -39,20 +39,19 @@ public class GitHubFetcher extends BasePackFetcher { //"user/repo/release" - Gets from the latest release. else if (parts[2].equalsIgnoreCase("release")) { 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; - for (JsonElement element : latestRelease.get("assets").getAsJsonArray()) { - JsonObject o = element.getAsJsonObject(); - if ("application/x-zip-compressed".equals(o.get("content_type").getAsString()) || o.get("name").getAsString().endsWith(".zip")) { - res = o.get("browser_download_url").getAsString(); + for (Release.Asset asset : latestRelease.assets) { + if ("application/x-zip-compressed".equals(asset.content_type) || asset.name.endsWith(".zip")) { + res = asset.browser_download_url; break; } } 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; } catch (Throwable e) { @@ -74,8 +73,8 @@ public class GitHubFetcher extends BasePackFetcher { private String getFromBranch(String repo, @Nullable String branch) { if (branch == null) { try { - branch = UrlUtils.readJsonFromURL("https://api.github.com/repos/" + repo, JsonObject.class).get("default_branch").getAsString(); - } catch (IOException e) { + branch = HttpUtils.get("https://api.github.com/repos/" + repo).sendSerialized(Repository.class).default_branch; + } catch (IOException | URISyntaxException e) { Resclone.LOGGER.error("Failed to fetch branch for " + repo + ". Choosing \"main\"", e); branch = "main"; } @@ -88,4 +87,4 @@ public class GitHubFetcher extends BasePackFetcher { Resclone.LOGGER.info("Getting from tag " + tag + "."); return "https://codeload.github.com/" + repo + "/legacy.zip/refs/tags/" + tag; } -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/mixin/FileResourcePackProviderMixin.java b/src/main/java/io/gitlab/jfronny/resclone/mixin/FileResourcePackProviderMixin.java index febc102..9c21a4b 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/mixin/FileResourcePackProviderMixin.java +++ b/src/main/java/io/gitlab/jfronny/resclone/mixin/FileResourcePackProviderMixin.java @@ -21,11 +21,11 @@ public class FileResourcePackProviderMixin { @Inject(at = @At("TAIL"), method = "register(Ljava/util/function/Consumer;Lnet/minecraft/resource/ResourcePackProfile$Factory;)V") public void registerExtra(Consumer consumer, ResourcePackProfile.Factory factory, CallbackInfo info) { - for (PackMetaLoaded meta : Resclone.downloadedPacks) { + for (PackMetaLoaded meta : Resclone.DOWNLOADED_PACKS) { ResourcePackProfile resourcePackProfile = ResourcePackProfile.of( - "resclone/" + meta.name, - meta.forceEnable, - () -> new RescloneResourcePack(meta.zipPath.toFile(), meta.name), + "resclone/" + meta.name(), + meta.forceEnable(), + () -> new RescloneResourcePack(meta.zipPath().toFile(), meta.name()), factory, ResourcePackProfile.InsertionPosition.TOP, this.source @@ -35,4 +35,4 @@ public class FileResourcePackProviderMixin { } } } -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/mixin/GameOptionsMixin.java b/src/main/java/io/gitlab/jfronny/resclone/mixin/GameOptionsMixin.java index fe5b6f1..2697c27 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/mixin/GameOptionsMixin.java +++ b/src/main/java/io/gitlab/jfronny/resclone/mixin/GameOptionsMixin.java @@ -19,12 +19,12 @@ public abstract class GameOptionsMixin { @Inject(at = @At("TAIL"), method = "load()V") public void load(CallbackInfo ci) { - for (PackMetaLoaded meta : Resclone.newPacks) { - Resclone.LOGGER.info(Resclone.MOD_ID + "/" + meta.name); - resourcePacks.add(Resclone.MOD_ID + "/" + meta.name); + for (PackMetaLoaded meta : Resclone.NEW_PACKS) { + Resclone.LOGGER.info(Resclone.MOD_ID + "/" + meta.name()); + resourcePacks.add(Resclone.MOD_ID + "/" + meta.name()); } - if (!Resclone.newPacks.isEmpty()) + if (!Resclone.NEW_PACKS.isEmpty()) write(); - Resclone.newPacks.clear(); + Resclone.NEW_PACKS.clear(); } } diff --git a/src/main/java/io/gitlab/jfronny/resclone/processors/PruneVanillaProcessor.java b/src/main/java/io/gitlab/jfronny/resclone/processors/PruneVanillaProcessor.java index 4d80f3c..2d47168 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/processors/PruneVanillaProcessor.java +++ b/src/main/java/io/gitlab/jfronny/resclone/processors/PruneVanillaProcessor.java @@ -1,5 +1,6 @@ package io.gitlab.jfronny.resclone.processors; +import io.gitlab.jfronny.resclone.*; import io.gitlab.jfronny.resclone.api.PackProcessor; import io.gitlab.jfronny.resclone.util.io.PathPruneVisitor; import net.minecraft.client.MinecraftClient; @@ -12,7 +13,6 @@ import java.nio.file.Files; import java.nio.file.StandardOpenOption; public class PruneVanillaProcessor implements PackProcessor { - @Override public void process(FileSystem p) throws Exception { ClassLoader cl = MinecraftClient.class.getClassLoader(); @@ -29,7 +29,7 @@ public class PruneVanillaProcessor implements PackProcessor { } } } catch (Throwable e) { - e.printStackTrace(); + Resclone.LOGGER.error("Could not prune unchanged assets", e); } return false; })); @@ -38,5 +38,4 @@ public class PruneVanillaProcessor implements PackProcessor { throw new Exception("Could not prune vanilla files", e); } } - -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/processors/RemoveEmptyProcessor.java b/src/main/java/io/gitlab/jfronny/resclone/processors/RemoveEmptyProcessor.java index d2cff71..b538845 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/processors/RemoveEmptyProcessor.java +++ b/src/main/java/io/gitlab/jfronny/resclone/processors/RemoveEmptyProcessor.java @@ -1,5 +1,6 @@ package io.gitlab.jfronny.resclone.processors; +import io.gitlab.jfronny.resclone.*; import io.gitlab.jfronny.resclone.api.PackProcessor; import io.gitlab.jfronny.resclone.util.io.PathPruneVisitor; @@ -10,7 +11,6 @@ import java.nio.file.Files; import java.nio.file.Path; public class RemoveEmptyProcessor implements PackProcessor { - @Override public void process(FileSystem p) throws Exception { if (Files.exists(p.getPath("/assets"))) { @@ -20,7 +20,7 @@ public class RemoveEmptyProcessor implements PackProcessor { try (DirectoryStream paths = Files.newDirectoryStream(s)) { return !paths.iterator().hasNext(); } catch (IOException e) { - e.printStackTrace(); + Resclone.LOGGER.error("Could not check whether directory has entries", e); } } return false; @@ -30,5 +30,4 @@ public class RemoveEmptyProcessor implements PackProcessor { } } } - -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/processors/RootPathProcessor.java b/src/main/java/io/gitlab/jfronny/resclone/processors/RootPathProcessor.java index f477bec..ae367bf 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/processors/RootPathProcessor.java +++ b/src/main/java/io/gitlab/jfronny/resclone/processors/RootPathProcessor.java @@ -7,7 +7,6 @@ import java.io.IOException; import java.nio.file.*; public class RootPathProcessor implements PackProcessor { - @Override public void process(FileSystem p) throws Exception { if (!Files.exists(p.getPath("/pack.mcmeta"))) { @@ -25,5 +24,4 @@ public class RootPathProcessor implements PackProcessor { } } } - -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/util/ConfigLoader.java b/src/main/java/io/gitlab/jfronny/resclone/util/ConfigLoader.java index 20a262f..ae2a1a8 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/util/ConfigLoader.java +++ b/src/main/java/io/gitlab/jfronny/resclone/util/ConfigLoader.java @@ -1,6 +1,7 @@ package io.gitlab.jfronny.resclone.util; 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.api.RescloneApi; import io.gitlab.jfronny.resclone.data.PackMetaUnloaded; @@ -23,23 +24,23 @@ public class ConfigLoader { text.append("\r\n"); text.append(s); } - Set data = Resclone.gson.fromJson(text.toString(), new TypeToken>(){}.getType()); + Set data = GsonHolder.getGson().fromJson(text.toString(), new TypeToken>(){}.getType()); for (PackMetaUnloaded meta : data) { api.addPack(meta.fetcher, meta.source, meta.name, meta.forceDownload, meta.forceEnable); } } catch (IOException e) { - e.printStackTrace(); + Resclone.LOGGER.error("Could not load config", e); } } public static void save(RescloneApi api, Set data) { Path configPath = api.getConfigPath().resolve("config.json"); Set text = new HashSet<>(); - text.add(Resclone.gson.toJson(data)); + text.add(GsonHolder.getGson().toJson(data)); try { Files.write(configPath, text); } catch (IOException e) { - e.printStackTrace(); + Resclone.LOGGER.error("Could not write config", e); } } -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/util/PackUrlCache.java b/src/main/java/io/gitlab/jfronny/resclone/util/PackUrlCache.java index df714de..10268f1 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/util/PackUrlCache.java +++ b/src/main/java/io/gitlab/jfronny/resclone/util/PackUrlCache.java @@ -1,5 +1,7 @@ package io.gitlab.jfronny.resclone.util; +import io.gitlab.jfronny.resclone.*; + import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; @@ -8,7 +10,6 @@ import java.nio.file.Path; import java.util.Properties; public class PackUrlCache { - private final Path file; Properties properties = new Properties(); @@ -18,7 +19,7 @@ public class PackUrlCache { try (BufferedReader r = Files.newBufferedReader(file)) { properties.load(r); } 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)) { properties.store(w, "This is an internal file used for offline pack loading, do not edit"); } 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) { properties.setProperty(key, value); } - -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/util/Result.java b/src/main/java/io/gitlab/jfronny/resclone/util/Result.java deleted file mode 100644 index 092fcad..0000000 --- a/src/main/java/io/gitlab/jfronny/resclone/util/Result.java +++ /dev/null @@ -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; - } - -} \ No newline at end of file diff --git a/src/main/java/io/gitlab/jfronny/resclone/util/UrlUtils.java b/src/main/java/io/gitlab/jfronny/resclone/util/UrlUtils.java deleted file mode 100644 index e8eb113..0000000 --- a/src/main/java/io/gitlab/jfronny/resclone/util/UrlUtils.java +++ /dev/null @@ -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 readJsonFromURL(String requestUrl, Class classOfT) throws IOException { - return Resclone.gson.fromJson(readStringFromURL(requestUrl), classOfT); - } - - public static Set readJsonFromURLSet(String requestUrl, Class classOfT) throws IOException { - return Resclone.gson.fromJson(readStringFromURL(requestUrl), TypeToken.getParameterized(Set.class, classOfT).getType()); - } - -} \ No newline at end of file diff --git a/src/main/java/io/gitlab/jfronny/resclone/util/io/MoveDirVisitor.java b/src/main/java/io/gitlab/jfronny/resclone/util/io/MoveDirVisitor.java index 395b504..7270704 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/util/io/MoveDirVisitor.java +++ b/src/main/java/io/gitlab/jfronny/resclone/util/io/MoveDirVisitor.java @@ -5,7 +5,6 @@ import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; public class MoveDirVisitor extends SimpleFileVisitor { - private final Path fromPath; private final Path toPath; private final CopyOption copyOption; @@ -36,5 +35,4 @@ public class MoveDirVisitor extends SimpleFileVisitor { Files.delete(dir); return FileVisitResult.CONTINUE; } - -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/util/io/PathPruneVisitor.java b/src/main/java/io/gitlab/jfronny/resclone/util/io/PathPruneVisitor.java index 040ac6b..c3638f0 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/util/io/PathPruneVisitor.java +++ b/src/main/java/io/gitlab/jfronny/resclone/util/io/PathPruneVisitor.java @@ -9,8 +9,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.function.Predicate; public class PathPruneVisitor extends SimpleFileVisitor { - - Predicate removalSelector; + private final Predicate removalSelector; public PathPruneVisitor(Predicate removalSelector) { this.removalSelector = removalSelector; @@ -27,5 +26,4 @@ public class PathPruneVisitor extends SimpleFileVisitor { if (removalSelector.test(dir)) Files.walkFileTree(dir, new RemoveDirVisitor()); return super.postVisitDirectory(dir, exc); } - -} \ No newline at end of file +} diff --git a/src/main/java/io/gitlab/jfronny/resclone/util/io/RemoveDirVisitor.java b/src/main/java/io/gitlab/jfronny/resclone/util/io/RemoveDirVisitor.java index f093229..5acbf03 100644 --- a/src/main/java/io/gitlab/jfronny/resclone/util/io/RemoveDirVisitor.java +++ b/src/main/java/io/gitlab/jfronny/resclone/util/io/RemoveDirVisitor.java @@ -8,7 +8,6 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; public class RemoveDirVisitor extends SimpleFileVisitor { - @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); @@ -20,5 +19,4 @@ public class RemoveDirVisitor extends SimpleFileVisitor { Files.delete(dir); return FileVisitResult.CONTINUE; } - -} \ No newline at end of file +}