package io.gitlab.jfronny.respackopts.filters; import io.gitlab.jfronny.libjf.*; import io.gitlab.jfronny.libjf.data.manipulation.api.*; import io.gitlab.jfronny.muscript.debug.*; import io.gitlab.jfronny.respackopts.*; import io.gitlab.jfronny.respackopts.gson.*; import io.gitlab.jfronny.respackopts.model.*; import io.gitlab.jfronny.respackopts.model.cache.*; import io.gitlab.jfronny.respackopts.model.enums.*; import io.gitlab.jfronny.respackopts.util.*; import net.minecraft.resource.*; import net.minecraft.util.*; import java.io.*; import java.util.*; public class DirFilterEventImpl { public static void init() { UserResourceEvents.OPEN.register((type, id, previous, pack) -> { if (!MetaCache.hasCapability(pack, PackCapability.DirFilter)) return previous.get(); String path = new ResourcePath(type, id).getName(); DirRpo rpo = findDirRpo(pack, path); if (rpo != null && dirHidden(rpo, MetaCache.getKeyByPack(pack), path)) { path = findReplacementDir(path, rpo); if (path == null) throw new FileNotFoundException(); ResourcePath rp = new ResourcePath(path); return pack.open(rp.getType(), rp.getId()); } return previous.get(); }); UserResourceEvents.FIND_RESOURCE.register((type, namespace, prefix, allowedPathPredicate, 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! Collection prevVals = previous.get(); if (!MetaCache.hasCapability(pack, PackCapability.DirFilter)) return prevVals; Collection nextRes = new LinkedHashSet<>(prevVals); boolean dirFilterAdditive = MetaCache.hasCapability(pack, PackCapability.DirFilterAdditive); for (Identifier identifier : prevVals) { String path = type.getDirectory() + "/" + identifier.getNamespace() + "/" + identifier.getPath(); DirRpo rpo = findDirRpo(pack, path); if (rpo != null) { if (dirHidden(rpo, MetaCache.getKeyByPack(pack), path)) { 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(), (a) -> true)) { String p = type.getDirectory() + "/" + resource.getNamespace() + "/" + resource.getPath(); p = p.replace(rpo.fallback, rpo.path + "/"); rp = new ResourcePath(p); if (allowedPathPredicate.test(rp.getId())) nextRes.add(rp.getId()); } } } } } } return nextRes; }); UserResourceEvents.CONTAINS.register((type, id, previous, pack) -> { if (!MetaCache.hasCapability(pack, PackCapability.DirFilter)) return previous.get(); String path = new ResourcePath(type, id).getName(); DirRpo rpo = findDirRpo(pack, path); if (rpo != null && dirHidden(rpo, MetaCache.getKeyByPack(pack), path)) { path = findReplacementDir(path, rpo); if (path == null) return false; ResourcePath rp = new ResourcePath(path); return pack.contains(rp.getType(), rp.getId()); } return previous.get(); }); } 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, CacheKey key, String file) { if (rpo.condition == null) return false; try { return !rpo.condition.get(MetaCache.getParameter(key)); } catch (Condition.ConditionException e) { String res = "Could not evaluate condition " + file + " (pack: " + key.packName() + ")"; try { Respackopts.LOGGER.error(res + " with condition:\n" + ObjectGraphPrinter.printGraph(rpo.condition) + ")", e); } catch (Throwable ex) { Respackopts.LOGGER.error(res, e); } } return false; } private static DirRpo findDirRpo(ResourcePack pack, String name) { CachedPackState state = MetaCache.getState(MetaCache.getKeyByPack(pack)); Map drpReg = state.cachedDirRPOs(); 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 + "/" + Respackopts.FILE_EXTENSION); } 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 = AttachmentHolder.deserialize(state.metadata().version, 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 " + rp.getName(), e); } } return null; } }