From 78337830c6929b759dc6c71dd872d1e945b949fd Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 12 Feb 2021 14:39:41 -0500 Subject: [PATCH] Use the real block for opening inventory when possible --- .../connector/inventory/Container.java | 15 ++++ .../inventory/Generic3X3Container.java | 48 +++++++++++++ .../network/session/GeyserSession.java | 17 +++-- ...BedrockInventoryTransactionTranslator.java | 5 +- .../BedrockLecternUpdateTranslator.java | 4 +- .../inventory/InventoryTranslator.java | 5 +- .../holder/BlockInventoryHolder.java | 60 +++++++++++++--- .../AbstractBlockInventoryTranslator.java | 8 +-- .../translators/AnvilInventoryTranslator.java | 3 +- .../Generic3X3InventoryTranslator.java | 71 +++++++++++++++++++ ...or.java => HopperInventoryTranslator.java} | 6 +- .../LecternInventoryTranslator.java | 3 +- .../chest/DoubleChestInventoryTranslator.java | 47 ++++++++++-- .../chest/SingleChestInventoryTranslator.java | 5 +- .../java/world/JavaBlockChangeTranslator.java | 2 +- .../DoubleChestBlockEntityTranslator.java | 52 ++++++++------ 16 files changed, 290 insertions(+), 61 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/{GenericBlockInventoryTranslator.java => HopperInventoryTranslator.java} (87%) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Container.java index 520a76ef3..6302a7daa 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Container.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Container.java @@ -38,6 +38,11 @@ public class Container extends Inventory { private final PlayerInventory playerInventory; private final int containerSize; + /** + * Whether we are using a real block when opening this inventory. + */ + private boolean isUsingRealBlock = false; + public Container(String title, int id, int size, PlayerInventory playerInventory) { super(title, id, size); this.playerInventory = playerInventory; @@ -66,4 +71,14 @@ public class Container extends Inventory { public int getSize() { return this.containerSize; } + + /** + * Will be overwritten for droppers. + * + * @param usingRealBlock whether this container is using a real container or not + * @param javaBlockId the Java block string of the block, if real + */ + public void setUsingRealBlock(boolean usingRealBlock, String javaBlockId) { + isUsingRealBlock = usingRealBlock; + } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java new file mode 100644 index 000000000..be8d13a74 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.inventory; + +import lombok.Getter; + +public class Generic3X3Container extends Container { + /** + * Whether we need to set the container type as {@link com.nukkitx.protocol.bedrock.data.inventory.ContainerType#DROPPER} + */ + @Getter + private boolean isDropper = false; + + public Generic3X3Container(String title, int id, int size, PlayerInventory playerInventory) { + super(title, id, size, playerInventory); + } + + @Override + public void setUsingRealBlock(boolean usingRealBlock, String javaBlockId) { + super.setUsingRealBlock(usingRealBlock, javaBlockId); + if (usingRealBlock) { + isDropper = javaBlockId.startsWith("minecraft:dropper"); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 15357ada3..00d654764 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -38,7 +38,6 @@ import com.github.steveice10.mc.protocol.data.SubProtocol; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; -import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; @@ -73,10 +72,10 @@ import lombok.Setter; import org.geysermc.common.window.CustomFormWindow; import org.geysermc.common.window.FormWindow; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.common.AuthType; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.entity.player.SessionPlayerEntity; import org.geysermc.connector.entity.player.SkullPlayerEntity; import org.geysermc.connector.inventory.Inventory; @@ -234,7 +233,15 @@ public class GeyserSession implements CommandSender { * Initialized as (0, 0, 0) so it is always not-null. */ @Setter - private Vector3i lastInteractionPosition = Vector3i.ZERO; + private Vector3i lastInteractionBlockPosition = Vector3i.ZERO; + + /** + * Stores the position of the player the last time they interacted. + * Used to verify that the player did not move since their last interaction.
+ * Initialized as (0, 0, 0) so it is always not-null. + */ + @Setter + private Vector3f lastInteractionPlayerPosition = Vector3f.ZERO; @Setter private Entity ridingVehicleEntity; @@ -242,15 +249,13 @@ public class GeyserSession implements CommandSender { @Setter private long lastWindowCloseTime = 0; - @Setter - private VillagerTrade[] villagerTrades; @Setter private long lastInteractedVillagerEid; @Setter private Int2ObjectMap craftingRecipes; private final Set unlockedRecipes; - private AtomicInteger lastRecipeNetId; + private final AtomicInteger lastRecipeNetId; /** * Saves a list of all stonecutter recipes, for use in a stonecutter inventory. diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index d6c9badb9..79f658188 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -117,8 +117,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { @Override public void translate(LecternUpdatePacket packet, GeyserSession session) { - session.getConnector().getLogger().error(packet.toString()); if (packet.isDroppingBook()) { // Bedrock drops the book outside of the GUI. Java drops it in the GUI // So, we enter the GUI and then drop it! :) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index e5a9705bc..7fd24080e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -33,7 +33,6 @@ import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; @@ -94,8 +93,8 @@ public abstract class InventoryTranslator { put(WindowType.STONECUTTER, new StonecutterInventoryTranslator()); /* Generics */ - put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); - put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); + put(WindowType.GENERIC_3X3, new Generic3X3InventoryTranslator()); + put(WindowType.HOPPER, new HopperInventoryTranslator()); /* Lectern */ put(WindowType.LECTERN, new LecternInventoryTranslator()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 5c49c723e..c6da2aeb2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -26,43 +26,79 @@ package org.geysermc.connector.network.translators.inventory.holder; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.google.common.collect.Sets; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; -import lombok.AllArgsConstructor; +import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import java.util.Collections; +import java.util.Set; + /** - * Manages the fake block we implement for each inventory. + * Manages the fake block we implement for each inventory, should we need to. + * This class will attempt to use a real block first, if possible. */ -@AllArgsConstructor public class BlockInventoryHolder extends InventoryHolder { - private final int blockId; + /** + * The default Bedrock block ID to use as a fake block + */ + private final int defaultBedrockBlockId; private final ContainerType containerType; + private final Set validBlocks; + + public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) { + int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); + this.defaultBedrockBlockId = BlockTranslator.getBedrockBlockId(javaBlockState); + this.containerType = containerType; + if (validBlocks != null) { + this.validBlocks = Sets.newHashSet(validBlocks); + this.validBlocks.add(javaBlockIdentifier.split("\\[")[0]); + } else { + this.validBlocks = Collections.singleton(javaBlockIdentifier.split("\\[")[0]); + } + } @Override public void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { - //TODO: Improve on this (for example, multiple block states). We need this for the beacon. - if (BlockTranslator.getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionPosition())) == blockId) { - inventory.setHolderPosition(session.getLastInteractionPosition()); - return; + // Check to see if there is an existing block we can use that the player just selected. + // First, verify that the player's position has not changed, so we don't try to select a block wildly out of range. + // (This could be a virtual inventory that the player is opening) + if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { + // Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid + int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); + String javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\[")[0]; + if (this.validBlocks.contains(javaBlockString)) { + // We can safely use this block + inventory.setHolderPosition(session.getLastInteractionBlockPosition()); + ((Container) inventory).setUsingRealBlock(true, javaBlockString); + setCustomName(session, session.getLastInteractionBlockPosition(), inventory); + return; + } } + + // Otherwise, time to conjure up a fake block! Vector3i position = session.getPlayerEntity().getPosition().toInt(); position = position.add(Vector3i.UP); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(blockId); + blockPacket.setRuntimeId(defaultBedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); inventory.setHolderPosition(position); + setCustomName(session, position, inventory); + } + + protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory) { NbtMap tag = NbtMap.builder() .putInt("x", position.getX()) .putInt("y", position.getY()) @@ -86,10 +122,12 @@ public class BlockInventoryHolder extends InventoryHolder { @Override public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { - Vector3i holderPos = inventory.getHolderPosition(); - if (holderPos.equals(session.getLastInteractionPosition())) { + if (((Container) inventory).isUsingRealBlock()) { + // No need to reset a block since we didn't change any blocks return; } + + Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java index 92710656d..8664dc192 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java @@ -31,7 +31,6 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; /** * Provided as a base for any inventory that requires a block for opening it @@ -45,11 +44,12 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran * @param javaBlockIdentifier a Java block identifier that is used as a temporary block * @param containerType the container type of this inventory * @param updater updater + * @param additionalValidBlocks any other block identifiers that can safely use this inventory without a fake block */ - public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) { + public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater, + String... additionalValidBlocks) { super(size); - int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); - this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), containerType); + this.holder = new BlockInventoryHolder(javaBlockIdentifier, containerType, additionalValidBlocks); this.updater = updater; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java index 9d4fbfeec..0d2b62153 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java @@ -48,7 +48,8 @@ import org.geysermc.connector.network.translators.item.ItemTranslator; public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { public AnvilInventoryTranslator() { - super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE); + super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE, + "minecraft:chipped_anvil", "minecraft:damaged_anvil"); } /* 1.16.100 support start */ diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java new file mode 100644 index 000000000..eb417c51e --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.inventory.translators; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; +import org.geysermc.connector.inventory.Generic3X3Container; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; + +/** + * Droppers and dispensers + */ +public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator { + + public Generic3X3InventoryTranslator() { + super(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, ContainerInventoryUpdater.INSTANCE, + "minecraft:dropper"); + } + + @Override + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + return new Generic3X3Container(name, windowId, this.size, playerInventory); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setId((byte) inventory.getId()); + containerOpenPacket.setType(((Generic3X3Container) inventory).isDropper() ? ContainerType.DROPPER : ContainerType.DISPENSER); + containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); + containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); + session.sendUpstreamPacket(containerOpenPacket); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot) { + if (javaSlot < this.size) { + return new BedrockContainerSlot(ContainerSlotType.CONTAINER, javaSlot); + } + return super.javaSlotToBedrockContainer(javaSlot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java similarity index 87% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java index 55df41c1e..7f067d1c0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java @@ -33,9 +33,9 @@ import org.geysermc.connector.network.translators.inventory.updater.ContainerInv /** * Implemented on top of any block that does not have special properties implemented */ -public class GenericBlockInventoryTranslator extends AbstractBlockInventoryTranslator { - public GenericBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType) { - super(size, javaBlockIdentifier, containerType, ContainerInventoryUpdater.INSTANCE); +public class HopperInventoryTranslator extends AbstractBlockInventoryTranslator { + public HopperInventoryTranslator() { + super(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, ContainerInventoryUpdater.INSTANCE); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java index 9ce0ee0d1..157f63164 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java @@ -98,7 +98,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { CompoundTag tag = geyserItemStack.getNbt(); if (tag != null) { // Position has to be the last interacted position... right? - Vector3i position = session.getLastInteractionPosition(); + Vector3i position = session.getLastInteractionBlockPosition(); // shouldRefresh means that we should boot out the client on our side because their lectern GUI isn't updated yet boolean shouldRefresh = !session.getConnector().getWorldManager().shouldExpectLecternHandled() && !session.getLecternCache().contains(position); int pagesSize = ((ListTag) tag.get("pages")).size(); @@ -124,7 +124,6 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(lecternContainer.getId()); session.sendDownstreamPacket(closeWindowPacket); InventoryUtils.closeInventory(session, inventory.getId()); - session.getConnector().getLogger().warning("Closing inventory"); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java index c27eacff5..d1e628fce 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java @@ -28,32 +28,66 @@ package org.geysermc.connector.network.translators.inventory.translators.chest; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.DoubleChestValue; +import org.geysermc.connector.network.translators.world.block.entity.DoubleChestBlockEntityTranslator; public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { - private final int blockId; + private final int defaultBedrockBlockId; public DoubleChestInventoryTranslator(int size) { super(size, 54); int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); - this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState); + this.defaultBedrockBlockId = BlockTranslator.getBedrockBlockId(javaBlockState); } @Override public void prepareInventory(GeyserSession session, Inventory inventory) { + // See BlockInventoryHolder - same concept there except we're also dealing with a specific block state + if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { + int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); + String[] javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\["); + if (javaBlockString.length > 1 && (javaBlockString[0].equals("minecraft:chest") || javaBlockString[0].equals("minecraft:trapped_chest")) + && !javaBlockString[1].contains("type=single")) { + inventory.setHolderPosition(session.getLastInteractionBlockPosition()); + ((Container) inventory).setUsingRealBlock(true, javaBlockString[0]); + + NbtMapBuilder tag = NbtMap.builder() + .putString("id", "Chest") + .putInt("x", session.getLastInteractionBlockPosition().getX()) + .putInt("y", session.getLastInteractionBlockPosition().getY()) + .putInt("z", session.getLastInteractionBlockPosition().getZ()) + .putString("CustomName", inventory.getTitle()) + .putString("id", "Chest"); + + DoubleChestValue chestValue = BlockStateValues.getDoubleChestValues().get(javaBlockId); + DoubleChestBlockEntityTranslator.translateChestValue(tag, chestValue, + session.getLastInteractionBlockPosition().getX(), session.getLastInteractionBlockPosition().getZ()); + + BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag.build()); + dataPacket.setBlockPosition(session.getLastInteractionBlockPosition()); + session.sendUpstreamPacket(dataPacket); + return; + } + } + Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP); Vector3i pairPosition = position.add(Vector3i.UNIT_X); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(blockId); + blockPacket.setRuntimeId(defaultBedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); @@ -73,7 +107,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(pairPosition); - blockPacket.setRuntimeId(blockId); + blockPacket.setRuntimeId(defaultBedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); @@ -105,6 +139,11 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { @Override public void closeInventory(GeyserSession session, Inventory inventory) { + if (((Container) inventory).isUsingRealBlock()) { + // No need to reset a block since we didn't change any blocks + return; + } + Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java index 9fc3c0165..7b9b12c4f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java @@ -30,15 +30,14 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; public class SingleChestInventoryTranslator extends ChestInventoryTranslator { private final InventoryHolder holder; public SingleChestInventoryTranslator(int size) { super(size, 27); - int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); - this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.CONTAINER); + this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, + "minecraft:ender_chest", "minecraft:trapped_chest"); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java index d74165b14..9bff2652e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java @@ -93,7 +93,7 @@ public class JavaBlockChangeTranslator extends PacketTranslator