diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 60c5b85b..8082c4d2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,10 +12,10 @@ jobs: matrix: # Use these Java versions java: [ - 17 # Minimum supported by Minecraft + 21 # Minimum supported by Minecraft ] # and run on both Linux and Windows - os: [ubuntu-20.04] + os: [ubuntu-22.04] runs-on: ${{ matrix.os }} steps: - name: checkout repository @@ -32,7 +32,7 @@ jobs: - name: build run: ./gradlew build - name: capture build artifacts - if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS + if: ${{ runner.os == 'Linux' && matrix.java == '21' }} # Only upload artifacts built from latest java on one OS uses: actions/upload-artifact@v2 with: name: Artifacts diff --git a/build.gradle b/build.gradle index 3cb849fc..7b93b5c2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ //file:noinspection GradlePackageVersionRange plugins { - id 'fabric-loom' version '1.4-SNAPSHOT' + id 'fabric-loom' version '1.6-SNAPSHOT' id 'maven-publish' } @@ -31,7 +31,7 @@ allprojects { } } - def targetJavaVersion = 17 + def targetJavaVersion = 21 tasks.withType(JavaCompile).configureEach { // ensure that the encoding is set to UTF-8, no matter what the system default is // this fixes some edge cases with special characters not displaying correctly @@ -119,7 +119,7 @@ loom { } dependencies { - modLocalRuntime("me.shedaniel:RoughlyEnoughItems-fabric:${project.rei_version}") +// modLocalRuntime("me.shedaniel:RoughlyEnoughItems-fabric:${project.rei_version}") modCompileOnly("me.shedaniel:RoughlyEnoughItems-default-plugin:${project.rei_version}") modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:${project.rei_version}") @@ -127,7 +127,7 @@ dependencies { // modLocalRuntime("dev.emi:emi-fabric:${project.emi_version}") modCompileOnly("com.terraformersmc:modmenu:${project.modmenu_version}") - modLocalRuntime("com.terraformersmc:modmenu:${project.modmenu_version}") +// modLocalRuntime("com.terraformersmc:modmenu:${project.modmenu_version}") api(include("blue.endless:jankson:${project.jankson_version}")) diff --git a/gradle.properties b/gradle.properties index b9c05edc..b01409cc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,16 +2,16 @@ org.gradle.jvmargs=-Xmx2G # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_base_version=1.20.3 -minecraft_version=1.20.3 -yarn_mappings=1.20.3+build.1 -loader_version=0.15.0 +minecraft_base_version=1.20.5 +minecraft_version=1.20.5 +yarn_mappings=1.20.5+build.1 +loader_version=0.15.10 # Mod Properties mod_version=0.12.6 maven_group=io.wispforest archives_base_name=owo-lib # Dependencies -fabric_version=0.91.1+1.20.3 +fabric_version=0.97.7+1.20.5 # https://maven.shedaniel.me/me/shedaniel/RoughlyEnoughItems-fabric/ rei_version=14.0.688 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a5952066..48c0a02c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/jitpack.yml b/jitpack.yml index 3e97b99c..a2027925 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,5 +1,2 @@ -before_install: - - wget https://github.com/sormuras/bach/raw/master/install-jdk.sh - - source install-jdk.sh --feature 16 - - jshell --version - +jdk: + - openjdk21 \ No newline at end of file diff --git a/src/main/java/io/wispforest/owo/client/screens/ScreenInternals.java b/src/main/java/io/wispforest/owo/client/screens/ScreenInternals.java index 46c610b8..8ae123ac 100644 --- a/src/main/java/io/wispforest/owo/client/screens/ScreenInternals.java +++ b/src/main/java/io/wispforest/owo/client/screens/ScreenInternals.java @@ -1,38 +1,70 @@ package io.wispforest.owo.client.screens; import io.wispforest.owo.Owo; +import io.wispforest.owo.serialization.Endec; +import io.wispforest.owo.serialization.endec.BuiltInEndecs; +import io.wispforest.owo.serialization.endec.StructEndecBuilder; import io.wispforest.owo.util.pond.OwoScreenHandlerExtension; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal public class ScreenInternals { - public static final Identifier LOCAL_PACKET = new Identifier("owo", "local_packet"); public static final Identifier SYNC_PROPERTIES = new Identifier("owo", "sync_screen_handler_properties"); public static void init() { - ServerPlayNetworking.registerGlobalReceiver(LOCAL_PACKET, (server, player, handler, buf, responseSender) -> { - buf.retain(); - server.execute(() -> { - var screenHandler = player.currentScreenHandler; + PayloadTypeRegistry.playS2C().register(LocalPacket.ID, LocalPacket.ENDEC.packetCodec()); + PayloadTypeRegistry.playC2S().register(LocalPacket.ID, LocalPacket.ENDEC.packetCodec()); + PayloadTypeRegistry.playS2C().register(SyncPropertiesPacket.ID, SyncPropertiesPacket.ENDEC.packetCodec()); - if (screenHandler == null) { - Owo.LOGGER.error("Received local packet for null ScreenHandler"); - return; - } + ServerPlayNetworking.registerGlobalReceiver(LocalPacket.ID, (payload, context) -> { + var screenHandler = context.player().currentScreenHandler; - ((OwoScreenHandlerExtension) screenHandler).owo$handlePacket(buf, false); - buf.release(); - }); + if (screenHandler == null) { + Owo.LOGGER.error("Received local packet for null ScreenHandler"); + return; + } + + ((OwoScreenHandlerExtension) screenHandler).owo$handlePacket(payload, false); }); } + public record LocalPacket(int packetId, PacketByteBuf payload) implements CustomPayload { + public static final Id ID = new Id<>(new Identifier("owo", "local_packet")); + public static final Endec ENDEC = StructEndecBuilder.of( + Endec.VAR_INT.fieldOf("packetId", LocalPacket::packetId), + BuiltInEndecs.PACKET_BYTE_BUF.fieldOf("payload", LocalPacket::payload), + LocalPacket::new + ); + + @Override + public Id getId() { + return ID; + } + } + + public record SyncPropertiesPacket(PacketByteBuf payload) implements CustomPayload { + public static final Id ID = new Id<>(SYNC_PROPERTIES); + public static final Endec ENDEC = StructEndecBuilder.of( + BuiltInEndecs.PACKET_BYTE_BUF.fieldOf("payload", SyncPropertiesPacket::payload), + SyncPropertiesPacket::new + ); + + @Override + public Id getId() { + return ID; + } + } + @Environment(EnvType.CLIENT) public static class Client { public static void init() { @@ -41,38 +73,26 @@ public static void init() { ((OwoScreenHandlerExtension) handled.getScreenHandler()).owo$attachToPlayer(client.player); }); - ClientPlayNetworking.registerGlobalReceiver(LOCAL_PACKET, (client, handler, buf, responseSender) -> { - if (client.player == null) return; - - buf.retain(); - client.execute(() -> { - var screenHandler = client.player.currentScreenHandler; + ClientPlayNetworking.registerGlobalReceiver(LocalPacket.ID, (payload, context) -> { + var screenHandler = context.player().currentScreenHandler; - if (screenHandler == null) { - Owo.LOGGER.error("Received local packet for null ScreenHandler"); - return; - } + if (screenHandler == null) { + Owo.LOGGER.error("Received local packet for null ScreenHandler"); + return; + } - ((OwoScreenHandlerExtension) screenHandler).owo$handlePacket(buf, true); - buf.release(); - }); + ((OwoScreenHandlerExtension) screenHandler).owo$handlePacket(payload, true); }); - ClientPlayNetworking.registerGlobalReceiver(SYNC_PROPERTIES, (client, handler, buf, responseSender) -> { - buf.retain(); - - client.execute(() -> { - if (client.player == null) return; - - if (client.player.currentScreenHandler == null) { - Owo.LOGGER.error("Received sync properties packet for null ScreenHandler"); - return; - } + ClientPlayNetworking.registerGlobalReceiver(SyncPropertiesPacket.ID, (payload, context) -> { + var screenHandler = context.player().currentScreenHandler; - ((OwoScreenHandlerExtension) client.player.currentScreenHandler).owo$readPropertySync(buf); + if (screenHandler == null) { + Owo.LOGGER.error("Received sync properties packet for null ScreenHandler"); + return; + } - buf.release(); - }); + ((OwoScreenHandlerExtension) screenHandler).owo$readPropertySync(payload); }); } } diff --git a/src/main/java/io/wispforest/owo/command/debug/DumpdataCommand.java b/src/main/java/io/wispforest/owo/command/debug/DumpdataCommand.java index 7f6d9fb0..c8091684 100644 --- a/src/main/java/io/wispforest/owo/command/debug/DumpdataCommand.java +++ b/src/main/java/io/wispforest/owo/command/debug/DumpdataCommand.java @@ -8,10 +8,13 @@ import io.wispforest.owo.Owo; import io.wispforest.owo.ops.TextOps; import net.minecraft.command.argument.NbtPathArgumentType; +import net.minecraft.component.ComponentChanges; +import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.projectile.ProjectileUtil; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtHelper; +import net.minecraft.nbt.NbtOps; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.server.command.ServerCommandSource; @@ -59,18 +62,18 @@ private static int executeItem(CommandContext context, NbtP informationHeader(source, "Item"); sendIdentifier(source, stack.getItem(), Registries.ITEM); - if (stack.getItem().isDamageable()) { - feedback(source, TextOps.withColor("Durability: §" + stack.getItem().getMaxDamage(), + if (stack.get(DataComponentTypes.MAX_DAMAGE) != null) { + feedback(source, TextOps.withColor("Durability: §" + stack.get(DataComponentTypes.MAX_DAMAGE), TextOps.color(Formatting.GRAY), KEY_BLUE)); } else { feedback(source, TextOps.withFormatting("Not damageable", Formatting.GRAY)); } - if (context.getSource().getPlayer().getMainHandStack().hasNbt()) { - feedback(source, TextOps.withFormatting("NBT" + formatPath(path) + ": ", Formatting.GRAY) - .append(NbtHelper.toPrettyPrintedText(getPath(stack.getNbt(), path)))); + if (!stack.getComponentChanges().isEmpty()) { + feedback(source, TextOps.withFormatting("Component changes" + formatPath(path) + ": ", Formatting.GRAY) + .append(NbtHelper.toPrettyPrintedText(getPath(ComponentChanges.CODEC.encodeStart(NbtOps.INSTANCE, stack.getComponentChanges()).getOrThrow(), path)))); } else { - feedback(source, TextOps.withFormatting("No NBT", Formatting.GRAY)); + feedback(source, TextOps.withFormatting("No component changes", Formatting.GRAY)); } feedback(source, TextOps.withFormatting("-----------------------", Formatting.GRAY)); @@ -144,7 +147,7 @@ private static int executeBlock(CommandContext context, Nbt final var blockEntity = player.getWorld().getBlockEntity(pos); if (blockEntity != null) { feedback(source, TextOps.withFormatting("Block Entity NBT" + formatPath(path) + ": ", Formatting.GRAY) - .append(NbtHelper.toPrettyPrintedText(getPath(blockEntity.createNbt(), path)))); + .append(NbtHelper.toPrettyPrintedText(getPath(blockEntity.createNbt(player.getRegistryManager()), path)))); } else { feedback(source, TextOps.withFormatting("No block entity", Formatting.GRAY)); } diff --git a/src/main/java/io/wispforest/owo/command/debug/MakeLootContainerCommand.java b/src/main/java/io/wispforest/owo/command/debug/MakeLootContainerCommand.java index ad84ae6e..c5d0e145 100644 --- a/src/main/java/io/wispforest/owo/command/debug/MakeLootContainerCommand.java +++ b/src/main/java/io/wispforest/owo/command/debug/MakeLootContainerCommand.java @@ -6,6 +6,8 @@ import net.minecraft.command.CommandRegistryAccess; import net.minecraft.command.argument.IdentifierArgumentType; import net.minecraft.command.argument.ItemStackArgumentType; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; import net.minecraft.server.command.LootCommand; import net.minecraft.server.command.ServerCommandSource; @@ -26,7 +28,12 @@ private static int execute(CommandContext context) throws C var targetStack = ItemStackArgumentType.getItemStackArgument(context, "item").createStack(1, false); var tableId = IdentifierArgumentType.getIdentifier(context, "loot_table"); - targetStack.getOrCreateSubNbt("BlockEntityTag").putString("LootTable", tableId.toString()); + var blockEntityTag = targetStack.getOrDefault(DataComponentTypes.BLOCK_ENTITY_DATA, NbtComponent.DEFAULT); + blockEntityTag = blockEntityTag.apply(x -> { + x.putString("LootTable", tableId.toString()); + }); + targetStack.set(DataComponentTypes.BLOCK_ENTITY_DATA, blockEntityTag); + context.getSource().getPlayer().getInventory().offerOrDrop(targetStack); return 0; diff --git a/src/main/java/io/wispforest/owo/compat/rei/OwoReiPlugin.java b/src/main/java/io/wispforest/owo/compat/rei/OwoReiPlugin.java index 6f3702ea..b9ccc81a 100644 --- a/src/main/java/io/wispforest/owo/compat/rei/OwoReiPlugin.java +++ b/src/main/java/io/wispforest/owo/compat/rei/OwoReiPlugin.java @@ -140,19 +140,19 @@ private static void renderOverlay(Screen screen, Runnable renderFunction) { final var time = System.currentTimeMillis(); float scale = .75f + (float) (Math.sin(time / 500d) * .5f); - modelView.push(); + modelView.pushMatrix(); modelView.translate(screen.width / 2f - scale / 2f * screen.width, screen.height / 2f - scale / 2f * screen.height, 0); modelView.scale(scale, scale, 1f); modelView.translate((float) (Math.sin(time / 1000d) * .75f) * screen.width, (float) (Math.sin(time / 500d) * .75f) * screen.height, 0); modelView.translate(screen.width / 2f, screen.height / 2f, 0); - modelView.multiply(RotationAxis.POSITIVE_Z.rotationDegrees((float) (time / 25d % 360d))); + modelView.rotate(RotationAxis.POSITIVE_Z.rotationDegrees((float) (time / 25d % 360d))); modelView.translate(screen.width / -2f, screen.height / -2f, 0); for (int i = 0; i < 20; i++) { - modelView.push(); + modelView.pushMatrix(); modelView.translate(screen.width / 2f, screen.height / 2f, 0); - modelView.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(i * 18)); + modelView.rotate(RotationAxis.POSITIVE_Z.rotationDegrees(i * 18)); modelView.translate(screen.width / -2f, screen.height / -2f, 0); RenderSystem.applyModelViewMatrix(); @@ -160,10 +160,10 @@ private static void renderOverlay(Screen screen, Runnable renderFunction) { renderFunction.run(); GlStateManager._enableScissorTest(); ScissorStack.pop(); - modelView.pop(); + modelView.popMatrix(); } - modelView.pop(); + modelView.popMatrix(); RenderSystem.applyModelViewMatrix(); } else { ScissorStack.pushDirect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE); diff --git a/src/main/java/io/wispforest/owo/config/ConfigSynchronizer.java b/src/main/java/io/wispforest/owo/config/ConfigSynchronizer.java index b6f6597b..4f5e71a2 100644 --- a/src/main/java/io/wispforest/owo/config/ConfigSynchronizer.java +++ b/src/main/java/io/wispforest/owo/config/ConfigSynchronizer.java @@ -4,22 +4,22 @@ import io.wispforest.owo.Owo; import io.wispforest.owo.mixin.ServerCommonNetworkHandlerAccessor; import io.wispforest.owo.ops.TextOps; +import io.wispforest.owo.serialization.Endec; +import io.wispforest.owo.serialization.endec.BuiltInEndecs; +import io.wispforest.owo.serialization.endec.StructEndecBuilder; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.network.ClientConnection; import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.MutableText; import net.minecraft.text.Text; @@ -72,78 +72,56 @@ static void register(ConfigWrapper config) { return getClientOptions(player, config.name()); } - private static void write(PacketByteBuf packet, Option.SyncMode targetMode) { - packet.writeVarInt(KNOWN_CONFIGS.size()); - - var configBuf = PacketByteBufs.create(); - var optionBuf = PacketByteBufs.create(); + private static ConfigSyncPacket toPacket(Option.SyncMode targetMode) { + Map configs = new HashMap<>(); KNOWN_CONFIGS.forEach((configName, config) -> { - packet.writeString(configName); - - configBuf.resetReaderIndex().resetWriterIndex(); - configBuf.writeVarInt((int) config.allOptions().values().stream().filter(option -> option.syncMode().ordinal() >= targetMode.ordinal()).count()); + var entry = new ConfigEntry(new HashMap<>()); config.allOptions().forEach((key, option) -> { if (option.syncMode().ordinal() < targetMode.ordinal()) return; - configBuf.writeString(key.asString()); - - optionBuf.resetReaderIndex().resetWriterIndex(); + PacketByteBuf optionBuf = PacketByteBufs.create(); option.write(optionBuf); - configBuf.writeVarInt(optionBuf.readableBytes()); - configBuf.writeBytes(optionBuf); + entry.options().put(key.asString(), optionBuf); }); - packet.writeVarInt(configBuf.readableBytes()); - packet.writeBytes(configBuf); + configs.put(configName, entry); }); + + return new ConfigSyncPacket(configs); } - private static void read(PacketByteBuf buf, BiConsumer, PacketByteBuf> optionConsumer) { - int configCount = buf.readVarInt(); - for (int i = 0; i < configCount; i++) { - var configName = buf.readString(); + private static void read(ConfigSyncPacket packet, BiConsumer, PacketByteBuf> optionConsumer) { + for (var configEntry : packet.configs().entrySet()) { + var configName = configEntry.getKey(); var config = KNOWN_CONFIGS.get(configName); if (config == null) { Owo.LOGGER.error("Received overrides for unknown config '{}', skipping", configName); - - // skip size of current config - buf.skipBytes(buf.readVarInt()); continue; } - // ignore size - buf.readVarInt(); - - int optionCount = buf.readVarInt(); - for (int j = 0; j < optionCount; j++) { - var optionKey = new Option.Key(buf.readString()); + for (var optionEntry : configEntry.getValue().options().entrySet()) { + var optionKey = new Option.Key(optionEntry.getKey()); var option = config.optionForKey(optionKey); if (option == null) { Owo.LOGGER.error("Received override for unknown option '{}' in config '{}', skipping", optionKey, configName); - - // skip size of current option - buf.skipBytes(buf.readVarInt()); continue; } - // ignore size - buf.readVarInt(); - - optionConsumer.accept(option, buf); + optionConsumer.accept(option, optionEntry.getValue()); } } } @Environment(EnvType.CLIENT) - private static void applyClient(MinecraftClient client, ClientPlayNetworkHandler handler, PacketByteBuf buf, PacketSender sender) { + private static void applyClient(ConfigSyncPacket payload, ClientPlayNetworking.Context context) { Owo.LOGGER.info("Applying server overrides"); var mismatchedOptions = new HashMap, Object>(); - if (!(client.isIntegratedServerRunning() && client.getServer().isSingleplayer())) { - read(buf, (option, packetByteBuf) -> { + if (!(context.client().isIntegratedServerRunning() && context.client().getServer().isSingleplayer())) { + read(payload, (option, packetByteBuf) -> { var mismatchedValue = option.read(packetByteBuf); if (mismatchedValue != null) mismatchedOptions.put(option, mismatchedValue); }); @@ -174,48 +152,65 @@ private static void applyClient(MinecraftClient client, ClientPlayNetworkHandler errorMessage.append(TextOps.withFormatting("they require your client to be restarted\n", Formatting.GRAY)); errorMessage.append(TextOps.withFormatting("change them manually and restart if you want to join this server", Formatting.GRAY)); - handler.getConnection().disconnect(TextOps.concat(PREFIX, errorMessage)); + context.player().networkHandler.getConnection().disconnect(TextOps.concat(PREFIX, errorMessage)); return; } } Owo.LOGGER.info("Responding with client values"); - var packet = PacketByteBufs.create(); - write(packet, Option.SyncMode.INFORM_SERVER); - - sender.sendPacket(CONFIG_SYNC_CHANNEL, packet); + context.responseSender().sendPacket(toPacket(Option.SyncMode.INFORM_SERVER)); } - private static void applyServer(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender sender) { + private static void applyServer(ConfigSyncPacket payload, ServerPlayNetworking.Context context) { Owo.LOGGER.info("Receiving client config"); - var connection = ((ServerCommonNetworkHandlerAccessor) player.networkHandler).owo$getConnection(); + var connection = ((ServerCommonNetworkHandlerAccessor) context.player().networkHandler).owo$getConnection(); - read(buf, (option, optionBuf) -> { + read(payload, (option, optionBuf) -> { var config = CLIENT_OPTION_STORAGE.computeIfAbsent(connection, $ -> new HashMap<>()).computeIfAbsent(option.configName(), s -> new HashMap<>()); config.put(option.key(), optionBuf.read(option.endec())); }); } + private record ConfigSyncPacket(Map configs) implements CustomPayload { + public static final Id ID = new Id<>(CONFIG_SYNC_CHANNEL); + public static final Endec ENDEC = StructEndecBuilder.of( + ConfigEntry.ENDEC.mapOf().fieldOf("configs", ConfigSyncPacket::configs), + ConfigSyncPacket::new + ); + + @Override + public Id getId() { + return ID; + } + } + + private record ConfigEntry(Map options) { + public static final Endec ENDEC = StructEndecBuilder.of( + BuiltInEndecs.PACKET_BYTE_BUF.mapOf().fieldOf("options", ConfigEntry::options), + ConfigEntry::new + ); + } + static { + PayloadTypeRegistry.playS2C().register(ConfigSyncPacket.ID, ConfigSyncPacket.ENDEC.packetCodec()); + PayloadTypeRegistry.playC2S().register(ConfigSyncPacket.ID, ConfigSyncPacket.ENDEC.packetCodec()); + var earlyPhase = new Identifier("owo", "early"); ServerPlayConnectionEvents.JOIN.addPhaseOrdering(earlyPhase, Event.DEFAULT_PHASE); ServerPlayConnectionEvents.JOIN.register(earlyPhase, (handler, sender, server) -> { Owo.LOGGER.info("Sending server config values to client"); - var packet = PacketByteBufs.create(); - write(packet, Option.SyncMode.OVERRIDE_CLIENT); - - sender.sendPacket(CONFIG_SYNC_CHANNEL, packet); + sender.sendPacket(toPacket(Option.SyncMode.OVERRIDE_CLIENT)); }); if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { - ClientPlayNetworking.registerGlobalReceiver(CONFIG_SYNC_CHANNEL, ConfigSynchronizer::applyClient); + ClientPlayNetworking.registerGlobalReceiver(ConfigSyncPacket.ID, ConfigSynchronizer::applyClient); ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> { KNOWN_CONFIGS.forEach((name, config) -> config.forEachOption(Option::reattach)); }); } - ServerPlayNetworking.registerGlobalReceiver(CONFIG_SYNC_CHANNEL, ConfigSynchronizer::applyServer); + ServerPlayNetworking.registerGlobalReceiver(ConfigSyncPacket.ID, ConfigSynchronizer::applyServer); } } diff --git a/src/main/java/io/wispforest/owo/itemgroup/OwoItemSettings.java b/src/main/java/io/wispforest/owo/itemgroup/OwoItemSettings.java index 6b7e49f1..1c82eef2 100644 --- a/src/main/java/io/wispforest/owo/itemgroup/OwoItemSettings.java +++ b/src/main/java/io/wispforest/owo/itemgroup/OwoItemSettings.java @@ -2,9 +2,7 @@ import net.fabricmc.fabric.api.item.v1.CustomDamageHandler; import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider; -import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.FoodComponent; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.util.Hand; @@ -14,7 +12,7 @@ import java.util.function.BiConsumer; -public class OwoItemSettings extends FabricItemSettings { +public class OwoItemSettings extends Item.Settings { @Nullable private OwoItemGroup group = null; @@ -86,21 +84,11 @@ public OwoItemSettings customDamage(CustomDamageHandler handler) { return (OwoItemSettings) super.customDamage(handler); } - @Override - public OwoItemSettings food(FoodComponent foodComponent) { - return (OwoItemSettings) super.food(foodComponent); - } - @Override public OwoItemSettings maxCount(int maxCount) { return (OwoItemSettings) super.maxCount(maxCount); } - @Override - public OwoItemSettings maxDamageIfAbsent(int maxDamage) { - return (OwoItemSettings) super.maxDamageIfAbsent(maxDamage); - } - @Override public OwoItemSettings maxDamage(int maxDamage) { return (OwoItemSettings) super.maxDamage(maxDamage); @@ -120,5 +108,4 @@ public OwoItemSettings rarity(Rarity rarity) { public OwoItemSettings fireproof() { return (OwoItemSettings) super.fireproof(); } - } diff --git a/src/main/java/io/wispforest/owo/itemgroup/json/WrapperGroup.java b/src/main/java/io/wispforest/owo/itemgroup/json/WrapperGroup.java index 182c4a56..c6ada99b 100644 --- a/src/main/java/io/wispforest/owo/itemgroup/json/WrapperGroup.java +++ b/src/main/java/io/wispforest/owo/itemgroup/json/WrapperGroup.java @@ -34,9 +34,9 @@ public WrapperGroup(ItemGroup parent, Identifier parentId, List ta int parentRawId = Registries.ITEM_GROUP.getRawId(parent); - ((SimpleRegistryAccessor) Registries.ITEM_GROUP).owo$getValueToEntry().remove(parent); - ((SimpleRegistryAccessor) Registries.ITEM_GROUP).owo$getEntryToLifecycle().remove(parent); - ((SimpleRegistry) Registries.ITEM_GROUP).set(parentRawId, RegistryKey.of(RegistryKeys.ITEM_GROUP, parentId), this, Lifecycle.stable()); + // TODO: set doesn't exist anymore. figure out what to do. +// ((SimpleRegistryAccessor) Registries.ITEM_GROUP).owo$getValueToEntry().remove(parent); +// ((SimpleRegistry) Registries.ITEM_GROUP).set(parentRawId, RegistryKey.of(RegistryKeys.ITEM_GROUP, parentId), this, Lifecycle.stable()); ((ItemGroupAccessor) this).owo$setDisplayName(parent.getDisplayName()); ((ItemGroupAccessor) this).owo$setColumn(parent.getColumn()); diff --git a/src/main/java/io/wispforest/owo/mixin/ClientConfigurationNetworkHandlerMixin.java b/src/main/java/io/wispforest/owo/mixin/ClientConfigurationNetworkHandlerMixin.java new file mode 100644 index 00000000..1e61cd9b --- /dev/null +++ b/src/main/java/io/wispforest/owo/mixin/ClientConfigurationNetworkHandlerMixin.java @@ -0,0 +1,21 @@ +package io.wispforest.owo.mixin; + +import io.wispforest.owo.network.OwoClientConnectionExtension; +import io.wispforest.owo.network.OwoHandshake; +import net.minecraft.client.network.ClientConfigurationNetworkHandler; +import net.minecraft.network.ClientConnection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(ClientConfigurationNetworkHandler.class) +public class ClientConfigurationNetworkHandlerMixin { + + @ModifyArg(method = "onReady", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;(Lnet/minecraft/client/MinecraftClient;Lnet/minecraft/network/ClientConnection;Lnet/minecraft/client/network/ClientConnectionState;)V")) + private ClientConnection applyChannelSet(ClientConnection connection) { + ((OwoClientConnectionExtension) connection).owo$setChannelSet(OwoHandshake.clientChannelSet); + OwoHandshake.clientChannelSet = null; + + return connection; + } +} diff --git a/src/main/java/io/wispforest/owo/mixin/ForwardingDynamicOpsAccessor.java b/src/main/java/io/wispforest/owo/mixin/ForwardingDynamicOpsAccessor.java new file mode 100644 index 00000000..55c00c77 --- /dev/null +++ b/src/main/java/io/wispforest/owo/mixin/ForwardingDynamicOpsAccessor.java @@ -0,0 +1,12 @@ +package io.wispforest.owo.mixin; + +import com.mojang.serialization.DynamicOps; +import net.minecraft.util.dynamic.ForwardingDynamicOps; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ForwardingDynamicOps.class) +public interface ForwardingDynamicOpsAccessor { + @Accessor("delegate") + DynamicOps owo$delegate(); +} diff --git a/src/main/java/io/wispforest/owo/mixin/ItemStackMixin.java b/src/main/java/io/wispforest/owo/mixin/ItemStackMixin.java deleted file mode 100644 index 3adbaaa0..00000000 --- a/src/main/java/io/wispforest/owo/mixin/ItemStackMixin.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.wispforest.owo.mixin; - -import io.wispforest.owo.serialization.SerializationAttribute; -import io.wispforest.owo.serialization.util.MapCarrier; -import io.wispforest.owo.serialization.endec.KeyedEndec; -import io.wispforest.owo.serialization.format.forwarding.ForwardingDeserializer; -import io.wispforest.owo.serialization.format.forwarding.ForwardingSerializer; -import io.wispforest.owo.serialization.format.nbt.NbtDeserializer; -import io.wispforest.owo.serialization.format.nbt.NbtSerializer; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@SuppressWarnings("AddedMixinMembersNamePattern") -@Mixin(ItemStack.class) -public abstract class ItemStackMixin implements MapCarrier { - - @Shadow - private @Nullable NbtCompound nbt; - - @Shadow - public abstract NbtCompound getOrCreateNbt(); - - @Override - public T getWithErrors(@NotNull KeyedEndec key) { - if (!this.has(key)) return key.defaultValue(); - return key.endec().decodeFully(e -> NbtDeserializer.of(e).withAttributes(SerializationAttribute.HUMAN_READABLE), this.nbt.get(key.key())); - } - - @Override - public void put(@NotNull KeyedEndec key, @NotNull T value) { - this.getOrCreateNbt().put(key.key(), key.endec().encodeFully(() -> NbtSerializer.of().withAttributes(SerializationAttribute.HUMAN_READABLE), value)); - } - - @Override - public void delete(@NotNull KeyedEndec key) { - if (this.nbt == null) return; - this.nbt.remove(key.key()); - } - - @Override - public boolean has(@NotNull KeyedEndec key) { - return this.nbt != null && this.nbt.contains(key.key()); - } -} diff --git a/src/main/java/io/wispforest/owo/mixin/NbtCompoundMixin.java b/src/main/java/io/wispforest/owo/mixin/NbtCompoundMixin.java index 9c262375..551702c2 100644 --- a/src/main/java/io/wispforest/owo/mixin/NbtCompoundMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/NbtCompoundMixin.java @@ -1,12 +1,11 @@ package io.wispforest.owo.mixin; -import io.wispforest.owo.serialization.SerializationAttribute; -import io.wispforest.owo.serialization.util.MapCarrier; +import io.wispforest.owo.serialization.SerializationAttributes; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.endec.KeyedEndec; -import io.wispforest.owo.serialization.format.forwarding.ForwardingDeserializer; -import io.wispforest.owo.serialization.format.forwarding.ForwardingSerializer; import io.wispforest.owo.serialization.format.nbt.NbtDeserializer; import io.wispforest.owo.serialization.format.nbt.NbtSerializer; +import io.wispforest.owo.serialization.util.MapCarrier; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import org.jetbrains.annotations.NotNull; @@ -28,14 +27,14 @@ public abstract class NbtCompoundMixin implements MapCarrier { public abstract boolean contains(String key); @Override - public T getWithErrors(@NotNull KeyedEndec key) { + public T getWithErrors(@NotNull KeyedEndec key, SerializationContext ctx) { if (!this.has(key)) return key.defaultValue(); - return key.endec().decodeFully(e -> NbtDeserializer.of(e).withAttributes(SerializationAttribute.HUMAN_READABLE), this.get(key.key())); + return key.endec().decodeFully(ctx.withAttributes(SerializationAttributes.HUMAN_READABLE), NbtDeserializer::of, this.get(key.key())); } @Override - public void put(@NotNull KeyedEndec key, @NotNull T value) { - this.put(key.key(), key.endec().encodeFully(() -> NbtSerializer.of().withAttributes(SerializationAttribute.HUMAN_READABLE), value)); + public void put(@NotNull KeyedEndec key, @NotNull T value, SerializationContext ctx) { + this.put(key.key(), key.endec().encodeFully(ctx.withAttributes(SerializationAttributes.HUMAN_READABLE), NbtSerializer::of, value)); } @Override diff --git a/src/main/java/io/wispforest/owo/mixin/PacketByteBufMixin.java b/src/main/java/io/wispforest/owo/mixin/PacketByteBufMixin.java index d1620a97..51da17ac 100644 --- a/src/main/java/io/wispforest/owo/mixin/PacketByteBufMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/PacketByteBufMixin.java @@ -1,6 +1,7 @@ package io.wispforest.owo.mixin; import io.wispforest.owo.serialization.Endec; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.format.bytebuf.ByteBufDeserializer; import io.wispforest.owo.serialization.format.bytebuf.ByteBufSerializer; import io.wispforest.owo.serialization.util.EndecBuffer; @@ -11,12 +12,12 @@ @Mixin(PacketByteBuf.class) public class PacketByteBufMixin implements EndecBuffer { @Override - public void write(Endec endec, T value) { - endec.encodeFully(() -> ByteBufSerializer.of((PacketByteBuf) (Object) this), value); + public void write(SerializationContext ctx, Endec endec, T value) { + endec.encodeFully(ctx, () -> ByteBufSerializer.of((PacketByteBuf) (Object) this), value); } @Override - public T read(Endec endec) { - return endec.decodeFully(ByteBufDeserializer::of, (PacketByteBuf) (Object) this); + public T read(SerializationContext ctx, Endec endec) { + return endec.decodeFully(ctx, ByteBufDeserializer::of, (PacketByteBuf) (Object) this); } } diff --git a/src/main/java/io/wispforest/owo/mixin/RegistryOpsAccessor.java b/src/main/java/io/wispforest/owo/mixin/RegistryOpsAccessor.java new file mode 100644 index 00000000..44d3bca2 --- /dev/null +++ b/src/main/java/io/wispforest/owo/mixin/RegistryOpsAccessor.java @@ -0,0 +1,11 @@ +package io.wispforest.owo.mixin; + +import net.minecraft.registry.RegistryOps; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(RegistryOps.class) +public interface RegistryOpsAccessor { + @Accessor("registryInfoGetter") + RegistryOps.RegistryInfoGetter owo$infoGetter(); +} diff --git a/src/main/java/io/wispforest/owo/mixin/ScreenHandlerMixin.java b/src/main/java/io/wispforest/owo/mixin/ScreenHandlerMixin.java index 42fd680a..336435e2 100644 --- a/src/main/java/io/wispforest/owo/mixin/ScreenHandlerMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/ScreenHandlerMixin.java @@ -13,13 +13,13 @@ import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.screen.ScreenHandler; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; 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; @@ -91,36 +91,37 @@ public void sendMessage(@NotNull R message) { } var buf = PacketByteBufs.create(); - buf.writeVarInt(messageData.id()); buf.write(messageData.endec(), message); + var packet = new ScreenInternals.LocalPacket(messageData.id(), buf); + if (messageData.clientbound()) { if (!(this.owo$player instanceof ServerPlayerEntity serverPlayer)) { throw new NetworkException("Tried to send clientbound message on the server"); } - ServerPlayNetworking.send(serverPlayer, ScreenInternals.LOCAL_PACKET, buf); + ServerPlayNetworking.send(serverPlayer, packet); } else { if (!this.owo$player.getWorld().isClient) { throw new NetworkException("Tried to send serverbound message on the client"); } - this.owo$sendToServer(ScreenInternals.LOCAL_PACKET, buf); + this.owo$sendToServer(packet); } } + @Unique @Environment(EnvType.CLIENT) - private void owo$sendToServer(Identifier channel, PacketByteBuf data) { - ClientPlayNetworking.send(channel, data); + private void owo$sendToServer(CustomPayload payload) { + ClientPlayNetworking.send(payload); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) - public void owo$handlePacket(PacketByteBuf buf, boolean clientbound) { - int id = buf.readVarInt(); - ScreenhandlerMessageData messageData = (clientbound ? this.owo$clientboundMessages : this.owo$serverboundMessages).get(id); + public void owo$handlePacket(ScreenInternals.LocalPacket packet, boolean clientbound) { + ScreenhandlerMessageData messageData = (clientbound ? this.owo$clientboundMessages : this.owo$serverboundMessages).get(packet.packetId()); - messageData.handler().accept(buf.read(messageData.endec())); + messageData.handler().accept(packet.payload().read(messageData.endec())); } @Override @@ -131,12 +132,12 @@ public SyncedProperty createProperty(Class clazz, Endec endec, T in } @Override - public void owo$readPropertySync(PacketByteBuf buf) { - int count = buf.readVarInt(); + public void owo$readPropertySync(ScreenInternals.SyncPropertiesPacket packet) { + int count = packet.payload().readVarInt(); for (int i = 0; i < count; i++) { - int idx = buf.readVarInt(); - this.owo$properties.get(idx).read(buf); + int idx = packet.payload().readVarInt(); + this.owo$properties.get(idx).read(packet.payload()); } } @@ -152,6 +153,7 @@ private void syncOnSendContentUpdates(CallbackInfo ci) { this.syncProperties(); } + @Unique private void syncProperties() { if (this.owo$player == null) return; if (!(this.owo$player instanceof ServerPlayerEntity player)) return; @@ -174,7 +176,7 @@ private void syncProperties() { prop.write(buf); } - ServerPlayNetworking.send(player, ScreenInternals.SYNC_PROPERTIES, buf); + ServerPlayNetworking.send(player, new ScreenInternals.SyncPropertiesPacket(buf)); } } diff --git a/src/main/java/io/wispforest/owo/mixin/SetComponentsLootFunctionAccessor.java b/src/main/java/io/wispforest/owo/mixin/SetComponentsLootFunctionAccessor.java new file mode 100644 index 00000000..5df96824 --- /dev/null +++ b/src/main/java/io/wispforest/owo/mixin/SetComponentsLootFunctionAccessor.java @@ -0,0 +1,17 @@ +package io.wispforest.owo.mixin; + +import net.minecraft.component.ComponentChanges; +import net.minecraft.loot.condition.LootCondition; +import net.minecraft.loot.function.SetComponentsLootFunction; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +@Mixin(SetComponentsLootFunction.class) +public interface SetComponentsLootFunctionAccessor { + @Invoker("") + static SetComponentsLootFunction createSetComponentsLootFunction(List list, ComponentChanges componentChanges) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeManagerMixin.java b/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeManagerMixin.java index 6a652da5..cd24e47d 100644 --- a/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeManagerMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/recipe_remainders/RecipeManagerMixin.java @@ -9,6 +9,7 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.recipe.*; +import net.minecraft.registry.RegistryWrapper; import net.minecraft.util.Identifier; import net.minecraft.util.JsonHelper; import net.minecraft.util.Util; @@ -27,7 +28,7 @@ public abstract class RecipeManagerMixin { @Inject(method = "deserialize", at = @At(value = "RETURN")) - private static void deserializeRecipeSpecificRemainders(Identifier id, JsonObject json, CallbackInfoReturnable> cir) { + private static void deserializeRecipeSpecificRemainders(Identifier id, JsonObject json, RegistryWrapper.WrapperLookup registryLookup, CallbackInfoReturnable> cir) { if (!json.has("owo:remainders")) return; var remainders = new HashMap(); @@ -35,7 +36,7 @@ private static void deserializeRecipeSpecificRemainders(Identifier id, JsonObjec var item = JsonHelper.asItem(new JsonPrimitive(remainderEntry.getKey()), remainderEntry.getKey()); if (remainderEntry.getValue().isJsonObject()) { - var remainderStack = Util.getResult(ItemStack.RECIPE_RESULT_CODEC.parse(JsonOps.INSTANCE, remainderEntry.getValue().getAsJsonObject()), JsonParseException::new); + var remainderStack = ItemStack.CODEC.parse(JsonOps.INSTANCE, remainderEntry.getValue().getAsJsonObject()).getOrThrow(JsonParseException::new); remainders.put(item.value(), remainderStack); } else { var remainderItem = JsonHelper.asItem(remainderEntry.getValue(), "item"); diff --git a/src/main/java/io/wispforest/owo/mixin/text/LanguageMixin.java b/src/main/java/io/wispforest/owo/mixin/text/LanguageMixin.java index 61023489..50b65083 100644 --- a/src/main/java/io/wispforest/owo/mixin/text/LanguageMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/text/LanguageMixin.java @@ -1,11 +1,15 @@ package io.wispforest.owo.mixin.text; import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.serialization.JsonOps; import io.wispforest.owo.text.LanguageAccess; import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import net.minecraft.text.TextCodecs; import net.minecraft.util.JsonHelper; import net.minecraft.util.Language; +import net.minecraft.util.Util; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -24,7 +28,7 @@ private static String skipIfObjectOrArray(JsonElement el, String str, InputStrea if (!el.isJsonPrimitive() && LanguageAccess.textConsumer != null) { skipNext = true; - MutableText text = Text.Serialization.fromJsonTree(el); + MutableText text = (MutableText) TextCodecs.CODEC.parse(JsonOps.INSTANCE, el).getOrThrow(JsonParseException::new); LanguageAccess.textConsumer.accept(str, text); return ""; diff --git a/src/main/java/io/wispforest/owo/mixin/text/TextCodecsMixin.java b/src/main/java/io/wispforest/owo/mixin/text/TextCodecsMixin.java index e1bf6bce..30e01e0f 100644 --- a/src/main/java/io/wispforest/owo/mixin/text/TextCodecsMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/text/TextCodecsMixin.java @@ -21,7 +21,7 @@ private static Codec injectCustomTextTypesExpl if (!types.getClass().getComponentType().isAssignableFrom(TextContent.Type.class)) return codec; //noinspection unchecked - var customTextTypeCodec = Codecs.idChecked(StringIdentifiable::asString, s -> (T) CustomTextRegistry.typesMap().get(s).type()); + var customTextTypeCodec = Codec.stringResolver(StringIdentifiable::asString, s -> (T) CustomTextRegistry.typesMap().get(s).type()); return new Codec<>() { @Override diff --git a/src/main/java/io/wispforest/owo/mixin/ui/EntityRendererMixin.java b/src/main/java/io/wispforest/owo/mixin/ui/EntityRendererMixin.java index 54cadff0..e0626d3a 100644 --- a/src/main/java/io/wispforest/owo/mixin/ui/EntityRendererMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/ui/EntityRendererMixin.java @@ -24,13 +24,13 @@ public class EntityRendererMixin { protected EntityRenderDispatcher dispatcher; @Inject(method = "renderLabelIfPresent", at = @At("HEAD"), cancellable = true) - private void cancelLabel(T entity, Text text, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { + private void cancelLabel(T entity, Text text, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, float tickDelta, CallbackInfo ci) { if (((OwoEntityRenderDispatcherExtension) this.dispatcher).owo$showNametag()) return; ci.cancel(); } @Inject(method = "renderLabelIfPresent", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;multiply(Lorg/joml/Quaternionf;)V", shift = At.Shift.AFTER)) - private void adjustLabelRotation(T entity, Text text, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { + private void adjustLabelRotation(T entity, Text text, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, float tickDelta, CallbackInfo ci) { if (!((OwoEntityRenderDispatcherExtension) this.dispatcher).owo$counterRotate()) return; matrices.multiply(new Quaternionf(this.dispatcher.getRotation()).invert()); diff --git a/src/main/java/io/wispforest/owo/mixin/ui/SimpleRegistryAccessor.java b/src/main/java/io/wispforest/owo/mixin/ui/SimpleRegistryAccessor.java index 8658c54e..a51860a5 100644 --- a/src/main/java/io/wispforest/owo/mixin/ui/SimpleRegistryAccessor.java +++ b/src/main/java/io/wispforest/owo/mixin/ui/SimpleRegistryAccessor.java @@ -14,6 +14,4 @@ public interface SimpleRegistryAccessor { @Accessor("valueToEntry") Map> owo$getValueToEntry(); - @Accessor("entryToLifecycle") - Map owo$getEntryToLifecycle(); } diff --git a/src/main/java/io/wispforest/owo/mixin/ui/access/ClickableWidgetAccessor.java b/src/main/java/io/wispforest/owo/mixin/ui/access/ClickableWidgetAccessor.java index f66bf416..18d53f2f 100644 --- a/src/main/java/io/wispforest/owo/mixin/ui/access/ClickableWidgetAccessor.java +++ b/src/main/java/io/wispforest/owo/mixin/ui/access/ClickableWidgetAccessor.java @@ -1,6 +1,6 @@ package io.wispforest.owo.mixin.ui.access; -import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.tooltip.TooltipState; import net.minecraft.client.gui.widget.ClickableWidget; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -21,5 +21,5 @@ public interface ClickableWidgetAccessor { void owo$setY(int y); @Accessor("tooltip") - Tooltip owo$getTooltip(); + TooltipState owo$getTooltip(); } diff --git a/src/main/java/io/wispforest/owo/mixin/ui/layers/MouseMixin.java b/src/main/java/io/wispforest/owo/mixin/ui/layers/MouseMixin.java index 300b7009..885fe4a5 100644 --- a/src/main/java/io/wispforest/owo/mixin/ui/layers/MouseMixin.java +++ b/src/main/java/io/wispforest/owo/mixin/ui/layers/MouseMixin.java @@ -14,7 +14,7 @@ public class MouseMixin { @Shadow private int activeButton; - @Inject(method = "method_1602", at = @At("HEAD"), cancellable = true) + @Inject(method = "method_55795", at = @At("HEAD"), cancellable = true) private void captureScreenMouseDrag(Screen screen, double mouseX, double mouseY, double deltaX, double deltaY, CallbackInfo ci) { boolean handled = false; for (var instance : Layers.getInstances(screen)) { diff --git a/src/main/java/io/wispforest/owo/network/OwoHandshake.java b/src/main/java/io/wispforest/owo/network/OwoHandshake.java index 69578d92..faa04bea 100644 --- a/src/main/java/io/wispforest/owo/network/OwoHandshake.java +++ b/src/main/java/io/wispforest/owo/network/OwoHandshake.java @@ -5,8 +5,9 @@ import io.wispforest.owo.mixin.ServerCommonNetworkHandlerAccessor; import io.wispforest.owo.ops.TextOps; import io.wispforest.owo.particles.systems.ParticleSystemController; -import io.wispforest.owo.serialization.endec.BuiltInEndecs; import io.wispforest.owo.serialization.Endec; +import io.wispforest.owo.serialization.endec.BuiltInEndecs; +import io.wispforest.owo.serialization.endec.StructEndecBuilder; import io.wispforest.owo.util.OwoFreezer; import io.wispforest.owo.util.ServicesFrozenException; import net.fabricmc.api.EnvType; @@ -14,14 +15,13 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientConfigurationNetworkHandler; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerConfigurationNetworkHandler; import net.minecraft.text.MutableText; @@ -39,6 +39,9 @@ @ApiStatus.Internal public final class OwoHandshake { + @Environment(EnvType.CLIENT) + public static Set clientChannelSet; + private static final Endec> CHANNEL_HASHES_ENDEC = Endec.map(BuiltInEndecs.IDENTIFIER, Endec.INT); private static final MutableText PREFIX = TextOps.concat(Owo.PREFIX, Text.of("§chandshake failure\n")); @@ -70,19 +73,29 @@ public static void requireHandshake() { } static { + PayloadTypeRegistry.configurationS2C().register(HandshakeRequest.ID, HandshakeRequest.ENDEC.packetCodec()); + PayloadTypeRegistry.configurationC2S().register(HandshakeResponse.ID, HandshakeResponse.ENDEC.packetCodec()); + ServerConfigurationConnectionEvents.CONFIGURE.register(OwoHandshake::configureStart); - ServerConfigurationNetworking.registerGlobalReceiver(OwoHandshake.CHANNEL_ID, OwoHandshake::syncServer); + ServerConfigurationNetworking.registerGlobalReceiver(HandshakeResponse.ID, OwoHandshake::syncServer); if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { if (!ENABLED) { - ClientConfigurationNetworking.registerGlobalReceiver(OwoHandshake.OFF_CHANNEL_ID, (client, handler, buf, responseSender) -> {}); + ClientConfigurationNetworking.registerGlobalReceiver(HandshakeOff.ID, (payload, context) -> {}); } - ClientConfigurationNetworking.registerGlobalReceiver(OwoHandshake.CHANNEL_ID, OwoHandshake::syncClient); + ClientConfigurationNetworking.registerGlobalReceiver(HandshakeRequest.ID, OwoHandshake::syncClient); ClientConfigurationConnectionEvents.READY.register(OwoHandshake::handleReadyClient); - ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> QUERY_RECEIVED = false); - ClientConfigurationConnectionEvents.DISCONNECT.register((handler, client) -> QUERY_RECEIVED = false); + ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> { + QUERY_RECEIVED = false; + clientChannelSet = null; + }); + + ClientConfigurationConnectionEvents.DISCONNECT.register((handler, client) -> { + QUERY_RECEIVED = false; + clientChannelSet = null; + }); } } @@ -110,49 +123,38 @@ private static void configureStart(ServerConfigurationNetworkHandler handler, Mi return; } - var request = PacketByteBufs.create(); - writeHashes(request, OwoNetChannel.OPTIONAL_CHANNELS, OwoHandshake::hashChannel); - ServerConfigurationNetworking.send(handler, OwoHandshake.CHANNEL_ID, request); + var optionalChannels = formatHashes(OwoNetChannel.OPTIONAL_CHANNELS, OwoHandshake::hashChannel); + ServerConfigurationNetworking.send(handler, new HandshakeRequest(optionalChannels)); Owo.LOGGER.info("[Handshake] Sending channel packet"); } @Environment(EnvType.CLIENT) - private static void syncClient(MinecraftClient client, ClientConfigurationNetworkHandler handler, PacketByteBuf buf, PacketSender sender) { + private static void syncClient(HandshakeRequest request, ClientConfigurationNetworking.Context context) { Owo.LOGGER.info("[Handshake] Sending client channels"); QUERY_RECEIVED = true; - if (buf.readableBytes() > 0) { - final var serverOptionalChannels = buf.read(CHANNEL_HASHES_ENDEC); - ((OwoClientConnectionExtension) ((ClientCommonNetworkHandlerAccessor) handler).getConnection()).owo$setChannelSet(filterOptionalServices(serverOptionalChannels, OwoNetChannel.REGISTERED_CHANNELS, OwoHandshake::hashChannel)); - } + clientChannelSet = filterOptionalServices(request.optionalChannels(), OwoNetChannel.REGISTERED_CHANNELS, OwoHandshake::hashChannel); - var response = PacketByteBufs.create(); - writeHashes(response, OwoNetChannel.REQUIRED_CHANNELS, OwoHandshake::hashChannel); - writeHashes(response, ParticleSystemController.REGISTERED_CONTROLLERS, OwoHandshake::hashController); - writeHashes(response, OwoNetChannel.OPTIONAL_CHANNELS, OwoHandshake::hashChannel); + var requiredChannels = formatHashes(OwoNetChannel.REQUIRED_CHANNELS, OwoHandshake::hashChannel); + var requiredControllers = formatHashes(ParticleSystemController.REGISTERED_CONTROLLERS, OwoHandshake::hashController); + var optionalChannels = formatHashes(OwoNetChannel.OPTIONAL_CHANNELS, OwoHandshake::hashChannel); - sender.sendPacket(CHANNEL_ID, response); + context.responseSender().sendPacket(new HandshakeResponse(requiredChannels, requiredControllers, optionalChannels)); } - private static void syncServer(MinecraftServer server, ServerConfigurationNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { + private static void syncServer(HandshakeResponse response, ServerConfigurationNetworking.Context context) { Owo.LOGGER.info("[Handshake] Receiving client channels"); - final var clientChannels = buf.read(CHANNEL_HASHES_ENDEC); - final var clientParticleControllers = buf.read(CHANNEL_HASHES_ENDEC); - StringBuilder disconnectMessage = new StringBuilder(); - boolean isAllGood = verifyReceivedHashes("channels", clientChannels, OwoNetChannel.REQUIRED_CHANNELS, OwoHandshake::hashChannel, disconnectMessage); - isAllGood &= verifyReceivedHashes("controllers", clientParticleControllers, ParticleSystemController.REGISTERED_CONTROLLERS, OwoHandshake::hashController, disconnectMessage); + boolean isAllGood = verifyReceivedHashes("channels", response.requiredChannels(), OwoNetChannel.REQUIRED_CHANNELS, OwoHandshake::hashChannel, disconnectMessage); + isAllGood &= verifyReceivedHashes("controllers", response.requiredControllers(), ParticleSystemController.REGISTERED_CONTROLLERS, OwoHandshake::hashController, disconnectMessage); if (!isAllGood) { - handler.disconnect(TextOps.concat(PREFIX, Text.of(disconnectMessage.toString()))); + context.responseSender().disconnect(TextOps.concat(PREFIX, Text.of(disconnectMessage.toString()))); } - if (buf.readableBytes() > 0) { - final var clientOptionalChannels = buf.read(CHANNEL_HASHES_ENDEC); - ((OwoClientConnectionExtension) ((ServerCommonNetworkHandlerAccessor) handler).owo$getConnection()).owo$setChannelSet(filterOptionalServices(clientOptionalChannels, OwoNetChannel.OPTIONAL_CHANNELS, OwoHandshake::hashChannel)); - } + ((OwoClientConnectionExtension) ((ServerCommonNetworkHandlerAccessor) context.networkHandler()).owo$getConnection()).owo$setChannelSet(filterOptionalServices(response.optionalChannels(), OwoNetChannel.OPTIONAL_CHANNELS, OwoHandshake::hashChannel)); Owo.LOGGER.info("[Handshake] Handshake completed successfully"); } @@ -228,14 +230,14 @@ private static boolean verifyReceivedHashes(String serviceNamePlural, Map void writeHashes(PacketByteBuf buffer, Map values, ToIntFunction hashFunction) { + private static Map formatHashes(Map values, ToIntFunction hashFunction) { Map hashes = new HashMap<>(); for (var entry : values.entrySet()) { hashes.put(entry.getKey(), hashFunction.applyAsInt(entry.getValue())); } - buffer.write(CHANNEL_HASHES_ENDEC, hashes); + return hashes; } private static Pair, Set> findCollisions(Set first, Set second) { @@ -258,7 +260,7 @@ private static int hashChannel(OwoNetChannel channel) { for (var entry : channel.endecsByIndex.int2ObjectEntrySet()) { serializersHash += entry.getIntKey() * 31 + entry.getValue().getRecordClass().getName().hashCode(); } - return 31 * channel.packetId.hashCode() + serializersHash; + return 31 * channel.packetId.id().hashCode() + serializersHash; } private static int hashController(ParticleSystemController controller) { @@ -268,4 +270,46 @@ private static int hashController(ParticleSystemController controller) { } return 31 * controller.channelId.hashCode() + serializersHash; } + + public record HandshakeRequest(Map optionalChannels) implements CustomPayload { + + public static final Id ID = new Id<>(OwoHandshake.CHANNEL_ID); + public static final Endec ENDEC = StructEndecBuilder.of( + CHANNEL_HASHES_ENDEC.fieldOf("optionalChannels", HandshakeRequest::optionalChannels), + HandshakeRequest::new + ); + + @Override + public Id getId() { + return ID; + } + } + + public record HandshakeOff() implements CustomPayload { + public static final Id ID = new Id<>(OwoHandshake.OFF_CHANNEL_ID); + + @Override + public Id getId() { + return ID; + } + + } + + private record HandshakeResponse(Map requiredChannels, + Map requiredControllers, + Map optionalChannels) implements CustomPayload { + + public static final Id ID = new Id<>(OwoHandshake.CHANNEL_ID); + public static final Endec ENDEC = StructEndecBuilder.of( + CHANNEL_HASHES_ENDEC.fieldOf("requiredChannels", HandshakeResponse::requiredChannels), + CHANNEL_HASHES_ENDEC.fieldOf("requiredControllers", HandshakeResponse::requiredControllers), + CHANNEL_HASHES_ENDEC.fieldOf("optionalChannels", HandshakeResponse::optionalChannels), + HandshakeResponse::new + ); + + @Override + public Id getId() { + return ID; + } + } } diff --git a/src/main/java/io/wispforest/owo/network/OwoNetChannel.java b/src/main/java/io/wispforest/owo/network/OwoNetChannel.java index 1d21362f..e2eb2cf7 100644 --- a/src/main/java/io/wispforest/owo/network/OwoNetChannel.java +++ b/src/main/java/io/wispforest/owo/network/OwoNetChannel.java @@ -14,6 +14,7 @@ import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.PlayerLookup; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.loader.api.FabricLoader; @@ -22,6 +23,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.network.ClientConnection; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; @@ -71,7 +73,7 @@ public class OwoNetChannel { private final Reference2IntMap> deferredClientEndecs = new Reference2IntOpenHashMap<>(); - final Identifier packetId; + final CustomPayload.Id packetId; private final String ownerClassName; final boolean required; @@ -115,7 +117,7 @@ private OwoNetChannel(Identifier id, String ownerClassName, boolean required) { deferredClientEndecs.defaultReturnValue(-1); - this.packetId = id; + this.packetId = new CustomPayload.Id<>(id); this.ownerClassName = ownerClassName; this.required = required; @@ -124,17 +126,30 @@ private OwoNetChannel(Identifier id, String ownerClassName, boolean required) { OwoHandshake.requireHandshake(); } - ServerPlayNetworking.registerGlobalReceiver(packetId, (server, player, handler, buf, responseSender) -> { - int handlerIndex = buf.readVarInt(); - final Record message = buf.read(endecsByIndex.get(handlerIndex).endec); - server.execute(() -> serverHandlers.get(handlerIndex).handle(message, new ServerAccess(player))); + Endec serverEndec = Endec.dispatched( + index -> this.endecsByIndex.get(index).endec, + msg -> this.endecsByClass.get(msg.getClass()).serverHandlerIndex, + Endec.VAR_INT + ) + .xmap(x -> new MessagePayload(this.packetId, x), x -> x.message); + + Endec clientEndec = Endec.dispatched( + index -> this.endecsByIndex.get(-index).endec, + msg -> this.endecsByClass.get(msg.getClass()).clientHandlerIndex, + Endec.VAR_INT + ) + .xmap(x -> new MessagePayload(this.packetId, x), x -> x.message); + + PayloadTypeRegistry.playC2S().register(this.packetId, serverEndec.packetCodec()); + PayloadTypeRegistry.playS2C().register(this.packetId, clientEndec.packetCodec()); + + ServerPlayNetworking.registerGlobalReceiver(this.packetId, (payload, context) -> { + serverHandlers.get(endecsByClass.get(payload.message().getClass()).serverHandlerIndex).handle(payload.message, new ServerAccess(context.player())); }); if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { - ClientPlayNetworking.registerGlobalReceiver(packetId, (client, handler, buf, responseSender) -> { - int handlerIndex = buf.readVarInt(); - final Record message = buf.read(endecsByIndex.get(-handlerIndex).endec); - client.execute(() -> clientHandlers.get(handlerIndex).handle(message, new ClientAccess(handler))); + ClientPlayNetworking.registerGlobalReceiver(this.packetId, (payload, context) -> { + clientHandlers.get(endecsByClass.get(payload.message.getClass()).clientHandlerIndex).handle(payload.message, new ClientAccess(context.player().networkHandler)); }); } @@ -274,7 +289,7 @@ public boolean canSendToPlayer(ServerPlayNetworkHandler networkHandler) { if (required) return true; return OwoHandshake.isValidClient() ? - getChannelSet(((ServerCommonNetworkHandlerAccessor) networkHandler).owo$getConnection()).contains(this.packetId) + getChannelSet(((ServerCommonNetworkHandlerAccessor) networkHandler).owo$getConnection()).contains(this.packetId.id()) : ServerPlayNetworking.canSend(networkHandler, this.packetId); } @@ -283,7 +298,7 @@ public boolean canSendToServer() { if (required) return true; return OwoHandshake.isValidClient() ? - getChannelSet(MinecraftClient.getInstance().getNetworkHandler().getConnection()).contains(packetId) + getChannelSet(MinecraftClient.getInstance().getNetworkHandler().getConnection()).contains(this.packetId.id()) : ClientPlayNetworking.canSend(this.packetId); } @@ -438,7 +453,7 @@ public class ClientHandle { * @see #send(Record[]) */ public void send(R message) { - ClientPlayNetworking.send(OwoNetChannel.this.packetId, OwoNetChannel.this.encode(message, EnvType.SERVER)); + ClientPlayNetworking.send(new MessagePayload(packetId, message)); } /** @@ -465,7 +480,7 @@ public class ServerHandle { * @see #send(Record[]) */ public void send(R message) { - this.targets.forEach(player -> ServerPlayNetworking.send(player, OwoNetChannel.this.packetId, OwoNetChannel.this.encode(message, EnvType.CLIENT))); + this.targets.forEach(player -> ServerPlayNetworking.send(player, new MessagePayload(packetId, message))); this.targets = null; } @@ -480,7 +495,7 @@ public void send(R message) { public final void send(R... messages) { this.targets.forEach(player -> { for (R message : messages) { - ServerPlayNetworking.send(player, OwoNetChannel.this.packetId, OwoNetChannel.this.encode(message, EnvType.CLIENT)); + ServerPlayNetworking.send(player, new MessagePayload(packetId, message)); } }); this.targets = null; @@ -532,7 +547,7 @@ public interface EnvironmentAccess

{ private void verify() { if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { if (!this.deferredClientEndecs.isEmpty()) { - throw new NetworkException("Some deferred client handlers for channel " + packetId + " haven't been registered: " + deferredClientEndecs.keySet().stream().map(Class::getName).collect(Collectors.joining(", "))); + throw new NetworkException("Some deferred client handlers for channel " + this.packetId + " haven't been registered: " + deferredClientEndecs.keySet().stream().map(Class::getName).collect(Collectors.joining(", "))); } } } @@ -580,5 +595,12 @@ public Class getRecordClass(){ return this.recordClass; } } + + record MessagePayload(CustomPayload.Id id, Record message) implements CustomPayload { + @Override + public Id getId() { + return id; + } + } } diff --git a/src/main/java/io/wispforest/owo/offline/OfflineAdvancementLookup.java b/src/main/java/io/wispforest/owo/offline/OfflineAdvancementLookup.java index e0b75a39..8161109d 100644 --- a/src/main/java/io/wispforest/owo/offline/OfflineAdvancementLookup.java +++ b/src/main/java/io/wispforest/owo/offline/OfflineAdvancementLookup.java @@ -64,7 +64,7 @@ public static void put(UUID player, Map map) { try { Path advancementsPath = Owo.currentServer().getSavePath(WorldSavePath.ADVANCEMENTS); Path advancementPath = advancementsPath.resolve(player.toString() + ".json"); - JsonElement saved = Util.getResult(CODEC.encodeStart(JsonOps.INSTANCE, map), IllegalStateException::new); + JsonElement saved = CODEC.encodeStart(JsonOps.INSTANCE, map).getOrThrow(IllegalStateException::new); try (BufferedWriter bw = Files.newBufferedWriter(advancementPath)) { GSON.toJson(saved, bw); @@ -103,7 +103,7 @@ public static void put(UUID player, Map map) { JsonReader reader = new JsonReader(streamReader)) { reader.setLenient(false); JsonElement jsonElement = Streams.parse(reader); - parsedMap = Util.getResult(CODEC.parse(JsonOps.INSTANCE, jsonElement), JsonParseException::new); + parsedMap = CODEC.parse(JsonOps.INSTANCE, jsonElement).getOrThrow(JsonParseException::new); } for (Map.Entry entry : parsedMap.entrySet()) { diff --git a/src/main/java/io/wispforest/owo/offline/OfflineDataLookup.java b/src/main/java/io/wispforest/owo/offline/OfflineDataLookup.java index 099de921..cc44ae65 100644 --- a/src/main/java/io/wispforest/owo/offline/OfflineDataLookup.java +++ b/src/main/java/io/wispforest/owo/offline/OfflineDataLookup.java @@ -5,7 +5,7 @@ import net.minecraft.datafixer.Schemas; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtTagSizeTracker; +import net.minecraft.nbt.NbtSizeTracker; import net.minecraft.util.Util; import net.minecraft.util.WorldSavePath; import org.jetbrains.annotations.Nullable; @@ -61,7 +61,7 @@ public static void put(UUID player, NbtCompound nbt) { try { Path savedPlayersPath = Owo.currentServer().getSavePath(WorldSavePath.PLAYERDATA); Path savedDataPath = savedPlayersPath.resolve(player.toString() + ".dat"); - NbtCompound rawNbt = NbtIo.readCompressed(savedDataPath, NbtTagSizeTracker.ofUnlimitedBytes()); + NbtCompound rawNbt = NbtIo.readCompressed(savedDataPath, NbtSizeTracker.ofUnlimitedBytes()); int dataVersion = rawNbt.contains("DataVersion", 3) ? rawNbt.getInt("DataVersion") : -1; return DataFixTypes.PLAYER.update(Schemas.getFixer(), rawNbt, dataVersion); } catch (IOException e) { diff --git a/src/main/java/io/wispforest/owo/ops/ItemOps.java b/src/main/java/io/wispforest/owo/ops/ItemOps.java index 219cc478..498d63fd 100644 --- a/src/main/java/io/wispforest/owo/ops/ItemOps.java +++ b/src/main/java/io/wispforest/owo/ops/ItemOps.java @@ -1,9 +1,11 @@ package io.wispforest.owo.ops; +import io.wispforest.owo.Owo; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; +import net.minecraft.registry.RegistryWrapper; import net.minecraft.util.Hand; /** @@ -22,7 +24,7 @@ private ItemOps() { * @return {@code true} if addition can stack onto base */ public static boolean canStack(ItemStack base, ItemStack addition) { - return base.isEmpty() || (canIncreaseBy(base, addition.getCount()) && ItemStack.canCombine(base, addition)); + return base.isEmpty() || (canIncreaseBy(base, addition.getCount()) && ItemStack.areItemsAndComponentsEqual(base, addition)); } /** @@ -114,12 +116,10 @@ public static boolean decrementPlayerHandItem(PlayerEntity player, Hand hand, in * @param nbt The nbt compound to write to * @param key The key to prefix the stack with */ - public static void store(ItemStack stack, NbtCompound nbt, String key) { + public static void store(RegistryWrapper.WrapperLookup registries, ItemStack stack, NbtCompound nbt, String key) { if (stack.isEmpty()) return; - var stackNbt = new NbtCompound(); - stack.writeNbt(stackNbt); - nbt.put(key, stackNbt); + nbt.put(key, stack.encode(registries)); } /** @@ -130,11 +130,11 @@ public static void store(ItemStack stack, NbtCompound nbt, String key) { * @param key The key to load from * @return The deserialized stack */ - public static ItemStack get(NbtCompound nbt, String key) { + public static ItemStack get(RegistryWrapper.WrapperLookup registries, NbtCompound nbt, String key) { if (!nbt.contains(key, NbtElement.COMPOUND_TYPE)) return ItemStack.EMPTY; var stackNbt = nbt.getCompound(key); - return ItemStack.fromNbt(stackNbt); + return ItemStack.fromNbtOrEmpty(registries, stackNbt); } } diff --git a/src/main/java/io/wispforest/owo/ops/LootOps.java b/src/main/java/io/wispforest/owo/ops/LootOps.java index 743ac247..43a0100a 100644 --- a/src/main/java/io/wispforest/owo/ops/LootOps.java +++ b/src/main/java/io/wispforest/owo/ops/LootOps.java @@ -1,5 +1,6 @@ package io.wispforest.owo.ops; +import io.wispforest.owo.mixin.SetComponentsLootFunctionAccessor; import net.fabricmc.fabric.api.loot.v2.LootTableEvents; import net.minecraft.item.ItemConvertible; import net.minecraft.item.ItemStack; @@ -8,13 +9,13 @@ import net.minecraft.loot.entry.ItemEntry; import net.minecraft.loot.entry.LootPoolEntry; import net.minecraft.loot.function.SetCountLootFunction; -import net.minecraft.loot.function.SetNbtLootFunction; import net.minecraft.loot.provider.number.ConstantLootNumberProvider; import net.minecraft.loot.provider.number.UniformLootNumberProvider; import net.minecraft.util.Identifier; import org.jetbrains.annotations.ApiStatus; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.Supplier; @@ -67,7 +68,7 @@ public static void injectItemWithCount(ItemConvertible item, float chance, int m public static void injectItemStack(ItemStack stack, float chance, Identifier... targetTables) { ADDITIONS.put(targetTables, () -> ItemEntry.builder(stack.getItem()) .conditionally(RandomChanceLootCondition.builder(chance)) - .apply(SetNbtLootFunction.builder(stack.getOrCreateNbt().copy())) + .apply(() -> SetComponentsLootFunctionAccessor.createSetComponentsLootFunction(List.of(), stack.getComponentChanges())) .apply(SetCountLootFunction.builder(ConstantLootNumberProvider.create(stack.getCount()))) .build()); } @@ -87,9 +88,9 @@ public static boolean anyMatch(Identifier target, Identifier... predicates) { @ApiStatus.Internal public static void registerListener() { - LootTableEvents.MODIFY.register((resourceManager, manager, id, tableBuilder, source) -> { + LootTableEvents.MODIFY.register((key, tableBuilder, source) -> { ADDITIONS.forEach((identifiers, lootPoolEntrySupplier) -> { - if (anyMatch(id, identifiers)) tableBuilder.pool(LootPool.builder().with(lootPoolEntrySupplier.get())); + if (anyMatch(key.getValue(), identifiers)) tableBuilder.pool(LootPool.builder().with(lootPoolEntrySupplier.get())); }); }); } diff --git a/src/main/java/io/wispforest/owo/ops/WorldOps.java b/src/main/java/io/wispforest/owo/ops/WorldOps.java index 6588cda7..b474bbf6 100644 --- a/src/main/java/io/wispforest/owo/ops/WorldOps.java +++ b/src/main/java/io/wispforest/owo/ops/WorldOps.java @@ -118,7 +118,7 @@ public static void teleportToWorld(ServerPlayerEntity player, ServerWorld target player.addExperience(0); player.getStatusEffects().forEach(effect -> { - player.networkHandler.sendPacket(new EntityStatusEffectS2CPacket(player.getId(), effect)); + player.networkHandler.sendPacket(new EntityStatusEffectS2CPacket(player.getId(), effect, false)); }); } diff --git a/src/main/java/io/wispforest/owo/particles/systems/ParticleSystemController.java b/src/main/java/io/wispforest/owo/particles/systems/ParticleSystemController.java index 46f56bb8..ef1f08d8 100644 --- a/src/main/java/io/wispforest/owo/particles/systems/ParticleSystemController.java +++ b/src/main/java/io/wispforest/owo/particles/systems/ParticleSystemController.java @@ -1,10 +1,11 @@ package io.wispforest.owo.particles.systems; -import io.wispforest.owo.Owo; import io.wispforest.owo.network.NetworkException; import io.wispforest.owo.network.OwoHandshake; import io.wispforest.owo.serialization.Endec; +import io.wispforest.owo.serialization.endec.BuiltInEndecs; import io.wispforest.owo.serialization.endec.ReflectiveEndecBuilder; +import io.wispforest.owo.serialization.endec.StructEndecBuilder; import io.wispforest.owo.util.OwoFreezer; import io.wispforest.owo.util.ReflectionUtils; import io.wispforest.owo.util.VectorSerializer; @@ -14,17 +15,17 @@ import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.PlayerLookup; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; import org.jetbrains.annotations.ApiStatus; import java.util.HashMap; @@ -48,6 +49,7 @@ public class ParticleSystemController { public final Int2ObjectMap> systemsByIndex = new Int2ObjectOpenHashMap<>(); public final Identifier channelId; + private final CustomPayload.Id payloadId; private int maxIndex = 0; private final String ownerClassName; @@ -69,13 +71,31 @@ public ParticleSystemController(Identifier channelId) { } this.channelId = channelId; + this.payloadId = new CustomPayload.Id<>(channelId); this.ownerClassName = ReflectionUtils.getCallingClassName(2); + var instanceEndec = Endec., Integer>dispatched( + index -> { + @SuppressWarnings("unchecked") + var system = (ParticleSystem) systemsByIndex.get(index); + return system.endec.xmap(x -> new ParticleSystemInstance<>(system, x), x -> x.data); + }, + instance -> instance.system.index, + Endec.VAR_INT + ); + var endec = StructEndecBuilder.of( + BuiltInEndecs.VEC3D.fieldOf("pos", ParticleSystemPayload::pos), + instanceEndec.fieldOf("instance", ParticleSystemPayload::instance), + (pos, instance) -> new ParticleSystemPayload(payloadId, pos, instance) + ); + + PayloadTypeRegistry.playS2C().register(payloadId, endec.packetCodec()); + OwoHandshake.enable(); OwoHandshake.requireHandshake(); if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { - ClientPlayNetworking.registerGlobalReceiver(channelId, new Client()::handler); + ClientPlayNetworking.registerGlobalReceiver(payloadId, new Client()::handler); } REGISTERED_CONTROLLERS.put(channelId, this); @@ -133,13 +153,10 @@ public ParticleSystem registerDeferred(Class dataClass) { } void sendPacket(ParticleSystem particleSystem, ServerWorld world, Vec3d pos, T data) { - PacketByteBuf buf = PacketByteBufs.create(); - buf.writeVarInt(particleSystem.index); - VectorSerializer.write(buf, pos); - buf.write(particleSystem.endec, data); + ParticleSystemPayload payload = new ParticleSystemPayload(payloadId, pos, new ParticleSystemInstance<>(particleSystem, data)); for (var player : PlayerLookup.tracking(world, BlockPos.ofFloored(pos))) { - ServerPlayNetworking.send(player, channelId, buf); + ServerPlayNetworking.send(player, payload); } } @@ -161,22 +178,23 @@ private void verify() { }); } - @Environment(EnvType.CLIENT) - private class Client { - @SuppressWarnings("unchecked") - private void handler(MinecraftClient client, ClientPlayNetworkHandler networkHandler, PacketByteBuf buf, PacketSender sender) { - int index = buf.readVarInt(); - - Vec3d pos = VectorSerializer.read(buf); + private record ParticleSystemInstance(ParticleSystem system, T data) { + public void execute(World world, Vec3d pos) { + system.handler.executeParticleSystem(world, pos, data); + } + } - if (maxIndex <= index || index < 0) { - Owo.LOGGER.warn("Received unknown particle system index {} on channel {}", index, channelId); - return; - } + private record ParticleSystemPayload(CustomPayload.Id id, Vec3d pos, ParticleSystemInstance instance) implements CustomPayload { + @Override + public Id getId() { + return id; + } + } - ParticleSystem system = (ParticleSystem) systemsByIndex.get(index); - var data = buf.read(system.endec); - client.execute(() -> system.handler.executeParticleSystem(client.world, pos, data)); + @Environment(EnvType.CLIENT) + private static class Client { + private void handler(ParticleSystemPayload payload, ClientPlayNetworking.Context context) { + payload.instance.execute(context.client().world, payload.pos); } } } diff --git a/src/main/java/io/wispforest/owo/serialization/Deserializer.java b/src/main/java/io/wispforest/owo/serialization/Deserializer.java index 8284af8d..4ea25dd0 100644 --- a/src/main/java/io/wispforest/owo/serialization/Deserializer.java +++ b/src/main/java/io/wispforest/owo/serialization/Deserializer.java @@ -1,39 +1,34 @@ package io.wispforest.owo.serialization; -import io.wispforest.owo.serialization.format.forwarding.ForwardingDeserializer; import org.jetbrains.annotations.Nullable; import java.util.Iterator; import java.util.Optional; -import java.util.Set; import java.util.function.Function; public interface Deserializer { - default Deserializer withAttributes(SerializationAttribute... assumedAttributes) { - if (assumedAttributes.length == 0) return this; - return ForwardingDeserializer.of(this, assumedAttributes); + default SerializationContext setupContext(SerializationContext ctx) { + return ctx; } - Set attributes(); + byte readByte(SerializationContext ctx); + short readShort(SerializationContext ctx); + int readInt(SerializationContext ctx); + long readLong(SerializationContext ctx); + float readFloat(SerializationContext ctx); + double readDouble(SerializationContext ctx); - byte readByte(); - short readShort(); - int readInt(); - long readLong(); - float readFloat(); - double readDouble(); + int readVarInt(SerializationContext ctx); + long readVarLong(SerializationContext ctx); - int readVarInt(); - long readVarLong(); + boolean readBoolean(SerializationContext ctx); + String readString(SerializationContext ctx); + byte[] readBytes(SerializationContext ctx); + Optional readOptional(SerializationContext ctx, Endec endec); - boolean readBoolean(); - String readString(); - byte[] readBytes(); - Optional readOptional(Endec endec); - - Sequence sequence(Endec elementEndec); - Map map(Endec valueEndec); + Sequence sequence(SerializationContext ctx, Endec elementEndec); + Map map(SerializationContext ctx, Endec valueEndec); Struct struct(); V tryRead(Function, V> reader); @@ -65,12 +60,12 @@ interface Struct { * Decode the value of field {@code name} using {@code endec}. If no * such field exists in the serialized data, an exception is thrown */ - @Nullable F field(String name, Endec endec); + @Nullable F field(String name, SerializationContext ctx, Endec endec); /** * Decode the value of field {@code name} using {@code endec}. If no * such field exists in the serialized data, {@code defaultValue} is returned */ - @Nullable F field(String name, Endec endec, @Nullable F defaultValue); + @Nullable F field(String name, SerializationContext ctx, Endec endec, @Nullable F defaultValue); } } diff --git a/src/main/java/io/wispforest/owo/serialization/Endec.java b/src/main/java/io/wispforest/owo/serialization/Endec.java index 7513b84d..421c3b68 100644 --- a/src/main/java/io/wispforest/owo/serialization/Endec.java +++ b/src/main/java/io/wispforest/owo/serialization/Endec.java @@ -5,9 +5,17 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import io.wispforest.owo.mixin.ForwardingDynamicOpsAccessor; +import io.wispforest.owo.mixin.RegistryOpsAccessor; import io.wispforest.owo.serialization.endec.*; +import io.wispforest.owo.serialization.format.bytebuf.ByteBufDeserializer; +import io.wispforest.owo.serialization.format.bytebuf.ByteBufSerializer; import io.wispforest.owo.serialization.format.edm.*; -import net.minecraft.util.Util; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.registry.RegistryOps; +import net.minecraft.util.dynamic.ForwardingDynamicOps; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -17,61 +25,70 @@ * A combined encoder and decoder for values of type {@code T}. *

* To convert between single instances of {@code T} and their serialized form, - * use {@link #encodeFully(Supplier, Object)} and {@link #decodeFully(Function, Object)} + * use {@link #encodeFully(SerializationContext, Supplier, Object)} and {@link #decodeFully(SerializationContext, Function, Object)} */ public interface Endec { /** * Write all data required to reconstruct {@code value} into {@code serializer} */ - void encode(Serializer serializer, T value); + void encode(SerializationContext ctx, Serializer serializer, T value); /** - * Decode the data specified by {@link #encode(Serializer, Object)} and reconstruct + * Decode the data specified by {@link #encode(SerializationContext, Serializer, Object)} and reconstruct * the corresponding instance of {@code T}. *

* Endecs which intend to handle deserialization failure by decoding a different * structure on error, must wrap their initial reads in a call to {@link Deserializer#tryRead(Function)} * to ensure that deserializer state is restored for the subsequent attempt */ - T decode(Deserializer deserializer); + T decode(SerializationContext ctx, Deserializer deserializer); // --- /** - * Create a new serializer with result type {@code E}, call {@link #encode(Serializer, Object)} + * Create a new serializer with result type {@code E}, call {@link #encode(SerializationContext, Serializer, Object)} * once for the provided {@code value} and return the serializer's {@linkplain Serializer#result() result} */ - default E encodeFully(Supplier> serializerConstructor, T value) { + default E encodeFully(SerializationContext ctx, Supplier> serializerConstructor, T value) { var serializer = serializerConstructor.get(); - this.encode(serializer, value); + this.encode(serializer.setupContext(ctx), serializer, value); return serializer.result(); } + default E encodeFully(Supplier> serializerConstructor, T value) { + return this.encodeFully(SerializationContext.empty(), serializerConstructor, value); + } + /** * Create a new deserializer by calling {@code deserializerConstructor} with {@code value} - * and return the result of {@link #decode(Deserializer)} + * and return the result of {@link #decode(SerializationContext, Deserializer)} */ + default T decodeFully(SerializationContext ctx, Function> deserializerConstructor, E value) { + var deserializer = deserializerConstructor.apply(value); + return this.decode(deserializer.setupContext(ctx), deserializer); + } + default T decodeFully(Function> deserializerConstructor, E value) { - return this.decode(deserializerConstructor.apply(value)); + return this.decodeFully(SerializationContext.empty(), deserializerConstructor, value); } // --- Serializer Primitives --- - Endec VOID = Endec.of((serializer, unused) -> {}, deserializer -> null); + Endec VOID = Endec.of((ctx, serializer, unused) -> {}, (ctx, deserializer) -> null); - Endec BOOLEAN = Endec.of(Serializer::writeBoolean, Deserializer::readBoolean); - Endec BYTE = Endec.of(Serializer::writeByte, Deserializer::readByte); - Endec SHORT = Endec.of(Serializer::writeShort, Deserializer::readShort); - Endec INT = Endec.of(Serializer::writeInt, Deserializer::readInt); - Endec VAR_INT = Endec.of(Serializer::writeVarInt, Deserializer::readVarInt); - Endec LONG = Endec.of(Serializer::writeLong, Deserializer::readLong); - Endec VAR_LONG = Endec.of(Serializer::writeVarLong, Deserializer::readVarLong); - Endec FLOAT = Endec.of(Serializer::writeFloat, Deserializer::readFloat); - Endec DOUBLE = Endec.of(Serializer::writeDouble, Deserializer::readDouble); - Endec STRING = Endec.of(Serializer::writeString, Deserializer::readString); - Endec BYTES = Endec.of(Serializer::writeBytes, Deserializer::readBytes); + Endec BOOLEAN = Endec.of((ctx, serializer, value) -> serializer.writeBoolean(ctx, value), (ctx, deserializer) -> deserializer.readBoolean(ctx)); + Endec BYTE = Endec.of((ctx, serializer, value) -> serializer.writeByte(ctx, value), (ctx, deserializer) -> deserializer.readByte(ctx)); + Endec SHORT = Endec.of((ctx, serializer, value) -> serializer.writeShort(ctx, value), (ctx, deserializer) -> deserializer.readShort(ctx)); + Endec INT = Endec.of((ctx, serializer, value) -> serializer.writeInt(ctx, value), (ctx, deserializer) -> deserializer.readInt(ctx)); + Endec VAR_INT = Endec.of((ctx, serializer, value) -> serializer.writeVarInt(ctx, value), (ctx, deserializer) -> deserializer.readVarInt(ctx)); + Endec LONG = Endec.of((ctx, serializer, value) -> serializer.writeLong(ctx, value), (ctx, deserializer) -> deserializer.readLong(ctx)); + Endec VAR_LONG = Endec.of((ctx, serializer, value) -> serializer.writeVarLong(ctx, value), (ctx, deserializer) -> deserializer.readVarLong(ctx)); + Endec FLOAT = Endec.of((ctx, serializer, value) -> serializer.writeFloat(ctx, value), (ctx, deserializer) -> deserializer.readFloat(ctx)); + Endec DOUBLE = Endec.of((ctx, serializer, value) -> serializer.writeDouble(ctx, value), (ctx, deserializer) -> deserializer.readDouble(ctx)); + Endec STRING = Endec.of((ctx, serializer, value) -> serializer.writeString(ctx, value), (ctx, deserializer) -> deserializer.readString(ctx)); + Endec BYTES = Endec.of((ctx, serializer, bytes) -> serializer.writeBytes(ctx, bytes), (ctx, deserializer) -> deserializer.readBytes(ctx)); // --- Serializer compound types --- @@ -80,12 +97,12 @@ default T decodeFully(Function> deserializerConstructor, * serialized using this endec */ default Endec> listOf() { - return of((serializer, list) -> { - try (var sequence = serializer.sequence(this, list.size())) { + return of((ctx, serializer, list) -> { + try (var sequence = serializer.sequence(ctx, this, list.size())) { list.forEach(sequence::element); } - }, deserializer -> { - var sequenceState = deserializer.sequence(this); + }, (ctx, deserializer) -> { + var sequenceState = deserializer.sequence(ctx, this); var list = new ArrayList(sequenceState.estimatedSize()); sequenceState.forEachRemaining(list::add); @@ -99,12 +116,12 @@ default Endec> listOf() { * keys to values serialized using this endec */ default Endec> mapOf() { - return of((serializer, map) -> { - try (var mapState = serializer.map(this, map.size())) { + return of((ctx, serializer, map) -> { + try (var mapState = serializer.map(ctx, this, map.size())) { map.forEach(mapState::entry); } - }, deserializer -> { - var mapState = deserializer.map(this); + }, (ctx, deserializer) -> { + var mapState = deserializer.map(ctx, this); var map = new HashMap(mapState.estimatedSize()); mapState.forEachRemaining(entry -> map.put(entry.getKey(), entry.getValue())); @@ -119,23 +136,23 @@ default Endec> mapOf() { */ default Endec> optionalOf() { return of( - (serializer, value) -> serializer.writeOptional(this, value), - deserializer -> deserializer.readOptional(this) + (ctx, serializer, value) -> serializer.writeOptional(ctx, this, value), + (ctx, deserializer) -> deserializer.readOptional(ctx, this) ); } // --- Constructors --- - static Endec of(BiConsumer, T> encode, Function, T> decode) { + static Endec of(Encoder encode, Decoder decode) { return new Endec<>() { @Override - public void encode(Serializer serializer, T value) { - encode.accept(serializer, value); + public void encode(SerializationContext ctx, Serializer serializer, T value) { + encode.encode(ctx, serializer, value); } @Override - public T decode(Deserializer deserializer) { - return decode.apply(deserializer); + public T decode(SerializationContext ctx, Deserializer deserializer) { + return decode.decode(ctx, deserializer); } }; } @@ -163,12 +180,12 @@ static Endec> map(Endec keyEndec, Endec valueEndec) { * using {@code valueEndec} */ static Endec> map(Function keyToString, Function stringToKey, Endec valueEndec) { - return of((serializer, map) -> { - try (var mapState = serializer.map(valueEndec, map.size())) { + return of((ctx, serializer, map) -> { + try (var mapState = serializer.map(ctx, valueEndec, map.size())) { map.forEach((k, v) -> mapState.entry(keyToString.apply(k), v)); } - }, deserializer -> { - var mapState = deserializer.map(valueEndec); + }, (ctx, deserializer) -> { + var mapState = deserializer.map(ctx, valueEndec); var map = new HashMap(mapState.estimatedSize()); mapState.forEachRemaining(entry -> map.put(stringToKey.apply(entry.getKey()), entry.getValue())); @@ -185,7 +202,7 @@ static Endec> map(Function keyToString, Function> Endec forEnum(Class enumClass) { return ifAttr( - SerializationAttribute.HUMAN_READABLE, + SerializationAttributes.HUMAN_READABLE, STRING.xmap(name -> Arrays.stream(enumClass.getEnumConstants()).filter(e -> e.name().equals(name)).findFirst().get(), Enum::name) ).orElse( VAR_INT.xmap(ordinal -> enumClass.getEnumConstants()[ordinal], Enum::ordinal) @@ -210,8 +227,22 @@ static > Endec forEnum(Class enumClass) { */ static Endec ofCodec(Codec codec) { return of( - (serializer, value) -> EdmEndec.INSTANCE.encode(serializer, Util.getResult(codec.encodeStart(EdmOps.INSTANCE, value), IllegalStateException::new)), - deserializer -> Util.getResult(codec.parse(EdmOps.INSTANCE, EdmEndec.INSTANCE.decode(deserializer)), IllegalStateException::new) + (ctx, serializer, value) -> { + DynamicOps> ops = EdmOps.withContext(ctx); + if (ctx.hasAttribute(SerializationAttributes.REGISTRIES)) { + ops = RegistryOps.of(ops, ctx.getAttributeValue(SerializationAttributes.REGISTRIES).infoGetter()); + } + + EdmEndec.INSTANCE.encode(ctx, serializer, codec.encodeStart(ops, value).getOrThrow(IllegalStateException::new)); + }, + (ctx, deserializer) -> { + DynamicOps> ops = EdmOps.withContext(ctx); + if (ctx.hasAttribute(SerializationAttributes.REGISTRIES)) { + ops = RegistryOps.of(ops, ctx.getAttributeValue(SerializationAttributes.REGISTRIES).infoGetter()); + } + + return codec.parse(ops, EdmEndec.INSTANCE.decode(ctx, deserializer)).getOrThrow(IllegalStateException::new); + } ); } @@ -240,7 +271,7 @@ static Endec dispatchedStruct(Function> va * ... more functionality here * } * } - * + *

* which is implemented by {@code Harald} and {@code Albrecht}, whose endecs we have * stored in a map: *

{@code
@@ -263,12 +294,12 @@ static  Endec dispatchedStruct(Function> va
      *      new Identifier("herbert", "albrecht"), Albrecht.ENDEC
      * );
      * }
- * + *

* We could then create an endec capable of serializing either {@code Harald} or {@code Albrecht} as follows: *

{@code
      * Endec.dispatchedStruct(HERBERT_REGISTRY::get, Herbert::id, BuiltInEndecs.IDENTIFIER, "type")
      * }
- * + *

* If we now encode an instance of {@code Albrecht} to JSON using this endec, we'll get the following result: *

{@code
      * {
@@ -279,7 +310,7 @@ static  Endec dispatchedStruct(Function> va
      *      ]
      * }
      * }
- * + *

* And similarly, the following data could be used for decoding an instance of {@code Harald}: *

{@code
      * {
@@ -291,18 +322,18 @@ static  Endec dispatchedStruct(Function> va
     static  Endec dispatchedStruct(Function> variantToEndec, Function instanceToVariant, Endec variantEndec, String variantKey) {
         return new StructEndec<>() {
             @Override
-            public void encodeStruct(Serializer.Struct struct, T value) {
+            public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, T value) {
                 var variant = instanceToVariant.apply(value);
-                struct.field(variantKey, variantEndec, variant);
+                struct.field(variantKey, ctx, variantEndec, variant);
 
                 //noinspection unchecked
-                ((StructEndec) variantToEndec.apply(variant)).encodeStruct(struct, value);
+                ((StructEndec) variantToEndec.apply(variant)).encodeStruct(ctx, struct, value);
             }
 
             @Override
-            public T decodeStruct(Deserializer.Struct struct) {
-                var variant = struct.field(variantKey, variantEndec);
-                return variantToEndec.apply(variant).decodeStruct(struct);
+            public T decodeStruct(SerializationContext ctx, Deserializer.Struct struct) {
+                var variant = struct.field(variantKey, ctx, variantEndec);
+                return variantToEndec.apply(variant).decodeStruct(ctx, struct);
             }
         };
     }
@@ -317,18 +348,18 @@ public T decodeStruct(Deserializer.Struct struct) {
     static  Endec dispatched(Function> variantToEndec, Function instanceToVariant, Endec variantEndec) {
         return new StructEndec<>() {
             @Override
-            public void encodeStruct(Serializer.Struct struct, T value) {
+            public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, T value) {
                 var variant = instanceToVariant.apply(value);
-                struct.field("variant", variantEndec, variant);
+                struct.field("variant", ctx, variantEndec, variant);
 
                 //noinspection unchecked
-                struct.field("instance", ((Endec) variantToEndec.apply(variant)), value);
+                struct.field("instance", ctx, ((Endec) variantToEndec.apply(variant)), value);
             }
 
             @Override
-            public T decodeStruct(Deserializer.Struct struct) {
-                var variant = struct.field("variant", variantEndec);
-                return struct.field("instance", variantToEndec.apply(variant));
+            public T decodeStruct(SerializationContext ctx, Deserializer.Struct struct) {
+                var variant = struct.field("variant", ctx, variantEndec);
+                return struct.field("instance", ctx, variantToEndec.apply(variant));
             }
         };
     }
@@ -369,8 +400,8 @@ static  AttributeEndecBuilder ifAttr(SerializationAttribute attribute, End
      */
     default  Endec xmap(Function to, Function from) {
         return of(
-                (serializer, value) -> Endec.this.encode(serializer, from.apply(value)),
-                deserializer -> to.apply(Endec.this.decode(deserializer))
+                (ctx, serializer, value) -> Endec.this.encode(ctx, serializer, from.apply(value)),
+                (ctx, deserializer) -> to.apply(Endec.this.decode(ctx, deserializer))
         );
     }
 
@@ -389,13 +420,13 @@ default Endec validate(Consumer validator) {
     }
 
     /**
-     * Create a new endec which, if decoding using this endec's {@link #decode(Deserializer)} fails,
+     * Create a new endec which, if decoding using this endec's {@link #decode(SerializationContext, Deserializer)} fails,
      * instead tries to decode using {@code decodeOnError}
      */
     default Endec catchErrors(BiFunction, Exception, T> decodeOnError) {
-        return of(this::encode, deserializer -> {
+        return of(this::encode, (ctx, deserializer) -> {
             try {
-                return deserializer.tryRead(this::decode);
+                return deserializer.tryRead(deserializer1 -> decode(ctx, deserializer1));
             } catch (Exception e) {
                 return decodeOnError.apply(deserializer, e);
             }
@@ -431,21 +462,44 @@ default Endec> setOf() {
      * The serialized representation of a codec created through this method is generally
      * identical to that of a codec manually created to describe the same data
      */
-    default Codec codec(SerializationAttribute... assumedAttributes) {
+    default Codec codec(SerializationContext assumedContext) {
         return new Codec<>() {
             @Override
             public  DataResult> decode(DynamicOps ops, D input) {
                 try {
-                    return DataResult.success(new Pair<>(Endec.this.decode(LenientEdmDeserializer.of(ops.convertTo(EdmOps.INSTANCE, input)).withAttributes(assumedAttributes)), input));
+                    var rootOps = ops;
+                    while (rootOps instanceof ForwardingDynamicOps) rootOps = ((ForwardingDynamicOpsAccessor) ops).owo$delegate();
+
+                    var context = rootOps instanceof EdmOps edmOps
+                            ? edmOps.capturedContext().and(assumedContext)
+                            : assumedContext;
+
+                    if (ops instanceof RegistryOps registryOps) {
+                        context = context.withAttributes(RegistriesAttribute.infoGetterOnly(((RegistryOpsAccessor) registryOps).owo$infoGetter()));
+                    }
+
+                    return DataResult.success(new Pair<>(Endec.this.decode(context, LenientEdmDeserializer.of(ops.convertTo(EdmOps.withoutContext(), input))), input));
                 } catch (Exception e) {
                     return DataResult.error(e::getMessage);
                 }
             }
 
             @Override
+            @SuppressWarnings("unchecked")
             public  DataResult encode(T input, DynamicOps ops, D prefix) {
                 try {
-                    return DataResult.success(EdmOps.INSTANCE.convertTo(ops, Endec.this.encodeFully(() -> EdmSerializer.of().withAttributes(assumedAttributes), input)));
+                    var rootOps = ops;
+                    while (rootOps instanceof ForwardingDynamicOps) rootOps = ((ForwardingDynamicOpsAccessor) ops).owo$delegate();
+
+                    var context = rootOps instanceof EdmOps edmOps
+                            ? edmOps.capturedContext().and(assumedContext)
+                            : assumedContext;
+
+                    if (ops instanceof RegistryOps registryOps) {
+                        context = context.withAttributes(RegistriesAttribute.infoGetterOnly(((RegistryOpsAccessor) registryOps).owo$infoGetter()));
+                    }
+
+                    return DataResult.success(EdmOps.withoutContext().convertTo(ops, Endec.this.encodeFully(context, EdmSerializer::of, input)));
                 } catch (Exception e) {
                     return DataResult.error(e::getMessage);
                 }
@@ -453,6 +507,39 @@ public  DataResult encode(T input, DynamicOps ops, D prefix) {
         };
     }
 
+    default Codec codec() {
+        return this.codec(SerializationContext.empty());
+    }
+
+    // the fact that we lose context here is certainly far from ideal,
+    // but for the most part *shouldn't* matter. after all, ideally nobody
+    // should ever be nesting packet codecs into endecs - there's little
+    // point to doing that and transferring any kind of context data becomes
+    // mostly impossible because the system turns into one opaque spaghetti mess
+    //
+    // glisco, 28.04.2024
+    default  PacketCodec packetCodec() {
+        return new PacketCodec<>() {
+            @Override
+            public T decode(B buf) {
+                var ctx = buf instanceof RegistryByteBuf registryByteBuf
+                        ? SerializationContext.attributes(RegistriesAttribute.of(registryByteBuf.getRegistryManager()))
+                        : SerializationContext.empty();
+
+                return Endec.this.decode(ctx, ByteBufDeserializer.of(buf));
+            }
+
+            @Override
+            public void encode(B buf, T value) {
+                var ctx = buf instanceof RegistryByteBuf registryByteBuf
+                        ? SerializationContext.attributes(RegistriesAttribute.of(registryByteBuf.getRegistryManager()))
+                        : SerializationContext.empty();
+
+                Endec.this.encode(ctx, ByteBufSerializer.of(buf), value);
+            }
+        };
+    }
+
     /**
      * Create a new keyed endec which (de)serializes the entry
      * with key {@code key} into/from a {@link io.wispforest.owo.serialization.util.MapCarrier},
@@ -488,4 +575,14 @@ default  StructField optionalFieldOf(String name, Function getter
     default  StructField optionalFieldOf(String name, Function getter, Supplier<@Nullable T> defaultValue) {
         return new StructField<>(name, this.optionalOf().xmap(optional -> optional.orElseGet(defaultValue), Optional::ofNullable), getter, defaultValue);
     }
+
+    @FunctionalInterface
+    interface Encoder {
+        void encode(SerializationContext ctx, Serializer serializer, T value);
+    }
+
+    @FunctionalInterface
+    interface Decoder {
+        T decode(SerializationContext ctx, Deserializer serializer);
+    }
 }
diff --git a/src/main/java/io/wispforest/owo/serialization/RegistriesAttribute.java b/src/main/java/io/wispforest/owo/serialization/RegistriesAttribute.java
new file mode 100644
index 00000000..00a8f6ea
--- /dev/null
+++ b/src/main/java/io/wispforest/owo/serialization/RegistriesAttribute.java
@@ -0,0 +1,56 @@
+package io.wispforest.owo.serialization;
+
+import net.minecraft.registry.DynamicRegistryManager;
+import net.minecraft.registry.RegistryOps;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public final class RegistriesAttribute implements SerializationAttribute.Instance {
+
+    private final RegistryOps.RegistryInfoGetter infoGetter;
+    private final @Nullable DynamicRegistryManager registryManager;
+
+    private RegistriesAttribute(RegistryOps.RegistryInfoGetter infoGetter, @Nullable DynamicRegistryManager registryManager) {
+        this.infoGetter = infoGetter;
+        this.registryManager = registryManager;
+    }
+
+    public static RegistriesAttribute of(DynamicRegistryManager registryManager) {
+        return new RegistriesAttribute(
+                new RegistryOps.CachedRegistryInfoGetter(registryManager),
+                registryManager
+        );
+    }
+
+    @ApiStatus.Internal
+    public static RegistriesAttribute infoGetterOnly(RegistryOps.RegistryInfoGetter lookup) {
+        return new RegistriesAttribute(lookup, null);
+    }
+
+    public RegistryOps.RegistryInfoGetter infoGetter() {
+        return this.infoGetter;
+    }
+
+    public boolean hasRegistryManager() {
+        return this.registryManager != null;
+    }
+
+    public @NotNull DynamicRegistryManager registryManager() {
+        if (!this.hasRegistryManager()) {
+            throw new IllegalStateException("This instance of RegistriesAttribute does not supply a DynamicRegistryManager");
+        }
+
+        return this.registryManager;
+    }
+
+    @Override
+    public SerializationAttribute attribute() {
+        return SerializationAttributes.REGISTRIES;
+    }
+
+    @Override
+    public Object value() {
+        return this;
+    }
+}
diff --git a/src/main/java/io/wispforest/owo/serialization/SelfDescribedDeserializer.java b/src/main/java/io/wispforest/owo/serialization/SelfDescribedDeserializer.java
index c1ffec3d..09a67135 100644
--- a/src/main/java/io/wispforest/owo/serialization/SelfDescribedDeserializer.java
+++ b/src/main/java/io/wispforest/owo/serialization/SelfDescribedDeserializer.java
@@ -1,5 +1,5 @@
 package io.wispforest.owo.serialization;
 
 public interface SelfDescribedDeserializer extends Deserializer {
-     void readAny(Serializer visitor);
+     void readAny(SerializationContext ctx, Serializer visitor);
 }
diff --git a/src/main/java/io/wispforest/owo/serialization/SelfDescribedSerializer.java b/src/main/java/io/wispforest/owo/serialization/SelfDescribedSerializer.java
new file mode 100644
index 00000000..e9b48fd5
--- /dev/null
+++ b/src/main/java/io/wispforest/owo/serialization/SelfDescribedSerializer.java
@@ -0,0 +1,3 @@
+package io.wispforest.owo.serialization;
+
+public interface SelfDescribedSerializer extends Serializer {}
diff --git a/src/main/java/io/wispforest/owo/serialization/SerializationAttribute.java b/src/main/java/io/wispforest/owo/serialization/SerializationAttribute.java
index 083d0051..d5d45f63 100644
--- a/src/main/java/io/wispforest/owo/serialization/SerializationAttribute.java
+++ b/src/main/java/io/wispforest/owo/serialization/SerializationAttribute.java
@@ -1,21 +1,58 @@
 package io.wispforest.owo.serialization;
 
-public enum SerializationAttribute {
-    /**
-     * This format is self-describing - that is, the deserializer supports
-     * {@link SelfDescribedDeserializer#readAny(Serializer)} to decode its current element
-     * based purely on structure data stored in the input alone
-     * 

- * Endecs should use this to make decisions like storing a hierarchical data - * structure without writing identifying data - */ - SELF_DESCRIBING, - - /** - * This format is intended to be human-readable (and potentially -editable) - *

- * Endecs should use this to make decisions like representing a - * {@link net.minecraft.util.math.BlockPos} as an integer sequence instead of packing it into a long - */ - HUMAN_READABLE +public sealed abstract class SerializationAttribute permits SerializationAttribute.Marker, SerializationAttribute.WithValue { + + public final String name; + protected SerializationAttribute(String name) { + this.name = name; + } + + public static SerializationAttribute.Marker marker(String name) { + return new Marker(name); + } + + public static SerializationAttribute.WithValue withValue(String name) { + return new WithValue<>(name); + } + + public static final class Marker extends SerializationAttribute implements Instance { + private Marker(String name) { + super(name); + } + + @Override + public SerializationAttribute attribute() { + return this; + } + + @Override + public Object value() { + return null; + } + } + + public static final class WithValue extends SerializationAttribute { + private WithValue(String name) { + super(name); + } + + public Instance instance(T value) { + return new Instance() { + @Override + public SerializationAttribute attribute() { + return WithValue.this; + } + + @Override + public Object value() { + return value; + } + }; + } + } + + public interface Instance { + SerializationAttribute attribute(); + Object value(); + } } diff --git a/src/main/java/io/wispforest/owo/serialization/SerializationAttributes.java b/src/main/java/io/wispforest/owo/serialization/SerializationAttributes.java new file mode 100644 index 00000000..92f996bc --- /dev/null +++ b/src/main/java/io/wispforest/owo/serialization/SerializationAttributes.java @@ -0,0 +1,26 @@ +package io.wispforest.owo.serialization; + +public final class SerializationAttributes { + + /** + * This format is self-describing - that is, the deserializer supports + * {@link SelfDescribedDeserializer#readAny(SerializationContext, Serializer)} to decode its current element + * based purely on structure data stored in the input alone + *

+ * Endecs should use this to make decisions like storing a hierarchical data + * structure without writing identifying data + */ +// public static final SerializationAttribute.Marker SELF_DESCRIBING = SerializationAttribute.marker("self_describing"); + + /** + * This format is intended to be human-readable (and potentially -editable) + *

+ * Endecs should use this to make decisions like representing a + * {@link net.minecraft.util.math.BlockPos} as an integer sequence instead of packing it into a long + */ + public static final SerializationAttribute.Marker HUMAN_READABLE = SerializationAttribute.marker("human_readable"); + + public static final SerializationAttribute.WithValue REGISTRIES = SerializationAttribute.withValue("registries"); + + private SerializationAttributes() {} +} diff --git a/src/main/java/io/wispforest/owo/serialization/SerializationContext.java b/src/main/java/io/wispforest/owo/serialization/SerializationContext.java new file mode 100644 index 00000000..0c8159f2 --- /dev/null +++ b/src/main/java/io/wispforest/owo/serialization/SerializationContext.java @@ -0,0 +1,102 @@ +package io.wispforest.owo.serialization; + +import java.util.*; + +public final class SerializationContext { + + private static final SerializationContext EMPTY = new SerializationContext(Map.of(), Set.of()); + + private final Map attributeValues; + private final Set suppressedAttributes; + + private SerializationContext(Map attributeValues, Set suppressedAttributes) { + this.attributeValues = Collections.unmodifiableMap(attributeValues); + this.suppressedAttributes = Collections.unmodifiableSet(suppressedAttributes); + } + + public static SerializationContext empty() { + return EMPTY; + } + + public static SerializationContext attributes(SerializationAttribute.Instance... attributes) { + if (attributes.length == 0) return EMPTY; + return new SerializationContext(unpackAttributes(attributes), Set.of()); + } + + public static SerializationContext suppressed(SerializationAttribute... attributes) { + if (attributes.length == 0) return EMPTY; + return new SerializationContext(Map.of(), Set.of(attributes)); + } + + public SerializationContext withAttributes(SerializationAttribute.Instance... attributes) { + var newAttributes = unpackAttributes(attributes); + this.attributeValues.forEach((attribute, value) -> { + if (!newAttributes.containsKey(attribute)) { + newAttributes.put(attribute, value); + } + }); + + return new SerializationContext(newAttributes, this.suppressedAttributes); + } + + public SerializationContext withoutAttributes(SerializationAttribute... attributes) { + var newAttributes = new HashMap<>(this.attributeValues); + for (var attribute : attributes) { + newAttributes.remove(attribute); + } + + return new SerializationContext(newAttributes, this.suppressedAttributes); + } + + public SerializationContext withSuppressed(SerializationAttribute... attributes) { + var newSuppressed = new HashSet(this.suppressedAttributes); + newSuppressed.addAll(Arrays.asList(attributes)); + + return new SerializationContext(this.attributeValues, newSuppressed); + } + + public SerializationContext withoutSuppressed(SerializationAttribute... attributes) { + var newSuppressed = new HashSet<>(this.suppressedAttributes); + for (var attribute : attributes) { + newSuppressed.remove(attribute); + } + + return new SerializationContext(this.attributeValues, newSuppressed); + } + + public SerializationContext and(SerializationContext other) { + var newAttributeValues = new HashMap<>(this.attributeValues); + newAttributeValues.putAll(other.attributeValues); + + var newSuppressed = new HashSet<>(this.suppressedAttributes); + newSuppressed.addAll(other.suppressedAttributes); + + return new SerializationContext(newAttributeValues, newSuppressed); + } + + public boolean hasAttribute(SerializationAttribute attribute) { + return this.attributeValues.containsKey(attribute) && !this.suppressedAttributes.contains(attribute); + } + + @SuppressWarnings("unchecked") + public A getAttributeValue(SerializationAttribute.WithValue attribute) { + return (A) this.attributeValues.get(attribute); + } + + public A requireAttributeValue(SerializationAttribute.WithValue attribute) { + if (!this.hasAttribute(attribute)) { + throw new IllegalStateException("Context did not provide a value for attribute '" + attribute.name + "'"); + } + + return this.getAttributeValue(attribute); + } + + private static Map unpackAttributes(SerializationAttribute.Instance[] attributes) { + var attributeValues = new HashMap(); + for (var instance : attributes) { + attributeValues.put(instance.attribute(), instance.value()); + } + + return attributeValues; + } +} diff --git a/src/main/java/io/wispforest/owo/serialization/Serializer.java b/src/main/java/io/wispforest/owo/serialization/Serializer.java index 4b211b32..a2ea852a 100644 --- a/src/main/java/io/wispforest/owo/serialization/Serializer.java +++ b/src/main/java/io/wispforest/owo/serialization/Serializer.java @@ -1,37 +1,32 @@ package io.wispforest.owo.serialization; -import io.wispforest.owo.serialization.format.forwarding.ForwardingSerializer; import io.wispforest.owo.serialization.util.Endable; import java.util.Optional; -import java.util.Set; public interface Serializer { - default Serializer withAttributes(SerializationAttribute... assumedAttributes) { - if (assumedAttributes.length == 0) return this; - return ForwardingSerializer.of(this, assumedAttributes); + default SerializationContext setupContext(SerializationContext ctx) { + return ctx; } - Set attributes(); + void writeByte(SerializationContext ctx, byte value); + void writeShort(SerializationContext ctx, short value); + void writeInt(SerializationContext ctx, int value); + void writeLong(SerializationContext ctx, long value); + void writeFloat(SerializationContext ctx, float value); + void writeDouble(SerializationContext ctx, double value); - void writeByte(byte value); - void writeShort(short value); - void writeInt(int value); - void writeLong(long value); - void writeFloat(float value); - void writeDouble(double value); + void writeVarInt(SerializationContext ctx, int value); + void writeVarLong(SerializationContext ctx, long value); - void writeVarInt(int value); - void writeVarLong(long value); + void writeBoolean(SerializationContext ctx, boolean value); + void writeString(SerializationContext ctx, String value); + void writeBytes(SerializationContext ctx, byte[] bytes); + void writeOptional(SerializationContext ctx, Endec endec, Optional optional); - void writeBoolean(boolean value); - void writeString(String value); - void writeBytes(byte[] bytes); - void writeOptional(Endec endec, Optional optional); - - Sequence sequence(Endec elementEndec, int size); - Map map(Endec valueEndec, int size); + Sequence sequence(SerializationContext ctx, Endec elementEndec, int size); + Map map(SerializationContext ctx, Endec valueEndec, int size); Struct struct(); T result(); @@ -45,6 +40,6 @@ interface Map extends Endable { } interface Struct extends Endable { - Struct field(String name, Endec endec, F value); + Struct field(String name, SerializationContext ctx, Endec endec, F value); } } diff --git a/src/main/java/io/wispforest/owo/serialization/StructEndec.java b/src/main/java/io/wispforest/owo/serialization/StructEndec.java index a45f2568..45d61197 100644 --- a/src/main/java/io/wispforest/owo/serialization/StructEndec.java +++ b/src/main/java/io/wispforest/owo/serialization/StructEndec.java @@ -1,9 +1,12 @@ package io.wispforest.owo.serialization; import com.mojang.serialization.*; +import io.wispforest.owo.mixin.ForwardingDynamicOpsAccessor; +import io.wispforest.owo.mixin.RegistryOpsAccessor; import io.wispforest.owo.serialization.endec.StructField; import io.wispforest.owo.serialization.format.edm.*; -import net.minecraft.util.Util; +import net.minecraft.registry.RegistryOps; +import net.minecraft.util.dynamic.ForwardingDynamicOps; import java.util.HashMap; import java.util.Map; @@ -13,25 +16,25 @@ /** * Marker and template interface for all endecs which serialize structs *

- * Every such endec should extend this interface to profit from the implementation of {@link #mapCodec(SerializationAttribute...)} + * Every such endec should extend this interface to profit from the implementation of {@link #mapCodec(SerializationContext)} * and composability which allows {@link Endec#dispatchedStruct(Function, Function, Endec, String)} to work */ public interface StructEndec extends Endec { - void encodeStruct(Serializer.Struct struct, T value); + void encodeStruct(SerializationContext ctx, Serializer.Struct struct, T value); - T decodeStruct(Deserializer.Struct struct); + T decodeStruct(SerializationContext ctx, Deserializer.Struct struct); @Override - default void encode(Serializer serializer, T value) { + default void encode(SerializationContext ctx, Serializer serializer, T value) { try (var struct = serializer.struct()) { - this.encodeStruct(struct, value); + this.encodeStruct(ctx, struct, value); } } @Override - default T decode(Deserializer deserializer) { - return this.decodeStruct(deserializer.struct()); + default T decode(SerializationContext ctx, Deserializer deserializer) { + return this.decodeStruct(ctx, deserializer.struct()); } default StructField flatFieldOf(Function getter) { @@ -42,17 +45,17 @@ default StructField flatFieldOf(Function getter) { default StructEndec xmap(Function to, Function from) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, R value) { - StructEndec.this.encodeStruct(struct, from.apply(value)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, R value) { + StructEndec.this.encodeStruct(ctx, struct, from.apply(value)); } @Override - public R decodeStruct(Deserializer.Struct struct) { - return to.apply(StructEndec.this.decodeStruct(struct)); + public R decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return to.apply(StructEndec.this.decodeStruct(ctx, struct)); } }; } - default MapCodec mapCodec(SerializationAttribute... assumedAttributes) { + default MapCodec mapCodec(SerializationContext assumedContext) { return new MapCodec<>() { @Override public Stream keys(DynamicOps ops) { @@ -65,15 +68,24 @@ public DataResult decode(DynamicOps ops, MapLike input) { var map = new HashMap>(); input.entries().forEach(pair -> { map.put( - Util.getResult( - ops.getStringValue(pair.getFirst()), - s -> new IllegalStateException("Unable to parse key: " + s) - ), - ops.convertTo(EdmOps.INSTANCE, pair.getSecond()) + ops.getStringValue(pair.getFirst()) + .getOrThrow(s -> new IllegalStateException("Unable to parse key: " + s)), + ops.convertTo(EdmOps.withoutContext(), pair.getSecond()) ); }); - return DataResult.success(StructEndec.this.decode(LenientEdmDeserializer.of(EdmElement.wrapMap(map)).withAttributes(assumedAttributes))); + var rootOps = ops; + while (rootOps instanceof ForwardingDynamicOps) rootOps = ((ForwardingDynamicOpsAccessor) ops).owo$delegate(); + + var context = rootOps instanceof EdmOps edmOps + ? edmOps.capturedContext().and(assumedContext) + : assumedContext; + + if (ops instanceof RegistryOps registryOps) { + context = context.withAttributes(RegistriesAttribute.infoGetterOnly(((RegistryOpsAccessor) registryOps).owo$infoGetter())); + } + + return DataResult.success(StructEndec.this.decode(context, LenientEdmDeserializer.of(EdmElement.wrapMap(map)))); } catch (Exception e) { return DataResult.error(e::getMessage); } @@ -82,11 +94,22 @@ public DataResult decode(DynamicOps ops, MapLike input) { @Override public RecordBuilder encode(T input, DynamicOps ops, RecordBuilder prefix) { try { - var element = StructEndec.this.encodeFully(() -> EdmSerializer.of().withAttributes(assumedAttributes), input).>>cast(); + var rootOps = ops; + while (rootOps instanceof ForwardingDynamicOps) rootOps = ((ForwardingDynamicOpsAccessor) ops).owo$delegate(); + + var context = rootOps instanceof EdmOps edmOps + ? edmOps.capturedContext().and(assumedContext) + : assumedContext; + + if (ops instanceof RegistryOps registryOps) { + context = context.withAttributes(RegistriesAttribute.infoGetterOnly(((RegistryOpsAccessor) registryOps).owo$infoGetter())); + } + + var element = StructEndec.this.encodeFully(context, EdmSerializer::of, input).>>cast(); var result = prefix; for (var entry : element.entrySet()) { - result = result.add(entry.getKey(), EdmOps.INSTANCE.convertTo(ops, entry.getValue())); + result = result.add(entry.getKey(), EdmOps.withoutContext().convertTo(ops, entry.getValue())); } return result; @@ -96,4 +119,8 @@ public RecordBuilder encode(T input, DynamicOps ops, RecordBuilder< } }; } + + default MapCodec mapCodec() { + return this.mapCodec(SerializationContext.empty()); + } } diff --git a/src/main/java/io/wispforest/owo/serialization/endec/AttributeEndecBuilder.java b/src/main/java/io/wispforest/owo/serialization/endec/AttributeEndecBuilder.java index 2d2ee729..ca9ec12b 100644 --- a/src/main/java/io/wispforest/owo/serialization/endec/AttributeEndecBuilder.java +++ b/src/main/java/io/wispforest/owo/serialization/endec/AttributeEndecBuilder.java @@ -1,9 +1,6 @@ package io.wispforest.owo.serialization.endec; -import io.wispforest.owo.serialization.Deserializer; -import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; -import io.wispforest.owo.serialization.Serializer; +import io.wispforest.owo.serialization.*; import java.util.LinkedHashMap; import java.util.Map; @@ -18,7 +15,7 @@ public AttributeEndecBuilder(Endec endec, SerializationAttribute attribute) { public AttributeEndecBuilder orElseIf(Endec endec, SerializationAttribute attribute) { if (this.branches.containsKey(attribute)) { - throw new IllegalStateException("Cannot have more than one branch for attribute " + attribute.name()); + throw new IllegalStateException("Cannot have more than one branch for attribute " + attribute.name); } this.branches.put(attribute, endec); @@ -28,31 +25,31 @@ public AttributeEndecBuilder orElseIf(Endec endec, SerializationAttribute public Endec orElse(Endec endec) { return new Endec<>() { @Override - public void encode(Serializer serializer, T value) { + public void encode(SerializationContext ctx, Serializer serializer, T value) { var branchEndec = endec; for (var branch : AttributeEndecBuilder.this.branches.entrySet()) { - if (serializer.attributes().contains(branch.getKey())) { + if (ctx.hasAttribute(branch.getKey())) { branchEndec = branch.getValue(); break; } } - branchEndec.encode(serializer, value); + branchEndec.encode(ctx, serializer, value); } @Override - public T decode(Deserializer deserializer) { + public T decode(SerializationContext ctx, Deserializer deserializer) { var branchEndec = endec; for (var branch : AttributeEndecBuilder.this.branches.entrySet()) { - if (deserializer.attributes().contains(branch.getKey())) { + if (ctx.hasAttribute(branch.getKey())) { branchEndec = branch.getValue(); break; } } - return branchEndec.decode(deserializer); + return branchEndec.decode(ctx, deserializer); } }; } diff --git a/src/main/java/io/wispforest/owo/serialization/endec/BuiltInEndecs.java b/src/main/java/io/wispforest/owo/serialization/endec/BuiltInEndecs.java index a04e5574..54f490b9 100644 --- a/src/main/java/io/wispforest/owo/serialization/endec/BuiltInEndecs.java +++ b/src/main/java/io/wispforest/owo/serialization/endec/BuiltInEndecs.java @@ -2,11 +2,9 @@ import com.mojang.datafixers.util.Function3; import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; -import io.wispforest.owo.serialization.format.nbt.NbtEndec; +import io.wispforest.owo.serialization.SerializationAttributes; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; @@ -40,7 +38,7 @@ private BuiltInEndecs() {} public static final Endec UUID = Endec .ifAttr( - SerializationAttribute.HUMAN_READABLE, + SerializationAttributes.HUMAN_READABLE, Endec.STRING.xmap(java.util.UUID::fromString, java.util.UUID::toString) ).orElse( INT_ARRAY.xmap(Uuids::toUuid, Uuids::toIntArray) @@ -48,7 +46,7 @@ private BuiltInEndecs() {} public static final Endec DATE = Endec .ifAttr( - SerializationAttribute.HUMAN_READABLE, + SerializationAttributes.HUMAN_READABLE, Endec.STRING.xmap(s -> Date.from(Instant.parse(s)), date -> date.toInstant().toString()) ).orElse( Endec.LONG.xmap(Date::new, Date::getTime) @@ -56,8 +54,21 @@ private BuiltInEndecs() {} // --- MC Types --- + public static final Endec PACKET_BYTE_BUF = Endec.BYTES + .xmap(bytes -> { + var buffer = PacketByteBufs.create(); + buffer.writeBytes(bytes); + + return buffer; + }, buffer -> { + var bytes = new byte[buffer.readableBytes()]; + buffer.readBytes(bytes); + + return bytes; + }); + public static final Endec IDENTIFIER = Endec.STRING.xmap(Identifier::new, Identifier::toString); - public static final Endec ITEM_STACK = NbtEndec.COMPOUND.xmap(ItemStack::fromNbt, stack -> stack.writeNbt(new NbtCompound())); + public static final Endec ITEM_STACK = Endec.ofCodec(ItemStack.OPTIONAL_CODEC); public static final Endec TEXT = Endec.ofCodec(TextCodecs.CODEC); public static final Endec VEC3I = vectorEndec("Vec3i", Endec.INT, Vec3i::new, Vec3i::getX, Vec3i::getY, Vec3i::getZ); @@ -66,7 +77,7 @@ private BuiltInEndecs() {} public static final Endec BLOCK_POS = Endec .ifAttr( - SerializationAttribute.HUMAN_READABLE, + SerializationAttributes.HUMAN_READABLE, vectorEndec("BlockPos", Endec.INT, BlockPos::new, BlockPos::getX, BlockPos::getY, BlockPos::getZ) ).orElse( Endec.LONG.xmap(BlockPos::fromLong, BlockPos::asLong) @@ -74,7 +85,7 @@ private BuiltInEndecs() {} public static final Endec CHUNK_POS = Endec .ifAttr( - SerializationAttribute.HUMAN_READABLE, + SerializationAttributes.HUMAN_READABLE, Endec.INT.listOf().validate(ints -> { if (ints.size() != 2) { throw new IllegalStateException("ChunkPos array must have two elements"); @@ -97,19 +108,6 @@ private BuiltInEndecs() {} : BlockHitResult.createMissed(pos, side, blockPos) ); - public static final Endec PACKET_BYTE_BUF = Endec.BYTES - .xmap(bytes -> { - var buffer = PacketByteBufs.create(); - buffer.writeBytes(bytes); - - return buffer; - }, buffer -> { - var bytes = new byte[buffer.readableBytes()]; - buffer.readBytes(bytes); - - return bytes; - }); - // --- Constructors for MC types --- public static Endec ofRegistry(Registry registry) { diff --git a/src/main/java/io/wispforest/owo/serialization/endec/EitherEndec.java b/src/main/java/io/wispforest/owo/serialization/endec/EitherEndec.java index 1deee997..a13062db 100644 --- a/src/main/java/io/wispforest/owo/serialization/endec/EitherEndec.java +++ b/src/main/java/io/wispforest/owo/serialization/endec/EitherEndec.java @@ -1,10 +1,7 @@ package io.wispforest.owo.serialization.endec; import com.mojang.datafixers.util.Either; -import io.wispforest.owo.serialization.Deserializer; -import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; -import io.wispforest.owo.serialization.Serializer; +import io.wispforest.owo.serialization.*; public final class EitherEndec implements Endec> { @@ -21,37 +18,37 @@ public EitherEndec(Endec leftEndec, Endec rightEndec, boolean exclusive) { } @Override - public void encode(Serializer serializer, Either either) { - if (serializer.attributes().contains(SerializationAttribute.SELF_DESCRIBING)) { - either.ifLeft(left -> this.leftEndec.encode(serializer, left)).ifRight(right -> this.rightEndec.encode(serializer, right)); + public void encode(SerializationContext ctx, Serializer serializer, Either either) { + if (serializer instanceof SelfDescribedSerializer) { + either.ifLeft(left -> this.leftEndec.encode(ctx, serializer, left)).ifRight(right -> this.rightEndec.encode(ctx, serializer, right)); } else { either.ifLeft(left -> { try (var struct = serializer.struct()) { - struct.field("is_left", Endec.BOOLEAN, true).field("left", this.leftEndec, left); + struct.field("is_left", ctx, Endec.BOOLEAN, true).field("left", ctx, this.leftEndec, left); } }).ifRight(right -> { try (var struct = serializer.struct()) { - struct.field("is_left", Endec.BOOLEAN, false).field("right", this.rightEndec, right); + struct.field("is_left", ctx, Endec.BOOLEAN, false).field("right", ctx, this.rightEndec, right); } }); } } @Override - public Either decode(Deserializer deserializer) { - boolean selfDescribing = deserializer.attributes().contains(SerializationAttribute.SELF_DESCRIBING); + public Either decode(SerializationContext ctx, Deserializer deserializer) { + boolean selfDescribing = deserializer instanceof SelfDescribedDeserializer; if (selfDescribing) { Either leftResult = null; try { - leftResult = Either.left(deserializer.tryRead(this.leftEndec::decode)); + leftResult = Either.left(deserializer.tryRead(deserializer1 -> this.leftEndec.decode(ctx, deserializer1))); } catch (Exception ignore) {} if (!this.exclusive && leftResult != null) return leftResult; Either rightResult = null; try { - rightResult = Either.right(deserializer.tryRead(this.rightEndec::decode)); + rightResult = Either.right(deserializer.tryRead(deserializer1 -> this.rightEndec.decode(ctx, deserializer1))); } catch (Exception ignore) {} if (this.exclusive && leftResult != null && rightResult != null) { @@ -64,10 +61,10 @@ public Either decode(Deserializer deserializer) { throw new IllegalStateException("Neither alternative read successfully"); } else { var struct = deserializer.struct(); - if (struct.field("is_left", Endec.BOOLEAN)) { - return Either.left(struct.field("left", this.leftEndec)); + if (struct.field("is_left", ctx, Endec.BOOLEAN)) { + return Either.left(struct.field("left", ctx, this.leftEndec)); } else { - return Either.right(struct.field("right", this.rightEndec)); + return Either.right(struct.field("right", ctx, this.rightEndec)); } } diff --git a/src/main/java/io/wispforest/owo/serialization/endec/RecordEndec.java b/src/main/java/io/wispforest/owo/serialization/endec/RecordEndec.java index 8fc026e8..d72f4951 100644 --- a/src/main/java/io/wispforest/owo/serialization/endec/RecordEndec.java +++ b/src/main/java/io/wispforest/owo/serialization/endec/RecordEndec.java @@ -1,10 +1,7 @@ package io.wispforest.owo.serialization.endec; import io.wispforest.owo.Owo; -import io.wispforest.owo.serialization.Deserializer; -import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.Serializer; -import io.wispforest.owo.serialization.StructEndec; +import io.wispforest.owo.serialization.*; import io.wispforest.owo.serialization.annotations.NullableComponent; import org.apache.commons.lang3.mutable.MutableInt; @@ -79,13 +76,13 @@ private static Object getRecordEntry(R instance, MethodHandle } @Override - public R decodeStruct(Deserializer.Struct struct) { + public R decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { Object[] fieldValues = new Object[this.fields.size()]; var index = new MutableInt(); this.fields.forEach((field) -> { - fieldValues[index.getAndIncrement()] = field.decodeField(struct); + fieldValues[index.getAndIncrement()] = field.decodeField(ctx, struct); }); try { @@ -98,7 +95,7 @@ public R decodeStruct(Deserializer.Struct struct) { } @Override - public void encodeStruct(Serializer.Struct struct, R instance) { - this.fields.forEach(field -> field.encodeField(struct, instance)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, R instance) { + this.fields.forEach(field -> field.encodeField(ctx, struct, instance)); } } diff --git a/src/main/java/io/wispforest/owo/serialization/endec/ReflectiveEndecBuilder.java b/src/main/java/io/wispforest/owo/serialization/endec/ReflectiveEndecBuilder.java index fa50e7b5..bfe9ba01 100644 --- a/src/main/java/io/wispforest/owo/serialization/endec/ReflectiveEndecBuilder.java +++ b/src/main/java/io/wispforest/owo/serialization/endec/ReflectiveEndecBuilder.java @@ -1,10 +1,8 @@ package io.wispforest.owo.serialization.endec; -import io.wispforest.owo.serialization.Deserializer; import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.Serializer; -import io.wispforest.owo.serialization.StructEndec; +import io.wispforest.owo.serialization.SerializationAttributes; import io.wispforest.owo.serialization.annotations.SealedPolymorphic; import io.wispforest.owo.serialization.format.nbt.NbtEndec; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -13,13 +11,17 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleType; import net.minecraft.registry.Registries; import net.minecraft.text.Text; import net.minecraft.util.Identifier; import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.*; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; @@ -241,22 +243,27 @@ private static Endec createSealedSerializer(Class commonClass) { register(BuiltInEndecs.BITSET, BitSet.class); register(BuiltInEndecs.TEXT, Text.class); - register(BuiltInEndecs.PACKET_BYTE_BUF.xmap( - byteBuf -> { - //noinspection rawtypes - final ParticleType particleType = Registries.PARTICLE_TYPE.get(byteBuf.readInt()); - //noinspection unchecked, ConstantConditions - - return particleType.getParametersFactory().read(particleType, byteBuf); - }, - particleEffect -> { - PacketByteBuf buf = PacketByteBufs.create(); - buf.writeInt(Registries.PARTICLE_TYPE.getRawId(particleEffect.getType())); - particleEffect.write(buf); - - return buf; - } - ), ParticleEffect.class); + register(Endec.of( + (ctx, serializer, particleEffect) -> { + var buffer = new RegistryByteBuf( + PacketByteBufs.create(), + ctx.requireAttributeValue(SerializationAttributes.REGISTRIES).registryManager() + ); + + buffer.writeInt(Registries.PARTICLE_TYPE.getRawId(particleEffect.getType())); + ((ParticleType) particleEffect.getType()).getPacketCodec().encode(buffer, particleEffect); + + BuiltInEndecs.PACKET_BYTE_BUF.encode(ctx, serializer, buffer); + }, (ctx, deserializer) -> { + var buffer = new RegistryByteBuf( + BuiltInEndecs.PACKET_BYTE_BUF.decode(ctx, deserializer), + ctx.requireAttributeValue(SerializationAttributes.REGISTRIES).registryManager() + ); + + return Registries.PARTICLE_TYPE.get(buffer.readInt()).getPacketCodec().decode(buffer); + }), + ParticleEffect.class + ); register(BuiltInEndecs.VEC3D, Vec3d.class); register(BuiltInEndecs.VECTOR3F, Vector3f.class); diff --git a/src/main/java/io/wispforest/owo/serialization/endec/StructEndecBuilder.java b/src/main/java/io/wispforest/owo/serialization/endec/StructEndecBuilder.java index 67b26f0e..6dfac010 100644 --- a/src/main/java/io/wispforest/owo/serialization/endec/StructEndecBuilder.java +++ b/src/main/java/io/wispforest/owo/serialization/endec/StructEndecBuilder.java @@ -2,6 +2,7 @@ import com.mojang.datafixers.util.*; import io.wispforest.owo.serialization.Deserializer; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.Serializer; import io.wispforest.owo.serialization.StructEndec; @@ -14,13 +15,13 @@ public class StructEndecBuilder { public static StructEndec of(StructField f1, Function constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); } @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct)); + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct)); } }; } @@ -28,15 +29,15 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, BiFunction constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); } @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct)); + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct)); } }; } @@ -44,17 +45,17 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, Function3 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); } @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct)); + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct)); } }; } @@ -62,19 +63,19 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, Function4 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); } @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct)); + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct)); } }; } @@ -82,21 +83,21 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, Function5 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); } @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct)); + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct)); } }; } @@ -104,23 +105,23 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, Function6 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); } @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct)); + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct)); } }; } @@ -128,25 +129,25 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, Function7 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); } @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct)); + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct)); } }; } @@ -154,27 +155,27 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, StructField f8, Function8 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); - f8.encodeField(struct, value); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); + f8.encodeField(ctx, struct, value); } @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct), - f8.decodeField(struct)); + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct), + f8.decodeField(ctx, struct)); } }; } @@ -182,29 +183,29 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, StructField f8, StructField f9, Function9 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); - f8.encodeField(struct, value); - f9.encodeField(struct, value); - } - - @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct), - f8.decodeField(struct), - f9.decodeField(struct)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); + f8.encodeField(ctx, struct, value); + f9.encodeField(ctx, struct, value); + } + + @Override + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct), + f8.decodeField(ctx, struct), + f9.decodeField(ctx, struct)); } }; } @@ -212,31 +213,31 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, StructField f8, StructField f9, StructField f10, Function10 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); - f8.encodeField(struct, value); - f9.encodeField(struct, value); - f10.encodeField(struct, value); - } - - @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct), - f8.decodeField(struct), - f9.decodeField(struct), - f10.decodeField(struct)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); + f8.encodeField(ctx, struct, value); + f9.encodeField(ctx, struct, value); + f10.encodeField(ctx, struct, value); + } + + @Override + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct), + f8.decodeField(ctx, struct), + f9.decodeField(ctx, struct), + f10.decodeField(ctx, struct)); } }; } @@ -244,33 +245,33 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, StructField f8, StructField f9, StructField f10, StructField f11, Function11 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); - f8.encodeField(struct, value); - f9.encodeField(struct, value); - f10.encodeField(struct, value); - f11.encodeField(struct, value); - } - - @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct), - f8.decodeField(struct), - f9.decodeField(struct), - f10.decodeField(struct), - f11.decodeField(struct)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); + f8.encodeField(ctx, struct, value); + f9.encodeField(ctx, struct, value); + f10.encodeField(ctx, struct, value); + f11.encodeField(ctx, struct, value); + } + + @Override + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct), + f8.decodeField(ctx, struct), + f9.decodeField(ctx, struct), + f10.decodeField(ctx, struct), + f11.decodeField(ctx, struct)); } }; } @@ -278,35 +279,35 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, StructField f8, StructField f9, StructField f10, StructField f11, StructField f12, Function12 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); - f8.encodeField(struct, value); - f9.encodeField(struct, value); - f10.encodeField(struct, value); - f11.encodeField(struct, value); - f12.encodeField(struct, value); - } - - @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct), - f8.decodeField(struct), - f9.decodeField(struct), - f10.decodeField(struct), - f11.decodeField(struct), - f12.decodeField(struct)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); + f8.encodeField(ctx, struct, value); + f9.encodeField(ctx, struct, value); + f10.encodeField(ctx, struct, value); + f11.encodeField(ctx, struct, value); + f12.encodeField(ctx, struct, value); + } + + @Override + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct), + f8.decodeField(ctx, struct), + f9.decodeField(ctx, struct), + f10.decodeField(ctx, struct), + f11.decodeField(ctx, struct), + f12.decodeField(ctx, struct)); } }; } @@ -314,37 +315,37 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, StructField f8, StructField f9, StructField f10, StructField f11, StructField f12, StructField f13, Function13 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); - f8.encodeField(struct, value); - f9.encodeField(struct, value); - f10.encodeField(struct, value); - f11.encodeField(struct, value); - f12.encodeField(struct, value); - f13.encodeField(struct, value); - } - - @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct), - f8.decodeField(struct), - f9.decodeField(struct), - f10.decodeField(struct), - f11.decodeField(struct), - f12.decodeField(struct), - f13.decodeField(struct)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); + f8.encodeField(ctx, struct, value); + f9.encodeField(ctx, struct, value); + f10.encodeField(ctx, struct, value); + f11.encodeField(ctx, struct, value); + f12.encodeField(ctx, struct, value); + f13.encodeField(ctx, struct, value); + } + + @Override + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct), + f8.decodeField(ctx, struct), + f9.decodeField(ctx, struct), + f10.decodeField(ctx, struct), + f11.decodeField(ctx, struct), + f12.decodeField(ctx, struct), + f13.decodeField(ctx, struct)); } }; } @@ -352,39 +353,39 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, StructField f8, StructField f9, StructField f10, StructField f11, StructField f12, StructField f13, StructField f14, Function14 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); - f8.encodeField(struct, value); - f9.encodeField(struct, value); - f10.encodeField(struct, value); - f11.encodeField(struct, value); - f12.encodeField(struct, value); - f13.encodeField(struct, value); - f14.encodeField(struct, value); - } - - @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct), - f8.decodeField(struct), - f9.decodeField(struct), - f10.decodeField(struct), - f11.decodeField(struct), - f12.decodeField(struct), - f13.decodeField(struct), - f14.decodeField(struct)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); + f8.encodeField(ctx, struct, value); + f9.encodeField(ctx, struct, value); + f10.encodeField(ctx, struct, value); + f11.encodeField(ctx, struct, value); + f12.encodeField(ctx, struct, value); + f13.encodeField(ctx, struct, value); + f14.encodeField(ctx, struct, value); + } + + @Override + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct), + f8.decodeField(ctx, struct), + f9.decodeField(ctx, struct), + f10.decodeField(ctx, struct), + f11.decodeField(ctx, struct), + f12.decodeField(ctx, struct), + f13.decodeField(ctx, struct), + f14.decodeField(ctx, struct)); } }; } @@ -392,41 +393,41 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, StructField f8, StructField f9, StructField f10, StructField f11, StructField f12, StructField f13, StructField f14, StructField f15, Function15 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); - f8.encodeField(struct, value); - f9.encodeField(struct, value); - f10.encodeField(struct, value); - f11.encodeField(struct, value); - f12.encodeField(struct, value); - f13.encodeField(struct, value); - f14.encodeField(struct, value); - f15.encodeField(struct, value); - } - - @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct), - f8.decodeField(struct), - f9.decodeField(struct), - f10.decodeField(struct), - f11.decodeField(struct), - f12.decodeField(struct), - f13.decodeField(struct), - f14.decodeField(struct), - f15.decodeField(struct)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); + f8.encodeField(ctx, struct, value); + f9.encodeField(ctx, struct, value); + f10.encodeField(ctx, struct, value); + f11.encodeField(ctx, struct, value); + f12.encodeField(ctx, struct, value); + f13.encodeField(ctx, struct, value); + f14.encodeField(ctx, struct, value); + f15.encodeField(ctx, struct, value); + } + + @Override + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct), + f8.decodeField(ctx, struct), + f9.decodeField(ctx, struct), + f10.decodeField(ctx, struct), + f11.decodeField(ctx, struct), + f12.decodeField(ctx, struct), + f13.decodeField(ctx, struct), + f14.decodeField(ctx, struct), + f15.decodeField(ctx, struct)); } }; } @@ -434,43 +435,43 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, StructField f8, StructField f9, StructField f10, StructField f11, StructField f12, StructField f13, StructField f14, StructField f15, StructField f16, Function16 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); - f8.encodeField(struct, value); - f9.encodeField(struct, value); - f10.encodeField(struct, value); - f11.encodeField(struct, value); - f12.encodeField(struct, value); - f13.encodeField(struct, value); - f14.encodeField(struct, value); - f15.encodeField(struct, value); - f16.encodeField(struct, value); - } - - @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct), - f8.decodeField(struct), - f9.decodeField(struct), - f10.decodeField(struct), - f11.decodeField(struct), - f12.decodeField(struct), - f13.decodeField(struct), - f14.decodeField(struct), - f15.decodeField(struct), - f16.decodeField(struct)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); + f8.encodeField(ctx, struct, value); + f9.encodeField(ctx, struct, value); + f10.encodeField(ctx, struct, value); + f11.encodeField(ctx, struct, value); + f12.encodeField(ctx, struct, value); + f13.encodeField(ctx, struct, value); + f14.encodeField(ctx, struct, value); + f15.encodeField(ctx, struct, value); + f16.encodeField(ctx, struct, value); + } + + @Override + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct), + f8.decodeField(ctx, struct), + f9.decodeField(ctx, struct), + f10.decodeField(ctx, struct), + f11.decodeField(ctx, struct), + f12.decodeField(ctx, struct), + f13.decodeField(ctx, struct), + f14.decodeField(ctx, struct), + f15.decodeField(ctx, struct), + f16.decodeField(ctx, struct)); } }; } @@ -478,45 +479,45 @@ public S decodeStruct(Deserializer.Struct struct) { public static StructEndec of(StructField f1, StructField f2, StructField f3, StructField f4, StructField f5, StructField f6, StructField f7, StructField f8, StructField f9, StructField f10, StructField f11, StructField f12, StructField f13, StructField f14, StructField f15, StructField f16, StructField f17, Function17 constructor) { return new StructEndec<>() { @Override - public void encodeStruct(Serializer.Struct struct, S value) { - f1.encodeField(struct, value); - f2.encodeField(struct, value); - f3.encodeField(struct, value); - f4.encodeField(struct, value); - f5.encodeField(struct, value); - f6.encodeField(struct, value); - f7.encodeField(struct, value); - f8.encodeField(struct, value); - f9.encodeField(struct, value); - f10.encodeField(struct, value); - f11.encodeField(struct, value); - f12.encodeField(struct, value); - f13.encodeField(struct, value); - f14.encodeField(struct, value); - f15.encodeField(struct, value); - f16.encodeField(struct, value); - f17.encodeField(struct, value); - } - - @Override - public S decodeStruct(Deserializer.Struct struct) { - return constructor.apply(f1.decodeField(struct), - f2.decodeField(struct), - f3.decodeField(struct), - f4.decodeField(struct), - f5.decodeField(struct), - f6.decodeField(struct), - f7.decodeField(struct), - f8.decodeField(struct), - f9.decodeField(struct), - f10.decodeField(struct), - f11.decodeField(struct), - f12.decodeField(struct), - f13.decodeField(struct), - f14.decodeField(struct), - f15.decodeField(struct), - f16.decodeField(struct), - f17.decodeField(struct)); + public void encodeStruct(SerializationContext ctx, Serializer.Struct struct, S value) { + f1.encodeField(ctx, struct, value); + f2.encodeField(ctx, struct, value); + f3.encodeField(ctx, struct, value); + f4.encodeField(ctx, struct, value); + f5.encodeField(ctx, struct, value); + f6.encodeField(ctx, struct, value); + f7.encodeField(ctx, struct, value); + f8.encodeField(ctx, struct, value); + f9.encodeField(ctx, struct, value); + f10.encodeField(ctx, struct, value); + f11.encodeField(ctx, struct, value); + f12.encodeField(ctx, struct, value); + f13.encodeField(ctx, struct, value); + f14.encodeField(ctx, struct, value); + f15.encodeField(ctx, struct, value); + f16.encodeField(ctx, struct, value); + f17.encodeField(ctx, struct, value); + } + + @Override + public S decodeStruct(SerializationContext ctx, Deserializer.Struct struct) { + return constructor.apply(f1.decodeField(ctx, struct), + f2.decodeField(ctx, struct), + f3.decodeField(ctx, struct), + f4.decodeField(ctx, struct), + f5.decodeField(ctx, struct), + f6.decodeField(ctx, struct), + f7.decodeField(ctx, struct), + f8.decodeField(ctx, struct), + f9.decodeField(ctx, struct), + f10.decodeField(ctx, struct), + f11.decodeField(ctx, struct), + f12.decodeField(ctx, struct), + f13.decodeField(ctx, struct), + f14.decodeField(ctx, struct), + f15.decodeField(ctx, struct), + f16.decodeField(ctx, struct), + f17.decodeField(ctx, struct)); } }; } diff --git a/src/main/java/io/wispforest/owo/serialization/endec/StructField.java b/src/main/java/io/wispforest/owo/serialization/endec/StructField.java index ebfd7c73..022b8069 100644 --- a/src/main/java/io/wispforest/owo/serialization/endec/StructField.java +++ b/src/main/java/io/wispforest/owo/serialization/endec/StructField.java @@ -2,6 +2,7 @@ import io.wispforest.owo.serialization.Deserializer; import io.wispforest.owo.serialization.Endec; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.Serializer; import io.wispforest.owo.serialization.StructEndec; import org.jetbrains.annotations.Nullable; @@ -31,14 +32,14 @@ public StructField(String name, Endec endec, Function getter) { this(name, endec, getter, (Supplier) null); } - public void encodeField(Serializer.Struct struct, S instance) { - struct.field(this.name, this.endec, this.getter.apply(instance)); + public void encodeField(SerializationContext ctx, Serializer.Struct struct, S instance) { + struct.field(this.name, ctx, this.endec, this.getter.apply(instance)); } - public F decodeField(Deserializer.Struct struct) { + public F decodeField(SerializationContext ctx, Deserializer.Struct struct) { return this.defaultValueFactory != null - ? struct.field(this.name, this.endec, this.defaultValueFactory.get()) - : struct.field(this.name, this.endec); + ? struct.field(this.name, ctx, this.endec, this.defaultValueFactory.get()) + : struct.field(this.name, ctx, this.endec); } public static final class Flat extends StructField { @@ -52,13 +53,13 @@ private StructEndec endec() { } @Override - public void encodeField(Serializer.Struct struct, S instance) { - this.endec().encodeStruct(struct, this.getter.apply(instance)); + public void encodeField(SerializationContext ctx, Serializer.Struct struct, S instance) { + this.endec().encodeStruct(ctx, struct, this.getter.apply(instance)); } @Override - public F decodeField(Deserializer.Struct struct) { - return this.endec().decodeStruct(struct); + public F decodeField(SerializationContext ctx, Deserializer.Struct struct) { + return this.endec().decodeStruct(ctx, struct); } } } diff --git a/src/main/java/io/wispforest/owo/serialization/format/bytebuf/ByteBufDeserializer.java b/src/main/java/io/wispforest/owo/serialization/format/bytebuf/ByteBufDeserializer.java index 9637b1db..28360963 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/bytebuf/ByteBufDeserializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/bytebuf/ByteBufDeserializer.java @@ -3,7 +3,7 @@ import io.netty.buffer.ByteBuf; import io.wispforest.owo.serialization.Deserializer; import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; +import io.wispforest.owo.serialization.SerializationContext; import net.minecraft.network.PacketByteBuf; import net.minecraft.network.encoding.StringEncoding; import net.minecraft.network.encoding.VarInts; @@ -11,7 +11,6 @@ import org.jetbrains.annotations.Nullable; import java.util.Optional; -import java.util.Set; import java.util.function.Function; public class ByteBufDeserializer implements Deserializer { @@ -29,78 +28,71 @@ public static ByteBufDeserializer of(ByteBuf buffer) { // --- @Override - public Set attributes() { - return Set.of(); - } - - // --- - - @Override - public byte readByte() { + public byte readByte(SerializationContext ctx) { return this.buffer.readByte(); } @Override - public short readShort() { + public short readShort(SerializationContext ctx) { return this.buffer.readShort(); } @Override - public int readInt() { + public int readInt(SerializationContext ctx) { return this.buffer.readInt(); } @Override - public long readLong() { + public long readLong(SerializationContext ctx) { return this.buffer.readLong(); } @Override - public float readFloat() { + public float readFloat(SerializationContext ctx) { return this.buffer.readFloat(); } @Override - public double readDouble() { + public double readDouble(SerializationContext ctx) { return this.buffer.readDouble(); } // --- @Override - public int readVarInt() { + public int readVarInt(SerializationContext ctx) { return VarInts.read(this.buffer); } @Override - public long readVarLong() { + public long readVarLong(SerializationContext ctx) { return VarLongs.read(this.buffer); } // --- @Override - public boolean readBoolean() { + public boolean readBoolean(SerializationContext ctx) { return this.buffer.readBoolean(); } @Override - public String readString() { + public String readString(SerializationContext ctx) { return StringEncoding.decode(this.buffer, PacketByteBuf.DEFAULT_MAX_STRING_LENGTH); } @Override - public byte[] readBytes() { - var array = new byte[this.readVarInt()]; + public byte[] readBytes(SerializationContext ctx) { + var array = new byte[this.readVarInt(ctx)]; this.buffer.readBytes(array); return array; } @Override - public Optional readOptional(Endec endec) { - return this.readBoolean() - ? Optional.of(endec.decode(this)) + public Optional readOptional(SerializationContext ctx, Endec endec) { + return this.readBoolean(ctx) + ? Optional.of(endec.decode(ctx, this)) : Optional.empty(); } @@ -121,30 +113,32 @@ public V tryRead(Function, V> reader) { // --- @Override - public Deserializer.Sequence sequence(Endec elementEndec) { - return new Sequence<>(elementEndec, this.readVarInt()); + public Deserializer.Sequence sequence(SerializationContext ctx, Endec elementEndec) { + return new Sequence<>(ctx, elementEndec, this.readVarInt(ctx)); } @Override - public Deserializer.Map map(Endec valueEndec) { - return new Map<>(valueEndec, this.readVarInt()); + public Deserializer.Map map(SerializationContext ctx, Endec valueEndec) { + return new Map<>(ctx, valueEndec, this.readVarInt(ctx)); } @Override public Struct struct() { - return new Sequence<>(null, 0); + return new Sequence<>(null, null, 0); } // --- private class Sequence implements Deserializer.Sequence, Struct { + private final SerializationContext ctx; private final Endec valueEndec; private final int size; private int index = 0; - private Sequence(Endec valueEndec, int size) { + private Sequence(SerializationContext ctx, Endec valueEndec, int size) { + this.ctx = ctx; this.valueEndec = valueEndec; this.size = size; } @@ -162,28 +156,30 @@ public boolean hasNext() { @Override public V next() { this.index++; - return this.valueEndec.decode(ByteBufDeserializer.this); + return this.valueEndec.decode(this.ctx, ByteBufDeserializer.this); } @Override - public @Nullable F field(String name, Endec endec) { - return this.field(name, endec, null); + public @Nullable F field(String name, SerializationContext ctx, Endec endec) { + return this.field(name, ctx, endec, null); } @Override - public @Nullable F field(String name, Endec endec, @Nullable F defaultValue) { - return endec.decode(ByteBufDeserializer.this); + public @Nullable F field(String name, SerializationContext ctx, Endec endec, @Nullable F defaultValue) { + return endec.decode(ctx, ByteBufDeserializer.this); } } private class Map implements Deserializer.Map { + private final SerializationContext ctx; private final Endec valueEndec; private final int size; private int index = 0; - private Map(Endec valueEndec, int size) { + private Map(SerializationContext ctx, Endec valueEndec, int size) { + this.ctx = ctx; this.valueEndec = valueEndec; this.size = size; } @@ -202,8 +198,8 @@ public boolean hasNext() { public java.util.Map.Entry next() { this.index++; return java.util.Map.entry( - ByteBufDeserializer.this.readString(), - this.valueEndec.decode(ByteBufDeserializer.this) + ByteBufDeserializer.this.readString(this.ctx), + this.valueEndec.decode(this.ctx, ByteBufDeserializer.this) ); } } diff --git a/src/main/java/io/wispforest/owo/serialization/format/bytebuf/ByteBufSerializer.java b/src/main/java/io/wispforest/owo/serialization/format/bytebuf/ByteBufSerializer.java index 1e56a1ba..af38df01 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/bytebuf/ByteBufSerializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/bytebuf/ByteBufSerializer.java @@ -2,7 +2,7 @@ import io.netty.buffer.ByteBuf; import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.Serializer; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.minecraft.network.PacketByteBuf; @@ -11,7 +11,6 @@ import net.minecraft.network.encoding.VarLongs; import java.util.Optional; -import java.util.Set; public class ByteBufSerializer implements Serializer { @@ -32,95 +31,88 @@ public static ByteBufSerializer packet() { // --- @Override - public Set attributes() { - return Set.of(); - } - - // --- - - @Override - public void writeByte(byte value) { + public void writeByte(SerializationContext ctx, byte value) { this.buffer.writeByte(value); } @Override - public void writeShort(short value) { + public void writeShort(SerializationContext ctx, short value) { this.buffer.writeShort(value); } @Override - public void writeInt(int value) { + public void writeInt(SerializationContext ctx, int value) { this.buffer.writeInt(value); } @Override - public void writeLong(long value) { + public void writeLong(SerializationContext ctx, long value) { this.buffer.writeLong(value); } @Override - public void writeFloat(float value) { + public void writeFloat(SerializationContext ctx, float value) { this.buffer.writeFloat(value); } @Override - public void writeDouble(double value) { + public void writeDouble(SerializationContext ctx, double value) { this.buffer.writeDouble(value); } // --- @Override - public void writeVarInt(int value) { + public void writeVarInt(SerializationContext ctx, int value) { VarInts.write(buffer, value); } @Override - public void writeVarLong(long value) { + public void writeVarLong(SerializationContext ctx, long value) { VarLongs.write(buffer, value); } // --- @Override - public void writeBoolean(boolean value) { + public void writeBoolean(SerializationContext ctx, boolean value) { this.buffer.writeBoolean(value); } @Override - public void writeString(String value) { + public void writeString(SerializationContext ctx, String value) { StringEncoding.encode(this.buffer, value, PacketByteBuf.DEFAULT_MAX_STRING_LENGTH); } @Override - public void writeBytes(byte[] bytes) { - this.writeVarInt(bytes.length); + public void writeBytes(SerializationContext ctx, byte[] bytes) { + this.writeVarInt(ctx, bytes.length); this.buffer.writeBytes(bytes); } @Override - public void writeOptional(Endec endec, Optional optional) { - this.writeBoolean(optional.isPresent()); - optional.ifPresent(value -> endec.encode(this, value)); + public void writeOptional(SerializationContext ctx, Endec endec, Optional optional) { + this.writeBoolean(ctx, optional.isPresent()); + optional.ifPresent(value -> endec.encode(ctx, this, value)); } // --- @Override - public Map map(Endec valueEndec, int size) { - this.writeVarInt(size); - return new Sequence<>(valueEndec); + public Map map(SerializationContext ctx, Endec valueEndec, int size) { + this.writeVarInt(ctx, size); + return new Sequence<>(ctx, valueEndec); } @Override - public Serializer.Sequence sequence(Endec elementEndec, int size) { - this.writeVarInt(size); - return new Sequence<>(elementEndec); + public Serializer.Sequence sequence(SerializationContext ctx, Endec elementEndec, int size) { + this.writeVarInt(ctx, size); + return new Sequence<>(ctx, elementEndec); } @Override public Struct struct() { - return new Sequence<>(null); + return new Sequence<>(null, null); } // --- @@ -134,26 +126,28 @@ public B result() { private class Sequence implements Serializer.Sequence, Struct, Map { + private final SerializationContext ctx; private final Endec valueEndec; - private Sequence(Endec valueEndec) { + private Sequence(SerializationContext ctx, Endec valueEndec) { + this.ctx = ctx; this.valueEndec = valueEndec; } @Override public void element(V element) { - this.valueEndec.encode(ByteBufSerializer.this, element); + this.valueEndec.encode(this.ctx, ByteBufSerializer.this, element); } @Override public void entry(String key, V value) { - ByteBufSerializer.this.writeString(key); - this.valueEndec.encode(ByteBufSerializer.this, value); + ByteBufSerializer.this.writeString(this.ctx, key); + this.valueEndec.encode(this.ctx, ByteBufSerializer.this, value); } @Override - public Struct field(String name, Endec endec, F value) { - endec.encode(ByteBufSerializer.this, value); + public Struct field(String name, SerializationContext ctx, Endec endec, F value) { + endec.encode(ctx, ByteBufSerializer.this, value); return this; } diff --git a/src/main/java/io/wispforest/owo/serialization/format/data/DataInputDeserializer.java b/src/main/java/io/wispforest/owo/serialization/format/data/DataInputDeserializer.java index 1422c328..5199fb86 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/data/DataInputDeserializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/data/DataInputDeserializer.java @@ -2,13 +2,12 @@ import io.wispforest.owo.serialization.Deserializer; import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; +import io.wispforest.owo.serialization.SerializationContext; import org.jetbrains.annotations.Nullable; import java.io.DataInput; import java.io.IOException; import java.util.Optional; -import java.util.Set; import java.util.function.Function; public class DataInputDeserializer implements Deserializer { @@ -26,14 +25,7 @@ public static DataInputDeserializer of(DataInput input) { // --- @Override - public Set attributes() { - return Set.of(); - } - - // --- - - @Override - public byte readByte() { + public byte readByte(SerializationContext ctx) { try { return this.input.readByte(); } catch (IOException e) { @@ -42,7 +34,7 @@ public byte readByte() { } @Override - public short readShort() { + public short readShort(SerializationContext ctx) { try { return this.input.readShort(); } catch (IOException e) { @@ -51,7 +43,7 @@ public short readShort() { } @Override - public int readInt() { + public int readInt(SerializationContext ctx) { try { return this.input.readInt(); } catch (IOException e) { @@ -60,7 +52,7 @@ public int readInt() { } @Override - public long readLong() { + public long readLong(SerializationContext ctx) { try { return this.input.readLong(); } catch (IOException e) { @@ -69,7 +61,7 @@ public long readLong() { } @Override - public float readFloat() { + public float readFloat(SerializationContext ctx) { try { return this.input.readFloat(); } catch (IOException e) { @@ -78,7 +70,7 @@ public float readFloat() { } @Override - public double readDouble() { + public double readDouble(SerializationContext ctx) { try { return this.input.readDouble(); } catch (IOException e) { @@ -89,7 +81,7 @@ public double readDouble() { // --- @Override - public int readVarInt() { + public int readVarInt(SerializationContext ctx) { try { int result = 0; int bytes = 0; @@ -110,7 +102,7 @@ public int readVarInt() { } @Override - public long readVarLong() { + public long readVarLong(SerializationContext ctx) { try { long result = 0L; int bytes = 0; @@ -133,7 +125,7 @@ public long readVarLong() { // --- @Override - public boolean readBoolean() { + public boolean readBoolean(SerializationContext ctx) { try { return this.input.readBoolean(); } catch (IOException e) { @@ -142,7 +134,7 @@ public boolean readBoolean() { } @Override - public String readString() { + public String readString(SerializationContext ctx) { try { return this.input.readUTF(); } catch (IOException e) { @@ -151,8 +143,8 @@ public String readString() { } @Override - public byte[] readBytes() { - var result = new byte[this.readVarInt()]; + public byte[] readBytes(SerializationContext ctx) { + var result = new byte[this.readVarInt(ctx)]; try { this.input.readFully(result); @@ -164,9 +156,9 @@ public byte[] readBytes() { } @Override - public Optional readOptional(Endec endec) { - return this.readBoolean() - ? Optional.of(endec.decode(this)) + public Optional readOptional(SerializationContext ctx, Endec endec) { + return this.readBoolean(ctx) + ? Optional.of(endec.decode(ctx, this)) : Optional.empty(); } @@ -180,30 +172,32 @@ public V tryRead(Function, V> reader) { // --- @Override - public Deserializer.Sequence sequence(Endec elementEndec) { - return new Sequence<>(elementEndec, this.readVarInt()); + public Deserializer.Sequence sequence(SerializationContext ctx, Endec elementEndec) { + return new Sequence<>(ctx, elementEndec, this.readVarInt(ctx)); } @Override - public Deserializer.Map map(Endec valueEndec) { - return new Map<>(valueEndec, this.readVarInt()); + public Deserializer.Map map(SerializationContext ctx, Endec valueEndec) { + return new Map<>(ctx, valueEndec, this.readVarInt(ctx)); } @Override public Struct struct() { - return new Sequence<>(null, 0); + return new Sequence<>(null, null, 0); } // --- private class Sequence implements Deserializer.Sequence, Struct { + private final SerializationContext ctx; private final Endec valueEndec; private final int size; private int index = 0; - private Sequence(Endec valueEndec, int size) { + private Sequence(SerializationContext ctx, Endec valueEndec, int size) { + this.ctx = ctx; this.valueEndec = valueEndec; this.size = size; } @@ -221,28 +215,30 @@ public boolean hasNext() { @Override public V next() { this.index++; - return this.valueEndec.decode(DataInputDeserializer.this); + return this.valueEndec.decode(this.ctx, DataInputDeserializer.this); } @Override - public @Nullable F field(String name, Endec endec) { - return endec.decode(DataInputDeserializer.this); + public @Nullable F field(String name, SerializationContext ctx, Endec endec) { + return endec.decode(ctx, DataInputDeserializer.this); } @Override - public @Nullable F field(@Nullable String field, Endec endec, @Nullable F defaultValue) { - return endec.decode(DataInputDeserializer.this); + public @Nullable F field(@Nullable String field, SerializationContext ctx, Endec endec, @Nullable F defaultValue) { + return endec.decode(ctx, DataInputDeserializer.this); } } private class Map implements Deserializer.Map { + private final SerializationContext ctx; private final Endec valueEndec; private final int size; private int index = 0; - private Map(Endec valueEndec, int size) { + private Map(SerializationContext ctx, Endec valueEndec, int size) { + this.ctx = ctx; this.valueEndec = valueEndec; this.size = size; } @@ -261,8 +257,8 @@ public boolean hasNext() { public java.util.Map.Entry next() { this.index++; return java.util.Map.entry( - DataInputDeserializer.this.readString(), - this.valueEndec.decode(DataInputDeserializer.this) + DataInputDeserializer.this.readString(this.ctx), + this.valueEndec.decode(this.ctx, DataInputDeserializer.this) ); } } diff --git a/src/main/java/io/wispforest/owo/serialization/format/data/DataOutputSerializer.java b/src/main/java/io/wispforest/owo/serialization/format/data/DataOutputSerializer.java index b230a3fd..01e3aa41 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/data/DataOutputSerializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/data/DataOutputSerializer.java @@ -1,13 +1,12 @@ package io.wispforest.owo.serialization.format.data; import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.Serializer; import java.io.DataOutput; import java.io.IOException; import java.util.Optional; -import java.util.Set; public class DataOutputSerializer implements Serializer { @@ -32,46 +31,39 @@ protected void write(Writer writer) { // --- @Override - public Set attributes() { - return null; - } - - // --- - - @Override - public void writeByte(byte value) { + public void writeByte(SerializationContext ctx, byte value) { this.write(() -> this.output.writeByte(value)); } @Override - public void writeShort(short value) { + public void writeShort(SerializationContext ctx, short value) { this.write(() -> this.output.writeShort(value)); } @Override - public void writeInt(int value) { + public void writeInt(SerializationContext ctx, int value) { this.write(() -> this.output.writeInt(value)); } @Override - public void writeLong(long value) { + public void writeLong(SerializationContext ctx, long value) { this.write(() -> this.output.writeLong(value)); } @Override - public void writeFloat(float value) { + public void writeFloat(SerializationContext ctx, float value) { this.write(() -> this.output.writeFloat(value)); } @Override - public void writeDouble(double value) { + public void writeDouble(SerializationContext ctx, double value) { this.write(() -> this.output.writeDouble(value)); } // --- @Override - public void writeVarInt(int value) { + public void writeVarInt(SerializationContext ctx, int value) { try { while ((value & -128) != 0) { this.output.writeByte(value & 127 | 128); @@ -85,7 +77,7 @@ public void writeVarInt(int value) { } @Override - public void writeVarLong(long value) { + public void writeVarLong(SerializationContext ctx, long value) { try { while ((value & -128L) != 0L) { this.output.writeByte((int) (value & 127L) | 128); @@ -101,46 +93,46 @@ public void writeVarLong(long value) { // --- @Override - public void writeBoolean(boolean value) { + public void writeBoolean(SerializationContext ctx, boolean value) { this.write(() -> this.output.writeBoolean(value)); } @Override - public void writeString(String value) { + public void writeString(SerializationContext ctx, String value) { this.write(() -> this.output.writeUTF(value)); } @Override - public void writeBytes(byte[] bytes) { + public void writeBytes(SerializationContext ctx, byte[] bytes) { this.write(() -> { - this.writeVarInt(bytes.length); + this.writeVarInt(ctx, bytes.length); this.output.write(bytes); }); } @Override - public void writeOptional(Endec endec, Optional optional) { - this.writeBoolean(optional.isPresent()); - optional.ifPresent(value -> endec.encode(this, value)); + public void writeOptional(SerializationContext ctx, Endec endec, Optional optional) { + this.writeBoolean(ctx, optional.isPresent()); + optional.ifPresent(value -> endec.encode(ctx, this, value)); } // --- @Override - public Map map(Endec valueEndec, int size) { - this.writeVarInt(size); - return new Sequence<>(valueEndec); + public Map map(SerializationContext ctx, Endec valueEndec, int size) { + this.writeVarInt(ctx, size); + return new Sequence<>(ctx, valueEndec); } @Override - public Serializer.Sequence sequence(Endec elementEndec, int size) { - this.writeVarInt(size); - return new Sequence<>(elementEndec); + public Serializer.Sequence sequence(SerializationContext ctx, Endec elementEndec, int size) { + this.writeVarInt(ctx, size); + return new Sequence<>(ctx, elementEndec); } @Override public Struct struct() { - return new Sequence<>(null); + return new Sequence<>(null, null); } // --- @@ -154,26 +146,28 @@ public D result() { protected class Sequence implements Serializer.Sequence, Serializer.Struct, Serializer.Map { + private final SerializationContext ctx; protected final Endec valueEndec; - protected Sequence(Endec valueEndec) { + protected Sequence(SerializationContext ctx, Endec valueEndec) { + this.ctx = ctx; this.valueEndec = valueEndec; } @Override public void element(V element) { - this.valueEndec.encode(DataOutputSerializer.this, element); + this.valueEndec.encode(this.ctx, DataOutputSerializer.this, element); } @Override public void entry(String key, V value) { - DataOutputSerializer.this.writeString(key); - this.valueEndec.encode(DataOutputSerializer.this, value); + DataOutputSerializer.this.writeString(this.ctx, key); + this.valueEndec.encode(this.ctx, DataOutputSerializer.this, value); } @Override - public Struct field(String name, Endec endec, F value) { - endec.encode(DataOutputSerializer.this, value); + public Struct field(String name, SerializationContext ctx, Endec endec, F value) { + endec.encode(ctx, DataOutputSerializer.this, value); return this; } diff --git a/src/main/java/io/wispforest/owo/serialization/format/edm/EdmDeserializer.java b/src/main/java/io/wispforest/owo/serialization/format/edm/EdmDeserializer.java index 9f1581e9..cf63f3bf 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/edm/EdmDeserializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/edm/EdmDeserializer.java @@ -4,14 +4,12 @@ import io.wispforest.owo.serialization.util.RecursiveDeserializer; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; public class EdmDeserializer extends RecursiveDeserializer> implements SelfDescribedDeserializer> { - private static final Set ATTRIBUTES = EnumSet.of( - SerializationAttribute.SELF_DESCRIBING - ); - protected EdmDeserializer(EdmElement serialized) { super(serialized); } @@ -20,81 +18,76 @@ public static EdmDeserializer of(EdmElement serialized) { return new EdmDeserializer(serialized); } - @Override - public Set attributes() { - return ATTRIBUTES; - } - // --- @Override - public byte readByte() { + public byte readByte(SerializationContext ctx) { return this.getValue().cast(); } @Override - public short readShort() { + public short readShort(SerializationContext ctx) { return this.getValue().cast(); } @Override - public int readInt() { + public int readInt(SerializationContext ctx) { return this.getValue().cast(); } @Override - public long readLong() { + public long readLong(SerializationContext ctx) { return this.getValue().cast(); } // --- @Override - public float readFloat() { + public float readFloat(SerializationContext ctx) { return this.getValue().cast(); } @Override - public double readDouble() { + public double readDouble(SerializationContext ctx) { return this.getValue().cast(); } // --- @Override - public int readVarInt() { - return this.readInt(); + public int readVarInt(SerializationContext ctx) { + return this.readInt(ctx); } @Override - public long readVarLong() { - return this.readLong(); + public long readVarLong(SerializationContext ctx) { + return this.readLong(ctx); } // --- @Override - public boolean readBoolean() { + public boolean readBoolean(SerializationContext ctx) { return this.getValue().cast(); } @Override - public String readString() { + public String readString(SerializationContext ctx) { return this.getValue().cast(); } @Override - public byte[] readBytes() { + public byte[] readBytes(SerializationContext ctx) { return this.getValue().cast(); } @Override - public Optional readOptional(Endec endec) { + public Optional readOptional(SerializationContext ctx, Endec endec) { var optional = this.getValue().>>cast(); if (optional.isPresent()) { return this.frame( optional::get, - () -> Optional.of(endec.decode(this)), + () -> Optional.of(endec.decode(ctx, this)), false ); } else { @@ -105,13 +98,13 @@ public Optional readOptional(Endec endec) { // --- @Override - public Deserializer.Sequence sequence(Endec elementEndec) { - return new Sequence<>(elementEndec, this.getValue().cast()); + public Deserializer.Sequence sequence(SerializationContext ctx, Endec elementEndec) { + return new Sequence<>(ctx, elementEndec, this.getValue().cast()); } @Override - public Deserializer.Map map(Endec valueEndec) { - return new Map<>(valueEndec, this.getValue().cast()); + public Deserializer.Map map(SerializationContext ctx, Endec valueEndec) { + return new Map<>(ctx, valueEndec, this.getValue().cast()); } @Override @@ -122,30 +115,29 @@ public Deserializer.Struct struct() { // --- @Override - public void readAny(Serializer visitor) { - this.visit(visitor, this.getValue()); + public void readAny(SerializationContext ctx, Serializer visitor) { + this.visit(ctx, visitor, this.getValue()); } - private void visit(Serializer visitor, EdmElement value) { + private void visit(SerializationContext ctx, Serializer visitor, EdmElement value) { switch (value.type()) { - case BYTE -> visitor.writeByte(value.cast()); - case SHORT -> visitor.writeShort(value.cast()); - case INT -> visitor.writeInt(value.cast()); - case LONG -> visitor.writeLong(value.cast()); - case FLOAT -> visitor.writeFloat(value.cast()); - case DOUBLE -> visitor.writeDouble(value.cast()); - case BOOLEAN -> visitor.writeBoolean(value.cast()); - case STRING -> visitor.writeString(value.cast()); - case BYTES -> visitor.writeBytes(value.cast()); - case OPTIONAL -> - visitor.writeOptional(Endec.>of(this::visit, deserializer -> null), value.cast()); + case BYTE -> visitor.writeByte(ctx, value.cast()); + case SHORT -> visitor.writeShort(ctx, value.cast()); + case INT -> visitor.writeInt(ctx, value.cast()); + case LONG -> visitor.writeLong(ctx, value.cast()); + case FLOAT -> visitor.writeFloat(ctx, value.cast()); + case DOUBLE -> visitor.writeDouble(ctx, value.cast()); + case BOOLEAN -> visitor.writeBoolean(ctx, value.cast()); + case STRING -> visitor.writeString(ctx, value.cast()); + case BYTES -> visitor.writeBytes(ctx, value.cast()); + case OPTIONAL -> visitor.writeOptional(ctx, Endec.>of(this::visit, (ctx1, deserializer) -> null), value.cast()); case SEQUENCE -> { - try (var sequence = visitor.sequence(Endec.>of(this::visit, deserializer -> null), value.>>cast().size())) { + try (var sequence = visitor.sequence(ctx, Endec.>of(this::visit, (ctx1, deserializer) -> null), value.>>cast().size())) { value.>>cast().forEach(sequence::element); } } case MAP -> { - try (var map = visitor.map(Endec.>of(this::visit, deserializer -> null), value.>>cast().size())) { + try (var map = visitor.map(ctx, Endec.>of(this::visit, (ctx1, deserializer) -> null), value.>>cast().size())) { value.>>cast().forEach(map::entry); } } @@ -156,11 +148,13 @@ private void visit(Serializer visitor, EdmElement value) { private class Sequence implements Deserializer.Sequence { + private final SerializationContext ctx; private final Endec valueEndec; private final Iterator> elements; private final int size; - private Sequence(Endec valueEndec, List> elements) { + private Sequence(SerializationContext ctx, Endec valueEndec, List> elements) { + this.ctx = ctx; this.valueEndec = valueEndec; this.elements = elements.iterator(); @@ -181,7 +175,7 @@ public boolean hasNext() { public V next() { return EdmDeserializer.this.frame( this.elements::next, - () -> this.valueEndec.decode(EdmDeserializer.this), + () -> this.valueEndec.decode(this.ctx, EdmDeserializer.this), false ); } @@ -189,11 +183,13 @@ public V next() { private class Map implements Deserializer.Map { + private final SerializationContext ctx; private final Endec valueEndec; private final Iterator>> entries; private final int size; - private Map(Endec valueEndec, java.util.Map> entries) { + private Map(SerializationContext ctx, Endec valueEndec, java.util.Map> entries) { + this.ctx = ctx; this.valueEndec = valueEndec; this.entries = entries.entrySet().iterator(); @@ -215,7 +211,7 @@ public java.util.Map.Entry next() { var entry = entries.next(); return EdmDeserializer.this.frame( entry::getValue, - () -> java.util.Map.entry(entry.getKey(), this.valueEndec.decode(EdmDeserializer.this)), + () -> java.util.Map.entry(entry.getKey(), this.valueEndec.decode(this.ctx, EdmDeserializer.this)), false ); } @@ -230,23 +226,23 @@ private Struct(java.util.Map> map) { } @Override - public @Nullable F field(String name, Endec endec) { + public @Nullable F field(String name, SerializationContext ctx, Endec endec) { if (!this.map.containsKey(name)) { throw new IllegalStateException("Field '" + name + "' was missing from serialized data, but no default value was provided"); } return EdmDeserializer.this.frame( () -> this.map.get(name), - () -> endec.decode(EdmDeserializer.this), + () -> endec.decode(ctx, EdmDeserializer.this), true ); } @Override - public @Nullable F field(String name, Endec endec, @Nullable F defaultValue) { + public @Nullable F field(String name, SerializationContext ctx, Endec endec, @Nullable F defaultValue) { if (!this.map.containsKey(name)) return defaultValue; return EdmDeserializer.this.frame( () -> this.map.get(name), - () -> endec.decode(EdmDeserializer.this), + () -> endec.decode(ctx, EdmDeserializer.this), true ); } diff --git a/src/main/java/io/wispforest/owo/serialization/format/edm/EdmEndec.java b/src/main/java/io/wispforest/owo/serialization/format/edm/EdmEndec.java index ab4f7fc1..cc350969 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/edm/EdmEndec.java +++ b/src/main/java/io/wispforest/owo/serialization/format/edm/EdmEndec.java @@ -8,15 +8,14 @@ public class EdmEndec implements Endec> { public static final EdmEndec INSTANCE = new EdmEndec(); - public static final Endec MAP = INSTANCE.xmap(EdmElement::asMap, edmMap -> edmMap); - + private EdmEndec() {} @Override - public void encode(Serializer serializer, EdmElement value) { - if (serializer.attributes().contains(SerializationAttribute.SELF_DESCRIBING)) { - new EdmDeserializer(value).readAny(serializer); + public void encode(SerializationContext ctx, Serializer serializer, EdmElement value) { + if (serializer instanceof SelfDescribedSerializer) { + new EdmDeserializer(value).readAny(ctx, serializer); return; } @@ -24,23 +23,23 @@ public void encode(Serializer serializer, EdmElement value) { var output = ByteStreams.newDataOutput(); EdmIo.encode(output, value); - serializer.writeBytes(output.toByteArray()); + serializer.writeBytes(ctx, output.toByteArray()); } catch (IOException e) { throw new RuntimeException("Failed to encode EDM element in EdmEndec", e); } } @Override - public EdmElement decode(Deserializer deserializer) { + public EdmElement decode(SerializationContext ctx, Deserializer deserializer) { if (deserializer instanceof SelfDescribedDeserializer selfDescribedDeserializer) { var nativeSerializer = new EdmSerializer(); - selfDescribedDeserializer.readAny(nativeSerializer); + selfDescribedDeserializer.readAny(ctx, nativeSerializer); return nativeSerializer.result(); } try { - return EdmIo.decode(ByteStreams.newDataInput(deserializer.readBytes())); + return EdmIo.decode(ByteStreams.newDataInput(deserializer.readBytes(ctx))); } catch (IOException e) { throw new RuntimeException("Failed to parse EDM element in EdmEndec", e); } diff --git a/src/main/java/io/wispforest/owo/serialization/format/edm/EdmMap.java b/src/main/java/io/wispforest/owo/serialization/format/edm/EdmMap.java index 67af06ce..1ccf4067 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/edm/EdmMap.java +++ b/src/main/java/io/wispforest/owo/serialization/format/edm/EdmMap.java @@ -1,5 +1,6 @@ package io.wispforest.owo.serialization.format.edm; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.endec.KeyedEndec; import io.wispforest.owo.serialization.util.MapCarrier; import org.jetbrains.annotations.NotNull; @@ -13,14 +14,14 @@ public final class EdmMap extends EdmElement>> impleme } @Override - public T getWithErrors(@NotNull KeyedEndec key) { + public T getWithErrors(@NotNull KeyedEndec key, SerializationContext ctx) { if (!this.has(key)) return key.defaultValue(); - return key.endec().decodeFully(EdmDeserializer::of, this.value().get(key.key())); + return key.endec().decodeFully(ctx, EdmDeserializer::of, this.value().get(key.key())); } @Override - public void put(@NotNull KeyedEndec key, @NotNull T value) { - this.value().put(key.key(), key.endec().encodeFully(EdmSerializer::of, value)); + public void put(@NotNull KeyedEndec key, @NotNull T value, SerializationContext ctx) { + this.value().put(key.key(), key.endec().encodeFully(ctx, EdmSerializer::of, value)); } @Override diff --git a/src/main/java/io/wispforest/owo/serialization/format/edm/EdmOps.java b/src/main/java/io/wispforest/owo/serialization/format/edm/EdmOps.java index ac07fbab..99d24784 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/edm/EdmOps.java +++ b/src/main/java/io/wispforest/owo/serialization/format/edm/EdmOps.java @@ -4,18 +4,33 @@ import com.mojang.datafixers.util.Pair; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import io.wispforest.owo.serialization.SerializationContext; import java.nio.ByteBuffer; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; -@SuppressWarnings("unchecked") public class EdmOps implements DynamicOps> { - public static final EdmOps INSTANCE = new EdmOps(); + private static final EdmOps NO_CONTEXT = new EdmOps(SerializationContext.empty()); - private EdmOps() {} + private final SerializationContext capturedContext; + private EdmOps(SerializationContext capturedContext) { + this.capturedContext = capturedContext; + } + + public static EdmOps withContext(SerializationContext context) { + return new EdmOps(context); + } + + public static EdmOps withoutContext() { + return NO_CONTEXT; + } + + public SerializationContext capturedContext() { + return this.capturedContext; + } // --- Serialization --- @@ -185,10 +200,8 @@ public U convertTo(DynamicOps outOps, EdmElement input) { case BOOLEAN -> outOps.createBoolean(input.cast()); case STRING -> outOps.createString(input.cast()); case BYTES -> outOps.createByteList(ByteBuffer.wrap(input.cast())); - case OPTIONAL -> - input.>>cast().map(element -> this.convertTo(outOps, element)).orElse(outOps.empty()); - case SEQUENCE -> - outOps.createList(input.>>cast().stream().map(element -> this.convertTo(outOps, element))); + case OPTIONAL -> input.>>cast().map(element -> this.convertTo(outOps, element)).orElse(outOps.empty()); + case SEQUENCE -> outOps.createList(input.>>cast().stream().map(element -> this.convertTo(outOps, element))); case MAP -> outOps.createMap(input.>>cast().entrySet().stream().map(entry -> new Pair<>(outOps.createString(entry.getKey()), this.convertTo(outOps, entry.getValue())))); }; diff --git a/src/main/java/io/wispforest/owo/serialization/format/edm/EdmSerializer.java b/src/main/java/io/wispforest/owo/serialization/format/edm/EdmSerializer.java index 8739f45f..fb07d02a 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/edm/EdmSerializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/edm/EdmSerializer.java @@ -1,19 +1,17 @@ package io.wispforest.owo.serialization.format.edm; -import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; -import io.wispforest.owo.serialization.Serializer; +import com.google.common.collect.ImmutableSet; +import io.wispforest.owo.serialization.*; import io.wispforest.owo.serialization.util.RecursiveSerializer; import org.apache.commons.lang3.mutable.MutableObject; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; -public class EdmSerializer extends RecursiveSerializer> { - - private static final Set ATTRIBUTES = EnumSet.of( - SerializationAttribute.SELF_DESCRIBING - ); +public class EdmSerializer extends RecursiveSerializer> implements SelfDescribedSerializer> { protected EdmSerializer() { super(null); @@ -26,78 +24,71 @@ public static EdmSerializer of() { // --- @Override - public Set attributes() { - return ATTRIBUTES; - } - - // --- - - @Override - public void writeByte(byte value) { + public void writeByte(SerializationContext ctx, byte value) { this.consume(EdmElement.wrapByte(value)); } @Override - public void writeShort(short value) { + public void writeShort(SerializationContext ctx, short value) { this.consume(EdmElement.wrapShort(value)); } @Override - public void writeInt(int value) { + public void writeInt(SerializationContext ctx, int value) { this.consume(EdmElement.wrapInt(value)); } @Override - public void writeLong(long value) { + public void writeLong(SerializationContext ctx, long value) { this.consume(EdmElement.wrapLong(value)); } // --- @Override - public void writeFloat(float value) { + public void writeFloat(SerializationContext ctx, float value) { this.consume(EdmElement.wrapFloat(value)); } @Override - public void writeDouble(double value) { + public void writeDouble(SerializationContext ctx, double value) { this.consume(EdmElement.wrapDouble(value)); } // --- @Override - public void writeVarInt(int value) { + public void writeVarInt(SerializationContext ctx, int value) { this.consume(EdmElement.wrapInt(value)); } @Override - public void writeVarLong(long value) { + public void writeVarLong(SerializationContext ctx, long value) { this.consume(EdmElement.wrapLong(value)); } // --- @Override - public void writeBoolean(boolean value) { + public void writeBoolean(SerializationContext ctx, boolean value) { this.consume(EdmElement.wrapBoolean(value)); } @Override - public void writeString(String value) { + public void writeString(SerializationContext ctx, String value) { this.consume(EdmElement.wrapString(value)); } @Override - public void writeBytes(byte[] bytes) { + public void writeBytes(SerializationContext ctx, byte[] bytes) { this.consume(EdmElement.wrapBytes(bytes)); } @Override - public void writeOptional(Endec endec, Optional optional) { + public void writeOptional(SerializationContext ctx, Endec endec, Optional optional) { var result = new MutableObject<@Nullable EdmElement>(); this.frame(encoded -> { - optional.ifPresent(v -> endec.encode(this, v)); + optional.ifPresent(v -> endec.encode(ctx, this, v)); result.setValue(encoded.get()); }, false); @@ -107,13 +98,13 @@ public void writeOptional(Endec endec, Optional optional) { // --- @Override - public Serializer.Sequence sequence(Endec elementEndec, int size) { - return new Sequence<>(elementEndec); + public Serializer.Sequence sequence(SerializationContext ctx, Endec elementEndec, int size) { + return new Sequence<>(ctx, elementEndec); } @Override - public Serializer.Map map(Endec valueEndec, int size) { - return new Map<>(valueEndec); + public Serializer.Map map(SerializationContext ctx, Endec valueEndec, int size) { + return new Map<>(ctx, valueEndec); } @Override @@ -125,10 +116,12 @@ public Serializer.Struct struct() { private class Sequence implements Serializer.Sequence { + private final SerializationContext ctx; private final Endec elementEndec; private final List> result; - private Sequence(Endec elementEndec) { + private Sequence(SerializationContext ctx, Endec elementEndec) { + this.ctx = ctx; this.elementEndec = elementEndec; this.result = new ArrayList<>(); } @@ -136,7 +129,7 @@ private Sequence(Endec elementEndec) { @Override public void element(V element) { EdmSerializer.this.frame(encoded -> { - this.elementEndec.encode(EdmSerializer.this, element); + this.elementEndec.encode(this.ctx, EdmSerializer.this, element); this.result.add(encoded.require("sequence element")); }, false); } @@ -149,10 +142,12 @@ public void end() { private class Map implements Serializer.Map { + private final SerializationContext ctx; private final Endec valueEndec; private final java.util.Map> result; - private Map(Endec valueEndec) { + private Map(SerializationContext ctx, Endec valueEndec) { + this.ctx = ctx; this.valueEndec = valueEndec; this.result = new HashMap<>(); } @@ -160,7 +155,7 @@ private Map(Endec valueEndec) { @Override public void entry(String key, V value) { EdmSerializer.this.frame(encoded -> { - this.valueEndec.encode(EdmSerializer.this, value); + this.valueEndec.encode(this.ctx, EdmSerializer.this, value); this.result.put(key, encoded.require("map value")); }, false); } @@ -180,9 +175,9 @@ private Struct() { } @Override - public Serializer.Struct field(String name, Endec endec, F value) { + public Serializer.Struct field(String name, SerializationContext ctx, Endec endec, F value) { EdmSerializer.this.frame(encoded -> { - endec.encode(EdmSerializer.this, value); + endec.encode(ctx, EdmSerializer.this, value); this.result.put(name, encoded.require("struct field")); }, true); diff --git a/src/main/java/io/wispforest/owo/serialization/format/edm/LenientEdmDeserializer.java b/src/main/java/io/wispforest/owo/serialization/format/edm/LenientEdmDeserializer.java index 93a20a04..7e390788 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/edm/LenientEdmDeserializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/edm/LenientEdmDeserializer.java @@ -1,7 +1,7 @@ package io.wispforest.owo.serialization.format.edm; import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; +import io.wispforest.owo.serialization.SerializationContext; import java.util.Optional; @@ -18,59 +18,59 @@ public static LenientEdmDeserializer of(EdmElement serialized) { // --- @Override - public byte readByte() { + public byte readByte(SerializationContext ctx) { return this.getValue().cast().byteValue(); } @Override - public short readShort() { + public short readShort(SerializationContext ctx) { return this.getValue().cast().shortValue(); } @Override - public int readInt() { + public int readInt(SerializationContext ctx) { return this.getValue().cast().intValue(); } @Override - public long readLong() { + public long readLong(SerializationContext ctx) { return this.getValue().cast().longValue(); } // --- @Override - public float readFloat() { + public float readFloat(SerializationContext ctx) { return this.getValue().cast().floatValue(); } @Override - public double readDouble() { + public double readDouble(SerializationContext ctx) { return this.getValue().cast().doubleValue(); } // --- @Override - public boolean readBoolean() { + public boolean readBoolean(SerializationContext ctx) { if(this.getValue().value() instanceof Number number){ return number.byteValue() == 1; } - return super.readBoolean(); + return super.readBoolean(ctx); } @Override - public Optional readOptional(Endec endec) { + public Optional readOptional(SerializationContext ctx, Endec endec) { var edmElement = this.getValue(); if(edmElement == null){ return Optional.empty(); } else if(edmElement.value() instanceof Optional){ - return super.readOptional(endec); + return super.readOptional(ctx, endec); } else { - return Optional.of(endec.decode(this)); + return Optional.of(endec.decode(ctx, this)); } } } diff --git a/src/main/java/io/wispforest/owo/serialization/format/forwarding/ForwardingDeserializer.java b/src/main/java/io/wispforest/owo/serialization/format/forwarding/ForwardingDeserializer.java deleted file mode 100644 index d6e27016..00000000 --- a/src/main/java/io/wispforest/owo/serialization/format/forwarding/ForwardingDeserializer.java +++ /dev/null @@ -1,132 +0,0 @@ -package io.wispforest.owo.serialization.format.forwarding; - -import com.google.common.collect.ImmutableSet; -import io.wispforest.owo.serialization.*; - -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; - -public class ForwardingDeserializer implements Deserializer { - - private final Set attributes; - private final Deserializer delegate; - - protected ForwardingDeserializer(Deserializer delegate, Set attributes) { - this.delegate = delegate; - this.attributes = attributes; - } - - public static ForwardingDeserializer of(Deserializer delegate, SerializationAttribute... assumedAttributes) { - var attributes = ImmutableSet.builder() - .addAll(delegate.attributes()) - .add(assumedAttributes) - .build(); - - return (delegate instanceof SelfDescribedDeserializer selfDescribedDeserializer) - ? new ForwardingSelfDescribedDeserializer<>(selfDescribedDeserializer, attributes) - : new ForwardingDeserializer<>(delegate, attributes); - } - - public Deserializer delegate() { - return this.delegate; - } - - //-- - - @Override - public Set attributes() { - return attributes; - } - - @Override - public byte readByte() { - return this.delegate.readByte(); - } - - @Override - public short readShort() { - return this.delegate.readShort(); - } - - @Override - public int readInt() { - return this.delegate.readInt(); - } - - @Override - public long readLong() { - return this.delegate.readLong(); - } - - @Override - public float readFloat() { - return this.delegate.readFloat(); - } - - @Override - public double readDouble() { - return this.delegate.readDouble(); - } - - @Override - public int readVarInt() { - return this.delegate.readVarInt(); - } - - @Override - public long readVarLong() { - return this.delegate.readVarLong(); - } - - @Override - public boolean readBoolean() { - return this.delegate.readBoolean(); - } - - @Override - public String readString() { - return this.delegate.readString(); - } - - @Override - public byte[] readBytes() { - return this.delegate.readBytes(); - } - - @Override - public Optional readOptional(Endec endec) { - return this.delegate.readOptional(endec); - } - - @Override - public Sequence sequence(Endec elementEndec) { - return this.delegate.sequence(elementEndec); - } - - @Override - public Map map(Endec valueEndec) { - return this.delegate.map(valueEndec); - } - - @Override - public Struct struct() { - return this.delegate.struct(); - } - - @Override - public V tryRead(Function, V> reader) { - return this.delegate.tryRead(reader); - } - - private static class ForwardingSelfDescribedDeserializer extends ForwardingDeserializer implements SelfDescribedDeserializer { - private ForwardingSelfDescribedDeserializer(Deserializer delegate, Set attributes) { - super(delegate, attributes); - } - - @Override - public void readAny(Serializer visitor) { - ((SelfDescribedDeserializer) this.delegate()).readAny(visitor); - } - } -} diff --git a/src/main/java/io/wispforest/owo/serialization/format/forwarding/ForwardingSerializer.java b/src/main/java/io/wispforest/owo/serialization/format/forwarding/ForwardingSerializer.java deleted file mode 100644 index fe5c3a63..00000000 --- a/src/main/java/io/wispforest/owo/serialization/format/forwarding/ForwardingSerializer.java +++ /dev/null @@ -1,121 +0,0 @@ -package io.wispforest.owo.serialization.format.forwarding; - -import com.google.common.collect.ImmutableSet; -import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; -import io.wispforest.owo.serialization.Serializer; - -import java.util.Optional; -import java.util.Set; - -public class ForwardingSerializer implements Serializer { - - private final Set attributes; - private final Serializer delegate; - - protected ForwardingSerializer(Serializer delegate, Set attributes) { - this.delegate = delegate; - this.attributes = attributes; - } - - public Serializer delegate() { - return this.delegate; - } - - public static ForwardingSerializer of(Serializer delegate, SerializationAttribute... assumedAttributes) { - return new ForwardingSerializer<>( - delegate, - ImmutableSet.builder() - .addAll(delegate.attributes()) - .add(assumedAttributes) - .build() - ); - } - - //-- - - @Override - public Set attributes() { - return attributes; - } - - @Override - public void writeByte(byte value) { - this.delegate.writeByte(value); - } - - @Override - public void writeShort(short value) { - this.delegate.writeShort(value); - } - - @Override - public void writeInt(int value) { - this.delegate.writeInt(value); - } - - @Override - public void writeLong(long value) { - this.delegate.writeLong(value); - } - - @Override - public void writeFloat(float value) { - this.delegate.writeFloat(value); - } - - @Override - public void writeDouble(double value) { - this.delegate.writeDouble(value); - } - - @Override - public void writeVarInt(int value) { - this.delegate.writeVarInt(value); - } - - @Override - public void writeVarLong(long value) { - this.delegate.writeVarLong(value); - } - - @Override - public void writeBoolean(boolean value) { - this.delegate.writeBoolean(value); - } - - @Override - public void writeString(String value) { - this.delegate.writeString(value); - } - - @Override - public void writeBytes(byte[] bytes) { - this.delegate.writeBytes(bytes); - } - - @Override - public void writeOptional(Endec endec, Optional optional) { - this.delegate.writeOptional(endec, optional); - } - - @Override - public Sequence sequence(Endec elementEndec, int size) { - return this.delegate.sequence(elementEndec, size); - } - - @Override - public Map map(Endec valueEndec, int size) { - return this.delegate.map(valueEndec, size); - } - - @Override - public Struct struct() { - return this.delegate.struct(); - } - - @Override - public T result() { - return this.delegate.result(); - } -} diff --git a/src/main/java/io/wispforest/owo/serialization/format/json/JsonDeserializer.java b/src/main/java/io/wispforest/owo/serialization/format/json/JsonDeserializer.java index b1d931bb..b6aae43c 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/json/JsonDeserializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/json/JsonDeserializer.java @@ -8,18 +8,11 @@ import io.wispforest.owo.serialization.util.RecursiveDeserializer; import org.jetbrains.annotations.Nullable; -import java.util.EnumSet; import java.util.Iterator; import java.util.Optional; -import java.util.Set; public class JsonDeserializer extends RecursiveDeserializer implements SelfDescribedDeserializer { - private static final Set ATTRIBUTES = EnumSet.of( - SerializationAttribute.SELF_DESCRIBING, - SerializationAttribute.HUMAN_READABLE - ); - protected JsonDeserializer(JsonElement serialized) { super(serialized); } @@ -28,71 +21,69 @@ public static JsonDeserializer of(JsonElement serialized) { return new JsonDeserializer(serialized); } - // --- - @Override - public Set attributes() { - return ATTRIBUTES; + public SerializationContext setupContext(SerializationContext ctx) { + return super.setupContext(ctx).withAttributes(SerializationAttributes.HUMAN_READABLE); } // --- @Override - public byte readByte() { + public byte readByte(SerializationContext ctx) { return this.getValue().getAsByte(); } @Override - public short readShort() { + public short readShort(SerializationContext ctx) { return this.getValue().getAsShort(); } @Override - public int readInt() { + public int readInt(SerializationContext ctx) { return this.getValue().getAsInt(); } @Override - public long readLong() { + public long readLong(SerializationContext ctx) { return this.getValue().getAsLong(); } @Override - public float readFloat() { + public float readFloat(SerializationContext ctx) { return this.getValue().getAsFloat(); } @Override - public double readDouble() { + public double readDouble(SerializationContext ctx) { return this.getValue().getAsDouble(); } // --- @Override - public int readVarInt() { - return this.readInt(); + public int readVarInt(SerializationContext ctx) { + return this.readInt(ctx); } @Override - public long readVarLong() { - return this.readLong(); + public long readVarLong(SerializationContext ctx) { + return this.readLong(ctx); } // --- @Override - public boolean readBoolean() { + public boolean readBoolean(SerializationContext ctx) { return this.getValue().getAsBoolean(); } @Override - public String readString() { + public String readString(SerializationContext ctx) { return this.getValue().getAsString(); } @Override - public byte[] readBytes() { + public byte[] readBytes(SerializationContext ctx) { var array = this.getValue().getAsJsonArray().asList(); var result = new byte[array.size()]; @@ -104,23 +95,23 @@ public byte[] readBytes() { } @Override - public Optional readOptional(Endec endec) { + public Optional readOptional(SerializationContext ctx, Endec endec) { var value = this.getValue(); return !value.isJsonNull() - ? Optional.of(endec.decode(this)) + ? Optional.of(endec.decode(ctx, this)) : Optional.empty(); } // --- @Override - public Deserializer.Sequence sequence(Endec elementEndec) { - return new Sequence<>(elementEndec, (JsonArray) this.getValue()); + public Deserializer.Sequence sequence(SerializationContext ctx, Endec elementEndec) { + return new Sequence<>(ctx, elementEndec, (JsonArray) this.getValue()); } @Override - public Deserializer.Map map(Endec valueEndec) { - return new Map<>(valueEndec, ((JsonObject) this.getValue())); + public Deserializer.Map map(SerializationContext ctx, Endec valueEndec) { + return new Map<>(ctx, valueEndec, ((JsonObject) this.getValue())); } @Override @@ -131,18 +122,18 @@ public Deserializer.Struct struct() { // --- @Override - public void readAny(Serializer visitor) { - this.decodeValue(visitor, this.getValue()); + public void readAny(SerializationContext ctx, Serializer visitor) { + this.decodeValue(ctx, visitor, this.getValue()); } - private void decodeValue(Serializer visitor, JsonElement element) { + private void decodeValue(SerializationContext ctx, Serializer visitor, JsonElement element) { if (element.isJsonNull()) { - visitor.writeOptional(JsonEndec.INSTANCE, Optional.empty()); + visitor.writeOptional(ctx, JsonEndec.INSTANCE, Optional.empty()); } else if (element instanceof JsonPrimitive primitive) { if (primitive.isString()) { - visitor.writeString(primitive.getAsString()); + visitor.writeString(ctx, primitive.getAsString()); } else if (primitive.isBoolean()) { - visitor.writeBoolean(primitive.getAsBoolean()); + visitor.writeBoolean(ctx, primitive.getAsBoolean()); } else { var value = primitive.getAsBigDecimal(); @@ -150,30 +141,30 @@ private void decodeValue(Serializer visitor, JsonElement element) { var asLong = value.longValueExact(); if ((byte) asLong == asLong) { - visitor.writeByte(element.getAsByte()); + visitor.writeByte(ctx, element.getAsByte()); } else if ((short) asLong == asLong) { - visitor.writeShort(element.getAsShort()); + visitor.writeShort(ctx, element.getAsShort()); } else if ((int) asLong == asLong) { - visitor.writeInt(element.getAsInt()); + visitor.writeInt(ctx, element.getAsInt()); } else { - visitor.writeLong(asLong); + visitor.writeLong(ctx, asLong); } } catch (ArithmeticException bruh /* quite cringe java moment, why use an exception for this */) { var asDouble = value.doubleValue(); if ((float) asDouble == asDouble) { - visitor.writeFloat(element.getAsFloat()); + visitor.writeFloat(ctx, element.getAsFloat()); } else { - visitor.writeDouble(asDouble); + visitor.writeDouble(ctx, asDouble); } } } } else if (element instanceof JsonArray array) { - try (var sequence = visitor.sequence(Endec.of(this::decodeValue, deserializer -> null), array.size())) { + try (var sequence = visitor.sequence(ctx, Endec.of(this::decodeValue, (ctx1, deserializer) -> null), array.size())) { array.forEach(sequence::element); } } else if (element instanceof JsonObject object) { - try (var map = visitor.map(Endec.of(this::decodeValue, deserializer -> null), object.size())) { + try (var map = visitor.map(ctx, Endec.of(this::decodeValue, (ctx1, deserializer) -> null), object.size())) { object.asMap().forEach(map::entry); } } else { @@ -185,11 +176,13 @@ private void decodeValue(Serializer visitor, JsonElement element) { private class Sequence implements Deserializer.Sequence { + private final SerializationContext ctx; private final Endec valueEndec; private final Iterator elements; private final int size; - private Sequence(Endec valueEndec, JsonArray elements) { + private Sequence(SerializationContext ctx, Endec valueEndec, JsonArray elements) { + this.ctx = ctx; this.valueEndec = valueEndec; this.elements = elements.iterator(); @@ -210,7 +203,7 @@ public boolean hasNext() { public V next() { return JsonDeserializer.this.frame( this.elements::next, - () -> this.valueEndec.decode(JsonDeserializer.this), + () -> this.valueEndec.decode(this.ctx, JsonDeserializer.this), false ); } @@ -218,11 +211,13 @@ public V next() { private class Map implements Deserializer.Map { + private final SerializationContext ctx; private final Endec valueEndec; private final Iterator> entries; private final int size; - private Map(Endec valueEndec, JsonObject entries) { + private Map(SerializationContext ctx, Endec valueEndec, JsonObject entries) { + this.ctx = ctx; this.valueEndec = valueEndec; this.entries = entries.entrySet().iterator(); @@ -244,7 +239,7 @@ public java.util.Map.Entry next() { var entry = entries.next(); return JsonDeserializer.this.frame( entry::getValue, - () -> java.util.Map.entry(entry.getKey(), this.valueEndec.decode(JsonDeserializer.this)), + () -> java.util.Map.entry(entry.getKey(), this.valueEndec.decode(this.ctx, JsonDeserializer.this)), false ); } @@ -259,23 +254,23 @@ private Struct(JsonObject object) { } @Override - public @Nullable F field(String name, Endec endec) { + public @Nullable F field(String name, SerializationContext ctx, Endec endec) { if (!this.object.has(name)) { throw new IllegalStateException("Field '" + name + "' was missing from serialized data, but no default value was provided"); } return JsonDeserializer.this.frame( () -> this.object.get(name), - () -> endec.decode(JsonDeserializer.this), + () -> endec.decode(ctx, JsonDeserializer.this), true ); } @Override - public @Nullable F field(String name, Endec endec, @Nullable F defaultValue) { + public @Nullable F field(String name, SerializationContext ctx, Endec endec, @Nullable F defaultValue) { if (!this.object.has(name)) return defaultValue; return JsonDeserializer.this.frame( () -> this.object.get(name), - () -> endec.decode(JsonDeserializer.this), + () -> endec.decode(ctx, JsonDeserializer.this), true ); } diff --git a/src/main/java/io/wispforest/owo/serialization/format/json/JsonEndec.java b/src/main/java/io/wispforest/owo/serialization/format/json/JsonEndec.java index 5af0e058..59f29cb2 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/json/JsonEndec.java +++ b/src/main/java/io/wispforest/owo/serialization/format/json/JsonEndec.java @@ -11,24 +11,24 @@ public final class JsonEndec implements Endec { private JsonEndec() {} @Override - public void encode(Serializer serializer, JsonElement value) { - if (serializer.attributes().contains(SerializationAttribute.SELF_DESCRIBING)) { - JsonDeserializer.of(value).readAny(serializer); + public void encode(SerializationContext ctx, Serializer serializer, JsonElement value) { + if (serializer instanceof SelfDescribedSerializer) { + JsonDeserializer.of(value).readAny(ctx, serializer); return; } - serializer.writeString(value.toString()); + serializer.writeString(ctx, value.toString()); } @Override - public JsonElement decode(Deserializer deserializer) { + public JsonElement decode(SerializationContext ctx, Deserializer deserializer) { if (deserializer instanceof SelfDescribedDeserializer selfDescribedDeserializer) { var json = JsonSerializer.of(); - selfDescribedDeserializer.readAny(json); + selfDescribedDeserializer.readAny(ctx, json); return json.result(); } - return new JsonStreamParser(deserializer.readString()).next(); + return new JsonStreamParser(deserializer.readString(ctx)).next(); } } diff --git a/src/main/java/io/wispforest/owo/serialization/format/json/JsonSerializer.java b/src/main/java/io/wispforest/owo/serialization/format/json/JsonSerializer.java index e890cd15..a92d68e9 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/json/JsonSerializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/json/JsonSerializer.java @@ -1,18 +1,14 @@ package io.wispforest.owo.serialization.format.json; import com.google.gson.*; -import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; -import io.wispforest.owo.serialization.Serializer; +import io.wispforest.owo.serialization.*; import io.wispforest.owo.serialization.util.RecursiveSerializer; +import io.wispforest.owo.ui.hud.Hud; -import java.util.EnumSet; import java.util.Optional; -import java.util.Set; -public class JsonSerializer extends RecursiveSerializer { +public class JsonSerializer extends RecursiveSerializer implements SelfDescribedSerializer { - private static final Set ATTRIBUTES = EnumSet.allOf(SerializationAttribute.class); private JsonElement prefix; protected JsonSerializer(JsonElement prefix) { @@ -28,71 +24,69 @@ public static JsonSerializer of() { return of(null); } - // --- - @Override - public Set attributes() { - return ATTRIBUTES; + public SerializationContext setupContext(SerializationContext ctx) { + return super.setupContext(ctx).withAttributes(SerializationAttributes.HUMAN_READABLE); } // --- @Override - public void writeByte(byte value) { + public void writeByte(SerializationContext ctx, byte value) { this.consume(new JsonPrimitive(value)); } @Override - public void writeShort(short value) { + public void writeShort(SerializationContext ctx, short value) { this.consume(new JsonPrimitive(value)); } @Override - public void writeInt(int value) { + public void writeInt(SerializationContext ctx, int value) { this.consume(new JsonPrimitive(value)); } @Override - public void writeLong(long value) { + public void writeLong(SerializationContext ctx, long value) { this.consume(new JsonPrimitive(value)); } @Override - public void writeFloat(float value) { + public void writeFloat(SerializationContext ctx, float value) { this.consume(new JsonPrimitive(value)); } @Override - public void writeDouble(double value) { + public void writeDouble(SerializationContext ctx, double value) { this.consume(new JsonPrimitive(value)); } // --- @Override - public void writeVarInt(int value) { - this.writeInt(value); + public void writeVarInt(SerializationContext ctx, int value) { + this.writeInt(ctx, value); } @Override - public void writeVarLong(long value) { - this.writeLong(value); + public void writeVarLong(SerializationContext ctx, long value) { + this.writeLong(ctx, value); } // --- @Override - public void writeBoolean(boolean value) { + public void writeBoolean(SerializationContext ctx, boolean value) { this.consume(new JsonPrimitive(value)); } @Override - public void writeString(String value) { + public void writeString(SerializationContext ctx, String value) { this.consume(new JsonPrimitive(value)); } @Override - public void writeBytes(byte[] bytes) { + public void writeBytes(SerializationContext ctx, byte[] bytes) { var result = new JsonArray(bytes.length); for (int i = 0; i < bytes.length; i++) { result.add(bytes[i]); @@ -102,12 +96,12 @@ public void writeBytes(byte[] bytes) { } @Override - public void writeOptional(Endec endec, Optional optional) { + public void writeOptional(SerializationContext ctx, Endec endec, Optional optional) { if (this.isWritingStructField()) { - optional.ifPresent(value -> endec.encode(this, value)); + optional.ifPresent(value -> endec.encode(ctx, this, value)); } else { optional.ifPresentOrElse( - value -> endec.encode(this, value), + value -> endec.encode(ctx, this, value), () -> this.consume(JsonNull.INSTANCE) ); } @@ -116,28 +110,30 @@ public void writeOptional(Endec endec, Optional optional) { // --- @Override - public Serializer.Sequence sequence(Endec elementEndec, int size) { - return new Sequence<>(elementEndec, size); + public Serializer.Sequence sequence(SerializationContext ctx, Endec elementEndec, int size) { + return new Sequence<>(ctx, elementEndec, size); } @Override - public Serializer.Map map(Endec valueEndec, int size) { - return new Map<>(valueEndec); + public Serializer.Map map(SerializationContext ctx, Endec valueEndec, int size) { + return new Map<>(ctx, valueEndec); } @Override public Struct struct() { - return new Map<>(null); + return new Map<>(null, null); } // --- private class Map implements Serializer.Map, Struct { + private final SerializationContext ctx; private final Endec valueEndec; private final JsonObject result; - private Map(Endec valueEndec) { + private Map(SerializationContext ctx, Endec valueEndec) { + this.ctx = ctx; this.valueEndec = valueEndec; if (JsonSerializer.this.prefix != null) { @@ -155,15 +151,15 @@ private Map(Endec valueEndec) { @Override public void entry(String key, V value) { JsonSerializer.this.frame(encoded -> { - this.valueEndec.encode(JsonSerializer.this, value); + this.valueEndec.encode(this.ctx, JsonSerializer.this, value); this.result.add(key, encoded.require("map value")); }, false); } @Override - public Struct field(String name, Endec endec, F value) { + public Struct field(String name, SerializationContext ctx, Endec endec, F value) { JsonSerializer.this.frame(encoded -> { - endec.encode(JsonSerializer.this, value); + endec.encode(ctx, JsonSerializer.this, value); this.result.add(name, encoded.require("struct field")); }, true); @@ -178,10 +174,12 @@ public void end() { private class Sequence implements Serializer.Sequence { + private final SerializationContext ctx; private final Endec valueEndec; private final JsonArray result; - private Sequence(Endec valueEndec, int size) { + private Sequence(SerializationContext ctx, Endec valueEndec, int size) { + this.ctx = ctx; this.valueEndec = valueEndec; if (JsonSerializer.this.prefix != null) { @@ -199,7 +197,7 @@ private Sequence(Endec valueEndec, int size) { @Override public void element(V element) { JsonSerializer.this.frame(encoded -> { - this.valueEndec.encode(JsonSerializer.this, element); + this.valueEndec.encode(this.ctx, JsonSerializer.this, element); this.result.add(encoded.require("sequence element")); }, false); } diff --git a/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtDeserializer.java b/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtDeserializer.java index a0863c59..471ede03 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtDeserializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtDeserializer.java @@ -9,10 +9,6 @@ public class NbtDeserializer extends RecursiveDeserializer implements SelfDescribedDeserializer { - private static final Set ATTRIBUTES = EnumSet.of( - SerializationAttribute.SELF_DESCRIBING - ); - protected NbtDeserializer(NbtElement element) { super(element); } @@ -32,79 +28,72 @@ private N getAs(NbtElement element, Class clazz) { // --- @Override - public Set attributes() { - return ATTRIBUTES; - } - - // --- - - @Override - public byte readByte() { + public byte readByte(SerializationContext ctx) { return this.getAs(this.getValue(), NbtByte.class).byteValue(); } @Override - public short readShort() { + public short readShort(SerializationContext ctx) { return this.getAs(this.getValue(), NbtShort.class).shortValue(); } @Override - public int readInt() { + public int readInt(SerializationContext ctx) { return this.getAs(this.getValue(), NbtInt.class).intValue(); } @Override - public long readLong() { + public long readLong(SerializationContext ctx) { return this.getAs(this.getValue(), NbtLong.class).longValue(); } @Override - public float readFloat() { + public float readFloat(SerializationContext ctx) { return this.getAs(this.getValue(), NbtFloat.class).floatValue(); } @Override - public double readDouble() { + public double readDouble(SerializationContext ctx) { return this.getAs(this.getValue(), NbtDouble.class).doubleValue(); } // --- @Override - public int readVarInt() { + public int readVarInt(SerializationContext ctx) { return this.getAs(this.getValue(), AbstractNbtNumber.class).intValue(); } @Override - public long readVarLong() { + public long readVarLong(SerializationContext ctx) { return this.getAs(this.getValue(), AbstractNbtNumber.class).longValue(); } // --- @Override - public boolean readBoolean() { + public boolean readBoolean(SerializationContext ctx) { return this.getAs(this.getValue(), NbtByte.class).byteValue() != 0; } @Override - public String readString() { + public String readString(SerializationContext ctx) { return this.getAs(this.getValue(), NbtString.class).asString(); } @Override - public byte[] readBytes() { + public byte[] readBytes(SerializationContext ctx) { return this.getAs(this.getValue(), NbtByteArray.class).getByteArray(); } @Override - public Optional readOptional(Endec endec) { + public Optional readOptional(SerializationContext ctx, Endec endec) { if (this.isReadingStructField()) { - return Optional.of(endec.decode(this)); + return Optional.of(endec.decode(ctx, this)); } else { var struct = this.struct(); - return struct.field("present", Endec.BOOLEAN) - ? Optional.of(struct.field("value", endec)) + return struct.field("present", ctx, Endec.BOOLEAN) + ? Optional.of(struct.field("value", ctx, endec)) : Optional.empty(); } } @@ -112,14 +101,14 @@ public Optional readOptional(Endec endec) { // --- @Override - public Deserializer.Sequence sequence(Endec elementEndec) { + public Deserializer.Sequence sequence(SerializationContext ctx, Endec elementEndec) { //noinspection unchecked - return new Sequence<>(elementEndec, this.getAs(this.getValue(), AbstractNbtList.class)); + return new Sequence<>(ctx, elementEndec, this.getAs(this.getValue(), AbstractNbtList.class)); } @Override - public Deserializer.Map map(Endec valueEndec) { - return new Map<>(valueEndec, this.getAs(this.getValue(), NbtCompound.class)); + public Deserializer.Map map(SerializationContext ctx, Endec valueEndec) { + return new Map<>(ctx, valueEndec, this.getAs(this.getValue(), NbtCompound.class)); } @Override @@ -130,29 +119,29 @@ public Deserializer.Struct struct() { // --- @Override - public void readAny(Serializer visitor) { - this.decodeValue(visitor, this.getValue()); + public void readAny(SerializationContext ctx, Serializer visitor) { + this.decodeValue(ctx, visitor, this.getValue()); } - private void decodeValue(Serializer visitor, NbtElement value) { + private void decodeValue(SerializationContext ctx, Serializer visitor, NbtElement value) { switch (value.getType()) { - case NbtElement.BYTE_TYPE -> visitor.writeByte(((NbtByte) value).byteValue()); - case NbtElement.SHORT_TYPE -> visitor.writeShort(((NbtShort) value).shortValue()); - case NbtElement.INT_TYPE -> visitor.writeInt(((NbtInt) value).intValue()); - case NbtElement.LONG_TYPE -> visitor.writeLong(((NbtLong) value).longValue()); - case NbtElement.FLOAT_TYPE -> visitor.writeFloat(((NbtFloat) value).floatValue()); - case NbtElement.DOUBLE_TYPE -> visitor.writeDouble(((NbtDouble) value).doubleValue()); - case NbtElement.STRING_TYPE -> visitor.writeString(value.asString()); - case NbtElement.BYTE_ARRAY_TYPE -> visitor.writeBytes(((NbtByteArray) value).getByteArray()); + case NbtElement.BYTE_TYPE -> visitor.writeByte(ctx, ((NbtByte) value).byteValue()); + case NbtElement.SHORT_TYPE -> visitor.writeShort(ctx, ((NbtShort) value).shortValue()); + case NbtElement.INT_TYPE -> visitor.writeInt(ctx, ((NbtInt) value).intValue()); + case NbtElement.LONG_TYPE -> visitor.writeLong(ctx, ((NbtLong) value).longValue()); + case NbtElement.FLOAT_TYPE -> visitor.writeFloat(ctx, ((NbtFloat) value).floatValue()); + case NbtElement.DOUBLE_TYPE -> visitor.writeDouble(ctx, ((NbtDouble) value).doubleValue()); + case NbtElement.STRING_TYPE -> visitor.writeString(ctx, value.asString()); + case NbtElement.BYTE_ARRAY_TYPE -> visitor.writeBytes(ctx, ((NbtByteArray) value).getByteArray()); case NbtElement.INT_ARRAY_TYPE, NbtElement.LONG_ARRAY_TYPE, NbtElement.LIST_TYPE -> { var list = (AbstractNbtList) value; - try (var sequence = visitor.sequence(Endec.of(this::decodeValue, deserializer -> null), list.size())) { + try (var sequence = visitor.sequence(ctx, Endec.of(this::decodeValue, (ctx1, deserializer) -> null), list.size())) { list.forEach(sequence::element); } } case NbtElement.COMPOUND_TYPE -> { var compound = (NbtCompound) value; - try (var map = visitor.map(Endec.of(this::decodeValue, deserializer -> null), compound.getSize())) { + try (var map = visitor.map(ctx, Endec.of(this::decodeValue, (ctx1, deserializer) -> null), compound.getSize())) { for (var key : compound.getKeys()) { map.entry(key, compound.get(key)); } @@ -167,11 +156,13 @@ private void decodeValue(Serializer visitor, NbtElement value) { private class Sequence implements Deserializer.Sequence { + private final SerializationContext ctx; private final Endec valueEndec; private final Iterator elements; private final int size; - private Sequence(Endec valueEndec, List elements) { + private Sequence(SerializationContext ctx, Endec valueEndec, List elements) { + this.ctx = ctx; this.valueEndec = valueEndec; this.elements = elements.iterator(); @@ -192,7 +183,7 @@ public boolean hasNext() { public V next() { return NbtDeserializer.this.frame( this.elements::next, - () -> this.valueEndec.decode(NbtDeserializer.this), + () -> this.valueEndec.decode(this.ctx, NbtDeserializer.this), false ); } @@ -200,12 +191,14 @@ public V next() { private class Map implements Deserializer.Map { + private final SerializationContext ctx; private final Endec valueEndec; private final NbtCompound compound; private final Iterator keys; private final int size; - private Map(Endec valueEndec, NbtCompound compound) { + private Map(SerializationContext ctx, Endec valueEndec, NbtCompound compound) { + this.ctx = ctx; this.valueEndec = valueEndec; this.compound = compound; @@ -228,7 +221,7 @@ public java.util.Map.Entry next() { var key = this.keys.next(); return NbtDeserializer.this.frame( () -> this.compound.get(key), - () -> java.util.Map.entry(key, this.valueEndec.decode(NbtDeserializer.this)), + () -> java.util.Map.entry(key, this.valueEndec.decode(this.ctx, NbtDeserializer.this)), false ); } @@ -243,24 +236,24 @@ public Struct(NbtCompound compound) { } @Override - public @Nullable F field(String name, Endec endec) { + public @Nullable F field(String name, SerializationContext ctx, Endec endec) { if (!this.compound.contains(name)) { throw new IllegalStateException("Field '" + name + "' was missing from serialized data, but no default value was provided"); } return NbtDeserializer.this.frame( () -> this.compound.get(name), - () -> endec.decode(NbtDeserializer.this), + () -> endec.decode(ctx, NbtDeserializer.this), true ); } @Override - public @Nullable F field(String name, Endec endec, @Nullable F defaultValue) { + public @Nullable F field(String name, SerializationContext ctx, Endec endec, @Nullable F defaultValue) { if (!this.compound.contains(name)) return defaultValue; return NbtDeserializer.this.frame( () -> this.compound.get(name), - () -> endec.decode(NbtDeserializer.this), + () -> endec.decode(ctx, NbtDeserializer.this), true ); } diff --git a/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtEndec.java b/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtEndec.java index 32a35911..f85800e0 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtEndec.java +++ b/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtEndec.java @@ -5,7 +5,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtTagSizeTracker; +import net.minecraft.nbt.NbtSizeTracker; import java.io.IOException; @@ -17,9 +17,9 @@ public final class NbtEndec implements Endec { private NbtEndec() {} @Override - public void encode(Serializer serializer, NbtElement value) { - if (serializer.attributes().contains(SerializationAttribute.SELF_DESCRIBING)) { - NbtDeserializer.of(value).readAny(serializer); + public void encode(SerializationContext ctx, Serializer serializer, NbtElement value) { + if (serializer instanceof SelfDescribedSerializer) { + NbtDeserializer.of(value).readAny(ctx, serializer); return; } @@ -27,23 +27,23 @@ public void encode(Serializer serializer, NbtElement value) { var output = ByteStreams.newDataOutput(); NbtIo.writeForPacket(value, output); - serializer.writeBytes(output.toByteArray()); + serializer.writeBytes(ctx, output.toByteArray()); } catch (IOException e) { throw new RuntimeException("Failed to encode binary NBT in NbtEndec", e); } } @Override - public NbtElement decode(Deserializer deserializer) { + public NbtElement decode(SerializationContext ctx, Deserializer deserializer) { if (deserializer instanceof SelfDescribedDeserializer selfDescribedDeserializer) { var nbt = NbtSerializer.of(); - selfDescribedDeserializer.readAny(nbt); + selfDescribedDeserializer.readAny(ctx, nbt); return nbt.result(); } try { - return NbtIo.read(ByteStreams.newDataInput(deserializer.readBytes()), NbtTagSizeTracker.ofUnlimitedBytes()); + return NbtIo.read(ByteStreams.newDataInput(deserializer.readBytes(ctx)), NbtSizeTracker.ofUnlimitedBytes()); } catch (IOException e) { throw new RuntimeException("Failed to parse binary NBT in NbtEndec", e); } diff --git a/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtSerializer.java b/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtSerializer.java index 83482057..5027a059 100644 --- a/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtSerializer.java +++ b/src/main/java/io/wispforest/owo/serialization/format/nbt/NbtSerializer.java @@ -1,22 +1,14 @@ package io.wispforest.owo.serialization.format.nbt; -import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; -import io.wispforest.owo.serialization.Serializer; +import io.wispforest.owo.serialization.*; import io.wispforest.owo.serialization.util.RecursiveSerializer; import net.minecraft.nbt.*; import net.minecraft.network.encoding.VarInts; import net.minecraft.network.encoding.VarLongs; -import java.util.EnumSet; import java.util.Optional; -import java.util.Set; -public class NbtSerializer extends RecursiveSerializer { - - private static final Set ATTRIBUTES = EnumSet.of( - SerializationAttribute.SELF_DESCRIBING - ); +public class NbtSerializer extends RecursiveSerializer implements SelfDescribedSerializer { protected NbtElement prefix; @@ -36,46 +28,39 @@ public static NbtSerializer of() { // --- @Override - public Set attributes() { - return ATTRIBUTES; - } - - // --- - - @Override - public void writeByte(byte value) { + public void writeByte(SerializationContext ctx, byte value) { this.consume(NbtByte.of(value)); } @Override - public void writeShort(short value) { + public void writeShort(SerializationContext ctx, short value) { this.consume(NbtShort.of(value)); } @Override - public void writeInt(int value) { + public void writeInt(SerializationContext ctx, int value) { this.consume(NbtInt.of(value)); } @Override - public void writeLong(long value) { + public void writeLong(SerializationContext ctx, long value) { this.consume(NbtLong.of(value)); } @Override - public void writeFloat(float value) { + public void writeFloat(SerializationContext ctx, float value) { this.consume(NbtFloat.of(value)); } @Override - public void writeDouble(double value) { + public void writeDouble(SerializationContext ctx, double value) { this.consume(NbtDouble.of(value)); } // --- @Override - public void writeVarInt(int value) { + public void writeVarInt(SerializationContext ctx, int value) { this.consume(switch (VarInts.getSizeInBytes(value)) { case 0, 1 -> NbtByte.of((byte) value); case 2 -> NbtShort.of((short) value); @@ -84,7 +69,7 @@ public void writeVarInt(int value) { } @Override - public void writeVarLong(long value) { + public void writeVarLong(SerializationContext ctx, long value) { this.consume(switch (VarLongs.getSizeInBytes(value)) { case 0, 1 -> NbtByte.of((byte) value); case 2 -> NbtShort.of((short) value); @@ -96,28 +81,28 @@ public void writeVarLong(long value) { // --- @Override - public void writeBoolean(boolean value) { + public void writeBoolean(SerializationContext ctx, boolean value) { this.consume(NbtByte.of(value)); } @Override - public void writeString(String value) { + public void writeString(SerializationContext ctx, String value) { this.consume(NbtString.of(value)); } @Override - public void writeBytes(byte[] bytes) { + public void writeBytes(SerializationContext ctx, byte[] bytes) { this.consume(new NbtByteArray(bytes)); } @Override - public void writeOptional(Endec endec, Optional optional) { + public void writeOptional(SerializationContext ctx, Endec endec, Optional optional) { if (this.isWritingStructField()) { - optional.ifPresent(v -> endec.encode(this, v)); + optional.ifPresent(v -> endec.encode(ctx, this, v)); } else { try (var struct = this.struct()) { - struct.field("present", Endec.BOOLEAN, optional.isPresent()); - optional.ifPresent(value -> struct.field("value", endec, value)); + struct.field("present", ctx, Endec.BOOLEAN, optional.isPresent()); + optional.ifPresent(value -> struct.field("value", ctx, endec, value)); } } } @@ -125,28 +110,30 @@ public void writeOptional(Endec endec, Optional optional) { // --- @Override - public Serializer.Sequence sequence(Endec elementEndec, int size) { - return new Sequence<>(elementEndec); + public Serializer.Sequence sequence(SerializationContext ctx, Endec elementEndec, int size) { + return new Sequence<>(ctx, elementEndec); } @Override - public Serializer.Map map(Endec valueEndec, int size) { - return new Map<>(valueEndec); + public Serializer.Map map(SerializationContext ctx, Endec valueEndec, int size) { + return new Map<>(ctx, valueEndec); } @Override public Struct struct() { - return new Map<>(null); + return new Map<>(null, null); } // --- private class Map implements Serializer.Map, Struct { + private final SerializationContext ctx; private final Endec valueEndec; private final NbtCompound result; - private Map(Endec valueEndec) { + private Map(SerializationContext ctx, Endec valueEndec) { + this.ctx = ctx; this.valueEndec = valueEndec; if (NbtSerializer.this.prefix != null) { @@ -163,15 +150,15 @@ private Map(Endec valueEndec) { @Override public void entry(String key, V value) { NbtSerializer.this.frame(encoded -> { - this.valueEndec.encode(NbtSerializer.this, value); + this.valueEndec.encode(this.ctx, NbtSerializer.this, value); this.result.put(key, encoded.require("map value")); }, false); } @Override - public Struct field(String name, Endec endec, F value) { + public Struct field(String name, SerializationContext ctx, Endec endec, F value) { NbtSerializer.this.frame(encoded -> { - endec.encode(NbtSerializer.this, value); + endec.encode(ctx, NbtSerializer.this, value); if (encoded.wasEncoded()) { this.result.put(name, encoded.get()); } @@ -188,10 +175,12 @@ public void end() { private class Sequence implements Serializer.Sequence { + private final SerializationContext ctx; private final Endec valueEndec; private final NbtList result; - private Sequence(Endec valueEndec) { + private Sequence(SerializationContext ctx, Endec valueEndec) { + this.ctx = ctx; this.valueEndec = valueEndec; if (NbtSerializer.this.prefix != null) { @@ -208,7 +197,7 @@ private Sequence(Endec valueEndec) { @Override public void element(V element) { NbtSerializer.this.frame(encoded -> { - this.valueEndec.encode(NbtSerializer.this, element); + this.valueEndec.encode(this.ctx, NbtSerializer.this, element); this.result.add(encoded.require("sequence element")); }, false); } diff --git a/src/main/java/io/wispforest/owo/serialization/util/EndecBuffer.java b/src/main/java/io/wispforest/owo/serialization/util/EndecBuffer.java index 2a7ab3d9..8969d389 100644 --- a/src/main/java/io/wispforest/owo/serialization/util/EndecBuffer.java +++ b/src/main/java/io/wispforest/owo/serialization/util/EndecBuffer.java @@ -1,13 +1,22 @@ package io.wispforest.owo.serialization.util; import io.wispforest.owo.serialization.Endec; +import io.wispforest.owo.serialization.SerializationContext; public interface EndecBuffer { + default void write(SerializationContext ctx, Endec endec, T value) { + throw new UnsupportedOperationException(); + } + default void write(Endec endec, T value) { + this.write(SerializationContext.empty(), endec, value); + } + + default T read(SerializationContext ctx, Endec endec) { throw new UnsupportedOperationException(); } default T read(Endec endec) { - throw new UnsupportedOperationException(); + return this.read(SerializationContext.empty(), endec); } } diff --git a/src/main/java/io/wispforest/owo/serialization/util/EndecRecipeSerializer.java b/src/main/java/io/wispforest/owo/serialization/util/EndecRecipeSerializer.java index e67d620a..438ca77b 100644 --- a/src/main/java/io/wispforest/owo/serialization/util/EndecRecipeSerializer.java +++ b/src/main/java/io/wispforest/owo/serialization/util/EndecRecipeSerializer.java @@ -1,23 +1,26 @@ package io.wispforest.owo.serialization.util; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; +import io.wispforest.owo.serialization.SerializationAttributes; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.StructEndec; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; import net.minecraft.recipe.Recipe; import net.minecraft.recipe.RecipeSerializer; public abstract class EndecRecipeSerializer> implements RecipeSerializer { private final StructEndec endec; - private final Endec networkEndec; - private final Codec codec; + private final PacketCodec packetCodec; + private final MapCodec codec; protected EndecRecipeSerializer(StructEndec endec, Endec networkEndec) { this.endec = endec; - this.networkEndec = networkEndec; - this.codec = this.endec.mapCodec(SerializationAttribute.HUMAN_READABLE).codec(); + this.packetCodec = networkEndec.packetCodec(); + this.codec = this.endec.mapCodec(SerializationContext.attributes(SerializationAttributes.HUMAN_READABLE)); } protected EndecRecipeSerializer(StructEndec endec) { @@ -25,17 +28,12 @@ protected EndecRecipeSerializer(StructEndec endec) { } @Override - public Codec codec() { + public MapCodec codec() { return this.codec; } @Override - public R read(PacketByteBuf buf) { - return buf.read(this.networkEndec); - } - - @Override - public void write(PacketByteBuf buf, R recipe) { - buf.write(this.networkEndec, recipe); + public PacketCodec packetCodec() { + return this.packetCodec.cast(); } } diff --git a/src/main/java/io/wispforest/owo/serialization/util/MapCarrier.java b/src/main/java/io/wispforest/owo/serialization/util/MapCarrier.java index fcce441d..346dd53f 100644 --- a/src/main/java/io/wispforest/owo/serialization/util/MapCarrier.java +++ b/src/main/java/io/wispforest/owo/serialization/util/MapCarrier.java @@ -1,5 +1,6 @@ package io.wispforest.owo.serialization.util; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.endec.KeyedEndec; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,17 +15,25 @@ public interface MapCarrier { *

* Any exceptions thrown during decoding are propagated to the caller */ - default T getWithErrors(@NotNull KeyedEndec key) { + default T getWithErrors(@NotNull KeyedEndec key, SerializationContext ctx) { throw new UnsupportedOperationException("Interface default method called"); } + default T getWithErrors(@NotNull KeyedEndec key) { + return this.getWithErrors(key, SerializationContext.empty()); + } + /** * Store {@code value} under {@code key} in this object's associated map */ - default void put(@NotNull KeyedEndec key, @NotNull T value) { + default void put(@NotNull KeyedEndec key, @NotNull T value, SerializationContext ctx) { throw new UnsupportedOperationException("Interface default method called"); } + default void put(@NotNull KeyedEndec key, @NotNull T value) { + this.put(key, value, SerializationContext.empty()); + } + /** * Delete the value stored under {@code key} from this object's associated map, * if it is present @@ -55,6 +64,19 @@ default T get(@NotNull KeyedEndec key) { } } + /** + * Get the value stored under {@code key} in this object's associated map. + * If no such value exists or an exception is thrown during decoding, + * the default value of {@code key} is returned + */ + default T get(@NotNull KeyedEndec key, SerializationContext ctx) { + try { + return this.getWithErrors(key, ctx); + } catch (Exception e) { + return key.defaultValue(); + } + } + /** * If {@code value} is not {@code null}, store it under {@code key} in this * object's associated map diff --git a/src/main/java/io/wispforest/owo/ui/component/BlockComponent.java b/src/main/java/io/wispforest/owo/ui/component/BlockComponent.java index 8c98c23f..c99307b8 100644 --- a/src/main/java/io/wispforest/owo/ui/component/BlockComponent.java +++ b/src/main/java/io/wispforest/owo/ui/component/BlockComponent.java @@ -74,8 +74,10 @@ public void draw(OwoUIDrawContext context, int mouseX, int mouseY, float partial protected static void prepareBlockEntity(BlockState state, BlockEntity blockEntity, @Nullable NbtCompound nbt) { if (blockEntity == null) return; + var world = MinecraftClient.getInstance().world; + ((BlockEntityAccessor) blockEntity).owo$setCachedState(state); - blockEntity.setWorld(MinecraftClient.getInstance().world); + blockEntity.setWorld(world); if (nbt == null) return; @@ -85,7 +87,7 @@ protected static void prepareBlockEntity(BlockState state, BlockEntity blockEnti nbtCopy.putInt("y", 0); nbtCopy.putInt("z", 0); - blockEntity.readNbt(nbtCopy); + blockEntity.read(nbtCopy, world.getRegistryManager()); } public static BlockComponent parse(Element element) { diff --git a/src/main/java/io/wispforest/owo/ui/component/ButtonComponent.java b/src/main/java/io/wispforest/owo/ui/component/ButtonComponent.java index e831c10d..c7615b9c 100644 --- a/src/main/java/io/wispforest/owo/ui/component/ButtonComponent.java +++ b/src/main/java/io/wispforest/owo/ui/component/ButtonComponent.java @@ -51,8 +51,8 @@ public void renderWidget(DrawContext context, int mouseX, int mouseY, float delt } var tooltip = ((ClickableWidgetAccessor) this).owo$getTooltip(); - if (this.hovered && tooltip != null) - context.drawTooltip(textRenderer, tooltip.getLines(MinecraftClient.getInstance()), HoveredTooltipPositioner.INSTANCE, mouseX, mouseY); + if (this.hovered && tooltip.getTooltip() != null) + context.drawTooltip(textRenderer, tooltip.getTooltip().getLines(MinecraftClient.getInstance()), HoveredTooltipPositioner.INSTANCE, mouseX, mouseY); } public ButtonComponent onPress(Consumer onPress) { diff --git a/src/main/java/io/wispforest/owo/ui/component/EntityComponent.java b/src/main/java/io/wispforest/owo/ui/component/EntityComponent.java index 3a12dfef..52f3db80 100644 --- a/src/main/java/io/wispforest/owo/ui/component/EntityComponent.java +++ b/src/main/java/io/wispforest/owo/ui/component/EntityComponent.java @@ -254,7 +254,7 @@ protected RenderablePlayerEntity(GameProfile profile) { profile, new WorldSession(TelemetrySender.NOOP, false, Duration.ZERO, ""), MinecraftClient.getInstance().world.getRegistryManager().toImmutable(), MinecraftClient.getInstance().world.getEnabledFeatures(), - "Wisp Forest Enterprises", null, null + "Wisp Forest Enterprises", null, null, Map.of(), null, false )), null, null, false, false ); diff --git a/src/main/java/io/wispforest/owo/ui/component/ItemComponent.java b/src/main/java/io/wispforest/owo/ui/component/ItemComponent.java index 4ebc6d30..6ce6b155 100644 --- a/src/main/java/io/wispforest/owo/ui/component/ItemComponent.java +++ b/src/main/java/io/wispforest/owo/ui/component/ItemComponent.java @@ -12,7 +12,7 @@ import net.fabricmc.fabric.api.client.rendering.v1.TooltipComponentCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.tooltip.TooltipComponent; -import net.minecraft.client.item.TooltipContext; +import net.minecraft.client.item.TooltipType; import net.minecraft.client.render.DiffuseLighting; import net.minecraft.client.render.LightmapTextureManager; import net.minecraft.client.render.OverlayTexture; @@ -21,8 +21,10 @@ import net.minecraft.client.render.model.json.ModelTransformationMode; import net.minecraft.command.argument.ItemStringReader; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.registry.Registries; +import net.minecraft.registry.RegistryWrapper; import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; @@ -32,6 +34,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.stream.Stream; public class ItemComponent extends BaseComponent { @@ -103,7 +106,8 @@ protected void updateTooltipForStack() { if (!this.setTooltipFromStack) return; if (!this.stack.isEmpty()) { - this.tooltip(tooltipFromItem(this.stack, MinecraftClient.getInstance().player, null)); + MinecraftClient client = MinecraftClient.getInstance(); + this.tooltip(tooltipFromItem(this.stack, Item.TooltipContext.create(client.world), client.player, null)); } else { this.tooltip((List) null); } @@ -145,17 +149,18 @@ public boolean showOverlay() { * provided via {@link net.minecraft.item.Item#getTooltipData(ItemStack)} * * @param stack The item stack from which to obtain the tooltip + * @param context the tooltip context * @param player The player to use for context, may be {@code null} - * @param context The tooltip context - {@code null} to fall back to the default provided by + * @param type The tooltip type - {@code null} to fall back to the default provided by * {@link net.minecraft.client.option.GameOptions#advancedItemTooltips} */ - public static List tooltipFromItem(ItemStack stack, @Nullable PlayerEntity player, @Nullable TooltipContext context) { - if (context == null) { - context = MinecraftClient.getInstance().options.advancedItemTooltips ? TooltipContext.ADVANCED : TooltipContext.BASIC; + public static List tooltipFromItem(ItemStack stack, Item.TooltipContext context, @Nullable PlayerEntity player, @Nullable TooltipType type) { + if (type == null) { + type = MinecraftClient.getInstance().options.advancedItemTooltips ? TooltipType.ADVANCED : TooltipType.BASIC; } var tooltip = new ArrayList(); - stack.getTooltip(player, context) + stack.getTooltip(context, player, type) .stream() .map(Text::asOrderedText) .map(TooltipComponent::of) @@ -186,10 +191,11 @@ public void parseProperties(UIModel model, Element element, Map UIParsing.apply(children, "stack", $ -> $.getTextContent().strip(), stackString -> { try { - var result = ItemStringReader.item(Registries.ITEM.getReadOnlyWrapper(), new StringReader(stackString)); + var result = new ItemStringReader(RegistryWrapper.WrapperLookup.of(Stream.of(Registries.ITEM.getReadOnlyWrapper()))) + .consume(new StringReader(stackString)); var stack = new ItemStack(result.item()); - stack.setNbt(result.nbt()); + stack.applyComponentsFrom(result.components()); this.stack(stack); } catch (CommandSyntaxException cse) { diff --git a/src/main/java/io/wispforest/owo/ui/core/OwoUIAdapter.java b/src/main/java/io/wispforest/owo/ui/core/OwoUIAdapter.java index cdb15418..18c73f89 100644 --- a/src/main/java/io/wispforest/owo/ui/core/OwoUIAdapter.java +++ b/src/main/java/io/wispforest/owo/ui/core/OwoUIAdapter.java @@ -71,7 +71,7 @@ public static OwoUIAdapter create(Screen screen, var adapter = new OwoUIAdapter<>(0, 0, screen.width, screen.height, rootComponent); screen.addDrawableChild(adapter); - screen.focusOn(adapter); + screen.setFocused(adapter); return adapter; } diff --git a/src/main/java/io/wispforest/owo/ui/core/Surface.java b/src/main/java/io/wispforest/owo/ui/core/Surface.java index 905b2048..eced8b1d 100644 --- a/src/main/java/io/wispforest/owo/ui/core/Surface.java +++ b/src/main/java/io/wispforest/owo/ui/core/Surface.java @@ -5,6 +5,7 @@ import io.wispforest.owo.ui.parsing.UIModelParsingException; import io.wispforest.owo.ui.parsing.UIParsing; import io.wispforest.owo.ui.util.NinePatchTexture; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.tooltip.TooltipBackgroundRenderer; @@ -39,9 +40,8 @@ public interface Surface { }; Surface OPTIONS_BACKGROUND = (context, component) -> { - RenderSystem.setShaderColor(64 / 255f, 64 / 255f, 64 / 255f, 1); - context.drawTexture(Screen.OPTIONS_BACKGROUND_TEXTURE, component.x(), component.y(), 0, 0, component.width(), component.height(), 32, 32); - RenderSystem.setShaderColor(1, 1, 1, 1); + MinecraftClient.getInstance().gameRenderer.renderBlur(0); + MinecraftClient.getInstance().getFramebuffer().beginWrite(false); }; Surface TOOLTIP = (context, component) -> { diff --git a/src/main/java/io/wispforest/owo/util/pond/OwoScreenHandlerExtension.java b/src/main/java/io/wispforest/owo/util/pond/OwoScreenHandlerExtension.java index c58cce24..5149bf90 100644 --- a/src/main/java/io/wispforest/owo/util/pond/OwoScreenHandlerExtension.java +++ b/src/main/java/io/wispforest/owo/util/pond/OwoScreenHandlerExtension.java @@ -1,12 +1,12 @@ package io.wispforest.owo.util.pond; +import io.wispforest.owo.client.screens.ScreenInternals; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; public interface OwoScreenHandlerExtension { void owo$attachToPlayer(PlayerEntity player); - void owo$readPropertySync(PacketByteBuf buf); + void owo$readPropertySync(ScreenInternals.SyncPropertiesPacket packet); - void owo$handlePacket(PacketByteBuf buf, boolean clientbound); + void owo$handlePacket(ScreenInternals.LocalPacket packet, boolean clientbound); } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 069908e7..454390a1 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -56,9 +56,6 @@ ] }, "loom:injected_interfaces": { - "net/minecraft/class_1799": [ - "io/wispforest/owo/serialization/util/MapCarrier" - ], "net/minecraft/class_2487": [ "io/wispforest/owo/serialization/util/MapCarrier" ], diff --git a/src/main/resources/owo.accesswidener b/src/main/resources/owo.accesswidener index 35df0009..fd9d4f65 100644 --- a/src/main/resources/owo.accesswidener +++ b/src/main/resources/owo.accesswidener @@ -9,3 +9,4 @@ transitive-accessible class net/minecraft/item/ItemGroup$EntriesImpl transitive-accessible class net/minecraft/client/gui/DrawContext$ScissorStack transitive-extendable method net/minecraft/client/gui/widget/CheckboxWidget (IILnet/minecraft/text/Text;Lnet/minecraft/client/font/TextRenderer;ZLnet/minecraft/client/gui/widget/CheckboxWidget$Callback;)V +accessible class net/minecraft/registry/RegistryOps$CachedRegistryInfoGetter \ No newline at end of file diff --git a/src/main/resources/owo.mixins.json b/src/main/resources/owo.mixins.json index 33550982..1901ac37 100644 --- a/src/main/resources/owo.mixins.json +++ b/src/main/resources/owo.mixins.json @@ -7,14 +7,16 @@ "ClientCommonNetworkHandlerAccessor", "ClientConnectionMixin", "Copenhagen", - "ItemStackMixin", + "ForwardingDynamicOpsAccessor", "NbtCompoundMixin", "PacketByteBufMixin", + "RegistryOpsAccessor", "ScreenHandlerInvoker", "ScreenHandlerMixin", "ServerCommonNetworkHandlerAccessor", "ServerPlayerEntityMixin", "ServerPlayerInteractionManagerMixin", + "SetComponentsLootFunctionAccessor", "SimpleRegistryMixin", "TagGroupLoaderMixin", "itemgroup.ItemGroupAccessor", @@ -37,6 +39,7 @@ "ui.access.BlockEntityAccessor" ], "client": [ + "ClientConfigurationNetworkHandlerMixin", "ClientLoginNetworkHandlerAccessor", "DrawContextMixin", "MinecraftClientMixin", diff --git a/src/testmod/java/io/wispforest/uwu/Uwu.java b/src/testmod/java/io/wispforest/uwu/Uwu.java index 3e867730..124d9edb 100644 --- a/src/testmod/java/io/wispforest/uwu/Uwu.java +++ b/src/testmod/java/io/wispforest/uwu/Uwu.java @@ -8,6 +8,8 @@ import com.mojang.authlib.GameProfile; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.logging.LogUtils; +import io.netty.buffer.Unpooled; +import io.wispforest.owo.Owo; import io.wispforest.owo.config.ConfigSynchronizer; import io.wispforest.owo.config.Option; import io.wispforest.owo.itemgroup.Icon; @@ -20,10 +22,10 @@ import io.wispforest.owo.particles.systems.ParticleSystem; import io.wispforest.owo.particles.systems.ParticleSystemController; import io.wispforest.owo.registration.reflect.FieldRegistrationHandler; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.endec.BuiltInEndecs; import io.wispforest.owo.serialization.Endec; import io.wispforest.owo.serialization.endec.StructEndecBuilder; -import io.wispforest.owo.serialization.format.bytebuf.ByteBufDeserializer; import io.wispforest.owo.serialization.format.bytebuf.ByteBufSerializer; import io.wispforest.owo.serialization.format.json.JsonDeserializer; import io.wispforest.owo.serialization.format.json.JsonEndec; @@ -44,7 +46,6 @@ import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.advancement.AdvancementProgress; import net.minecraft.block.Blocks; @@ -57,7 +58,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtHelper; import net.minecraft.nbt.NbtOps; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; import net.minecraft.particle.ParticleTypes; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; @@ -92,7 +93,11 @@ public class Uwu implements ModInitializer { public static final Identifier OWO_ICON_TEXTURE = new Identifier("uwu", "textures/gui/icon.png"); public static final Identifier ANIMATED_BUTTON_TEXTURE = new Identifier("uwu", "textures/gui/animated_icon_test.png"); - public static final ScreenHandlerType EPIC_SCREEN_HANDLER_TYPE = new ScreenHandlerType<>(EpicScreenHandler::new, FeatureFlags.VANILLA_FEATURES); + public static final ScreenHandlerType EPIC_SCREEN_HANDLER_TYPE = Registry.register( + Registries.SCREEN_HANDLER, + new Identifier("uwu", "epic_screen_handler"), + new ScreenHandlerType<>(EpicScreenHandler::new, FeatureFlags.VANILLA_FEATURES) + ); public static final OwoItemGroup FOUR_TAB_GROUP = OwoItemGroup.builder(new Identifier("uwu", "four_tab_group"), () -> Icon.of(Items.AXOLOTL_BUCKET)) .disableDynamicTitle() @@ -184,13 +189,13 @@ public void onInitialize() { } """; - var stacknite = stackEndec.decode(JsonDeserializer.of(new Gson().fromJson(stackData, JsonObject.class))); + var stacknite = stackEndec.decode(SerializationContext.empty(), JsonDeserializer.of(new Gson().fromJson(stackData, JsonObject.class))); System.out.println(stacknite); var serializer = ByteBufSerializer.packet(); - stackEndec.encode(serializer, stacknite); + stackEndec.encode(SerializationContext.empty(), serializer, stacknite); - System.out.println(serializer.result().read(stackEndec)); + System.out.println(serializer.result().read(SerializationContext.empty(), stackEndec)); System.out.println(BuiltInEndecs.BLOCK_POS.codec().encodeStart(NbtOps.INSTANCE, new BlockPos(34, 35, 69)).result().get()); FieldRegistrationHandler.register(UwuItems.class, "uwu", true); @@ -331,7 +336,7 @@ public void onInitialize() { ItemStack handStack = source.getPlayer().getStackInHand(Hand.MAIN_HAND); LOGGER.info(handStack.toString()); - LOGGER.info(handStack.getOrCreateNbt().asString().replace("\n", "\\n")); + LOGGER.info(handStack.getComponents().toString().replace("\n", "\\n")); LOGGER.info("---"); @@ -360,7 +365,7 @@ public void onInitialize() { } LOGGER.info(handStack.toString()); - LOGGER.info(handStack.getOrCreateNbt().asString().replace("\n", "\\n")); + LOGGER.info(handStack.getComponents().toString().replace("\n", "\\n")); LOGGER.info(""); @@ -369,7 +374,7 @@ public void onInitialize() { { LOGGER.info("--- Format Based Endec Test"); - var nbtDataStack = handStack.getOrCreateNbt(); + var nbtDataStack = handStack.encode(access); LOGGER.info(" Input: " + nbtDataStack.asString().replace("\n", "\\n")); @@ -391,7 +396,7 @@ public void onInitialize() { { LOGGER.info("--- Transpose Format Based Endec Test"); - var nbtDataStack = handStack.getOrCreateNbt(); + var nbtDataStack = handStack.encode(access); LOGGER.info(" Input: " + nbtDataStack.asString().replace("\n", "\\n")); @@ -452,7 +457,8 @@ public void onInitialize() { iterations("Vanilla", (buf) -> { ItemStack stack = source.getPlayer().getStackInHand(Hand.MAIN_HAND); - var stackFromByte = buf.writeItemStack(stack).readItemStack(); + ItemStack.PACKET_CODEC.encode(buf, stack); + var stackFromByte = ItemStack.PACKET_CODEC.decode(buf); }); //Codeck @@ -480,7 +486,7 @@ public void onInitialize() { UwuOptionalNetExample.init(); } - private static void iterations(String label, Consumer action){ + private static void iterations(String label, Consumer action){ int maxTrials = 3; int maxIterations = 50; @@ -493,7 +499,7 @@ private static void iterations(String label, Consumer action){ durations.clear(); for (int i = 0; i < maxIterations; i++) { - PacketByteBuf buf = PacketByteBufs.create(); + RegistryByteBuf buf = new RegistryByteBuf(Unpooled.buffer(), Owo.currentServer().getRegistryManager()); long startTime = System.nanoTime(); diff --git a/src/testmod/java/io/wispforest/uwu/client/ComponentTestScreen.java b/src/testmod/java/io/wispforest/uwu/client/ComponentTestScreen.java index 13363459..0e496d45 100644 --- a/src/testmod/java/io/wispforest/uwu/client/ComponentTestScreen.java +++ b/src/testmod/java/io/wispforest/uwu/client/ComponentTestScreen.java @@ -16,6 +16,8 @@ import net.minecraft.client.texture.SpriteAtlasTexture; import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.BundleContentsComponent; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; @@ -292,9 +294,10 @@ protected void init() { ); var bundle = Items.BUNDLE.getDefaultStack(); - var itemList = new NbtList(); - itemList.add(new ItemStack(Items.EMERALD, 16).writeNbt(new NbtCompound())); - bundle.getOrCreateNbt().put("Items", itemList); + var itemList = new ArrayList(); + itemList.add(new ItemStack(Items.EMERALD, 16)); + + bundle.set(DataComponentTypes.BUNDLE_CONTENTS, new BundleContentsComponent(itemList)); rootComponent.child(Components.item(new ItemStack(Items.EMERALD, 16)) .showOverlay(true) @@ -369,6 +372,9 @@ protected void init() { uiAdapter.inflateAndMount(); } + @Override + public void renderBackground(DrawContext context, int mouseX, int mouseY, float delta) {} + @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { super.render(context, mouseX, mouseY, delta); diff --git a/src/testmod/java/io/wispforest/uwu/items/UwuTestStickItem.java b/src/testmod/java/io/wispforest/uwu/items/UwuTestStickItem.java index 021724c4..4ae92f9f 100644 --- a/src/testmod/java/io/wispforest/uwu/items/UwuTestStickItem.java +++ b/src/testmod/java/io/wispforest/uwu/items/UwuTestStickItem.java @@ -1,39 +1,82 @@ package io.wispforest.uwu.items; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import io.wispforest.owo.itemgroup.OwoItemGroup; import io.wispforest.owo.itemgroup.OwoItemSettings; import io.wispforest.owo.ops.WorldOps; -import io.wispforest.owo.serialization.endec.BuiltInEndecs; +import io.wispforest.owo.serialization.Endec; +import io.wispforest.owo.serialization.RegistriesAttribute; +import io.wispforest.owo.serialization.SerializationContext; import io.wispforest.owo.serialization.endec.KeyedEndec; +import io.wispforest.owo.serialization.endec.StructEndecBuilder; import io.wispforest.uwu.Uwu; import io.wispforest.uwu.text.BasedTextContent; +import net.minecraft.component.DataComponentType; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; import net.minecraft.enchantment.Enchantments; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUsageContext; import net.minecraft.item.Items; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryOps; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import net.minecraft.text.TextCodecs; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; +import net.minecraft.util.Identifier; import net.minecraft.util.TypedActionResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class UwuTestStickItem extends Item { - private static final KeyedEndec TEXT_KEY = BuiltInEndecs.TEXT.keyed("Text", Text.empty()); + private static final DataComponentType TEXT_COMPONENT = Registry.register( + Registries.DATA_COMPONENT_TYPE, + new Identifier("uwu", "text"), + DataComponentType.builder() + .codec(TextCodecs.CODEC) + .packetCodec(TextCodecs.PACKET_CODEC) + .build() + ); + + private static final Codec THIS_CODEC_NEEDS_REGISTRIES = new Codec<>() { + @Override + public DataResult> decode(DynamicOps ops, T input) { + if (!(ops instanceof RegistryOps)) return DataResult.error(() -> "need the registries bro"); + return DataResult.success(new Pair<>(ops.getStringValue(input).getOrThrow(), input)); + } + @Override + public DataResult encode(String input, DynamicOps ops, T prefix) { + if (!(ops instanceof RegistryOps)) return DataResult.error(() -> "need the registries bro"); + return DataResult.success(ops.createString(input)); + } + }; + + private static final Endec YEP_SAME_HERE = Endec.ofCodec(Endec.ofCodec(THIS_CODEC_NEEDS_REGISTRIES).codec()); + private static final KeyedEndec KYED = YEP_SAME_HERE.keyed("kyed", (String) null); public UwuTestStickItem() { - super(new OwoItemSettings().group(Uwu.SIX_TAB_GROUP).tab(3).maxCount(1) + super(new OwoItemSettings() + .group(Uwu.SIX_TAB_GROUP).tab(3).maxCount(1) .trackUsageStat() .stackGenerator(OwoItemGroup.DEFAULT_STACK_GENERATOR.andThen((item, stacks) -> { final var stack = new ItemStack(item); - stack.setCustomName(Text.literal("the stick of the test").styled(style -> style.withItalic(false))); + stack.set(DataComponentTypes.CUSTOM_NAME, Text.literal("the stick of the test").styled(style -> style.withItalic(false))); stacks.add(stack); }))); + + Uwu.CHANNEL.registerServerbound(ThatPacket.class, StructEndecBuilder.of(YEP_SAME_HERE.fieldOf("mhmm", ThatPacket::mhmm), ThatPacket::new), (message, access) -> { + System.out.println("that's a packet received alright: " + message.mhmm); + }); } @Override @@ -63,7 +106,29 @@ public TypedActionResult use(World world, PlayerEntity user, Hand han @Override public ActionResult useOnBlock(ItemUsageContext context) { - if (!context.getPlayer().isSneaking()) return ActionResult.PASS; + if (!context.getPlayer().isSneaking()) { + if (context.getWorld().isClient) Uwu.CHANNEL.clientHandle().send(new ThatPacket("stringnite")); + + try { + var stack = context.getStack(); + context.getPlayer().sendMessage(Text.literal("current: " + stack.getOrDefault(DataComponentTypes.CUSTOM_DATA, NbtComponent.DEFAULT).getNbt().get( + KYED, + SerializationContext.attributes(RegistriesAttribute.of(context.getWorld().getRegistryManager())) + ))); + + stack.apply(DataComponentTypes.CUSTOM_DATA, NbtComponent.DEFAULT, nbt -> nbt.apply(nbtCompound -> nbtCompound.put( + KYED, + String.valueOf(context.getWorld().random.nextInt(10000)), + SerializationContext.attributes(RegistriesAttribute.of(context.getWorld().getRegistryManager())) + ))); + context.getPlayer().sendMessage(Text.literal("modified")); + } catch (Exception bruh) { + context.getPlayer().sendMessage(Text.literal("bruh: " + bruh.getMessage())); + } + + return ActionResult.SUCCESS; + } + if (context.getWorld().isClient) return ActionResult.SUCCESS; final var breakStack = new ItemStack(Items.NETHERITE_PICKAXE); @@ -72,16 +137,18 @@ public ActionResult useOnBlock(ItemUsageContext context) { final var stickStack = context.getStack(); - if (!stickStack.has(TEXT_KEY)) { - stickStack.put(TEXT_KEY, Text.of(String.valueOf(context.getWorld().random.nextInt(1000000)))); + if (!stickStack.contains(TEXT_COMPONENT)) { + stickStack.set(TEXT_COMPONENT, Text.of(String.valueOf(context.getWorld().random.nextInt(1000000)))); } - stickStack.mutate(TEXT_KEY, text -> MutableText.of(new BasedTextContent("basednite, ")).append(text)); + stickStack.set(TEXT_COMPONENT, MutableText.of(new BasedTextContent("basednite, ")).append(stickStack.get(TEXT_COMPONENT))); - context.getPlayer().sendMessage(stickStack.getNbt().get(TEXT_KEY), false); + context.getPlayer().sendMessage(stickStack.get(TEXT_COMPONENT), false); Uwu.BREAK_BLOCK_PARTICLES.spawn(context.getWorld(), Vec3d.of(context.getBlockPos()), null); return ActionResult.SUCCESS; } + + private record ThatPacket(String mhmm) {} } diff --git a/src/testmod/java/io/wispforest/uwu/recipe/EndecRecipeSerializer.java b/src/testmod/java/io/wispforest/uwu/recipe/EndecRecipeSerializer.java deleted file mode 100644 index 8afca3d5..00000000 --- a/src/testmod/java/io/wispforest/uwu/recipe/EndecRecipeSerializer.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.wispforest.uwu.recipe; - -import com.mojang.serialization.Codec; -import io.wispforest.owo.serialization.Endec; -import io.wispforest.owo.serialization.SerializationAttribute; -import io.wispforest.owo.serialization.format.bytebuf.ByteBufDeserializer; -import io.wispforest.owo.serialization.format.bytebuf.ByteBufSerializer; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.recipe.Recipe; -import net.minecraft.recipe.RecipeSerializer; - -public class EndecRecipeSerializer> implements RecipeSerializer { - - public final Endec endec; - public final Codec codec; - - public EndecRecipeSerializer(Endec endec){ - this.codec = endec.codec(SerializationAttribute.HUMAN_READABLE); - this.endec = endec; - } - - @Override - public Codec codec() { - return this.codec; - } - - @Override - public void write(PacketByteBuf buf, T recipe) { - buf.write(this.endec, recipe); - } - - @Override - public T read(PacketByteBuf buf) { - return buf.read(this.endec); - } -} diff --git a/src/testmod/resources/data/uwu/recipes/test_recipe.json b/src/testmod/resources/data/uwu/recipes/test_recipe.json index 55c70523..457bf889 100644 --- a/src/testmod/resources/data/uwu/recipes/test_recipe.json +++ b/src/testmod/resources/data/uwu/recipes/test_recipe.json @@ -11,7 +11,7 @@ "owo:remainders": { "minecraft:sand": "minecraft:sand", "minecraft:stick": { - "item": "minecraft:stick", + "id": "minecraft:stick", "count": 64 } }, @@ -21,6 +21,6 @@ "XXX" ], "result": { - "item": "minecraft:bedrock" + "id": "minecraft:bedrock" } } \ No newline at end of file