Resclone/src/main/java/io/gitlab/jfronny/resclone/Resclone.java

158 lines
6.1 KiB
Java

package io.gitlab.jfronny.resclone;
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.*;
import java.net.*;
import java.nio.file.FileSystem;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
public class Resclone implements ModInitializer, RescloneApi {
public static final Set<PackMetaUnloaded> CONF = new LinkedHashSet<>();
public static final Map<String, PackFetcher> FETCHER_INSTANCES = new LinkedHashMap<>();
public static final Set<PackProcessor> PROCESSORS = new LinkedHashSet<>();
public static final Set<PackMetaLoaded> DOWNLOADED_PACKS = new LinkedHashSet<>();
public static final Set<PackMetaLoaded> NEW_PACKS = new LinkedHashSet<>(); // Client-only!
public static final String MOD_ID = "resclone";
public static final Logger LOGGER = Logger.forName(MOD_ID);
public static PackUrlCache urlCache;
public static int packCount = 0;
@Override
public void onInitialize() {
LOGGER.info("Initialising Resclone.");
GsonHolder.register();
urlCache = new PackUrlCache(getConfigPath().resolve("urlCache.properties"));
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) {
Resclone.LOGGER.error("Could not initialize resclone pack supplier", e);
}
}
addProcessor(new RemoveEmptyProcessor());
reload();
LOGGER.info("Installed {} resource pack{}.", packCount, packCount == 1 ? "" : "s");
}
@Override
public void addFetcher(PackFetcher fetcher) {
FETCHER_INSTANCES.put(fetcher.getSourceTypeName(), fetcher);
}
@Override
public void addProcessor(PackProcessor processor) {
PROCESSORS.add(processor);
}
@Override
public void addPack(String fetcher, String pack, String name) {
addPack(fetcher, pack, name, false);
}
@Override
public void addPack(String fetcher, String pack, String name, boolean forceRedownload) {
addPack(fetcher, pack, name, forceRedownload, false);
}
@Override
public void addPack(String fetcher, String pack, String name, boolean forceRedownload, boolean forceEnable) {
CONF.add(new PackMetaUnloaded(fetcher, pack, name, forceRedownload, forceEnable));
}
@Override
public void reload() {
Set<PackMetaLoaded> metas = new LinkedHashSet<>();
try {
if (CONF.isEmpty()) {
LOGGER.info("No resclone pack was specified, add one");
}
else {
ExecutorService pool = Executors.newFixedThreadPool(CONF.size());
for (PackMetaUnloaded s : CONF) {
pool.submit(generateTask(s, metas));
}
pool.shutdown();
if (!pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS)) {
LOGGER.error("Download timed out. This shouldn't be possible");
}
}
} catch (InterruptedException e) {
LOGGER.error("Could not execute pack download task", e);
}
urlCache.save();
DOWNLOADED_PACKS.clear();
DOWNLOADED_PACKS.addAll(metas);
}
private Runnable generateTask(PackMetaUnloaded meta, Set<PackMetaLoaded> metas) {
return () -> {
try {
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
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 && FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) NEW_PACKS.add(p);
if (fr.freshDownload()) {
//Process
Map<String, String> props = new HashMap<>();
props.put("create", "false");
URI zipfile = URI.create("jar:" + p.zipPath().toUri());
try (FileSystem zipfs = FileSystems.newFileSystem(zipfile, props)) {
for (PackProcessor processor : PROCESSORS) {
processor.process(zipfs);
}
} catch (Throwable e) {
LOGGER.error("Could not run pack processors on " + p.zipPath(), e);
}
}
} catch (Throwable e) {
throw new Exception("Failed to download pack", e);
}
} catch (Throwable e) {
LOGGER.error("Encountered issue while preparing " + meta.name, e);
}
};
}
@Override
public Path getConfigPath() {
Path configPath = FabricLoader.getInstance().getConfigDir().resolve("resclone");
if (!Files.isDirectory(configPath.resolve("cache"))) {
try {
Files.createDirectories(configPath.resolve("cache"));
} catch (IOException e) {
LOGGER.error("Could not create cache directory", e);
}
}
return configPath;
}
}