From c9d4b9a797cef8152e979a9ff93240338cb38693 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 24 Mar 2024 00:56:01 +0100 Subject: [PATCH] no more parsing of java structure templates --- .../mod/world/GeyserModWorldManager.java | 140 ------------------ .../manager/GeyserSpigotWorldManager.java | 40 ----- .../geyser/level/GeyserWorldManager.java | 39 ----- .../geysermc/geyser/level/WorldManager.java | 9 -- .../geyser/session/GeyserSession.java | 6 + .../StructureBlockBlockEntityTranslator.java | 2 - ...tructureTemplateDataRequestTranslator.java | 72 ++++++++- .../level/JavaBlockEntityDataTranslator.java | 47 ++++++ 8 files changed, 121 insertions(+), 234 deletions(-) diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java index b495994c6..04c538632 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java @@ -27,12 +27,8 @@ package org.geysermc.geyser.platform.mod.world; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.SharedConstants; import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.ByteTag; import net.minecraft.nbt.CompoundTag; @@ -44,12 +40,10 @@ import net.minecraft.nbt.IntTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.LongArrayTag; import net.minecraft.nbt.LongTag; -import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.ShortTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.nbt.TagVisitor; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.ItemStack; @@ -60,23 +54,15 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BannerBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.LecternBlockEntity; -import net.minecraft.world.level.block.entity.StructureBlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; -import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateResponseType; -import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataRequestPacket; -import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataResponsePacket; import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.network.GameProtocol; @@ -87,7 +73,6 @@ import org.geysermc.geyser.util.BlockEntityUtils; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.Optional; import java.util.concurrent.CompletableFuture; public class GeyserModWorldManager extends GeyserWorldManager { @@ -227,131 +212,6 @@ public class GeyserModWorldManager extends GeyserWorldManager { NbtMap blockEntityTag = lecternTag.build(); BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z)); } - @Override - public void handleStructureDataRequest(StructureTemplateDataRequestPacket packet, GeyserSession session) { - server.execute(() -> { - ResourceLocation location = ResourceLocation.tryParse(packet.getName()); - if (location == null) { - sendNoStructureFound(session); - return; - } - - Optional structure = server.getStructureManager().get(location); - if (structure.isEmpty()) { - sendNoStructureFound(session); - return; - } - - // Required to find structure block - ServerPlayer player = this.getPlayer(session); - if (player == null) { - sendNoStructureFound(session); - return; - } - BlockEntity blockEntity = player.level().getBlockEntity(new BlockPos(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); - if (!(blockEntity instanceof StructureBlockEntity)) { - sendNoStructureFound(session); - return; - } - - StructureTemplate structureTemplate = structure.get(); - // Easiest to use a tag, I guess - CompoundTag tag = structure.get().save(new CompoundTag()); - int sizeX = structureTemplate.getSize().getX(); - int sizeY = structureTemplate.getSize().getY(); - int sizeZ = structureTemplate.getSize().getZ(); - - NbtMapBuilder builder = NbtMap.builder(); - builder.putInt("format_version", 1); - builder.putList("structure_world_origin", NbtType.INT, packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()); // ??? - builder.putList("size", NbtType.INT, sizeX, sizeY, sizeZ); - - IntList layerZero = new IntArrayList(); - //layerZero.add(0); // ?? - IntList layerOne = new IntArrayList(); - //layerOne.add(-1); // palette header??? - List bedrockPalette = new ObjectArrayList<>(); - - ListTag javaPalette = tag.getList("palette", 10); - ListTag blocks = tag.getList("blocks", 10); - for (int y = 0; y < sizeY; y++) { - for (int x = 0; x < sizeX; x++) { - for (int z = 0; z < sizeZ; z++) { - boolean hasAppliedBlock = false; - for (int i = 0; i < blocks.size(); i++) { - CompoundTag currentBlock = blocks.getCompound(i); - ListTag pos = currentBlock.getList("pos", 6); - if (pos.getInt(0) != x && pos.getInt(1) != y && pos.getInt(2) != z) { - // Position doesn't match - continue; - } - // Lookup the table of which Java block this is mapped to - CompoundTag javaBlock = javaPalette.getCompound(currentBlock.getInt("state")); - BlockState blockState = NbtUtils.readBlockState(BuiltInRegistries.BLOCK.asLookup(), javaBlock); - int javaId = Block.getId(blockState); - int bedrockIndex = getOrAddToBedrockPalette(session, javaId, bedrockPalette); - layerZero.add(bedrockIndex); - - var optional = blockState.getOptionalValue(BlockStateProperties.WATERLOGGED); - if (optional.isPresent() && optional.get()) { - layerOne.add(1); - } else { - layerOne.add(0); - } - - blocks.remove(i); // Already used - hasAppliedBlock = true; - break; - } - if (!hasAppliedBlock) { - // Not found - air? - layerZero.add(getOrAddToBedrockPalette(session,0, bedrockPalette)); - layerOne.add(-1); - } - } - } - } - - NbtMapBuilder structureBuilder = NbtMap.builder(); - structureBuilder.putList("block_indices", NbtType.LIST, new NbtList<>(NbtType.INT, layerZero), new NbtList<>(NbtType.INT, layerOne)); - - structureBuilder.putList("entities", NbtType.COMPOUND); - - structureBuilder.putCompound("palette", NbtMap.builder().putCompound("default", - NbtMap.builder().putList("block_palette", NbtType.COMPOUND, bedrockPalette) - .putCompound("block_position_data", NbtMap.EMPTY).build()).build()); - - builder.putCompound("structure", structureBuilder.build()); - - System.out.println(builder); - - StructureTemplateDataResponsePacket responsePacket = new StructureTemplateDataResponsePacket(); - responsePacket.setName(packet.getName()); - responsePacket.setSave(true); - responsePacket.setTag(builder.build()); - responsePacket.setType(StructureTemplateResponseType.QUERY); - session.sendUpstreamPacket(responsePacket); - }); - } - protected int getOrAddToBedrockPalette(GeyserSession session, int javaState, List bedrockPalette) { - NbtMap tag = session.getBlockMappings().getBedrockBlock(javaState).getState(); - - for (int i = 0; i < bedrockPalette.size(); i++) { - if (tag == bedrockPalette.get(i)) { - return i; - } - } - bedrockPalette.add(tag); - return bedrockPalette.size() - 1; - } - - protected void sendNoStructureFound(GeyserSession session) { - StructureTemplateDataResponsePacket packet = new StructureTemplateDataResponsePacket(); - packet.setName(""); - packet.setSave(false); - packet.setType(StructureTemplateResponseType.NONE); - session.sendUpstreamPacket(packet); - } @Override public boolean hasPermission(GeyserSession session, String permission) { diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 1779f0a55..42f0d17f4 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -36,13 +36,7 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.cloudburstmc.nbt.NbtType; -import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateResponseType; -import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataRequestPacket; -import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataResponsePacket; import org.geysermc.erosion.bukkit.BukkitLecterns; import org.geysermc.erosion.bukkit.BukkitUtils; import org.geysermc.erosion.bukkit.PickBlockUtils; @@ -65,19 +59,6 @@ import java.util.concurrent.CompletableFuture; public class GeyserSpigotWorldManager extends WorldManager { private final Plugin plugin; private final BukkitLecterns lecterns; - private static final NbtMap EMPTY_STRUCTURE_DATA; - - static { - NbtMapBuilder builder = NbtMap.builder(); - builder.putInt("format_version", 1); - builder.putCompound("structure", NbtMap.builder() - .putList("block_indices", NbtType.LIST, NbtList.EMPTY, NbtList.EMPTY) - .putList("entities", NbtType.COMPOUND) - .putCompound("palette", NbtMap.EMPTY) - .build()); - builder.putList("structure_world_origin", NbtType.INT, 0, 0, 0); - EMPTY_STRUCTURE_DATA = builder.build(); - } public GeyserSpigotWorldManager(Plugin plugin) { this.plugin = plugin; @@ -149,27 +130,6 @@ public class GeyserSpigotWorldManager extends WorldManager { } } - // TODO adapt to actually send the requests - @Override - public void handleStructureDataRequest(StructureTemplateDataRequestPacket packet, GeyserSession session) { - // Always send a blank form - sendEmptyStructureData(session, packet); - } - - /** - * Send an empty structure data that tricks Bedrock into thinking it loaded successfully - */ - protected void sendEmptyStructureData(GeyserSession session, StructureTemplateDataRequestPacket packet) { - StructureTemplateDataResponsePacket responsePacket = new StructureTemplateDataResponsePacket(); - responsePacket.setName(packet.getName()); - responsePacket.setSave(true); - responsePacket.setTag(EMPTY_STRUCTURE_DATA.toBuilder() - .putList("size", NbtType.INT, packet.getSettings().getSize().getX(), packet.getSettings().getSize().getY(), packet.getSettings().getSize().getZ()) - .build()); - responsePacket.setType(StructureTemplateResponseType.QUERY); - session.sendUpstreamPacket(responsePacket); - } - private @Nullable Chunk getChunk(World world, int x, int z) { if (!world.isChunkLoaded(x, z)) { return null; diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index 4bbf27a5d..27b5273d5 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -34,13 +34,8 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.cloudburstmc.nbt.NbtType; -import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateResponseType; -import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataRequestPacket; -import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataResponsePacket; import org.geysermc.erosion.packet.backendbound.BackendboundBatchBlockEntityPacket; import org.geysermc.erosion.packet.backendbound.BackendboundBatchBlockRequestPacket; import org.geysermc.erosion.packet.backendbound.BackendboundBlockEntityPacket; @@ -57,20 +52,6 @@ import java.util.concurrent.CompletableFuture; public class GeyserWorldManager extends WorldManager { private final Object2ObjectMap gameruleCache = new Object2ObjectOpenHashMap<>(); - private static final NbtMap EMPTY_STRUCTURE_DATA; - - static { - NbtMapBuilder builder = NbtMap.builder(); - builder.putInt("format_version", 1); - builder.putCompound("structure", NbtMap.builder() - .putList("block_indices", NbtType.LIST, NbtList.EMPTY, NbtList.EMPTY) - .putList("entities", NbtType.COMPOUND) - .putCompound("palette", NbtMap.EMPTY) - .build()); - builder.putList("structure_world_origin", NbtType.INT, 0, 0, 0); - EMPTY_STRUCTURE_DATA = builder.build(); - } - @Override public int getBlockAt(GeyserSession session, int x, int y, int z) { var erosionHandler = session.getErosionHandler().getAsActive(); @@ -154,26 +135,6 @@ public class GeyserWorldManager extends WorldManager { BlockEntityUtils.updateBlockEntity(session, lecternTag.build(), Vector3i.from(x, y, z)); } - @Override - public void handleStructureDataRequest(StructureTemplateDataRequestPacket packet, GeyserSession session) { - // Always send a blank form - sendEmptyStructureData(session, packet); - } - - /** - * Send an empty structure data that tricks Bedrock into thinking it loaded successfully - */ - protected void sendEmptyStructureData(GeyserSession session, StructureTemplateDataRequestPacket packet) { - StructureTemplateDataResponsePacket responsePacket = new StructureTemplateDataResponsePacket(); - responsePacket.setName(packet.getName()); - responsePacket.setSave(true); - responsePacket.setTag(EMPTY_STRUCTURE_DATA.toBuilder() - .putList("size", NbtType.INT, packet.getSettings().getSize().getX(), packet.getSettings().getSize().getY(), packet.getSettings().getSize().getZ()) - .build()); - responsePacket.setType(StructureTemplateResponseType.QUERY); - session.sendUpstreamPacket(responsePacket); - } - @Override public boolean shouldExpectLecternHandled(GeyserSession session) { return session.getErosionHandler().isActive(); diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index c75b337ca..be7e2c139 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -32,7 +32,6 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataRequestPacket; import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.session.GeyserSession; @@ -127,14 +126,6 @@ public abstract class WorldManager { */ public abstract void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos); - /** - * Handle Bedrock requesting data for a structure. - * - * @param session the session of the player requested structure information - * @param packet the packet the Bedrock client has sent - */ - public abstract void handleStructureDataRequest(StructureTemplateDataRequestPacket packet, GeyserSession session); - /** * @return whether we should expect lectern data to update, or if we have to fall back on a workaround. */ diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 7a4a8ff6f..906d3e46d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -602,6 +602,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private @Nullable ItemData currentBook = null; + /** + * Stores the current structure block position, if we are in one + */ + @Setter @Getter + private @Nullable Vector3i currentStructureBlock; + private final GeyserCameraData cameraData; private final GeyserEntityData entityData; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java index aa9aa5a85..9af65a880 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java @@ -37,8 +37,6 @@ public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - GeyserImpl.getInstance().getLogger().info("structure block tag: " + - tag.toString() + " " + builder.toString() + " " + blockState); if (tag.size() < 5) { return; // These values aren't here } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java index d25162d80..9e0cffe85 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java @@ -25,24 +25,88 @@ package org.geysermc.geyser.translator.protocol.bedrock; +import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockAction; +import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockMode; +import com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror; +import com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetStructureBlockPacket; +import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateRequestOperation; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateResponseType; import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataRequestPacket; +import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataResponsePacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; /** - * Packet used in Bedrock to load structures into the structure block GUI. + * Packet used in Bedrock to load structure size into the structure block GUI. *

- * Java does not have this functionality. + * Java does not have this preview, instead, Java clients are forced out of the GUI to look at the area. */ @Translator(packet = StructureTemplateDataRequestPacket.class) public class BedrockStructureTemplateDataRequestTranslator extends PacketTranslator { + private static final NbtMap EMPTY_STRUCTURE_DATA; + + static { + NbtMapBuilder builder = NbtMap.builder(); + builder.putInt("format_version", 1); + builder.putCompound("structure", NbtMap.builder() + .putList("block_indices", NbtType.LIST, NbtList.EMPTY, NbtList.EMPTY) + .putList("entities", NbtType.COMPOUND) + .putCompound("palette", NbtMap.EMPTY) + .build()); + builder.putList("structure_world_origin", NbtType.INT, 0, 0, 0); + EMPTY_STRUCTURE_DATA = builder.build(); + } + @Override public void translate(GeyserSession session, StructureTemplateDataRequestPacket packet) { - GeyserImpl.getInstance().getLogger().info(packet.toString()); + GeyserImpl.getInstance().getLogger().error(packet.toString()); + if (packet.getOperation().equals(StructureTemplateRequestOperation.QUERY_SAVED_STRUCTURE)) { + session.setCurrentStructureBlock(packet.getPosition()); - session.getGeyser().getWorldManager().handleStructureDataRequest(packet, session); + // Request a "load" from Java server so it sends us the structures size :p + var settings = packet.getSettings(); + com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation rotation = switch (settings.getRotation()) { + case ROTATE_90 -> StructureRotation.CLOCKWISE_90; + case ROTATE_180 -> StructureRotation.CLOCKWISE_180; + case ROTATE_270 -> StructureRotation.COUNTERCLOCKWISE_90; + default -> StructureRotation.NONE; + }; + + ServerboundSetStructureBlockPacket structureBlockPacket = new ServerboundSetStructureBlockPacket( + packet.getPosition(), + UpdateStructureBlockAction.LOAD_STRUCTURE, + UpdateStructureBlockMode.LOAD, + packet.getName(), + settings.getOffset(), + settings.getSize(), + StructureMirror.NONE, + rotation, + "", + settings.getIntegrityValue(), + settings.getIntegritySeed(), + settings.isIgnoringEntities(), + false, + true + ); + session.sendDownstreamPacket(structureBlockPacket); + } else { + StructureTemplateDataResponsePacket responsePacket = new StructureTemplateDataResponsePacket(); + responsePacket.setName(packet.getName()); + responsePacket.setSave(true); + responsePacket.setTag(EMPTY_STRUCTURE_DATA.toBuilder() + .putList("size", NbtType.INT, packet.getSettings().getSize().getX(), + packet.getSettings().getSize().getY(), packet.getSettings().getSize().getZ()) + .build()); + responsePacket.setType(StructureTemplateResponseType.QUERY); + session.sendUpstreamPacket(responsePacket); + } } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java index c67a6dee4..cb6396e8f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java @@ -28,11 +28,19 @@ package org.geysermc.geyser.translator.protocol.java.level; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockEntityDataPacket; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateResponseType; import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; +import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataResponsePacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; @@ -45,6 +53,20 @@ import org.geysermc.geyser.util.BlockEntityUtils; @Translator(packet = ClientboundBlockEntityDataPacket.class) public class JavaBlockEntityDataTranslator extends PacketTranslator { + private static final NbtMap EMPTY_STRUCTURE_DATA; + + static { + NbtMapBuilder builder = NbtMap.builder(); + builder.putInt("format_version", 1); + builder.putCompound("structure", NbtMap.builder() + .putList("block_indices", NbtType.LIST, NbtList.EMPTY, NbtList.EMPTY) + .putList("entities", NbtType.COMPOUND) + .putCompound("palette", NbtMap.EMPTY) + .build()); + builder.putList("structure_world_origin", NbtType.INT, 0, 0, 0); + EMPTY_STRUCTURE_DATA = builder.build(); + } + @Override public void translate(GeyserSession session, ClientboundBlockEntityDataPacket packet) { final BlockEntityType type = packet.getType(); @@ -95,5 +117,30 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator 5) { + CompoundTag map = packet.getNbt(); + + String mode = (String) map.get("mode").getValue(); + if (!mode.equalsIgnoreCase("LOAD")) { + GeyserImpl.getInstance().getLogger().info(mode); + return; + } + + StructureTemplateDataResponsePacket responsePacket = new StructureTemplateDataResponsePacket(); + responsePacket.setName((String) map.get("name").getValue()); + responsePacket.setSave(true); + responsePacket.setTag(EMPTY_STRUCTURE_DATA.toBuilder() + .putList("size", NbtType.INT, (int) map.get("sizeX").getValue(), (int) map.get("sizeY").getValue(), (int) map.get("sizeZ").getValue()) + .build()); + responsePacket.setType(StructureTemplateResponseType.QUERY); + GeyserImpl.getInstance().getLogger().info(responsePacket.toString()); + session.sendUpstreamPacket(responsePacket); + + session.setCurrentStructureBlock(null); + } } }