Update to 1.19.3
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/jfmod Pipeline was successful Details

This commit is contained in:
Johannes Frohnmeyer 2022-12-08 19:00:41 +01:00
parent 2b6f4853d2
commit 25739e28a5
Signed by: Johannes
GPG Key ID: E76429612C2929F4
21 changed files with 393 additions and 362 deletions

View File

@ -26,7 +26,7 @@ dependencies {
modClientCompileOnly("io.vram:frex-fabric-mc119:+")
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil:${prop("libjf_version")}")
modLocalRuntime("com.terraformersmc:modmenu:4.1.1")
modLocalRuntime("com.terraformersmc:modmenu:5.0.0-alpha.4")
testImplementation("org.junit.jupiter:junit-jupiter:5.9.0")

View File

@ -13,7 +13,7 @@ You will need to navigate to the file you would like to toggle inside your resou
`some_recipe.json` would be `some_recipe.json.rpo`<br>
### `.rpo` explanation :
You need a `.rpo` file per texture (except for the last one in your list) if you have 3 files to select beteen then you will need 2 `.rpo` files,
You need a `.rpo` file per texture (except for the last one in your list) if you have 3 files to select between then you will need 2 `.rpo` files,
if you have 4 files to select between then you will need 3 `.rpo` files and so on etc...
### Layout:

View File

@ -1,6 +1,6 @@
# Switch between two files
This is a simple `IF` statement simply returning true/false to if the texture/file should be loaded into the pack.
(Pick one file over another).
Imagine a simple `IF` statement controlling whether the texture/file should be loaded into the pack.
That is exactly what this page is about.
You will need the `Pack ID` and `Entry Name` from your `respackopts.json5` that you created earlier
if you have not, see [Main Config](../setup/MainConfig.md) on how to do so.
<br>
@ -28,6 +28,9 @@ You will need to navigate to the file you would like to toggle inside your resou
}
```
Please be aware that Minecraft restricts file and path names.
You MUST follow these! If you don't (for example by using uppercase letters or symbols), your pack WILL NOT WORK!
## Another way to do this:
Respackopts supports specifying multiple possible fallbacks when configuring single files.
You can use this functionality as follows:

View File

@ -1,6 +1,6 @@
# https://fabricmc.net/develop/
minecraft_version=1.19.2
yarn_mappings=build.28
minecraft_version=1.19.3
yarn_mappings=build.2
loader_version=0.14.11
maven_group=io.gitlab.jfronny
@ -13,6 +13,6 @@ curseforge_id=430090
curseforge_required_dependencies=fabric-api, libjf
curseforge_optional_dependencies=modmenu
fabric_version=0.68.0+1.19.2
libjf_version=3.2.1
fabric_version=0.68.1+1.19.3
libjf_version=3.3.1
muscript_version=1.0-SNAPSHOT

View File

@ -5,8 +5,7 @@ import io.gitlab.jfronny.gson.Gson;
import io.gitlab.jfronny.gson.GsonBuilder;
import io.gitlab.jfronny.libjf.config.api.v1.ConfigHolder;
import io.gitlab.jfronny.muscript.compiler.expr.*;
import io.gitlab.jfronny.respackopts.filters.DirFilterEventImpl;
import io.gitlab.jfronny.respackopts.filters.FileFilterEventImpl;
import io.gitlab.jfronny.respackopts.filters.*;
import io.gitlab.jfronny.respackopts.gson.*;
import io.gitlab.jfronny.respackopts.gson.entry.*;
import io.gitlab.jfronny.respackopts.integration.SaveHook;
@ -16,6 +15,8 @@ import io.gitlab.jfronny.respackopts.server.ServerInstanceHolder;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.resource.InputSupplier;
import net.minecraft.util.Util;
import java.io.IOException;
import java.nio.file.Files;
@ -41,7 +42,7 @@ public class Respackopts implements ModInitializer, SaveHook {
public static final String ID = "respackopts";
public static final Logger LOGGER = Logger.forName(ID);
public static Path FALLBACK_CONF_DIR = FabricLoader.getInstance().getConfigDir().resolve(ID);
public static final Path FALLBACK_CONF_DIR = FabricLoader.getInstance().getConfigDir().resolve(ID);
@Override
public void onInitialize() {
@ -50,8 +51,8 @@ public class Respackopts implements ModInitializer, SaveHook {
} catch (IOException e) {
LOGGER.error("Could not initialize config directory", e);
}
DirFilterEventImpl.init();
FileFilterEventImpl.init();
DirFilterEvents.init();
FileFilterEvents.init();
ServerInstanceHolder.init();
}

View File

@ -0,0 +1,45 @@
package io.gitlab.jfronny.respackopts.filters;
import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents;
import io.gitlab.jfronny.respackopts.Respackopts;
import net.minecraft.resource.*;
import net.minecraft.resource.metadata.ResourceMetadataReader;
import net.minecraft.util.Identifier;
import java.io.InputStream;
import java.util.function.Supplier;
public enum DebugEvents implements UserResourceEvents.FindResource, UserResourceEvents.ParseMetadata, UserResourceEvents.Open, UserResourceEvents.OpenRoot {
INSTANCE;
public static void init() {
UserResourceEvents.FIND_RESOURCE.register(INSTANCE);
UserResourceEvents.PARSE_METADATA.register(INSTANCE);
UserResourceEvents.OPEN.register(INSTANCE);
UserResourceEvents.OPEN_ROOT.register(INSTANCE);
}
@Override
public ResourcePack.ResultConsumer findResources(ResourceType type, String namespace, String prefix, ResourcePack.ResultConsumer previous, ResourcePack pack) {
Respackopts.LOGGER.info("FIND_RESOURCE " + type + " in " + namespace + " " + prefix + " of " + pack.getName());
return previous;
}
@Override
public InputSupplier<InputStream> open(ResourceType type, Identifier id, InputSupplier<InputStream> previous, ResourcePack pack) {
Respackopts.LOGGER.info("OPEN " + type + " at " + id + " of " + pack.getName());
return previous;
}
@Override
public InputSupplier<InputStream> openRoot(String[] fileName, InputSupplier<InputStream> previous, ResourcePack pack) {
Respackopts.LOGGER.info("OPEN_ROOT " + String.join("/", fileName) + " of " + pack.getName());
return previous;
}
@Override
public <T> T parseMetadata(ResourceMetadataReader<T> reader, Supplier<T> previous, ResourcePack pack) {
Respackopts.LOGGER.info("PARSE_METADATA " + reader.getKey() + " of " + pack.getName());
return previous.get();
}
}

View File

@ -1,140 +0,0 @@
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;
}
}

View File

@ -0,0 +1,124 @@
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<InputStream> open(ResourceType type, Identifier id, InputSupplier<InputStream> 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<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;
}
InputSupplier<InputStream> 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;
}
}

View File

@ -1,109 +0,0 @@
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.Respackopts;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import io.gitlab.jfronny.respackopts.model.enums.PackCapability;
import io.gitlab.jfronny.respackopts.filters.util.FileExclusionProvider;
import io.gitlab.jfronny.respackopts.filters.util.FileExpansionProvider;
import io.gitlab.jfronny.respackopts.filters.util.FileFallbackProvider;
import net.minecraft.resource.AbstractFileResourcePack;
import net.minecraft.resource.ResourcePack;
import net.minecraft.util.Identifier;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class FileFilterEventImpl {
private static final Map<Long, Boolean> containsFileWasFallback = new HashMap<>();
private static boolean containsFileWasFallback() {
boolean v = FileFilterEventImpl.containsFileWasFallback.getOrDefault(Thread.currentThread().getId(), false);
containsFileWasFallback(false);
return v;
}
private static void containsFileWasFallback(boolean value) {
FileFilterEventImpl.containsFileWasFallback.put(Thread.currentThread().getId(), value);
}
public static void init() {
UserResourceEvents.OPEN.register((type, id, previous, pack) -> {
if (skip(pack)) return previous.get();
String name = new ResourcePath(type, id).getName();
if (pack.contains(type, id)) {
return containsFileWasFallback()
? FileFallbackProvider.getReplacement(pack, name)
: FileExpansionProvider.replace(previous.get(), pack, name);
}
else return null;
});
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 (skip(pack)) return prevVals;
prevVals.removeIf(s -> {
String fileName = type.getDirectory() + "/" + s.getNamespace() + "/" + s.getPath();
return FileExclusionProvider.fileHidden(pack, fileName) && !FileFallbackProvider.fileHasFallback(pack, fileName);
});
// Completion of the path is handled separately here
FileFallbackProvider.addFallbackResources(pack, prevVals, namespace, type);
return prevVals;
});
UserResourceEvents.CONTAINS.register((type, id, previous, pack) -> {
if (skip(pack)) return previous.get();
containsFileWasFallback(false);
return containsHook(previous.get(), pack, new ResourcePath(type, id).getName());
});
UserResourceEvents.OPEN_ROOT.register((fileName, previous, pack) -> {
if (skip(pack)) return previous.get();
InputStream is = previous.get();
if (containsHook(is != null, pack, fileName)) {
return containsFileWasFallback()
? FileFallbackProvider.getReplacement(pack, fileName)
: FileExpansionProvider.replace(previous.get(), pack, fileName);
}
else return null;
});
}
private static boolean containsHook(boolean previous, ResourcePack pack, String name) {
if (previous) {
if (FileExclusionProvider.fileHidden(pack, name)) {
if (FileFallbackProvider.fileHasFallback(pack, name)) {
containsFileWasFallback(true);
} else {
return false;
}
}
return true;
}
else {
boolean hasRpo;
try {
hasRpo = UserResourceEvents.disable(() -> {
if (name.contains("/")) {
ResourcePath rp = new ResourcePath(name + Respackopts.FILE_EXTENSION);
return pack.contains(rp.getType(), rp.getId());
}
return pack.openRoot(name + Respackopts.FILE_EXTENSION) != null;
});
} catch (IOException e) {
hasRpo = false;
}
if (hasRpo && FileFallbackProvider.fileHasFallback(pack, name)) {
containsFileWasFallback(true);
return true;
}
return false;
}
}
private static boolean skip(ResourcePack pack) {
return !(pack instanceof AbstractFileResourcePack) || !MetaCache.hasCapability(pack, PackCapability.FileFilter);
}
}

View File

@ -0,0 +1,89 @@
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.Respackopts;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import io.gitlab.jfronny.respackopts.model.enums.PackCapability;
import io.gitlab.jfronny.respackopts.filters.util.FileExclusionProvider;
import io.gitlab.jfronny.respackopts.filters.util.FileExpansionProvider;
import io.gitlab.jfronny.respackopts.filters.util.FileFallbackProvider;
import net.minecraft.resource.*;
import net.minecraft.util.Identifier;
import java.io.InputStream;
import java.util.*;
public enum FileFilterEvents implements UserResourceEvents.OpenRoot, UserResourceEvents.Open, UserResourceEvents.FindResource {
INSTANCE;
public static void init() {
UserResourceEvents.OPEN_ROOT.register(INSTANCE);
UserResourceEvents.OPEN.register(INSTANCE);
UserResourceEvents.FIND_RESOURCE.register(INSTANCE);
}
@Override
public InputSupplier<InputStream> openRoot(String[] fileName, InputSupplier<InputStream> previous, ResourcePack pack) {
if (skip(pack)) return previous;
String path = String.join("/", fileName);
return switch (probe(previous != null, pack, path)) {
case MISSING -> null;
case FALLBACK -> FileFallbackProvider.getReplacement(pack, path);
case CONTAINS -> FileExpansionProvider.replace(previous, pack, path);
};
}
@Override
public InputSupplier<InputStream> open(ResourceType type, Identifier id, InputSupplier<InputStream> previous, ResourcePack pack) {
if (skip(pack)) return previous;
String name = new ResourcePath(type, id).getName();
return switch (probe(previous != null, pack, name)) {
case MISSING -> null;
case FALLBACK -> FileFallbackProvider.getReplacement(pack, name);
case CONTAINS -> FileExpansionProvider.replace(previous, pack, name);
};
}
@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 (skip(pack)) return previous;
Set<Identifier> ids = new HashSet<>();
return (identifier, value) -> {
// Completion of the path is handled separately here
String fileName = type.getDirectory() + "/" + identifier.getNamespace() + "/" + identifier.getPath();
if (!FileExclusionProvider.fileHidden(pack, fileName) || FileFallbackProvider.fileHasFallback(pack, fileName)) {
ids.add(identifier);
previous.accept(identifier, open(type, identifier, value, pack));
}
FileFallbackProvider.addFallbackResources(namespace, type, identifier, pack, ids, previous);
};
}
private ContainsResult probe(boolean previous, ResourcePack pack, String name) {
if (previous) {
if (!FileExclusionProvider.fileHidden(pack, name)) return ContainsResult.CONTAINS;
else if (FileFallbackProvider.fileHasFallback(pack, name)) return ContainsResult.FALLBACK;
else return ContainsResult.MISSING;
}
else {
boolean missing;
if (name.contains("/")) {
ResourcePath rp = new ResourcePath(name + Respackopts.FILE_EXTENSION);
missing = UserResourceEvents.disable(() -> pack.open(rp.getType(), rp.getId())) == null;
} else missing = UserResourceEvents.disable(() -> pack.openRoot(name + Respackopts.FILE_EXTENSION)) == null;
if (missing && FileFallbackProvider.fileHasFallback(pack, name)) return ContainsResult.FALLBACK;
else return ContainsResult.MISSING;
}
}
enum ContainsResult {
MISSING, CONTAINS, FALLBACK
}
private boolean skip(ResourcePack pack) {
return !(pack instanceof AbstractFileResourcePack && MetaCache.hasCapability(pack, PackCapability.FileFilter));
}
}

View File

@ -3,7 +3,9 @@ package io.gitlab.jfronny.respackopts.filters.util;
import io.gitlab.jfronny.commons.data.dynamic.Dynamic;
import io.gitlab.jfronny.muscript.compiler.expr.StringExpr;
import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.RespackoptsConfig;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.minecraft.resource.InputSupplier;
import net.minecraft.resource.ResourcePack;
import java.io.*;
@ -18,15 +20,10 @@ public class FileExpansionProvider {
return new ByteArrayInputStream(s.getBytes());
}
public static InputStream replace(InputStream inputStream, ResourcePack pack, String file) {
return FileRpoSearchProvider.modifyWithRpo(file, pack, rpo -> {
if (rpo.expansions == null || rpo.expansions.isEmpty())
return inputStream;
try {
return replace(MetaCache.getParameter(MetaCache.getKeyByPack(pack)), inputStream, rpo.expansions);
} catch (IOException e) {
Respackopts.LOGGER.error("Could not perform file expansion on " + file, e);
return inputStream;
public static InputSupplier<InputStream> replace(InputSupplier<InputStream> inputStream, ResourcePack pack, String file) {
return FileRpoSearchProvider.modifyWithRpo(file, pack, rpo -> rpo.expansions == null || rpo.expansions.isEmpty() ? inputStream : () -> {
try (InputStream is = inputStream.get()) {
return replace(MetaCache.getParameter(MetaCache.getKeyByPack(pack)), is, rpo.expansions);
}
}, inputStream);
}

View File

@ -2,12 +2,11 @@ package io.gitlab.jfronny.respackopts.filters.util;
import io.gitlab.jfronny.libjf.ResourcePath;
import io.gitlab.jfronny.respackopts.Respackopts;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import net.minecraft.resource.*;
import net.minecraft.util.Identifier;
import java.io.InputStream;
import java.util.Collection;
import java.util.Set;
public class FileFallbackProvider {
public static boolean fileHasFallback(ResourcePack pack, String file) {
@ -15,22 +14,21 @@ public class FileFallbackProvider {
if (rpo.fallbacks != null) {
for (String s : rpo.fallbacks) {
ResourcePath tmp = new ResourcePath(s);
if (pack.contains(tmp.getType(), tmp.getId()))
return true;
if (pack.open(tmp.getType(), tmp.getId()) != null) return true;
}
}
return false;
}, false);
}
public static InputStream getReplacement(ResourcePack pack, String file) {
public static InputSupplier<InputStream> getReplacement(ResourcePack pack, String file) {
return FileRpoSearchProvider.modifyWithRpo(file, pack, rpo -> {
try {
if (rpo.fallbacks != null) {
for (String s : rpo.fallbacks) {
ResourcePath tmp = new ResourcePath(s);
if (pack.contains(tmp.getType(), tmp.getId()))
return pack.open(tmp.getType(), tmp.getId());
InputSupplier<InputStream> is = pack.open(tmp.getType(), tmp.getId());
if (is != null) return is;
}
}
Respackopts.LOGGER.error("Could not determine replacement for " + file);
@ -42,15 +40,15 @@ public class FileFallbackProvider {
}, null);
}
public static void addFallbackResources(ResourcePack pack, Collection<Identifier> ret, String namespace, ResourceType type) {
public static void addFallbackResources(String namespace, ResourceType type, Identifier identifier, ResourcePack pack, Set<Identifier> ids, ResourcePack.ResultConsumer out) {
// Warning: the Identifiers here DON'T CONTAIN THE TYPE! Therefore, it needs to be added when calling a method that generates a ResourcePath!
for (Identifier identifier : ret) {
String path = identifier.getPath();
if (FileRpoSearchProvider.isRpo(path)) {
String expectedTarget = path.substring(0, path.length() - Respackopts.FILE_EXTENSION.length());
if (ret.stream().noneMatch(s -> s.getPath().equals(expectedTarget)) && fileHasFallback(pack, type.getDirectory() + "/" + expectedTarget)) {
ret.add(new Identifier(namespace, expectedTarget));
}
String path = identifier.getPath();
if (FileRpoSearchProvider.isRpo(path)) {
String expectedTarget = path.substring(0, path.length() - Respackopts.FILE_EXTENSION.length());
if (ids.stream().noneMatch(s -> s.getPath().equals(expectedTarget)) && fileHasFallback(pack, type.getDirectory() + "/" + expectedTarget)) {
Identifier id = new Identifier(namespace, expectedTarget);
ids.add(id);
out.accept(id, pack.open(type, id));
}
}
}

View File

@ -2,18 +2,14 @@ package io.gitlab.jfronny.respackopts.filters.util;
import io.gitlab.jfronny.libjf.ResourcePath;
import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.gson.*;
import io.gitlab.jfronny.respackopts.model.DirRpo;
import io.gitlab.jfronny.respackopts.gson.AttachmentHolder;
import io.gitlab.jfronny.respackopts.model.FileRpo;
import io.gitlab.jfronny.respackopts.model.cache.*;
import io.gitlab.jfronny.respackopts.model.cache.CachedPackState;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.minecraft.resource.ResourceNotFoundException;
import net.minecraft.resource.InputSupplier;
import net.minecraft.resource.ResourcePack;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.*;
import java.util.Map;
public class FileRpoSearchProvider {
@ -21,40 +17,37 @@ public class FileRpoSearchProvider {
return fileName.endsWith(Respackopts.FILE_EXTENSION);
}
public static <T> T modifyWithRpo(String fileName, ResourcePack pack, ModifiedGenerator<T> getModified, T defaultValue) {
if (FileRpoSearchProvider.isRpo(fileName))
return defaultValue;
public static <T> T modifyWithRpo(String fileName, ResourcePack pack, Action<T> action, T defaultValue) {
if (isRpo(fileName)) return defaultValue;
CachedPackState state = MetaCache.getState(MetaCache.getKeyByPack(pack));
Map<String, FileRpo> frpReg = state.cachedFileRPOs();
String rpPathName = fileName + Respackopts.FILE_EXTENSION;
if (frpReg.containsKey(rpPathName))
return getModified.getModified(frpReg.get(rpPathName));
Map<String, FileRpo> rpoCache = state.cachedFileRPOs();
String rpoPathS = fileName + Respackopts.FILE_EXTENSION;
if (rpoCache.containsKey(rpoPathS)) return action.run(rpoCache.get(rpoPathS));
ResourcePath rpoPath = null;
InputSupplier<InputStream> is;
if (fileName.contains("/")) {
try {
rpoPath = new ResourcePath(rpPathName);
if (!pack.contains(rpoPath.getType(), rpoPath.getId()))
return defaultValue;
rpoPath = new ResourcePath(rpoPathS);
is = pack.open(rpoPath.getType(), rpoPath.getId());
} catch (Throwable e) {
Respackopts.LOGGER.error("Could not check file filter status", e);
return defaultValue;
}
}
try (InputStream stream = rpoPath == null ? pack.openRoot(rpPathName) : pack.open(rpoPath.getType(), rpoPath.getId());
Reader w = stream == null ? null : new InputStreamReader(stream)) {
if (w == null) throw new FileNotFoundException("Could not find file: " + fileName);
} else is = pack.openRoot(rpoPathS);
if (is == null) return defaultValue;
try (Reader w = new InputStreamReader(is.get())) {
FileRpo frp = AttachmentHolder.deserialize(state.metadata().version, w, FileRpo.class);
frp.path = rpPathName;
frpReg.put(rpPathName, frp);
return getModified.getModified(frp);
frp.path = rpoPathS;
rpoCache.put(rpoPathS, frp);
return action.run(frp);
}
catch (Exception e) {
if (!(e instanceof ResourceNotFoundException)) Respackopts.LOGGER.error("Could not generate replacement for " + (rpoPath == null ? fileName : rpoPath.getName()) + " in " + pack.getName(), e);
Respackopts.LOGGER.error("Could not get replacement for " + (rpoPath == null ? fileName : rpoPath.getName()) + " in " + pack.getName(), e);
return defaultValue;
}
}
public interface ModifiedGenerator<T> {
T getModified(FileRpo rpo);
public interface Action<T> {
T run(FileRpo rpo);
}
}

View File

@ -1,13 +0,0 @@
package io.gitlab.jfronny.respackopts.mixin;
import net.minecraft.resource.AbstractFileResourcePack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.io.File;
@Mixin(AbstractFileResourcePack.class)
public interface AbstractFileResourcePackAccessor {
@Accessor("base")
File getBase();
}

View File

@ -0,0 +1,13 @@
package io.gitlab.jfronny.respackopts.mixin;
import net.minecraft.resource.DirectoryResourcePack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.nio.file.Path;
@Mixin(DirectoryResourcePack.class)
public interface DirectoryResourcePackAccessor {
@Accessor("root")
Path getRoot();
}

View File

@ -0,0 +1,20 @@
package io.gitlab.jfronny.respackopts.mixin;
import io.gitlab.jfronny.respackopts.Respackopts;
import net.minecraft.resource.FileResourcePackProvider;
import net.minecraft.resource.ResourcePackProfile;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.nio.file.Files;
import java.nio.file.Path;
@Mixin(FileResourcePackProvider.class)
public class FileResourcePackProviderMixin {
@Inject(method = "getFactory(Ljava/nio/file/Path;Z)Lnet/minecraft/resource/ResourcePackProfile$PackFactory;", at = @At("HEAD"), cancellable = true)
private static void getFactory(Path path, boolean alwaysStable, CallbackInfoReturnable<ResourcePackProfile.PackFactory> cir) {
if (Files.isRegularFile(path) && path.getFileName().toString().endsWith(Respackopts.FILE_EXTENSION)) cir.setReturnValue(null);
}
}

View File

@ -44,38 +44,38 @@ public class ResourcePackManagerMixin {
private void rpo$checkProfile(String profileName, String displayName, ResourcePack rpi, Set<Path> toRemove) {
Path dataLocation = null;
if (rpi instanceof AbstractFileResourcePack arr) {
File pack = arr.getBase();
if (pack != null) {
dataLocation = pack.toPath().getParent().resolve(pack.getName() + Respackopts.FILE_EXTENSION);
} else {
Respackopts.LOGGER.warn("Base path of abstract file resource pack " + arr.getName() + " is null. This shouldn't happen!");
}
if (rpi instanceof DirectoryResourcePack drp) {
Path pack = ((DirectoryResourcePackAccessor) drp).getRoot();
if (pack != null) dataLocation = pack.getParent().resolve(pack.getFileName() + Respackopts.FILE_EXTENSION);
else Respackopts.LOGGER.warn("Base path of directory resource pack " + rpi.getName() + " is null. This shouldn't happen!");
} else if (rpi instanceof ZipResourcePack zrp) {
File pack = ((ZipResourcePackAccessor) zrp).getBackingZipFile();
if (pack != null) dataLocation = pack.toPath().getParent().resolve(pack.getName() + Respackopts.FILE_EXTENSION);
else Respackopts.LOGGER.warn("Base path of zip resource pack " + rpi.getName() + " is null. This shouldn't happen!");
}
try (InputStream is = rpi.openRoot(Respackopts.ID + ".json5")) {
rpo$readConfiguration(is, dataLocation, rpi.getName(), displayName, toRemove);
return;
} catch (FileNotFoundException ignored) {
} catch (IOException e) {
String message = "Could not read respackopts config in root for " + profileName;
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.error(message, e);
else Respackopts.LOGGER.error(message);
var conf = rpi.openRoot(Respackopts.ID + ".json5");
if (conf != null) {
try (InputStream is = conf.get()) {
rpo$readConfiguration(is, dataLocation, rpi.getName(), displayName, toRemove);
return;
} catch (IOException e) {
String message = "Could not read respackopts config in root for " + profileName;
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.error(message, e);
else Respackopts.LOGGER.error(message);
}
}
Identifier confId = new Identifier(Respackopts.ID, "conf.json");
ResourceType packConfType = null;
for (ResourceType type : ResourceType.values()) {
if (rpi.contains(type, confId)) {
packConfType = type;
}
}
if (packConfType != null) {
try (InputStream is = rpi.open(packConfType, confId)) {
rpo$readConfiguration(is, dataLocation, rpi.getName(), displayName, toRemove);
} catch (Throwable e) {
Respackopts.LOGGER.error("Could not initialize pack meta for " + profileName, e);
conf = rpi.open(type, confId);
if (conf != null) {
try (InputStream is = conf.get()) {
rpo$readConfiguration(is, dataLocation, rpi.getName(), displayName, toRemove);
return;
} catch (Throwable e) {
Respackopts.LOGGER.error("Could not initialize pack meta for " + profileName, e);
}
}
}
}

View File

@ -0,0 +1,13 @@
package io.gitlab.jfronny.respackopts.mixin;
import net.minecraft.resource.ZipResourcePack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.io.File;
@Mixin(ZipResourcePack.class)
public interface ZipResourcePackAccessor {
@Accessor("backingZipFile")
File getBackingZipFile();
}

View File

@ -42,7 +42,7 @@ public class ServerInstanceHolder {
SaveProperties saveProperties = server.getSaveProperties();
List<String> enabled = Lists.newArrayList(manager.getEnabledNames());
manager.scanPacks();
List<String> disabled = saveProperties.getDataPackSettings().getDisabled();
List<String> disabled = saveProperties.getDataConfiguration().dataPacks().getDisabled();
for (String name : manager.getNames()) {
if (!disabled.contains(name) && !enabled.contains(name)) {
enabled.add(name);

View File

@ -39,10 +39,5 @@
},
"conflicts": {
"libjf": "<3.0.0"
},
"custom": {
"loom:injected_interfaces": {
"net/minecraft/class_3255": ["io/gitlab/jfronny/respackopts/mixin/AbstractFileResourcePackAccessor"]
}
}
}

View File

@ -4,8 +4,10 @@
"package": "io.gitlab.jfronny.respackopts.mixin",
"compatibilityLevel": "JAVA_8",
"mixins": [
"AbstractFileResourcePackAccessor",
"ResourcePackManagerMixin"
"DirectoryResourcePackAccessor",
"FileResourcePackProviderMixin",
"ResourcePackManagerMixin",
"ZipResourcePackAccessor"
],
"injectors": {
"defaultRequire": 1