package io.gitlab.jfronny.resclone; import com.google.gson.Gson; import io.gitlab.jfronny.resclone.data.PackMetaLoaded; import io.gitlab.jfronny.resclone.api.RescloneApi; import io.gitlab.jfronny.resclone.api.RescloneEntry; import io.gitlab.jfronny.resclone.data.PackMetaUnloaded; import io.gitlab.jfronny.resclone.data.RescloneException; import io.gitlab.jfronny.resclone.fetchers.PackFetcher; import io.gitlab.jfronny.resclone.processors.PackProcessor; import io.gitlab.jfronny.resclone.processors.RemoveEmptyProcessor; import io.gitlab.jfronny.resclone.processors.RootPathProcessor; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import java.io.IOException; import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; 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 Gson gson = new Gson(); public static final String MOD_ID = "resclone"; @Override public void onInitialize() { conf.clear(); fetcherInstances.clear(); processors.clear(); downloadedPacks.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 (RescloneException e) { e.printStackTrace(); } } addProcessor(new RemoveEmptyProcessor()); reload(); } @Override public void addFetcher(PackFetcher fetcher) { fetcherInstances.put(fetcher.getSourceTypeName(), fetcher); } @Override public void addProcessor(PackProcessor processor) { processors.add(processor); } @Override public void addPack(String fetcher, String pack, String name) { conf.add(new PackMetaUnloaded(fetcher, pack, name)); } @Override public void reload() { //Get paths from patchers. Downloading is implemented in PackFetcher to allow for unconsidered sources //TODO implement downloading again after a set time if downloadable Set metas = new LinkedHashSet<>(); //Download for (PackMetaUnloaded s : conf) { try { if (!fetcherInstances.containsKey(s.fetcher)) throw new RescloneException("Invalid fetcher: " + s.fetcher); String fileName = ""; fileName += Integer.toHexString(s.fetcher.hashCode()); fileName += Integer.toHexString(s.source.hashCode()); PackMetaLoaded p = new PackMetaLoaded(getConfigPath().resolve("cache").resolve(fileName), s.name); //If file is not present: download and process pack Path p1 = p.zipPath; if (Files.exists(p.zipPath)) { p1 = p.zipPath.getParent().resolve(p.zipPath.getFileName() + ".bak"); Files.deleteIfExists(p1); Files.move(p.zipPath, p1); } try { //Download fetcherInstances.get(s.fetcher).get(s.source, p.zipPath); //Process Map props = new HashMap<>(); props.put("create", "false"); URI zipfile = URI.create("jar:" + p.zipPath.toUri().toString()); try (FileSystem zipfs = FileSystems.newFileSystem(zipfile, props)) { for (PackProcessor processor : processors) { processor.process(zipfs); } } catch (Throwable e) { e.printStackTrace(); } } catch (Throwable e) { if (!p1.equals(p.zipPath)) { e.printStackTrace(); System.err.println("Failed to download, using cache"); Files.deleteIfExists(p.zipPath); Files.move(p1, p.zipPath); } else throw new RescloneException("Failed to download initial", e); } if (!p1.equals(p.zipPath)) Files.deleteIfExists(p1); metas.add(p); } catch (Throwable e) { System.err.println("Encountered issue while preparing " + s.name); e.printStackTrace(); } } //Set variable downloadedPacks.clear(); downloadedPacks.addAll(metas); } @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) { e.printStackTrace(); } } return configPath; } }