Compare commits

...

5 Commits

34 changed files with 212 additions and 106 deletions

View File

@ -30,7 +30,7 @@ jfMod {
minecraftVersion = "1.20.6"
yarn("build.1")
loaderVersion = "0.15.10"
libJfVersion = "3.15.2"
libJfVersion = "3.15.8"
fabricApiVersion = "0.97.8+1.20.6"
modrinth {

View File

@ -15,6 +15,10 @@ You can use the dumped scope as a reference for what actually exists for your co
## Ensure you are using the correct dots
Respackopts only supports normal dots. If you write commas or colons by accident, your pack WILL fail to load.
## Ensure there are no ID conflicts
If you have multiple packs with the same ID, your conditions might not work as expected.
You will see a warning in the log if this is the case.
## Run the condition manually
You can use `/rpoc execute` to run muScript code snippets in-game with all configs applied (be aware that you will need to prefix your entries with your pack id when doing so).

View File

@ -1,8 +1,11 @@
package io.gitlab.jfronny.respackopts;
import io.gitlab.jfronny.respackopts.integration.*;
import io.gitlab.jfronny.respackopts.integration.FrexCompat;
import io.gitlab.jfronny.respackopts.integration.SaveHook;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.fabricmc.api.*;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.server.integrated.IntegratedServer;

View File

@ -6,13 +6,11 @@ import com.mojang.brigadier.arguments.StringArgumentType;
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
import io.gitlab.jfronny.commons.throwable.ThrowingSupplier;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.context.ExprUtils;
import io.gitlab.jfronny.muscript.core.LocationalException;
import io.gitlab.jfronny.muscript.data.additional.DataExprMapper;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import io.gitlab.jfronny.muscript.parser.Parser;
import io.gitlab.jfronny.muscript.runtime.Runtime;
import io.gitlab.jfronny.muscript.serialize.Decompiler;
import io.gitlab.jfronny.respackopts.muscript.ScopeVersion;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
@ -25,13 +23,18 @@ import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.nio.file.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.CompletableFuture;
import static io.gitlab.jfronny.muscript.ast.context.ExprUtils.asString;
import static io.gitlab.jfronny.muscript.serialize.Decompiler.decompile;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
public class RpoClientCommand {
private static final Version VERSION = FabricLoader.getInstance().getModContainer(Respackopts.ID).orElseThrow().getMetadata().getVersion();

View File

@ -11,7 +11,9 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Mixin(LanguageManager.class)
public class LanguageManagerMixin {

View File

@ -1,10 +1,14 @@
package io.gitlab.jfronny.respackopts.mixin;
import io.gitlab.jfronny.respackopts.*;
import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.RespackoptsClient;
import io.gitlab.jfronny.respackopts.RespackoptsConfig;
import net.minecraft.client.gui.screen.option.OptionsScreen;
import net.minecraft.client.option.GameOptions;
import net.minecraft.resource.ResourcePackManager;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

View File

@ -1,11 +1,15 @@
package io.gitlab.jfronny.respackopts.mixin;
import io.gitlab.jfronny.respackopts.Respackopts;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.nio.file.*;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.util.ArrayList;
import java.util.List;

View File

@ -11,7 +11,10 @@ import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.pack.PackListWidget;
import net.minecraft.client.gui.screen.pack.ResourcePackOrganizer;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

View File

@ -1,7 +1,10 @@
package io.gitlab.jfronny.respackopts;
import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
import io.gitlab.jfronny.respackopts.filters.*;
import io.gitlab.jfronny.respackopts.filters.DirFilterEvents;
import io.gitlab.jfronny.respackopts.filters.FileFilterEvents;
import io.gitlab.jfronny.respackopts.filters.IOLogEvents;
import io.gitlab.jfronny.respackopts.filters.ValidationLayer;
import io.gitlab.jfronny.respackopts.integration.SaveHook;
import io.gitlab.jfronny.respackopts.server.ServerInstanceHolder;
import net.fabricmc.api.EnvType;

View File

@ -13,11 +13,18 @@ import io.gitlab.jfronny.respackopts.model.cache.CachedPackState;
import io.gitlab.jfronny.respackopts.model.enums.PackCapability;
import io.gitlab.jfronny.respackopts.muscript.RespackoptsFS;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.minecraft.resource.*;
import net.minecraft.util.Identifier;
import net.minecraft.resource.InputSupplier;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import java.io.*;
import java.util.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public enum DirFilterEvents implements IEvents {
INSTANCE;
@ -64,7 +71,7 @@ public enum DirFilterEvents implements IEvents {
// New search for fallback path
String newPath = replacement.toFallback(path);
if (newPath.split("/", 3).length != 3) {
Respackopts.LOGGER.error("Directory fallback path MUST be long enough to support representation as identifier (3 segments), but is too short: " + newPath);
Respackopts.LOGGER.error("Directory fallback path MUST be long enough to support representation as identifier (3 segments), but is too short: {0}", newPath);
return;
}
if (!dirFilterAdditive) {
@ -79,16 +86,16 @@ public enum DirFilterEvents implements IEvents {
int prefixSize = replacement.original.prefix().length();
if (prefixSize < searchPrefix.length()) {
if (!searchPrefix.startsWith(replacement.original.prefix())) {
Respackopts.LOGGER.error("Unexpected prefix path " + replacement.original.prefix() + " for search prefix " + searchPrefix + ", skipping");
Respackopts.LOGGER.error("Unexpected prefix path {0} for search prefix {1}, skipping", replacement.original.prefix(), searchPrefix);
return;
}
fallbackDir += searchPrefix.substring(prefixSize);
} else if (!replacement.original.prefix().startsWith(searchPrefix)) {
Respackopts.LOGGER.error("Unexpected prefix path " + replacement.original.prefix() + " for search prefix " + searchPrefix + ", skipping");
Respackopts.LOGGER.error("Unexpected prefix path {0} for search prefix {1}, skipping", replacement.original.prefix(), searchPrefix);
return;
}
if (fallbackDir.split("/", 3).length != 3) {
Respackopts.LOGGER.error("Directory fallback path MUST be long enough to support representation as identifier (3 segments), but is too short: " + fallbackDir);
Respackopts.LOGGER.error("Directory fallback path MUST be long enough to support representation as identifier (3 segments), but is too short: {0}", fallbackDir);
return;
}
ResourcePath rp = new ResourcePath(fallbackDir);
@ -142,7 +149,7 @@ public enum DirFilterEvents implements IEvents {
currentRPOs.add(newRPO);
return currentRPOs;
} catch (IOException e) {
Respackopts.LOGGER.error("Couldn't open dir rpo " + rp, e);
Respackopts.LOGGER.error("Couldn't open dir rpo {0}", rp, e);
}
return parentRPOs;
});

View File

@ -2,12 +2,16 @@ package io.gitlab.jfronny.respackopts.filters;
import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents;
import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.filters.util.*;
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 io.gitlab.jfronny.respackopts.model.cache.CacheKey;
import io.gitlab.jfronny.respackopts.model.enums.PackCapability;
import io.gitlab.jfronny.respackopts.muscript.RespackoptsFS;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.minecraft.resource.*;
import net.minecraft.resource.InputSupplier;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;
import java.io.InputStream;

View File

@ -2,7 +2,9 @@ package io.gitlab.jfronny.respackopts.filters;
import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents;
import net.minecraft.resource.*;
import net.minecraft.resource.InputSupplier;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import net.minecraft.resource.metadata.ResourceMetadataReader;
import net.minecraft.util.Identifier;

View File

@ -73,7 +73,7 @@ public sealed interface DirRpoResult {
return m.replaceAll(this.fallback.quoted);
}
if (!m.find()) {
Respackopts.LOGGER.error("Attempted conversion to fallback path, but could not find original prefix for: " + original);
Respackopts.LOGGER.error("Attempted conversion to fallback path, but could not find original prefix for: {0}", original);
return original;
}
return m.replaceFirst(this.fallback.quoted);
@ -85,7 +85,7 @@ public sealed interface DirRpoResult {
return m.replaceAll(this.original.quoted);
}
if (!m.find()) {
Respackopts.LOGGER.error("Attempted conversion to original path, but could not find fallback prefix for: " + fallback);
Respackopts.LOGGER.error("Attempted conversion to original path, but could not find fallback prefix for: {0}", fallback);
return fallback;
}
return m.replaceFirst(this.original.quoted);

View File

@ -2,7 +2,10 @@ package io.gitlab.jfronny.respackopts.filters.util;
import io.gitlab.jfronny.respackopts.Respackopts;
import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class FileDependencyTracker {
private final String pack;
@ -16,7 +19,7 @@ public class FileDependencyTracker {
public void addDependency(String to, String on) {
if (to.equals(on)) {
if (reportedRecursions.add(to)) Respackopts.LOGGER.warn("Discovered recursive dependency in " + pack + "! If you get a StackOverflowException, please validate your fallbacks for " + to);
if (reportedRecursions.add(to)) Respackopts.LOGGER.warn("Discovered recursive dependency in {0}! If you get a StackOverflowException, please validate your fallbacks for {1}", pack, to);
return;
}
gs(dependencies, to).add(on);

View File

@ -3,14 +3,15 @@ package io.gitlab.jfronny.respackopts.filters.util;
import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.data.additional.context.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.DObject;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import io.gitlab.jfronny.muscript.runtime.Runtime;
import io.gitlab.jfronny.respackopts.model.cache.CacheKey;
import io.gitlab.jfronny.respackopts.muscript.RespackoptsFS;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.minecraft.resource.InputSupplier;
import java.io.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
public class FileExpansionProvider {

View File

@ -4,7 +4,9 @@ import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.model.cache.CacheKey;
import io.gitlab.jfronny.respackopts.muscript.RespackoptsFS;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.minecraft.resource.*;
import net.minecraft.resource.InputSupplier;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;
import java.io.InputStream;
@ -33,7 +35,7 @@ public class FileFallbackProvider {
if (is != null) return is;
}
}
Respackopts.LOGGER.error("Could not determine replacement for " + file);
Respackopts.LOGGER.error("Could not determine replacement for {0}", file);
}
catch (Exception e) {
Respackopts.LOGGER.error("Could not determine replacement for " + file, e);

View File

@ -11,7 +11,9 @@ import io.gitlab.jfronny.respackopts.muscript.RespackoptsFS;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.minecraft.resource.InputSupplier;
import java.io.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Map;
public class FileRpoSearchProvider {

View File

@ -5,14 +5,23 @@ import io.gitlab.jfronny.commons.serialize.SerializeReader;
import io.gitlab.jfronny.commons.serialize.SerializeWriter;
import io.gitlab.jfronny.commons.serialize.databind.api.SerializerFor;
import io.gitlab.jfronny.commons.serialize.databind.api.TypeAdapter;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.bool.And;
import io.gitlab.jfronny.muscript.ast.bool.Not;
import io.gitlab.jfronny.muscript.ast.bool.Or;
import io.gitlab.jfronny.muscript.ast.context.ExprUtils;
import io.gitlab.jfronny.muscript.parser.lexer.Token;
import io.gitlab.jfronny.muscript.ast.*;
import io.gitlab.jfronny.muscript.ast.bool.*;
import io.gitlab.jfronny.muscript.ast.dynamic.*;
import io.gitlab.jfronny.muscript.ast.dynamic.Call;
import io.gitlab.jfronny.muscript.ast.dynamic.Equals;
import io.gitlab.jfronny.muscript.ast.dynamic.Get;
import io.gitlab.jfronny.muscript.ast.dynamic.Variable;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.parser.lexer.Token;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@SerializerFor(targets = BoolExpr.class)
public class BoolExprDeserializer extends TypeAdapter<BoolExpr> {

View File

@ -6,7 +6,9 @@ import io.gitlab.jfronny.commons.serialize.SerializeWriter;
import io.gitlab.jfronny.commons.serialize.Token;
import io.gitlab.jfronny.commons.serialize.databind.api.SerializerFor;
import io.gitlab.jfronny.commons.serialize.databind.api.TypeAdapter;
import io.gitlab.jfronny.respackopts.model.tree.*;
import io.gitlab.jfronny.respackopts.model.tree.ConfigBranch;
import io.gitlab.jfronny.respackopts.model.tree.ConfigEntry;
import io.gitlab.jfronny.respackopts.model.tree.GC_ConfigEntry;
import java.util.Map;

View File

@ -7,7 +7,9 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
@Mixin(FileResourcePackProvider.class)
public class FileResourcePackProviderMixin {

View File

@ -3,69 +3,67 @@ package io.gitlab.jfronny.respackopts.mixin;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.RespackoptsConfig;
import io.gitlab.jfronny.respackopts.integration.SaveHook;
import io.gitlab.jfronny.respackopts.model.DiscoveredPack;
import io.gitlab.jfronny.respackopts.model.GC_PackMeta;
import io.gitlab.jfronny.respackopts.model.PackMeta;
import io.gitlab.jfronny.respackopts.model.cache.CacheKey;
import io.gitlab.jfronny.respackopts.util.FallbackI18n;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.minecraft.resource.*;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.*;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.io.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Mixin(ResourcePackManager.class)
public class ResourcePackManagerMixin {
@Shadow private Map<String, ResourcePackProfile> profiles;
@Unique private final Set<Path> dataLocations = new HashSet<>();
@Inject(at = @At("TAIL"), method = "scanPacks()V")
private void scanPacks(CallbackInfo info) {
RespackoptsConfig.scanState = RespackoptsConfig.ScanState.SCANNING;
FallbackI18n.clear();
Set<Path> newDataLocations = new HashSet<>();
Set<Path> toRemove = new HashSet<>(dataLocations);
List<DiscoveredPack> discoveredPacks = new ArrayList<>();
profiles.forEach((s, v) -> {
try (ResourcePack rpi = v.createResourcePack()) {
String id = rpo$checkProfile(s, v.getDisplayName().getString(), rpi, newDataLocations, toRemove);
if (id != null) FallbackI18n.loadFrom(rpi, id);
DiscoveredPack dp = rpo$checkProfile(s, v.getDisplayName().getString(), rpi);
if (dp != null) discoveredPacks.add(dp);
}
});
dataLocations.clear();
dataLocations.addAll(newDataLocations);
for (Path s : toRemove) {
CacheKey k = MetaCache.getKeyByDataLocation(s);
if (k != null) MetaCache.remove(k);
}
MetaCache.save(SaveHook.Arguments.DO_NOTHING);
MetaCache.addFromScan(discoveredPacks);
RespackoptsConfig.scanState = RespackoptsConfig.ScanState.DONE;
}
@Unique
private static String rpo$checkProfile(String profileName, String displayName, ResourcePack rpi, Set<Path> dataLocations, Set<Path> toRemove) {
private static @Nullable DiscoveredPack rpo$checkProfile(String profileName, String displayName, ResourcePack rpi) {
Path dataLocation = null;
if (rpi instanceof DirectoryResourcePack drp) {
Path pack = ((DirectoryResourcePackAccessor) drp).getRoot();
Path parent = pack == null ? null : pack.getParent();
if (parent != null) dataLocation = parent.resolve(pack.getFileName() + Respackopts.FILE_EXTENSION);
else Respackopts.LOGGER.warn("Base path of directory resource pack " + rpi.getId() + " is null. This shouldn't happen!");
else Respackopts.LOGGER.warn("Base path of directory resource pack {0} is null. This shouldn't happen!", rpi.getId());
} else if (rpi instanceof ZipResourcePack zrp) {
File pack = ((ZipFileWrapperAccessor) ((ZipResourcePackAccessor) zrp).getZipFile()).getFile();
Path parent = pack == null ? null : pack.toPath().getParent();
if (parent != null) dataLocation = parent.resolve(pack.getName() + Respackopts.FILE_EXTENSION);
else Respackopts.LOGGER.warn("Base path of zip resource pack " + rpi.getId() + " is null. This shouldn't happen!");
else Respackopts.LOGGER.warn("Base path of zip resource pack {0} is null. This shouldn't happen!", rpi.getId());
}
var conf = rpi.openRoot(Respackopts.ID + ".json5");
if (conf != null) {
try (InputStream is = conf.get()) {
return rpo$readConfiguration(is, dataLocation, rpi.getId(), displayName, dataLocations, toRemove);
return rpo$readConfiguration(rpi, is, dataLocation, rpi.getId(), displayName);
} catch (Throwable e) {
String message = "Could not read respackopts config in root for " + profileName;
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.error(message, e);
@ -78,7 +76,7 @@ public class ResourcePackManagerMixin {
conf = rpi.open(type, confId);
if (conf != null) {
try (InputStream is = conf.get()) {
return rpo$readConfiguration(is, dataLocation, rpi.getId(), displayName, dataLocations, toRemove);
return rpo$readConfiguration(rpi, is, dataLocation, rpi.getId(), displayName);
} catch (Throwable e) {
Respackopts.LOGGER.error("Could not initialize pack meta for " + profileName, e);
}
@ -89,25 +87,22 @@ public class ResourcePackManagerMixin {
}
@Unique
private static String rpo$readConfiguration(InputStream is, Path dataLocation, String packName, String displayName, Set<Path> dataLocations, Set<Path> toRemove) throws IOException {
private static @Nullable DiscoveredPack rpo$readConfiguration(ResourcePack pack, InputStream is, Path dataLocation, String packName, String displayName) throws IOException {
try (InputStreamReader isr = new InputStreamReader(is)) {
PackMeta conf = GC_PackMeta.deserialize(isr, LibJf.LENIENT_TRANSPORT);
if (!Respackopts.isLegal(conf.id)) {
if (conf.version >= 10) {
Respackopts.LOGGER.error(displayName + " was not loaded as it uses an unsupported pack id: " + conf.id);
Respackopts.LOGGER.error("{0} was not loaded as it uses an unsupported pack id: {1}", displayName, conf.id);
return null;
} else conf.id = Respackopts.sanitizeString(conf.id);
}
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("Discovered pack: " + conf.id);
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("Discovered pack: {0}", conf.id);
if (Respackopts.META_VERSION < conf.version) {
Respackopts.LOGGER.error(displayName + " was not loaded as it specifies a newer respackopts version than is installed");
Respackopts.LOGGER.error("{0} was not loaded as it specifies a newer respackopts version than is installed", displayName);
return null;
}
if (dataLocation == null) dataLocation = Respackopts.FALLBACK_CONF_DIR.resolve(conf.id + ".json");
MetaCache.addFromScan(displayName, packName, conf, dataLocation);
dataLocations.add(dataLocation);
toRemove.remove(dataLocation);
return conf.id;
return new DiscoveredPack(displayName, packName, conf, dataLocation, FallbackI18n.loadFrom(pack, conf.id));
}
}
}

View File

@ -1,8 +1,8 @@
package io.gitlab.jfronny.respackopts.model;
import io.gitlab.jfronny.commons.serialize.generator.annotations.GSerializable;
import io.gitlab.jfronny.commons.serialize.annotations.Ignore;
import io.gitlab.jfronny.commons.serialize.annotations.SerializedName;
import io.gitlab.jfronny.commons.serialize.generator.annotations.GSerializable;
@GSerializable
public class DirRpo {

View File

@ -0,0 +1,7 @@
package io.gitlab.jfronny.respackopts.model;
import java.nio.file.Path;
import java.util.Map;
public record DiscoveredPack(String displayName, String packName, PackMeta meta, Path dataLocation, Map<String, String> translations) {
}

View File

@ -1,8 +1,8 @@
package io.gitlab.jfronny.respackopts.model;
import io.gitlab.jfronny.commons.serialize.generator.annotations.GSerializable;
import io.gitlab.jfronny.commons.serialize.annotations.Ignore;
import io.gitlab.jfronny.commons.serialize.annotations.SerializedName;
import io.gitlab.jfronny.commons.serialize.generator.annotations.GSerializable;
import io.gitlab.jfronny.muscript.ast.StringExpr;
import java.util.Map;

View File

@ -1,8 +1,6 @@
package io.gitlab.jfronny.respackopts.model;
import io.gitlab.jfronny.commons.serialize.databind.api.SerializeWithAdapter;
import io.gitlab.jfronny.commons.serialize.generator.annotations.GSerializable;
import io.gitlab.jfronny.respackopts.gson.entry.ConfigBranchSerializer;
import io.gitlab.jfronny.respackopts.model.enums.PackCapability;
import io.gitlab.jfronny.respackopts.model.tree.ConfigBranch;

View File

@ -4,12 +4,17 @@ import io.gitlab.jfronny.muscript.ast.context.Script;
import io.gitlab.jfronny.muscript.data.additional.context.Scope;
import io.gitlab.jfronny.respackopts.RespackoptsConfig;
import io.gitlab.jfronny.respackopts.filters.util.FileDependencyTracker;
import io.gitlab.jfronny.respackopts.model.*;
import io.gitlab.jfronny.respackopts.model.DirRpo;
import io.gitlab.jfronny.respackopts.model.FileRpo;
import io.gitlab.jfronny.respackopts.model.PackMeta;
import io.gitlab.jfronny.respackopts.model.tree.ConfigBranch;
import io.gitlab.jfronny.respackopts.muscript.MuScriptScope;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public record CachedPackState(
String packId,
@ -39,4 +44,18 @@ public record CachedPackState(
RespackoptsConfig.debugLogs ? new FileDependencyTracker(key.displayName()) : null
);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CachedPackState that)) return false;
return Objects.equals(packId, that.packId)
&& Objects.equals(displayName, that.displayName)
&& Objects.equals(packName, that.packName);
}
@Override
public int hashCode() {
return Objects.hash(packId, displayName, packName);
}
}

View File

@ -6,7 +6,6 @@ import io.gitlab.jfronny.muscript.data.dynamic.DBool;
import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.RespackoptsConfig;
import io.gitlab.jfronny.respackopts.gson.entry.BooleanEntrySerializer;
import io.gitlab.jfronny.respackopts.gson.entry.ConfigBranchSerializer;
import java.util.Objects;

View File

@ -33,7 +33,7 @@ public class ConfigBranch extends ConfigEntry<Map<String, ConfigEntry<?>>> imple
for (Iterator<String> iterator = getValue().keySet().iterator(); iterator.hasNext(); ) {
String s = iterator.next();
if (!Respackopts.isLegal(s)) {
Respackopts.LOGGER.error("Illegal entry for " + getName() + ", skipping: " + s);
Respackopts.LOGGER.error("Illegal entry for {0}, skipping: {1}", getName(), s);
iterator.remove();
}
}
@ -60,10 +60,10 @@ public class ConfigBranch extends ConfigEntry<Map<String, ConfigEntry<?>>> imple
}
else {
if (mode == ConfigSyncMode.RESPACK_LOAD) {
Respackopts.LOGGER.warn("Type mismatch in config (" + getName() + "), overwriting");
Respackopts.LOGGER.warn("Type mismatch in config ({0}), overwriting", getName());
add(e.getKey(), e.getValue().clone());
} else
Respackopts.LOGGER.warn("Type mismatch in config (" + getName() + "), ignoring");
Respackopts.LOGGER.warn("Type mismatch in config ({0}}), ignoring", getName());
}
}
}
@ -82,7 +82,7 @@ public class ConfigBranch extends ConfigEntry<Map<String, ConfigEntry<?>>> imple
public <T> void add(String name, ConfigEntry<T> val) {
if (version >= 10 && !Respackopts.isLegal(name)) {
Respackopts.LOGGER.error("Illegal entry for " + getName() + ", skipping: " + name);
Respackopts.LOGGER.error("Illegal entry for {0}, skipping: {1}", getName(), name);
return;
}
val.setVersion(version);
@ -125,7 +125,7 @@ public class ConfigBranch extends ConfigEntry<Map<String, ConfigEntry<?>>> imple
super.getValue().forEach((key, value) -> {
if (Respackopts.isLegal(key)) map.put(key, value);
else if (version >= 10) {
Respackopts.LOGGER.error("Illegal key in " + getName() + ", skipping: " + key);
Respackopts.LOGGER.error("Illegal key in {0}, skipping: {1}", getName(), key);
} else map.put(Respackopts.sanitizeString(key), value);
});
return DFinal.of(map);
@ -161,7 +161,7 @@ public class ConfigBranch extends ConfigEntry<Map<String, ConfigEntry<?>>> imple
);
});
builder.executeAfterWrite(cfg -> {
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("GuiFactory SavingRunnable " + agg.get());
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("GuiFactory SavingRunnable {0}", agg.get());
MetaCache.save(new SaveHook.Arguments(agg.get() == PackReloadType.Resource, false, true));
});
builder.setPath(dataLocation);

View File

@ -43,7 +43,7 @@ public abstract class ConfigEntry<T> implements DynamicBase {
public T getValue() {
if (value == null) {
if (defaultValue == null) {
Respackopts.LOGGER.warn("No default value or current value set for entry, returning null in " + getName());
Respackopts.LOGGER.warn("No default value or current value set for entry, returning null in {0}", getName());
return null;
}
value = getDefault();
@ -60,7 +60,7 @@ public abstract class ConfigEntry<T> implements DynamicBase {
public T getDefault() {
if (defaultValue == null) {
defaultValue = getValue();
Respackopts.LOGGER.warn("No default value set for entry, using current in " + getName());
Respackopts.LOGGER.warn("No default value set for entry, using current in {0}", getName());
}
return defaultValue;
}

View File

@ -7,12 +7,14 @@ import io.gitlab.jfronny.muscript.data.additional.DelegateDynamic;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.RespackoptsConfig;
import io.gitlab.jfronny.respackopts.gson.entry.ConfigBranchSerializer;
import io.gitlab.jfronny.respackopts.gson.entry.EnumEntrySerializer;
import io.gitlab.jfronny.respackopts.model.enums.ConfigSyncMode;
import io.gitlab.jfronny.respackopts.util.IndentingStringBuilder;
import java.util.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@SerializeWithAdapter(adapter = EnumEntrySerializer.class)
public class ConfigEnumEntry extends ConfigEntry<String> implements DelegateDynamic {
@ -73,7 +75,7 @@ public class ConfigEnumEntry extends ConfigEntry<String> implements DelegateDyna
for (Iterator<String> iterator = values.iterator(); iterator.hasNext();) {
String value = iterator.next();
if (!Respackopts.isLegal(value)) {
Respackopts.LOGGER.error("Illegal enum entry for " + getName() + ", skipping: " + value);
Respackopts.LOGGER.error("Illegal enum entry for {0}, skipping: {1}", getName(), value);
iterator.remove();
}
}
@ -93,7 +95,7 @@ public class ConfigEnumEntry extends ConfigEntry<String> implements DelegateDyna
setValue(values.get(n.nextValue));
}
else {
Respackopts.LOGGER.error("Could not load default value for enum in " + getName());
Respackopts.LOGGER.error("Could not load default value for enum in {0}", getName());
}
} else nextValue = null;
}

View File

@ -5,7 +5,6 @@ import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder;
import io.gitlab.jfronny.muscript.data.dynamic.DNumber;
import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.RespackoptsConfig;
import io.gitlab.jfronny.respackopts.gson.entry.ConfigBranchSerializer;
import io.gitlab.jfronny.respackopts.gson.entry.NumericEntrySerializer;
import io.gitlab.jfronny.respackopts.model.enums.ConfigSyncMode;
import io.gitlab.jfronny.respackopts.util.IndentingStringBuilder;

View File

@ -3,7 +3,9 @@ package io.gitlab.jfronny.respackopts.muscript;
import io.gitlab.jfronny.libjf.ResourcePath;
import io.gitlab.jfronny.muscript.core.SourceFS;
import io.gitlab.jfronny.respackopts.Respackopts;
import net.minecraft.resource.*;
import net.minecraft.resource.InputSupplier;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;

View File

@ -16,7 +16,8 @@ public class FallbackI18n {
translations.clear();
}
public static void loadFrom(ResourcePack pack, String packId) {
public static Map<String, String> loadFrom(ResourcePack pack, String packId) {
Map<String, String> translations = new HashMap<>();
for (String namespace : pack.getNamespaces(ResourceType.CLIENT_RESOURCES)) {
var translation = pack.open(ResourceType.CLIENT_RESOURCES, new Identifier(namespace, "lang/en_us.json"));
if (translation == null) continue;
@ -29,6 +30,11 @@ public class FallbackI18n {
} catch (Throwable ignored) {
}
}
return translations;
}
public static void add(Map<String, String> translations) {
FallbackI18n.translations.putAll(translations);
}
public static void insertInto(Map<String, String> target) {

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.RespackoptsConfig;
import io.gitlab.jfronny.respackopts.filters.util.FileDependencyTracker;
import io.gitlab.jfronny.respackopts.integration.SaveHook;
import io.gitlab.jfronny.respackopts.model.DiscoveredPack;
import io.gitlab.jfronny.respackopts.model.PackMeta;
import io.gitlab.jfronny.respackopts.model.cache.CacheKey;
import io.gitlab.jfronny.respackopts.model.cache.CachedPackState;
@ -22,7 +23,9 @@ import net.minecraft.resource.ResourcePack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@ -54,9 +57,24 @@ public class MetaCache {
}
}
public static void addFromScan(String displayName, String packName, PackMeta meta, Path dataLocation) {
public static void addFromScan(List<DiscoveredPack> discoveredPacks) {
FallbackI18n.clear();
Set<CacheKey> newKeys = new HashSet<>();
Set<String> ids = new HashSet<>();
for (DiscoveredPack pack : discoveredPacks) {
newKeys.add(addFromScan(pack.displayName(), pack.packName(), pack.meta(), pack.dataLocation()));
FallbackI18n.add(pack.translations());
if (!ids.add(pack.meta().id) && RespackoptsConfig.debugLogs) {
Respackopts.LOGGER.warn("Duplicate pack id: {0}", pack.meta().id);
}
}
PACK_STATES.keySet().stream().filter(s -> !newKeys.contains(s)).toList().forEach(MetaCache::remove);
save(SaveHook.Arguments.DO_NOTHING);
}
public static CacheKey addFromScan(String displayName, String packName, PackMeta meta, Path dataLocation) {
if (Respackopts.META_VERSION > meta.version) {
Respackopts.LOGGER.warn(displayName + " uses an outdated RPO format (" + meta.version + "). Although this is supported, using the latest version (" + Respackopts.META_VERSION + ") is recommended");
Respackopts.LOGGER.warn("{0} uses an outdated RPO format ({1}). Although this is supported, using the latest version ({2}) is recommended", displayName, meta.version, Respackopts.META_VERSION);
}
meta.conf.setVersion(meta.version);
if (meta.version < 5) meta.capabilities.add(PackCapability.DirFilter);
@ -91,6 +109,7 @@ public class MetaCache {
}
load(key);
save(dataLocation, meta.conf);
return key;
}
public static CompletableFuture<Void> save(SaveHook.Arguments args) {
@ -124,7 +143,7 @@ public class MetaCache {
public static void load(CacheKey key) {
if (Files.exists(key.dataLocation())) {
if (RespackoptsConfig.debugLogs)
Respackopts.LOGGER.info("Loading configs for: " + key.displayName());
Respackopts.LOGGER.info("Loading configs for: {0}", key.displayName());
try (Reader reader = Files.newBufferedReader(key.dataLocation())) {
ConfigBranch b = GC_ConfigBranch.deserialize(reader, LibJf.LENIENT_TRANSPORT);
if (PACK_STATES.containsKey(key))
@ -165,20 +184,20 @@ public class MetaCache {
public static Scope getScope(int version) {
Scope scope = MuScriptScope.fork(version);
return populate(scope);
return populate(scope, null);
}
public static Scope getScope(@NotNull CacheKey key, RespackoptsFS fs) {
CachedPackState state = MetaCache.getState(key);
Scope scope = state.executionScope().fork();
return populate(MuScriptScope.configureFS(scope, state, fs));
return populate(MuScriptScope.configureFS(scope, state, fs), state);
}
private static Scope populate(Scope scope) {
private static Scope populate(Scope scope, @Nullable CachedPackState pack) {
forEach((id, state) -> {
if (!scope.has(state.packId())) {
scope.set(state.packId(), state.configBranch());
}
if (scope.has(state.packId())) return;
if (pack != null && pack.packId().equals(state.packId()) && !pack.equals(state)) return;
scope.set(state.packId(), state.configBranch());
});
return scope;
}