Respackopts/src/main/java/io/gitlab/jfronny/respackopts/filters/DirFilterEventImpl.java

141 lines
6.4 KiB
Java

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<Identifier> prevVals = previous.get();
if (!MetaCache.hasCapability(pack, PackCapability.DirFilter))
return prevVals;
Collection<Identifier> 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<String, DirRpo> 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;
}
}