package io.gitlab.jfronny.respackopts.filters; import io.gitlab.jfronny.libjf.ResourcePath; import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents; import io.gitlab.jfronny.respackopts.util.MetaCache; import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.model.DirRpo; import io.gitlab.jfronny.respackopts.model.enums.PackCapability; import io.gitlab.jfronny.respackopts.util.RpoFormatException; import net.minecraft.resource.ResourcePack; import net.minecraft.util.Identifier; import java.io.*; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Map; public class DirFilterEventImpl { public static void init() { UserResourceEvents.OPEN.register((type, id, previous, pack) -> { if (!MetaCache.hasCapability(pack, PackCapability.DirFilter)) return previous; String path = new ResourcePath(type, id).getName(); DirRpo rpo = findDirRpo(pack, path); if (rpo != null && dirHidden(rpo, MetaCache.getId(pack))) { path = findReplacementDir(path, rpo); if (path == null) throw new FileNotFoundException(); ResourcePath rp = new ResourcePath(path); return pack.open(rp.getType(), rp.getId()); } return previous; }); UserResourceEvents.FIND_RESOURCE.register((type, namespace, prefix, maxDepth, pathFilter, previous, pack) -> { // Warning: the Identifiers here DON'T CONTAIN THE TYPE! // Therefore, it needs to be added when calling a method that generates a ResourcePath! if (!MetaCache.hasCapability(pack, PackCapability.DirFilter)) return previous; Collection nextRes = new LinkedHashSet<>(previous); boolean dirFilterAdditive = MetaCache.hasCapability(pack, PackCapability.DirFilterAdditive); for (Identifier identifier : previous) { String path = type.getDirectory() + "/" + identifier.getNamespace() + "/" + identifier.getPath(); DirRpo rpo = findDirRpo(pack, path); if (rpo != null) { if (dirHidden(rpo, MetaCache.getId(pack))) { path = findReplacementDir(path, rpo); if (path == null) nextRes.remove(identifier); else if (dirFilterAdditive) { String[] s = path.split("/", 3); if (s.length == 3) { ResourcePath rp = new ResourcePath(path); //TODO improve this impl (used for files that aren't at the original location for (Identifier resource : pack.findResources(rp.getType(), rp.getId().getNamespace(), rp.getId().getPath(), maxDepth, (a) -> true)) { String p = type.getDirectory() + "/" + resource.getNamespace() + "/" + resource.getPath(); p = p.replace(rpo.fallback, rpo.path + "/"); rp = new ResourcePath(p); if (pathFilter.test(p)) nextRes.add(rp.getId()); } } } } } } return nextRes; }); UserResourceEvents.CONTAINS.register((type, id, previous, pack) -> { if (!MetaCache.hasCapability(pack, PackCapability.DirFilter)) return previous; String path = new ResourcePath(type, id).getName(); DirRpo rpo = findDirRpo(pack, path); if (rpo != null && dirHidden(rpo, MetaCache.getId(pack))) { path = findReplacementDir(path, rpo); if (path == null) return false; ResourcePath rp = new ResourcePath(path); return pack.contains(rp.getType(), rp.getId()); } return previous; }); } private static String findReplacementDir(String dir, DirRpo rpo) { if (rpo.fallback == null) return null; return dir.replace(rpo.path + "/", rpo.fallback); } private static boolean dirHidden(DirRpo rpo, String packId) { if (rpo.conditions == null) return false; try { return !rpo.conditions.evaluate(packId); } catch (RpoFormatException e) { Respackopts.LOGGER.error("Couldn't parse dir conditions", e); } return false; } private static DirRpo findDirRpo(ResourcePack pack, String name) { Map drpReg = MetaCache.DIR_RPOS.get(MetaCache.getId(pack)); int li = name.lastIndexOf('/'); if (li <= 0) return null; name = name.substring(0, li); if (drpReg.containsKey(name)) return drpReg.get(name); DirRpo drp = findDirRpo(pack, name); if (drp != null) { drpReg.put(name, drp); return drp; } ResourcePath rp; try { rp = new ResourcePath(name + "/.rpo"); } catch (Exception e) { return null; } if (UserResourceEvents.disable(() -> pack.contains(rp.getType(), rp.getId()))) { try (InputStream stream = UserResourceEvents.disable(() -> pack.open(rp.getType(), rp.getId())); Reader w = new InputStreamReader(stream)) { drp = Respackopts.GSON.fromJson(w, DirRpo.class); drp.path = name; if (drp.fallback != null && !drp.fallback.endsWith("/")) drp.fallback += "/"; drpReg.put(name, drp); return drp; } catch (IOException e) { Respackopts.LOGGER.error("Couldn't open dir rpo", e); } } return null; } }