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.muscript.debug.ObjectGraphPrinter; import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.gson.AttachmentHolder; import io.gitlab.jfronny.respackopts.model.Condition; import io.gitlab.jfronny.respackopts.model.DirRpo; import io.gitlab.jfronny.respackopts.model.cache.CacheKey; import io.gitlab.jfronny.respackopts.model.cache.CachedPackState; import io.gitlab.jfronny.respackopts.model.enums.PackCapability; import io.gitlab.jfronny.respackopts.util.MetaCache; import net.minecraft.resource.*; import net.minecraft.util.Identifier; import java.io.*; import java.util.Map; public enum DirFilterEvents implements UserResourceEvents.Open, UserResourceEvents.FindResource { INSTANCE; public static void init() { UserResourceEvents.OPEN.register(INSTANCE); UserResourceEvents.FIND_RESOURCE.register(INSTANCE); } @Override public InputSupplier open(ResourceType type, Identifier id, InputSupplier previous, ResourcePack 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.getKeyByPack(pack), path)) { path = findReplacementDir(path, rpo); if (path == null) return null; ResourcePath rp = new ResourcePath(path); return pack.open(rp.getType(), rp.getId()); } return previous; } @Override public ResourcePack.ResultConsumer findResources(ResourceType type, String namespace, String prefix, ResourcePack.ResultConsumer previous, ResourcePack 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; boolean dirFilterAdditive = MetaCache.hasCapability(pack, PackCapability.DirFilterAdditive); return (identifier, value) -> { String path = type.getDirectory() + "/" + identifier.getNamespace() + "/" + identifier.getPath(); DirRpo rpo = findDirRpo(pack, path); if (rpo != null && dirHidden(rpo, MetaCache.getKeyByPack(pack), path)) { path = findReplacementDir(path, rpo); if (path != null && 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 pack.findResources(rp.getType(), rp.getId().getNamespace(), rp.getId().getPath(), (resource, resVal) -> { String p = type.getDirectory() + "/" + resource.getNamespace() + "/" + resource.getPath(); p = p.replace(rpo.fallback, rpo.path + "/"); previous.accept(new ResourcePath(p).getId(), resVal); }); } } } else previous.accept(identifier, value); }; } private String findReplacementDir(String dir, DirRpo rpo) { if (rpo.fallback == null) return null; return dir.replace(rpo.path + "/", rpo.fallback); } private 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 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; } InputSupplier is = UserResourceEvents.disable(() -> pack.open(rp.getType(), rp.getId())); if (is == null) return null; try (Reader w = new InputStreamReader(is.get())) { 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; } }