diff --git a/build.gradle.kts b/build.gradle.kts index 0e20fe0..3b13183 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("jfmod") version "1.5-SNAPSHOT" + id("jfmod") version "1.6-SNAPSHOT" } allprojects { group = "io.gitlab.jfronny" } @@ -25,14 +25,14 @@ repositories { } } -val fabricVersion = "0.91.1+1.20.4" -val muscriptVersion = "1.5-SNAPSHOT" -val modmenuVersion = "9.0.0-pre.1" +val muscriptVersion = "1.7-SNAPSHOT" +val modmenuVersion = "10.0.0-beta.1" jfMod { - minecraftVersion = "1.20.4" + minecraftVersion = "1.20.5" yarn("build.1") - loaderVersion = "0.15.0" - libJfVersion = "3.14.1" + loaderVersion = "0.15.10" + libJfVersion = "3.15.1" + fabricApiVersion = "0.97.5+1.20.5" modrinth { projectId = "respackopts" @@ -47,17 +47,20 @@ jfMod { } dependencies { - modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricVersion") - include(modImplementation("io.gitlab.jfronny:muscript:$muscriptVersion")!!) - include(modImplementation("io.gitlab.jfronny:muscript-gson:$muscriptVersion")!!) - modImplementation("io.gitlab.jfronny.libjf:libjf-data-manipulation-v0:${jfMod.libJfVersion.get()}") - modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v2:${jfMod.libJfVersion.get()}") - modImplementation("io.gitlab.jfronny.libjf:libjf-config-ui-tiny:${jfMod.libJfVersion.get()}") + modImplementation("net.fabricmc.fabric-api:fabric-api") + include(modImplementation("io.gitlab.jfronny:muscript-all:$muscriptVersion")!!) + modImplementation("io.gitlab.jfronny:muscript-json:$muscriptVersion") { + isTransitive = false + } + include("io.gitlab.jfronny:muscript-json:$muscriptVersion") + modImplementation("io.gitlab.jfronny.libjf:libjf-data-manipulation-v0") + modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v2") + modImplementation("io.gitlab.jfronny.libjf:libjf-config-ui-tiny") val nofabric: Action = Action { exclude("net.fabricmc") // required to work around duplicate fabric loaders } - modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil:${jfMod.libJfVersion.get()}", nofabric) + modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil", nofabric) modLocalRuntime("com.terraformersmc:modmenu:$modmenuVersion", nofabric) // Temporarily disabled since modmenu doesn't support snapshots modClientCompileOnly("com.terraformersmc:modmenu:$modmenuVersion", nofabric) @@ -66,6 +69,9 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter:5.9.3") + compileOnly("io.gitlab.jfronny:commons-serialize-generator-annotations:$muscriptVersion") + annotationProcessor("io.gitlab.jfronny:commons-serialize-generator:$muscriptVersion") + // Canvas for FREX testing // modClientRuntimeOnly("io.vram:canvas-fabric:20.0.+") diff --git a/settings.gradle.kts b/settings.gradle.kts index 5b75c0e..84f1b06 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,6 +2,8 @@ pluginManagement { repositories { maven("https://maven.fabricmc.net/") // FabricMC maven("https://maven.frohnmeyer-wds.de/artifacts") // scripts + maven("https://maven.architectury.dev/") // Architectury + maven("https://files.minecraftforge.net/maven/") // Forge gradlePluginPortal() } } diff --git a/src/client/java/io/gitlab/jfronny/respackopts/RespackoptsClient.java b/src/client/java/io/gitlab/jfronny/respackopts/RespackoptsClient.java index 2d77d80..82793df 100644 --- a/src/client/java/io/gitlab/jfronny/respackopts/RespackoptsClient.java +++ b/src/client/java/io/gitlab/jfronny/respackopts/RespackoptsClient.java @@ -75,7 +75,7 @@ public class RespackoptsClient implements ClientModInitializer, SaveHook { IntegratedServer is = MinecraftClient.getInstance().getServer(); if (is != null) { is.getDataPackManager().scanPacks(); - return is.reloadResources(is.getDataPackManager().getEnabledNames()); + return is.reloadResources(is.getDataPackManager().getEnabledIds()); } return CompletableFuture.completedFuture(null); } diff --git a/src/client/java/io/gitlab/jfronny/respackopts/RpoClientCommand.java b/src/client/java/io/gitlab/jfronny/respackopts/RpoClientCommand.java index b7de978..72c8359 100644 --- a/src/client/java/io/gitlab/jfronny/respackopts/RpoClientCommand.java +++ b/src/client/java/io/gitlab/jfronny/respackopts/RpoClientCommand.java @@ -5,8 +5,14 @@ import com.mojang.brigadier.arguments.IntegerArgumentType; 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.compiler.Parser; -import io.gitlab.jfronny.muscript.error.LocationalException; +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; @@ -23,6 +29,8 @@ import java.io.*; import java.nio.file.*; 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.*; public class RpoClientCommand { @@ -42,13 +50,13 @@ public class RpoClientCommand { return 1; }; Command dumpScope = ctx -> { - ctx.getSource().sendFeedback(dump(MetaCache.getScope(Respackopts.META_VERSION).toExpr().toString(), "_root.mu")); - MetaCache.forEach((id, branch) -> ctx.getSource().sendFeedback(dump(branch.executionScope().getOverrides().toExpr().toString(), branch.packId() + ".mu"))); + ctx.getSource().sendFeedback(dump(MetaCache.getScope(Respackopts.META_VERSION), "_root.mu")); + MetaCache.forEach((id, branch) -> ctx.getSource().sendFeedback(dump(branch.executionScope().getOverrides(), branch.packId() + ".mu"))); return 1; }; Command dumpScopeVersioned = ctx -> { - ctx.getSource().sendFeedback(dump(MetaCache.getScope(IntegerArgumentType.getInteger(ctx, "version")).toExpr().toString(), "_root.mu")); - MetaCache.forEach((id, branch) -> ctx.getSource().sendFeedback(dump(branch.executionScope().getOverrides().toExpr().toString(), branch.packId() + ".mu"))); + ctx.getSource().sendFeedback(dump(MetaCache.getScope(IntegerArgumentType.getInteger(ctx, "version")), "_root.mu")); + MetaCache.forEach((id, branch) -> ctx.getSource().sendFeedback(dump(branch.executionScope().getOverrides(), branch.packId() + ".mu"))); return 1; }; Command dumpAsset = ctx -> { @@ -60,7 +68,7 @@ public class RpoClientCommand { String snippet = StringArgumentType.getString(ctx, "snippet"); try { int ver = IntegerArgumentType.getInteger(ctx, "version"); - String result = Parser.parse(ScopeVersion.by(ver).muScriptVersion, snippet, "snippet").asStringExpr().get(MetaCache.getScope(ver)); + String result = Runtime.evaluate(asString(Parser.parse(ScopeVersion.by(ver).muScriptVersion, snippet, "snippet")), MetaCache.getScope(ver)); ctx.getSource().sendFeedback(Text.translatable("respackopts.snippet.success", result)); } catch (LocationalException | Parser.ParseException e) { Respackopts.LOGGER.error("Could not execute snippet", e); @@ -92,6 +100,13 @@ public class RpoClientCommand { }); } + private static Text dump(Dynamic dynamic, String fileName) { + return dump(DataExprMapper.map(dynamic), fileName); + } + private static Text dump(Expr expr, String fileName) { + return dump(decompile(expr), fileName); + } + private static final Path dumpPath = FabricLoader.getInstance().getGameDir().resolve("respackopts").toAbsolutePath(); private static Text dump(String text, String fileName) { return dump(path -> Files.writeString(path, text, StandardOpenOption.CREATE), fileName); diff --git a/src/client/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java b/src/client/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java index 531fc9e..2b3d30e 100644 --- a/src/client/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java +++ b/src/client/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java @@ -20,11 +20,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(PackListWidget.ResourcePackEntry.class) public abstract class ResourcePackEntryMixin { @Final @Shadow private PackListWidget widget; - @Shadow protected abstract boolean isSelectable(); - @Shadow @Final private ResourcePackOrganizer.Pack pack; - boolean rpo$selected; + @Unique boolean rpo$selected; @Inject(at = @At("TAIL"), method = "render(Lnet/minecraft/client/gui/DrawContext;IIIIIIIZF)V") private void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta, CallbackInfo info) { @@ -37,23 +35,23 @@ public abstract class ResourcePackEntryMixin { } } - @Inject(at = @At("RETURN"), method = "mouseClicked(DDI)Z", cancellable = true) + @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/AlwaysSelectedEntryListWidget$Entry;mouseClicked(DDI)Z"), method = "mouseClicked(DDI)Z", cancellable = true) public void mouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable info) { - if (!info.getReturnValue()) { - if (this.isSelectable()) { - CacheKey dataLocation = MetaCache.getKeyByDisplayName(pack.getDisplayName().getString()); - if (dataLocation != null && rpo$selected) { - info.setReturnValue(true); - MinecraftClient c = MinecraftClient.getInstance(); - String id = MetaCache.getId(dataLocation); - ConfigInstance ci = DSL.create(id).config(builder -> MetaCache.getBranch(dataLocation).buildConfig(builder, id, dataLocation.dataLocation())); - ConfigScreenFactory.Built screen = ConfigScreenFactory.getInstance().create(ci, c.currentScreen); - c.setScreen(screen.get()); - } + // Inject before super call + if (this.isSelectable()) { + CacheKey dataLocation = MetaCache.getKeyByDisplayName(pack.getDisplayName().getString()); + if (dataLocation != null && rpo$selected) { + info.setReturnValue(true); + MinecraftClient c = MinecraftClient.getInstance(); + String id = MetaCache.getId(dataLocation); + ConfigInstance ci = DSL.create(id).config(builder -> MetaCache.getBranch(dataLocation).buildConfig(builder, id, dataLocation.dataLocation())); + ConfigScreenFactory.Built screen = ConfigScreenFactory.getInstance().create(ci, c.currentScreen); + c.setScreen(screen.get()); } } } + @Unique private void rpo$renderButton(DrawContext context, boolean hovered, Identifier texture, int x, int y) { RenderSystem.setShaderColor(1, 1, 1, 1f); RenderSystem.disableDepthTest(); diff --git a/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java b/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java index ecdb9a1..b347afa 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java @@ -1,14 +1,8 @@ package io.gitlab.jfronny.respackopts; -import io.gitlab.jfronny.commons.logging.Logger; -import io.gitlab.jfronny.gson.*; -import io.gitlab.jfronny.muscript.ast.*; +import io.gitlab.jfronny.commons.logger.SystemLoggerPlus; 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; -import io.gitlab.jfronny.respackopts.model.Condition; -import io.gitlab.jfronny.respackopts.model.tree.*; import io.gitlab.jfronny.respackopts.server.ServerInstanceHolder; import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; @@ -23,21 +17,9 @@ import java.util.regex.Pattern; public class Respackopts implements ModInitializer, SaveHook { public static final Integer META_VERSION = 12; public static final String FILE_EXTENSION = ".rpo"; - public static final Gson GSON = new GsonBuilder() - .registerTypeAdapter(ConfigEnumEntry.class, new EnumEntrySerializer()) - .registerTypeAdapter(ConfigNumericEntry.class, new NumericEntrySerializer()) - .registerTypeAdapter(ConfigBooleanEntry.class, new BooleanEntrySerializer()) - .registerTypeAdapter(ConfigBranch.class, new ConfigBranchSerializer()) - .registerTypeAdapter(Expr.class, new ExprDeserializer()) - .registerTypeAdapter(StringExpr.class, new StringExprDeserializer()) - .registerTypeAdapter(BoolExpr.class, new BoolExprDeserializer()) - .registerTypeAdapter(Condition.class, new ConditionDeserializer()) - .setStrictness(Strictness.LENIENT) - .setPrettyPrinting() - .create(); public static final String ID = "respackopts"; - public static final Logger LOGGER = Logger.forName(ID); + public static final SystemLoggerPlus LOGGER = SystemLoggerPlus.forName(ID); public static final Path FALLBACK_CONF_DIR = FabricLoader.getInstance().getConfigDir().resolve(ID); diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/DebugEvents.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/DebugEvents.java index 563ed1f..c266263 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/DebugEvents.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/DebugEvents.java @@ -23,7 +23,7 @@ public enum DebugEvents implements UserResourceEvents.FindResource, UserResource @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()); + Respackopts.LOGGER.info("FIND_RESOURCE " + type + " in " + namespace + " " + prefix + " of " + pack.getId()); Set results = new HashSet<>(); return (identifier, inputStreamInputSupplier) -> { if (!results.add(identifier)) { @@ -35,19 +35,19 @@ public enum DebugEvents implements UserResourceEvents.FindResource, UserResource @Override public InputSupplier open(ResourceType type, Identifier id, InputSupplier previous, ResourcePack pack) { - Respackopts.LOGGER.info("OPEN " + type + " at " + id + " of " + pack.getName()); + Respackopts.LOGGER.info("OPEN " + type + " at " + id + " of " + pack.getId()); return previous; } @Override public InputSupplier openRoot(String[] fileName, InputSupplier previous, ResourcePack pack) { - Respackopts.LOGGER.info("OPEN_ROOT " + String.join("/", fileName) + " of " + pack.getName()); + Respackopts.LOGGER.info("OPEN_ROOT " + String.join("/", fileName) + " of " + pack.getId()); return previous; } @Override public T parseMetadata(ResourceMetadataReader reader, Supplier previous, ResourcePack pack) { - Respackopts.LOGGER.info("PARSE_METADATA " + reader.getKey() + " of " + pack.getName()); + Respackopts.LOGGER.info("PARSE_METADATA " + reader.getKey() + " of " + pack.getId()); return previous.get(); } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/DirFilterEvents.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/DirFilterEvents.java index e8b110a..f55f750 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/DirFilterEvents.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/DirFilterEvents.java @@ -1,11 +1,13 @@ package io.gitlab.jfronny.respackopts.filters; +import io.gitlab.jfronny.libjf.LibJf; 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.filters.util.DirRpoResult; import io.gitlab.jfronny.respackopts.gson.AttachmentHolder; import io.gitlab.jfronny.respackopts.model.DirRpo; +import io.gitlab.jfronny.respackopts.model.GC_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; @@ -139,7 +141,7 @@ public enum DirFilterEvents implements UserResourceEvents.Open, UserResourceEven if (state.tracker() != null) state.tracker().addDependency(path, rp); try (Reader w = new InputStreamReader(is.get())) { List currentRPOs = new LinkedList<>(parentRPOs); - DirRpo newRPO = AttachmentHolder.deserialize(state.metadata().version, w, DirRpo.class); + DirRpo newRPO = AttachmentHolder.attach(state.metadata().version, () -> GC_DirRpo.deserialize(w, LibJf.LENIENT_TRANSPORT)); newRPO.hydrate(path); if (newRPO.fallback != null && !newRPO.fallback.endsWith("/")) newRPO.fallback += "/"; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/DirRpoResult.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/DirRpoResult.java index 8736f3a..6b4d5f8 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/DirRpoResult.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/DirRpoResult.java @@ -1,8 +1,8 @@ package io.gitlab.jfronny.respackopts.filters.util; import io.gitlab.jfronny.commons.LazySupplier; -import io.gitlab.jfronny.muscript.data.Scope; -import io.gitlab.jfronny.muscript.debug.ObjectGraphPrinter; +import io.gitlab.jfronny.muscript.data.additional.context.Scope; +import io.gitlab.jfronny.muscript.data.additional.impl.ObjectGraphPrinter; import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.model.Condition; import io.gitlab.jfronny.respackopts.model.DirRpo; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExclusionProvider.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExclusionProvider.java index 75a8276..5b0db07 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExclusionProvider.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExclusionProvider.java @@ -1,12 +1,10 @@ package io.gitlab.jfronny.respackopts.filters.util; -import io.gitlab.jfronny.muscript.debug.ObjectGraphPrinter; import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.model.Condition; 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.ResourcePack; public class FileExclusionProvider { public static boolean fileHidden(CacheKey key, RespackoptsFS fs, String file) { @@ -18,7 +16,7 @@ public class FileExclusionProvider { } catch (Condition.ConditionException e) { String res = "Could not evaluate condition for " + file + " (pack: " + key.packName() + ")"; try { - Respackopts.LOGGER.error(res + " with condition:\n" + ObjectGraphPrinter.printGraph(rpo.condition) + ")", e); + Respackopts.LOGGER.error(res + " with condition:\n" + rpo.condition + ")", e); } catch (Throwable ex) { Respackopts.LOGGER.error(res, e); } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExpansionProvider.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExpansionProvider.java index 7736982..a1505bd 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExpansionProvider.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExpansionProvider.java @@ -1,8 +1,10 @@ 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; @@ -15,7 +17,7 @@ public class FileExpansionProvider { public static synchronized InputStream replace(DObject parameter, InputStream is, Map expansions) throws IOException { String s = new String(is.readAllBytes()); for (Map.Entry entry : expansions.entrySet()) { - s = s.replace("${" + entry.getKey() + "}", entry.getValue().get(parameter)); + s = s.replace("${" + entry.getKey() + "}", Runtime.evaluate(entry.getValue(), Scope.of(parameter))); } return new ByteArrayInputStream(s.getBytes()); } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileRpoSearchProvider.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileRpoSearchProvider.java index 2e48575..2a78634 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileRpoSearchProvider.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileRpoSearchProvider.java @@ -1,8 +1,10 @@ package io.gitlab.jfronny.respackopts.filters.util; +import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.gson.AttachmentHolder; import io.gitlab.jfronny.respackopts.model.FileRpo; +import io.gitlab.jfronny.respackopts.model.GC_FileRpo; import io.gitlab.jfronny.respackopts.model.cache.CacheKey; import io.gitlab.jfronny.respackopts.model.cache.CachedPackState; import io.gitlab.jfronny.respackopts.muscript.RespackoptsFS; @@ -27,7 +29,7 @@ public class FileRpoSearchProvider { if (is == null) return defaultValue; if (state.tracker() != null) state.tracker().addDependency(fileName, rpoPathS); try (Reader w = new InputStreamReader(is.get())) { - FileRpo frp = AttachmentHolder.deserialize(state.metadata().version, w, FileRpo.class); + FileRpo frp = AttachmentHolder.attach(state.metadata().version, () -> GC_FileRpo.deserialize(w, LibJf.LENIENT_TRANSPORT)); frp.hydrate(rpoPathS); rpoCache.put(rpoPathS, frp); return action.run(frp); diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/AttachmentHolder.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/AttachmentHolder.java index 084ccc3..cb983be 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/gson/AttachmentHolder.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/AttachmentHolder.java @@ -1,36 +1,29 @@ package io.gitlab.jfronny.respackopts.gson; +import io.gitlab.jfronny.commons.concurrent.ScopedValue; +import io.gitlab.jfronny.commons.throwable.ExceptionWrapper; import io.gitlab.jfronny.commons.throwable.ThrowingRunnable; import io.gitlab.jfronny.commons.throwable.ThrowingSupplier; -import io.gitlab.jfronny.respackopts.Respackopts; - -import java.io.Reader; public class AttachmentHolder { - private static final ThreadLocal attachments = new ThreadLocal<>(); + private static final ScopedValue attachments = new ScopedValue<>(); public static void attach(int version, ThrowingRunnable runnable) throws TEx { try { - attachments.set(new Attachment(version)); - runnable.run(); - } finally { - attachments.remove(); + ScopedValue.runWhere(attachments, new Attachment(version), runnable.orThrow()); + } catch (ExceptionWrapper e) { + throw (TEx) ExceptionWrapper.unwrap(e); } } public static TOut attach(int version, ThrowingSupplier runnable) throws TEx { try { - attachments.set(new Attachment(version)); - return runnable.get(); - } finally { - attachments.remove(); + return ScopedValue.getWhere(attachments, new Attachment(version), runnable.orThrow()); + } catch (ExceptionWrapper e) { + throw (TEx) ExceptionWrapper.unwrap(e); } } - public static T deserialize(int version, Reader r, Class klazz) { - return attach(version, () -> Respackopts.GSON.fromJson(r, klazz)); - } - public static int getAttachedVersion() { return attachments.get().version; } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/BoolExprDeserializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/BoolExprDeserializer.java index 4d7b82e..cb6a9cd 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/gson/BoolExprDeserializer.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/BoolExprDeserializer.java @@ -1,68 +1,81 @@ package io.gitlab.jfronny.respackopts.gson; -import io.gitlab.jfronny.gson.*; -import io.gitlab.jfronny.gson.reflect.TypeToken; +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +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.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.compare.Equal; import io.gitlab.jfronny.muscript.ast.dynamic.*; -import io.gitlab.jfronny.muscript.compiler.CodeLocation; -import io.gitlab.jfronny.muscript.compiler.Token; +import io.gitlab.jfronny.muscript.core.CodeLocation; -import java.lang.reflect.Type; import java.util.*; -public class BoolExprDeserializer implements JsonDeserializer { - private static final Type conditionListType = new TypeToken>(){}.getType(); +@SerializerFor(targets = BoolExpr.class) +public class BoolExprDeserializer extends TypeAdapter { + public static final BoolExprDeserializer INSTANCE = new BoolExprDeserializer(); @Override - public BoolExpr deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + public > BoolExpr deserialize(Reader reader) throws TEx, MalformedDataException { if (AttachmentHolder.getAttachedVersion() > 7) { - return context.>deserialize(json, Expr.class).asBoolExpr(); + return ExprUtils.asBool(ExprDeserializer.INSTANCE.deserialize(reader)); } // Legacy JSON syntax - if (json.isJsonObject()) { - JsonObject jo = json.getAsJsonObject(); - if (jo.size() != 1) - throw new JsonParseException("More than one key in a condition object"); - Map.Entry entry = jo.entrySet().stream().findFirst().orElseThrow(); - return switch (entry.getKey().toLowerCase(Locale.ROOT)) { - case "and", "add", "&" -> merge(context.deserialize(entry.getValue(), conditionListType), Token.And); - case "==", "=", "equal", "eq" -> merge(context.deserialize(entry.getValue(), conditionListType), Token.EqualEqual); - case "not", "nor", "!" -> new Not(CodeLocation.NONE, merge(context.deserialize(entry.getValue(), conditionListType), Token.Or)); - case "or", "|" -> merge(context.deserialize(entry.getValue(), conditionListType), Token.Or); - case "^", "xor" -> merge(context.deserialize(entry.getValue(), conditionListType), Token.BangEqual); - default -> throw new JsonParseException("Unknown condition type: " + entry.getKey()); - }; - } - else if (json.isJsonArray()) { - return merge(context.deserialize(json, conditionListType), Token.And); - } - else if (json.isJsonPrimitive()) { - JsonPrimitive pr = json.getAsJsonPrimitive(); - if (pr.isString()) { - String name = pr.getAsString(); - if (name.toLowerCase(Locale.ROOT).equals("true")) - return Expr.literal(CodeLocation.NONE, true); - if (name.toLowerCase(Locale.ROOT).equals("false")) - return Expr.literal(CodeLocation.NONE, false); - return rpoBooleanCondition(name); - } - else if (pr.isBoolean()) { - return Expr.literal(CodeLocation.NONE, pr.getAsBoolean()); + if (reader.peek() == io.gitlab.jfronny.commons.serialize.Token.BEGIN_OBJECT) { + reader.beginObject(); + if (reader.hasNext()) { + String key = reader.nextName(); + BoolExpr expr = switch (key.toLowerCase(Locale.ROOT)) { + case "and", "add", "&" -> merge(reader, Token.And); + case "==", "=", "equal", "eq" -> merge(reader, Token.EqualEqual); + case "not", "nor", "!" -> new Not(CodeLocation.NONE, merge(reader, Token.Or)); + case "or", "|" -> merge(reader, Token.Or); + case "^", "xor" -> merge(reader, Token.BangEqual); + default -> throw new MalformedDataException("Unknown condition type: " + key); + }; + reader.endObject(); + return expr; + } else { + reader.endObject(); + throw new MalformedDataException("Empty condition object"); } + } else if (reader.peek() == io.gitlab.jfronny.commons.serialize.Token.BEGIN_ARRAY) { + return merge(reader, Token.And); + } else if (reader.peek() == io.gitlab.jfronny.commons.serialize.Token.STRING) { + String name = reader.nextString(); + if (name.toLowerCase(Locale.ROOT).equals("true")) + return Expr.literal(CodeLocation.NONE, true); + if (name.toLowerCase(Locale.ROOT).equals("false")) + return Expr.literal(CodeLocation.NONE, false); + return rpoBooleanCondition(name); + } else if (reader.peek() == io.gitlab.jfronny.commons.serialize.Token.BOOLEAN) { + return Expr.literal(CodeLocation.NONE, reader.nextBoolean()); + } else { + throw new MalformedDataException("Invalid data type for condition"); } - throw new JsonParseException("Invalid data type for condition"); } - private BoolExpr merge(List expressions, Token token) { + private > BoolExpr merge(Reader source, Token token) throws TEx, MalformedDataException { if (token == Token.BangEqual) - return new Not(CodeLocation.NONE, merge(expressions, Token.EqualEqual)); - BoolExpr current = expressions.get(0); + return new Not(CodeLocation.NONE, merge(source, Token.EqualEqual)); + List expressions = new ArrayList<>(); + if (source.peek() == io.gitlab.jfronny.commons.serialize.Token.BEGIN_ARRAY) { + source.beginArray(); + while (source.hasNext()) { + expressions.add(deserialize(source)); + } + source.endArray(); + } else { + expressions.add(deserialize(source)); + } + BoolExpr current = expressions.getFirst(); for (BoolExpr expr : expressions.subList(1, expressions.size())) { current = switch (token) { - case EqualEqual -> new Equal(CodeLocation.NONE, current, expr); + case EqualEqual -> new Equals(CodeLocation.NONE, current, expr); case And -> new And(CodeLocation.NONE, current, expr); case Or -> new Or(CodeLocation.NONE, current, expr); default -> throw new IllegalArgumentException(); @@ -71,15 +84,15 @@ public class BoolExprDeserializer implements JsonDeserializer { return current; } - private BoolExpr rpoBooleanCondition(String name) { + private BoolExpr rpoBooleanCondition(String name) throws MalformedDataException { if (name.startsWith("modversion:")) { String code = name.substring("modversion:".length()); String mod = code.substring(0, code.indexOf(':')); String predicate = code.substring(code.indexOf(':') + 1); - return new Call(CodeLocation.NONE, new Variable(CodeLocation.NONE, "version"), List.of( - new Call.Arg(Expr.literal(mod).asDynamicExpr(), false), - new Call.Arg(Expr.literal(predicate).asDynamicExpr(), false) - )).asBoolExpr(); + return ExprUtils.asBool(new Call(CodeLocation.NONE, new Variable(CodeLocation.NONE, "version"), List.of( + new Call.Argument(ExprUtils.asDynamic(Expr.literal(mod)), false), + new Call.Argument(ExprUtils.asDynamic(Expr.literal(predicate)), false) + ))); } DynamicExpr e = null; String[] arr = name.split("[:.]"); @@ -87,7 +100,12 @@ public class BoolExprDeserializer implements JsonDeserializer { if (i == 0) e = new Variable(CodeLocation.NONE, arr[i]); else e = new Get(CodeLocation.NONE, e, Expr.literal(arr[i])); } - if (e == null) throw new JsonParseException("Invalid RPO condition: \"" + name + "\""); - return e.asBoolExpr(); + if (e == null) throw new MalformedDataException("Invalid RPO condition: \"" + name + "\""); + return ExprUtils.asBool(e); + } + + @Override + public > void serialize(BoolExpr boolExpr, Writer writer) throws TEx, MalformedDataException { + ExprDeserializer.INSTANCE.serialize(boolExpr, writer); } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/ConditionDeserializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/ConditionDeserializer.java index 0cf7592..2b455ff 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/gson/ConditionDeserializer.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/ConditionDeserializer.java @@ -1,19 +1,28 @@ package io.gitlab.jfronny.respackopts.gson; -import io.gitlab.jfronny.gson.*; -import io.gitlab.jfronny.muscript.ast.BoolExpr; +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +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.muscript.ast.context.ExprUtils; import io.gitlab.jfronny.respackopts.model.Condition; -import java.lang.reflect.Type; - -public class ConditionDeserializer implements JsonDeserializer { +@SerializerFor(targets = Condition.class) +public class ConditionDeserializer extends TypeAdapter { @Override - public Condition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + public > void serialize(Condition condition, Writer writer) throws TEx, MalformedDataException { + BoolExprDeserializer.INSTANCE.serialize(condition.expr(), writer); + } + + @Override + public > Condition deserialize(Reader reader) throws TEx, MalformedDataException { String source = "Source unavailable"; - if (json.isJsonPrimitive()) { - JsonPrimitive primitive = json.getAsJsonPrimitive(); - if (primitive.isString()) source = primitive.getAsString(); + if (reader.peek() == Token.STRING) { + source = reader.nextString(); + return new Condition(source, null, ExprUtils.asBool(ExprDeserializer.INSTANCE.parse(source))); } - return new Condition(source, null, context.deserialize(json, BoolExpr.class)); + return new Condition(source, null, BoolExprDeserializer.INSTANCE.deserialize(reader)); } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigEntryTypeAdapter.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigEntryTypeAdapter.java new file mode 100644 index 0000000..0608a3c --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigEntryTypeAdapter.java @@ -0,0 +1,78 @@ +package io.gitlab.jfronny.respackopts.gson; + +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +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.commons.serialize.emulated.DataElement; +import io.gitlab.jfronny.commons.serialize.emulated.EmulatedReader; +import io.gitlab.jfronny.commons.serialize.emulated.EmulatedWriter; +import io.gitlab.jfronny.respackopts.Respackopts; +import io.gitlab.jfronny.respackopts.gson.entry.BooleanEntrySerializer; +import io.gitlab.jfronny.respackopts.gson.entry.EnumEntrySerializer; +import io.gitlab.jfronny.respackopts.gson.entry.NumericEntrySerializer; +import io.gitlab.jfronny.respackopts.model.tree.*; + +@SerializerFor(targets = ConfigEntry.class) +public class ConfigEntryTypeAdapter extends TypeAdapter> { + @Override + public > void serialize(ConfigEntry entry, Writer writer) throws TEx, MalformedDataException { + switch (entry) { + case ConfigBooleanEntry bl -> GC_ConfigBooleanEntry.serialize(bl, writer); + case ConfigNumericEntry num -> GC_ConfigNumericEntry.serialize(num, writer); + case ConfigEnumEntry en -> GC_ConfigEnumEntry.serialize(en, writer); + case ConfigBranch br -> GC_ConfigBranch.serialize(br, writer); + default -> throw new MalformedDataException("Unknown entry type: " + entry.getClass().getName()); + } + } + + @Override + public > ConfigEntry deserialize(Reader reader) throws TEx, MalformedDataException { + return switch (reader.peek()) { + case BOOLEAN -> GC_ConfigBooleanEntry.deserialize(reader); + case NUMBER -> GC_ConfigNumericEntry.deserialize(reader); + case STRING, BEGIN_ARRAY -> GC_ConfigEnumEntry.deserialize(reader); + case BEGIN_OBJECT -> { + final ConfigEntry entry; + String type = null; + DataElement.Object de; + reader.beginObject(); + try (EmulatedWriter ew = new EmulatedWriter()) { + ew.beginObject(); + while (reader.hasNext()) { + String key; + ew.name(key = reader.nextName()); + if (key.equals("type")) ew.value(type = reader.nextString()); + else reader.copyTo(ew); + } + ew.endObject(); + de = (DataElement.Object) ew.get(); + } + reader.endObject(); + if (type != null) { + if (BooleanEntrySerializer.TYPES.contains(type)) { + entry = GC_ConfigBooleanEntry.deserialize(new EmulatedReader(de)); + } else if (NumericEntrySerializer.TYPES.contains(type)) { + var e = GC_ConfigNumericEntry.deserialize(new EmulatedReader(de)); + entry = NumericEntrySerializer.INT_TYPES.contains(type) ? e.asInteger() : e; + } else if (EnumEntrySerializer.TYPES.contains(type)) { + entry = GC_ConfigEnumEntry.deserialize(new EmulatedReader(de)); + } else { + throw new MalformedDataException("Invalid type for entry: " + type); + } + } else { + if (de.members().keySet().stream().allMatch(k -> "default".equals(k) || "min".equals(k) || "max".equals(k))) { + Respackopts.LOGGER.info("No \"type\" property for non-branch entry object, assuming slider"); + entry = GC_ConfigNumericEntry.deserialize(new EmulatedReader(de)); + } else { + entry = GC_ConfigBranch.deserialize(new EmulatedReader(de)); + } + } + yield entry; + } + case NULL -> throw new MalformedDataException("Unexpected null value for entry"); + default -> throw new MalformedDataException("Invalid data type for entry"); + }; + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/ExprDeserializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/ExprDeserializer.java index 3dd3d9a..5b7abd2 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/gson/ExprDeserializer.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/ExprDeserializer.java @@ -1,38 +1,53 @@ package io.gitlab.jfronny.respackopts.gson; -import io.gitlab.jfronny.gson.*; -import io.gitlab.jfronny.muscript.StarScriptIngester; +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +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.muscript.ast.Expr; -import io.gitlab.jfronny.muscript.compiler.Parser; +import io.gitlab.jfronny.muscript.parser.Parser; +import io.gitlab.jfronny.muscript.parser.StarScriptIngester; +import io.gitlab.jfronny.muscript.serialize.Decompiler; import io.gitlab.jfronny.respackopts.muscript.ScopeVersion; -import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; -public class ExprDeserializer implements JsonDeserializer> { - private static final Map> compiledScripts = new HashMap<>(); +@SerializerFor(targets = Expr.class) +public class ExprDeserializer extends TypeAdapter { + public static final ExprDeserializer INSTANCE = new ExprDeserializer(); + private static final Map compiledScripts = new HashMap<>(); @Override - public Expr deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString()) { - String s = json.getAsJsonPrimitive().getAsString(); - if (compiledScripts.containsKey(s)) - return compiledScripts.get(s); - try { - int v = AttachmentHolder.getAttachedVersion(); - Expr expr = Parser.parse(ScopeVersion.by(v).muScriptVersion, v <= 7 - ? StarScriptIngester.starScriptToMu(s) - : s); - compiledScripts.put(s, expr); - return expr; - } catch (Parser.ParseException e) { - throw new JsonParseException("Could not create script", e); - } + public > void serialize(Expr expr, Writer writer) throws TEx, MalformedDataException { + writer.value(Decompiler.decompile(expr)); + } + + @Override + public > Expr deserialize(Reader reader) throws TEx, MalformedDataException { + if (reader.peek() == Token.STRING) { + return parse(reader.nextString()); + } else if (reader.peek() == Token.BEGIN_OBJECT) { + throw new MalformedDataException("Could not parse script: Expected string but got object (did you forget to migrate this rpo to muScript?)"); + } else { + throw new MalformedDataException("Could not parse script: Expected string"); } - else { - if (json.isJsonObject()) throw new JsonParseException("Could not parse script: Expected string but got object (did you forget to migrate this rpo to muScript?)"); - throw new JsonParseException("Could not parse script: Expected string"); + } + + public Expr parse(String source) throws MalformedDataException { + if (compiledScripts.containsKey(source)) + return compiledScripts.get(source); + try { + int v = AttachmentHolder.getAttachedVersion(); + Expr expr = Parser.parse(ScopeVersion.by(v).muScriptVersion, v <= 7 + ? StarScriptIngester.starScriptToMu(source) + : source); + compiledScripts.put(source, expr); + return expr; + } catch (Parser.ParseException e) { + throw new MalformedDataException("Could not create script", e); } } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/StringExprDeserializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/StringExprDeserializer.java index 6d0becb..bc871e0 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/gson/StringExprDeserializer.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/StringExprDeserializer.java @@ -1,15 +1,22 @@ package io.gitlab.jfronny.respackopts.gson; -import io.gitlab.jfronny.gson.*; -import io.gitlab.jfronny.muscript.ast.Expr; +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +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.StringExpr; +import io.gitlab.jfronny.muscript.ast.context.ExprUtils; -import java.lang.reflect.Type; - -public class StringExprDeserializer implements JsonDeserializer { +@SerializerFor(targets = StringExpr.class) +public class StringExprDeserializer extends TypeAdapter { @Override - public StringExpr deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { - Expr expr = jsonDeserializationContext.deserialize(jsonElement, Expr.class); - return expr.asStringExpr(); + public > void serialize(StringExpr stringExpr, Writer writer) throws TEx, MalformedDataException { + ExprDeserializer.INSTANCE.serialize(stringExpr, writer); + } + + @Override + public > StringExpr deserialize(Reader reader) throws TEx, MalformedDataException { + return ExprUtils.asString(ExprDeserializer.INSTANCE.deserialize(reader)); } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/BooleanEntrySerializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/BooleanEntrySerializer.java index 55762a0..feb9566 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/BooleanEntrySerializer.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/BooleanEntrySerializer.java @@ -1,26 +1,53 @@ package io.gitlab.jfronny.respackopts.gson.entry; -import io.gitlab.jfronny.gson.*; +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +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.enums.PackReloadType; import io.gitlab.jfronny.respackopts.model.tree.ConfigBooleanEntry; -import java.lang.reflect.Type; +import java.util.Set; + +@SerializerFor(targets = ConfigBooleanEntry.class) +public class BooleanEntrySerializer extends TypeAdapter { + public static final Set TYPES = Set.of("boolean", "toggle"); -public class BooleanEntrySerializer implements JsonSerializer, JsonDeserializer { @Override - public ConfigBooleanEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - if (json.isJsonPrimitive()) return new ConfigBooleanEntry(json.getAsBoolean()); - else if (json.isJsonObject()) { - JsonObject o = json.getAsJsonObject(); - if (o.has("default")) - return new ConfigBooleanEntry(o.get("default").getAsBoolean()); - else - throw new JsonSyntaxException("Default value for boolean entry must be a boolean"); - } - else throw new JsonSyntaxException("Invalid type for boolean entry"); + public > void serialize(ConfigBooleanEntry configBooleanEntry, Writer writer) throws TEx, MalformedDataException { + writer.value(configBooleanEntry.getValue()); } @Override - public JsonElement serialize(ConfigBooleanEntry src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(src.getValue()); + public > ConfigBooleanEntry deserialize(Reader reader) throws TEx, MalformedDataException { + if (reader.peek() == Token.BOOLEAN) { + return new ConfigBooleanEntry(reader.nextBoolean()); + } else if (reader.peek() == Token.BEGIN_OBJECT) { + reader.beginObject(); + ConfigBooleanEntry result = new ConfigBooleanEntry(false); + while (reader.hasNext()) { + String key = reader.nextName(); + switch (key) { + case "type" -> { + if (!TYPES.contains(reader.nextString())) { + throw new MalformedDataException("Invalid type for boolean entry"); + } + } + case "default" -> { + boolean value = reader.nextBoolean(); + result.setDefault(value); + result.setValue(value); + } + case "reloadType" -> result.setReloadType(PackReloadType.valueOf(reader.nextString())); + default -> throw new MalformedDataException("Unknown key in boolean entry: " + key); + }; + } + reader.endObject(); + return result; + } else { + throw new MalformedDataException("Invalid data type for boolean entry"); + } } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/ConfigBranchSerializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/ConfigBranchSerializer.java index 6df4df6..8e9dff9 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/ConfigBranchSerializer.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/ConfigBranchSerializer.java @@ -1,79 +1,37 @@ package io.gitlab.jfronny.respackopts.gson.entry; -import io.gitlab.jfronny.gson.*; -import io.gitlab.jfronny.respackopts.Respackopts; -import io.gitlab.jfronny.respackopts.model.enums.PackReloadType; +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +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 java.lang.reflect.Type; import java.util.Map; -public class ConfigBranchSerializer implements JsonSerializer, JsonDeserializer { +@SerializerFor(targets = ConfigBranch.class) +public class ConfigBranchSerializer extends TypeAdapter { @Override - public JsonElement serialize(ConfigBranch src, Type typeOfSrc, JsonSerializationContext context) { - JsonObject o = new JsonObject(); - for (Map.Entry> entry : src.getValue().entrySet()) { - o.add(entry.getKey(), context.serialize(entry.getValue())); + public > void serialize(ConfigBranch configBranch, Writer writer) throws TEx, MalformedDataException { + writer.beginObject(); + for (Map.Entry> entry : configBranch.getValue().entrySet()) { + writer.name(entry.getKey()); + GC_ConfigEntry.serialize(entry.getValue(), writer); } - return o; + writer.endObject(); } @Override - public ConfigBranch deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - if (!json.isJsonObject()) - throw new JsonSyntaxException("ConfigBranch is not an object"); - JsonObject o = json.getAsJsonObject(); + public > ConfigBranch deserialize(Reader reader) throws TEx, MalformedDataException { + if (reader.peek() != Token.BEGIN_OBJECT) throw new MalformedDataException("ConfigBranch is not an object"); + reader.beginObject(); ConfigBranch cbNew = new ConfigBranch(); - for (Map.Entry e : o.entrySet()) { - JsonElement j = e.getValue(); - String s = e.getKey(); - if (j.isJsonPrimitive()) { - JsonPrimitive p = j.getAsJsonPrimitive(); - if (p.isBoolean()) - cbNew.add(s, new ConfigBooleanEntry(p.getAsBoolean())); - else if (p.isNumber()) - cbNew.add(s, context.deserialize(j, ConfigNumericEntry.class)); - else if (p.isString()) - cbNew.add(s, context.deserialize(j, ConfigEnumEntry.class)); - } - else if (j.isJsonArray()) - cbNew.add(s, context.deserialize(j, ConfigEnumEntry.class)); - else if (j.isJsonObject()) { - JsonObject jo = j.getAsJsonObject(); - String type; - if (jo.has("type")) { - type = jo.get("type").getAsString(); - } - else { - if (jo.entrySet().stream().allMatch(entry -> "default".equals(entry.getKey()) || "min".equals(entry.getKey()) || "max".equals(entry.getKey()))) { - Respackopts.LOGGER.info("No \"type\" property for non-branch entry object, assuming slider"); - type = "slider"; - } - else { - cbNew.add(s, context.deserialize(j, ConfigBranch.class)); - continue; - } - } - ConfigEntry entry = switch (type.toLowerCase()) { - case "slider", "number", "numeric" -> context.deserialize(j, ConfigNumericEntry.class); - case "integer", "int", "long", "whole" -> context.deserialize(j, ConfigNumericEntry.class).asInteger(); - case "boolean", "toggle" -> context.deserialize(j, ConfigBooleanEntry.class); - case "enum", "select" -> context.deserialize(j, ConfigEnumEntry.class); - default -> throw new JsonSyntaxException("Unknown entry type: " + type); - }; - if (jo.has("default")) { - entry.setDefault(context.deserialize(jo.get("default"), entry.getEntryClass())); - entry.setValue(context.deserialize(jo.get("default"), entry.getEntryClass())); - } - if (jo.has("reloadType")) { - entry.setReloadType(context.deserialize(jo.get("reloadType"), PackReloadType.class)); - } - cbNew.add(s, entry); - } else if (j.isJsonNull()) - throw new JsonSyntaxException("Unexpected json null"); - else - throw new JsonSyntaxException("Unexpected json object type"); + while (reader.hasNext()) { + String s = reader.nextName(); + cbNew.add(s, GC_ConfigEntry.deserialize(reader)); } + reader.endObject(); return cbNew; } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/EnumEntrySerializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/EnumEntrySerializer.java index 10d82d1..dee1eb3 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/EnumEntrySerializer.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/EnumEntrySerializer.java @@ -1,56 +1,87 @@ package io.gitlab.jfronny.respackopts.gson.entry; -import io.gitlab.jfronny.gson.*; -import io.gitlab.jfronny.respackopts.Respackopts; +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +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.enums.PackReloadType; import io.gitlab.jfronny.respackopts.model.tree.ConfigEnumEntry; -import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; +import java.util.Set; + +@SerializerFor(targets = ConfigEnumEntry.class) +public class EnumEntrySerializer extends TypeAdapter { + public static final Set TYPES = Set.of("enum", "select"); -public class EnumEntrySerializer implements JsonSerializer, JsonDeserializer { @Override - public JsonElement serialize(ConfigEnumEntry src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(src.getValue()); + public > void serialize(ConfigEnumEntry configEnumEntry, Writer writer) throws TEx, MalformedDataException { + writer.value(configEnumEntry.getValue()); } @Override - public ConfigEnumEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + public > ConfigEnumEntry deserialize(Reader reader) throws TEx, MalformedDataException { ConfigEnumEntry result = new ConfigEnumEntry(); - if (json.isJsonPrimitive()) { - JsonPrimitive jp = json.getAsJsonPrimitive(); - if (jp.isString()) { - result.setValue(jp.getAsString()); - return result; - } - else if (jp.isNumber()) { - result.setNextValue(jp.getAsInt()); - return result; - } - else - throw new JsonSyntaxException("Expected primitive string key for enum"); - } - else if (json.isJsonArray()) { - List replacement = new ArrayList<>(); - for (JsonElement e : json.getAsJsonArray()) { - if (e.isJsonPrimitive() && e.getAsJsonPrimitive().isString()) { - replacement.add(e.getAsString()); - } - else - throw new JsonSyntaxException("Expected string entry in enum"); - } - result.setValues(replacement); - if (replacement.isEmpty()) - Respackopts.LOGGER.warn("Enum entry empty"); - else - result.setDefault(replacement.get(0)); + if (reader.peek() == Token.STRING) { + result.setValue(reader.nextString()); return result; + } else if (reader.peek() == Token.NUMBER) { + result.setNextValue(reader.nextInt()); + return result; + } else if (reader.peek() == Token.BEGIN_ARRAY) { + List replacement = new ArrayList<>(); + reader.beginArray(); + while (reader.hasNext()) { + if (reader.peek() != Token.STRING) throw new MalformedDataException("Expected string entry in enum"); + replacement.add(reader.nextString()); + } + reader.endArray(); + result.setValues(replacement); + result.setDefault(replacement.getFirst()); + result.setValue(replacement.getFirst()); + return result; + } else if (reader.peek() == Token.BEGIN_OBJECT) { + reader.beginObject(); + while (reader.hasNext()) { + String key = reader.nextName(); + switch (key) { + case "type" -> { + if (!TYPES.contains(reader.nextString())) { + throw new MalformedDataException("Invalid type for enum entry"); + } + } + case "default" -> { + if (reader.peek() != Token.STRING) throw new MalformedDataException("Expected string for enum default"); + String value = reader.nextString(); + result.setDefault(value); + result.setValue(value); + } + case "reloadType" -> result.setReloadType(PackReloadType.valueOf(reader.nextString())); + case "values" -> { + if (reader.peek() != Token.BEGIN_ARRAY) throw new MalformedDataException("Expected array for enum values"); + List replacement = new ArrayList<>(); + reader.beginArray(); + while (reader.hasNext()) { + if (reader.peek() != Token.STRING) throw new MalformedDataException("Expected string entry in enum"); + replacement.add(reader.nextString()); + } + reader.endArray(); + result.setValues(replacement); + if (!result.hasDefault()) { + result.setDefault(replacement.getFirst()); + result.setValue(replacement.getFirst()); + } + } + default -> throw new MalformedDataException("Unknown key in enum entry: " + key); + } + } + reader.endObject(); + return result; + } else { + throw new MalformedDataException("Invalid data type for enum entry"); } - else if (json.isJsonObject()) { - JsonObject o = json.getAsJsonObject(); - return deserialize(o.get("values"), typeOfT, context); - } - else - throw new JsonSyntaxException("Expected primitive string key or string array for enum"); } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/NumericEntrySerializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/NumericEntrySerializer.java index 4c301dc..aecd354 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/NumericEntrySerializer.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/NumericEntrySerializer.java @@ -1,42 +1,59 @@ package io.gitlab.jfronny.respackopts.gson.entry; -import io.gitlab.jfronny.gson.*; +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +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.enums.PackReloadType; import io.gitlab.jfronny.respackopts.model.tree.ConfigNumericEntry; -import java.lang.reflect.Type; +import java.util.Set; + +@SerializerFor(targets = ConfigNumericEntry.class) +public class NumericEntrySerializer extends TypeAdapter { + public static final Set TYPES = Set.of("numeric", "number", "slider", "integer", "int", "long", "whole"); + public static final Set INT_TYPES = Set.of("integer", "int", "long", "whole"); -public class NumericEntrySerializer implements JsonSerializer, JsonDeserializer { @Override - public JsonElement serialize(ConfigNumericEntry src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(src.getValue()); + public > void serialize(ConfigNumericEntry configNumericEntry, Writer writer) throws TEx, MalformedDataException { + writer.value(configNumericEntry.getValue()); } + @Override - public ConfigNumericEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isNumber()) { - ConfigNumericEntry result = new ConfigNumericEntry(); - result.setValue(json.getAsDouble()); - result.setDefault(json.getAsDouble()); + public > ConfigNumericEntry deserialize(Reader reader) throws TEx, MalformedDataException { + ConfigNumericEntry result = new ConfigNumericEntry(); + if (reader.peek() == Token.NUMBER) { + double value = reader.nextDouble(); + result.setValue(value); + result.setDefault(value); return result; - } - else if (json.isJsonObject()) { - JsonObject o = json.getAsJsonObject(); - ConfigNumericEntry result = new ConfigNumericEntry(); - JsonElement min = o.get("min"); - JsonElement max = o.get("max"); - if (min != null) { - if (min.isJsonPrimitive() && min.getAsJsonPrimitive().isNumber()) { - result.setMin(min.getAsNumber().doubleValue()); + } else if (reader.peek() == Token.BEGIN_OBJECT) { + reader.beginObject(); + while (reader.hasNext()) { + String key = reader.nextName(); + switch (key) { + case "type" -> { + if (!TYPES.contains(reader.nextString())) { + throw new MalformedDataException("Invalid type for numeric entry"); + } + } + case "default" -> { + double value = reader.nextDouble(); + result.setDefault(value); + result.setValue(value); + } + case "reloadType" -> result.setReloadType(PackReloadType.valueOf(reader.nextString())); + case "min" -> result.setMin(reader.nextDouble()); + case "max" -> result.setMax(reader.nextDouble()); + default -> throw new MalformedDataException("Unknown key in numeric entry: " + key); } - else throw new JsonSyntaxException("Expected number as min of numeric entry"); - } - if (max != null) { - if (max.isJsonPrimitive() && max.getAsJsonPrimitive().isNumber()) { - result.setMax(max.getAsNumber().doubleValue()); - } - else throw new JsonSyntaxException("Expected number as max of numeric entry"); } + reader.endObject(); return result; + } else { + throw new MalformedDataException("Invalid data type for numeric entry"); } - throw new JsonSyntaxException("Could not deserialize numeric entry"); } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/mixin/FileResourcePackProviderMixin.java b/src/main/java/io/gitlab/jfronny/respackopts/mixin/FileResourcePackProviderMixin.java index 98860dd..0f3368d 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/mixin/FileResourcePackProviderMixin.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/mixin/FileResourcePackProviderMixin.java @@ -12,7 +12,7 @@ import java.nio.file.*; @Mixin(FileResourcePackProvider.class) public class FileResourcePackProviderMixin { //TODO use MixinExtras Wrap instead of redirecting - @Redirect(method = "forEachProfile(Ljava/nio/file/Path;Lnet/minecraft/util/path/SymlinkFinder;ZLjava/util/function/BiConsumer;)V", at = @At(value = "INVOKE", target = "Ljava/nio/file/Files;newDirectoryStream(Ljava/nio/file/Path;)Ljava/nio/file/DirectoryStream;")) + @Redirect(method = "forEachProfile(Ljava/nio/file/Path;Lnet/minecraft/util/path/SymlinkFinder;Ljava/util/function/BiConsumer;)V", at = @At(value = "INVOKE", target = "Ljava/nio/file/Files;newDirectoryStream(Ljava/nio/file/Path;)Ljava/nio/file/DirectoryStream;")) private static DirectoryStream createFilteredStream(Path dir) throws IOException { return Files.newDirectoryStream(dir, path -> !(Files.isRegularFile(path) && path.getFileName().toString().endsWith(Respackopts.FILE_EXTENSION))); } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java b/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java index ac80584..4932edb 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java @@ -1,8 +1,10 @@ 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.GC_PackMeta; import io.gitlab.jfronny.respackopts.model.PackMeta; import io.gitlab.jfronny.respackopts.model.cache.CacheKey; import io.gitlab.jfronny.respackopts.util.FallbackI18n; @@ -50,18 +52,18 @@ public class ResourcePackManagerMixin { 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.getName() + " is null. This shouldn't happen!"); + else Respackopts.LOGGER.warn("Base path of directory resource pack " + rpi.getId() + " is null. This shouldn't happen!"); } 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.getName() + " is null. This shouldn't happen!"); + else Respackopts.LOGGER.warn("Base path of zip resource pack " + rpi.getId() + " is null. This shouldn't happen!"); } var conf = rpi.openRoot(Respackopts.ID + ".json5"); if (conf != null) { try (InputStream is = conf.get()) { - return rpo$readConfiguration(is, dataLocation, rpi.getName(), displayName, dataLocations, toRemove); + return rpo$readConfiguration(is, dataLocation, rpi.getId(), displayName, dataLocations, toRemove); } catch (Throwable e) { String message = "Could not read respackopts config in root for " + profileName; if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.error(message, e); @@ -74,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.getName(), displayName, dataLocations, toRemove); + return rpo$readConfiguration(is, dataLocation, rpi.getId(), displayName, dataLocations, toRemove); } catch (Throwable e) { Respackopts.LOGGER.error("Could not initialize pack meta for " + profileName, e); } @@ -86,7 +88,7 @@ public class ResourcePackManagerMixin { private static String rpo$readConfiguration(InputStream is, Path dataLocation, String packName, String displayName, Set dataLocations, Set toRemove) throws IOException { try (InputStreamReader isr = new InputStreamReader(is)) { - PackMeta conf = Respackopts.GSON.fromJson(isr, PackMeta.class); + 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); diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/Condition.java b/src/main/java/io/gitlab/jfronny/respackopts/model/Condition.java index bcfd3c0..ff882eb 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/Condition.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/Condition.java @@ -1,16 +1,20 @@ package io.gitlab.jfronny.respackopts.model; +import io.gitlab.jfronny.commons.serialize.databind.api.SerializeWithAdapter; import io.gitlab.jfronny.muscript.ast.BoolExpr; -import io.gitlab.jfronny.muscript.compiler.CodeLocation; -import io.gitlab.jfronny.muscript.data.Scope; -import io.gitlab.jfronny.muscript.error.LocationalException; -import io.gitlab.jfronny.muscript.error.PrettyPrintError; +import io.gitlab.jfronny.muscript.core.CodeLocation; +import io.gitlab.jfronny.muscript.core.LocationalException; +import io.gitlab.jfronny.muscript.core.PrettyPrintError; +import io.gitlab.jfronny.muscript.data.additional.context.Scope; +import io.gitlab.jfronny.muscript.runtime.Runtime; +import io.gitlab.jfronny.respackopts.gson.ConditionDeserializer; import org.jetbrains.annotations.Nullable; +@SerializeWithAdapter(adapter = ConditionDeserializer.class) public record Condition(String source, String sourceFile, BoolExpr expr) { public boolean get(Scope dataRoot) throws ConditionException { try { - return expr.get(dataRoot); + return Runtime.evaluate(expr, dataRoot); } catch (LocationalException e) { throw new ConditionException( e.asPrintable(), diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/DirRpo.java b/src/main/java/io/gitlab/jfronny/respackopts/model/DirRpo.java index d5c3b9b..cee14a4 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/DirRpo.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/DirRpo.java @@ -1,8 +1,10 @@ package io.gitlab.jfronny.respackopts.model; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.Ignore; -import io.gitlab.jfronny.gson.annotations.SerializedName; +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; +@GSerializable public class DirRpo { @SerializedName(value = "condition", alternate = {"conditions"}) public Condition condition; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/FileRpo.java b/src/main/java/io/gitlab/jfronny/respackopts/model/FileRpo.java index 7bbfccd..7a3c5b0 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/FileRpo.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/FileRpo.java @@ -1,12 +1,14 @@ package io.gitlab.jfronny.respackopts.model; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.Ignore; -import io.gitlab.jfronny.gson.annotations.SerializedName; +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.muscript.ast.StringExpr; import java.util.Map; import java.util.Set; +@GSerializable public class FileRpo { @SerializedName(value = "condition", alternate = {"conditions"}) public Condition condition; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/PackMeta.java b/src/main/java/io/gitlab/jfronny/respackopts/model/PackMeta.java index 82b0df6..c716ce2 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/PackMeta.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/PackMeta.java @@ -1,11 +1,15 @@ 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; import java.util.HashSet; import java.util.Set; +@GSerializable public class PackMeta { public ConfigBranch conf; public String id; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/cache/CachedPackState.java b/src/main/java/io/gitlab/jfronny/respackopts/model/cache/CachedPackState.java index febbf93..0e2d938 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/cache/CachedPackState.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/cache/CachedPackState.java @@ -1,8 +1,7 @@ package io.gitlab.jfronny.respackopts.model.cache; -import io.gitlab.jfronny.muscript.data.Scope; -import io.gitlab.jfronny.muscript.data.Script; -import io.gitlab.jfronny.respackopts.Respackopts; +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.*; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigBooleanEntry.java b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigBooleanEntry.java index 0153728..8a0c17c 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigBooleanEntry.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigBooleanEntry.java @@ -1,12 +1,16 @@ package io.gitlab.jfronny.respackopts.model.tree; +import io.gitlab.jfronny.commons.serialize.databind.api.SerializeWithAdapter; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; 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; +@SerializeWithAdapter(adapter = BooleanEntrySerializer.class) public class ConfigBooleanEntry extends ConfigEntry implements DBool { public ConfigBooleanEntry(boolean v) { super(Boolean.class); diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigBranch.java b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigBranch.java index cf1e27d..0a0d612 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigBranch.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigBranch.java @@ -1,15 +1,17 @@ package io.gitlab.jfronny.respackopts.model.tree; import com.google.common.collect.ImmutableMap; -import io.gitlab.jfronny.gson.reflect.TypeToken; +import io.gitlab.jfronny.commons.serialize.databind.api.SerializeWithAdapter; +import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; import io.gitlab.jfronny.libjf.config.api.v2.dsl.ConfigBuilder; -import io.gitlab.jfronny.muscript.data.Scope; +import io.gitlab.jfronny.muscript.data.additional.DFinal; +import io.gitlab.jfronny.muscript.data.additional.DelegateDynamic; +import io.gitlab.jfronny.muscript.data.additional.context.Scope; import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; -import io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal; -import io.gitlab.jfronny.muscript.data.dynamic.additional.DelegateDynamic; 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.integration.SaveHook; import io.gitlab.jfronny.respackopts.model.enums.ConfigSyncMode; import io.gitlab.jfronny.respackopts.model.enums.PackReloadType; @@ -19,6 +21,7 @@ import io.gitlab.jfronny.respackopts.util.MetaCache; import java.nio.file.Path; import java.util.*; +@SerializeWithAdapter(adapter = ConfigBranchSerializer.class) public class ConfigBranch extends ConfigEntry>> implements DelegateDynamic { public ConfigBranch() { super(new TypeToken>>(){}.getRawType()); diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigEntry.java b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigEntry.java index bdd872f..b2b8087 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigEntry.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigEntry.java @@ -1,14 +1,17 @@ package io.gitlab.jfronny.respackopts.model.tree; +import io.gitlab.jfronny.commons.serialize.databind.api.SerializeWithAdapter; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; import io.gitlab.jfronny.muscript.data.dynamic.DynamicBase; import io.gitlab.jfronny.respackopts.Respackopts; +import io.gitlab.jfronny.respackopts.gson.ConfigEntryTypeAdapter; import io.gitlab.jfronny.respackopts.model.enums.ConfigSyncMode; import io.gitlab.jfronny.respackopts.model.enums.PackReloadType; import io.gitlab.jfronny.respackopts.util.IndentingStringBuilder; import java.util.Objects; +@SerializeWithAdapter(adapter = ConfigEntryTypeAdapter.class) public abstract class ConfigEntry implements DynamicBase { private final Class entryClass; private T defaultValue; @@ -67,6 +70,10 @@ public abstract class ConfigEntry implements DynamicBase { defaultValue = value; return defaultValue; } + + public boolean hasDefault() { + return defaultValue != null; + } public void sync(ConfigEntry source, ConfigSyncMode mode) { if (mode == ConfigSyncMode.RESPACK_LOAD) diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigEnumEntry.java b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigEnumEntry.java index c2b030f..2046610 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigEnumEntry.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigEnumEntry.java @@ -1,16 +1,20 @@ package io.gitlab.jfronny.respackopts.model.tree; +import io.gitlab.jfronny.commons.serialize.databind.api.SerializeWithAdapter; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; +import io.gitlab.jfronny.muscript.data.additional.DEnum; +import io.gitlab.jfronny.muscript.data.additional.DelegateDynamic; import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; -import io.gitlab.jfronny.muscript.data.dynamic.additional.DEnum; -import io.gitlab.jfronny.muscript.data.dynamic.additional.DelegateDynamic; 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.*; +@SerializeWithAdapter(adapter = EnumEntrySerializer.class) public class ConfigEnumEntry extends ConfigEntry implements DelegateDynamic { private final List values = new ArrayList<>(); private Integer nextValue; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigNumericEntry.java b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigNumericEntry.java index 3d9982e..1e287d4 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigNumericEntry.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigNumericEntry.java @@ -1,14 +1,18 @@ package io.gitlab.jfronny.respackopts.model.tree; +import io.gitlab.jfronny.commons.serialize.databind.api.SerializeWithAdapter; 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; import java.util.Objects; +@SerializeWithAdapter(adapter = NumericEntrySerializer.class) public class ConfigNumericEntry extends ConfigEntry implements DNumber { private Double min = null; private Double max = null; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/muscript/MuScriptScope.java b/src/main/java/io/gitlab/jfronny/respackopts/muscript/MuScriptScope.java index c724bc2..6e37345 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/muscript/MuScriptScope.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/muscript/MuScriptScope.java @@ -1,11 +1,13 @@ package io.gitlab.jfronny.respackopts.muscript; -import io.gitlab.jfronny.muscript.compiler.MuScriptVersion; -import io.gitlab.jfronny.muscript.compiler.SourceFS; -import io.gitlab.jfronny.muscript.data.Scope; -import io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal; -import io.gitlab.jfronny.muscript.gson.GsonLib; -import io.gitlab.jfronny.muscript.libs.*; +import io.gitlab.jfronny.muscript.core.MuScriptVersion; +import io.gitlab.jfronny.muscript.core.SourceFS; +import io.gitlab.jfronny.muscript.data.additional.DFinal; +import io.gitlab.jfronny.muscript.data.additional.context.Scope; +import io.gitlab.jfronny.muscript.data.additional.libs.IOLib; +import io.gitlab.jfronny.muscript.data.additional.libs.IOWrapper; +import io.gitlab.jfronny.muscript.data.additional.libs.StandardLib; +import io.gitlab.jfronny.muscript.json.JsonLib; import io.gitlab.jfronny.respackopts.model.cache.CachedPackState; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.VersionParsingException; @@ -32,7 +34,7 @@ public class MuScriptScope { .map(c -> predicate.test(c.getMetadata().getVersion())) .orElse(false)); }); - if (version.contains(ScopeVersion.V13)) scope = GsonLib.addTo(scope); + if (version.contains(ScopeVersion.V13)) scope = JsonLib.addTo(scope); map.put(version, scope); } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/muscript/RespackoptsFS.java b/src/main/java/io/gitlab/jfronny/respackopts/muscript/RespackoptsFS.java index 067323a..db38199 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/muscript/RespackoptsFS.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/muscript/RespackoptsFS.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.respackopts.muscript; import io.gitlab.jfronny.libjf.ResourcePath; -import io.gitlab.jfronny.muscript.compiler.SourceFS; +import io.gitlab.jfronny.muscript.core.SourceFS; import io.gitlab.jfronny.respackopts.Respackopts; import net.minecraft.resource.*; import net.minecraft.util.Identifier; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/muscript/ScopeVersion.java b/src/main/java/io/gitlab/jfronny/respackopts/muscript/ScopeVersion.java index 92935a4..18c044e 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/muscript/ScopeVersion.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/muscript/ScopeVersion.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.respackopts.muscript; -import io.gitlab.jfronny.muscript.compiler.MuScriptVersion; +import io.gitlab.jfronny.muscript.core.MuScriptVersion; public enum ScopeVersion { V10(MuScriptVersion.V1), diff --git a/src/main/java/io/gitlab/jfronny/respackopts/server/ServerInstanceHolder.java b/src/main/java/io/gitlab/jfronny/respackopts/server/ServerInstanceHolder.java index d96d755..f077202 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/server/ServerInstanceHolder.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/server/ServerInstanceHolder.java @@ -40,10 +40,10 @@ public class ServerInstanceHolder { for (MinecraftServer server : SERVERS) { ResourcePackManager manager = server.getDataPackManager(); SaveProperties saveProperties = server.getSaveProperties(); - List enabled = Lists.newArrayList(manager.getEnabledNames()); + List enabled = Lists.newArrayList(manager.getEnabledIds()); manager.scanPacks(); List disabled = saveProperties.getDataConfiguration().dataPacks().getDisabled(); - for (String name : manager.getNames()) { + for (String name : manager.getIds()) { if (!disabled.contains(name) && !enabled.contains(name)) { enabled.add(name); } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/util/MetaCache.java b/src/main/java/io/gitlab/jfronny/respackopts/util/MetaCache.java index 564f52e..2afdf3e 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/util/MetaCache.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/util/MetaCache.java @@ -1,7 +1,8 @@ package io.gitlab.jfronny.respackopts.util; import io.gitlab.jfronny.commons.throwable.ThrowingBiConsumer; -import io.gitlab.jfronny.muscript.data.Scope; +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.muscript.data.additional.context.Scope; import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.RespackoptsConfig; import io.gitlab.jfronny.respackopts.filters.util.FileDependencyTracker; @@ -12,6 +13,7 @@ import io.gitlab.jfronny.respackopts.model.cache.CachedPackState; import io.gitlab.jfronny.respackopts.model.enums.ConfigSyncMode; import io.gitlab.jfronny.respackopts.model.enums.PackCapability; import io.gitlab.jfronny.respackopts.model.tree.ConfigBranch; +import io.gitlab.jfronny.respackopts.model.tree.GC_ConfigBranch; import io.gitlab.jfronny.respackopts.muscript.MuScriptScope; import io.gitlab.jfronny.respackopts.muscript.RespackoptsFS; import net.fabricmc.api.EnvType; @@ -113,8 +115,7 @@ public class MetaCache { private static void save(Path dataLocation, ConfigBranch branch) { try (Writer writer = Files.newBufferedWriter(dataLocation)) { - Respackopts.GSON.toJson(branch, writer); - writer.flush(); + GC_ConfigBranch.serialize(branch, writer, LibJf.LENIENT_TRANSPORT); } catch (IOException ex) { Respackopts.LOGGER.error("Could not save config", ex); } @@ -125,7 +126,7 @@ public class MetaCache { if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("Loading configs for: " + key.displayName()); try (Reader reader = Files.newBufferedReader(key.dataLocation())) { - ConfigBranch b = Respackopts.GSON.fromJson(reader, ConfigBranch.class); + ConfigBranch b = GC_ConfigBranch.deserialize(reader, LibJf.LENIENT_TRANSPORT); if (PACK_STATES.containsKey(key)) getBranch(key).sync(b, ConfigSyncMode.CONF_LOAD); } catch (IOException e) { @@ -139,7 +140,7 @@ public class MetaCache { } public static @Nullable CacheKey getKeyByPack(ResourcePack pack) { - return KEYS_BY_PACK_NAME.get(pack.getName()); + return KEYS_BY_PACK_NAME.get(pack.getId()); } public static @Nullable CacheKey getKeyByDisplayName(String displayName) {