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.ClientModInitializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; 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.*; @Environment(EnvType.CLIENT) public class Resclone implements ClientModInitializer, 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 onInitializeClient() { 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(false); } @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(boolean forceResourceReload) { //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 if (!Files.isRegularFile(p.zipPath)) { //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)) { //ZipFile file = new ZipFile(meta.zipPath.toFile()); for (PackProcessor processor : processors) { processor.process(zipfs); } } catch (Throwable e) { e.printStackTrace(); } } metas.add(p); } catch (RescloneException e) { e.printStackTrace(); } } //Set variable downloadedPacks.clear(); downloadedPacks.addAll(metas); if (forceResourceReload) MinecraftClient.getInstance().reloadResources(); } @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; } }