diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java index e10ad0afd69..79711b0cbb7 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java @@ -35,6 +35,7 @@ import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; +import lombok.Getter; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.item.ItemEntry; @@ -69,6 +70,11 @@ public class ItemFrameEntity extends Entity { * Cached item frame's Bedrock compound tag. */ private NbtMap cachedTag; + /** + * The item currently in the item frame. Used for block picking. + */ + @Getter + private ItemStack heldItem = null; public ItemFrameEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, HangingDirection direction) { super(entityId, geyserId, entityType, position, motion, rotation); @@ -87,7 +93,8 @@ public void spawnEntity(GeyserSession session) { bedrockRuntimeId = session.getBlockTranslator().getItemFrame(blockBuilder.build()); bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ()); - session.getItemFrameCache().put(bedrockPosition, entityId); + session.getItemFrameCache().put(bedrockPosition, this); + // Delay is required, or else loading in frames on chunk load is sketchy at best session.getConnector().getGeneralThreadPool().schedule(() -> { updateBlock(session); @@ -99,13 +106,14 @@ public void spawnEntity(GeyserSession session) { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 7 && entityMetadata.getValue() != null) { - ItemData itemData = ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue()); + this.heldItem = (ItemStack) entityMetadata.getValue(); + ItemData itemData = ItemTranslator.translateToBedrock(session, heldItem); ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue()); NbtMapBuilder builder = NbtMap.builder(); builder.putByte("Count", (byte) itemData.getCount()); if (itemData.getTag() != null) { - builder.put("tag", itemData.getTag().toBuilder().build()); + builder.put("tag", itemData.getTag()); } builder.putShort("Damage", (short) itemData.getDamage()); builder.putString("Name", itemEntry.getBedrockIdentifier()); @@ -146,7 +154,9 @@ public boolean despawnEntity(GeyserSession session) { updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); session.sendUpstreamPacket(updateBlockPacket); - session.getItemFrameCache().remove(position, entityId); + + session.getItemFrameCache().remove(bedrockPosition, this); + valid = false; return true; } @@ -192,16 +202,7 @@ public void updateBlock(GeyserSession session) { * @param session GeyserSession. * @return Java entity ID or -1 if not found. */ - public static long getItemFrameEntityId(GeyserSession session, Vector3i position) { - return session.getItemFrameCache().getOrDefault(position, -1); - } - - /** - * Force-remove from the position-to-ID map so it doesn't cause conflicts. - * @param session GeyserSession. - * @param position position of the removed item frame. - */ - public static void removePosition(GeyserSession session, Vector3i position) { - session.getItemFrameCache().remove(position); + public static ItemFrameEntity getItemFrameEntity(GeyserSession session, Vector3i position) { + return session.getItemFrameCache().get(position); } } 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 081ad859a8c..28aff40b914 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 @@ -66,10 +66,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectIterator; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import it.unimi.dsi.fastutil.objects.*; import lombok.AccessLevel; import lombok.Getter; import lombok.NonNull; @@ -81,6 +78,7 @@ import org.geysermc.connector.common.AuthType; import org.geysermc.connector.configuration.EmoteOffhandWorkaroundOption; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.ItemFrameEntity; import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.entity.attribute.Attribute; import org.geysermc.connector.entity.attribute.AttributeType; @@ -189,10 +187,10 @@ public class GeyserSession implements CommandSender { private final Long2ObjectMap storedMaps = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); /** - * A map of Vector3i positions to Java entity IDs. + * A map of Vector3i positions to Java entities. * Used for translating Bedrock block actions to Java entity actions. */ - private final Object2LongMap itemFrameCache = new Object2LongOpenHashMap<>(); + private final Map itemFrameCache = new Object2ObjectOpenHashMap<>(); /** * Stores a list of all lectern locations and their block entity tags. diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java index 350c029ffe4..ba74c7769d2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java @@ -27,6 +27,7 @@ import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.BlockPickRequestPacket; +import org.geysermc.connector.entity.ItemFrameEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -43,6 +44,18 @@ public void translate(BlockPickRequestPacket packet, GeyserSession session) { // Block is air - chunk caching is probably off if (blockToPick == BlockTranslator.JAVA_AIR_ID) { + // Check for an item frame since the client thinks that's a block when it's an entity in Java + ItemFrameEntity entity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition()); + if (entity != null) { + // Check to see if the item frame has an item in it first + if (entity.getHeldItem() != null && entity.getHeldItem().getId() != 0) { + // Grab the item in the frame + InventoryUtils.findOrCreateItem(session, entity.getHeldItem()); + } else { + // Grab the frame as the item + InventoryUtils.findOrCreateItem(session, "minecraft:item_frame"); + } + } return; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java index fcb62d44506..d326321cd7b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java @@ -94,7 +94,7 @@ public void translate(EntityPickRequestPacket packet, GeyserSession session) { break; case ARMOR_STAND: case END_CRYSTAL: - case ITEM_FRAME: + //case ITEM_FRAME: Not an entity in Bedrock Edition case MINECART: case PAINTING: // No spawn egg, just an item 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 7dd67019741..2358fa2783e 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 @@ -126,16 +126,19 @@ public void translate(InventoryTransactionPacket packet, GeyserSession session) } // Bedrock sends block interact code for a Java entity so we send entity code back to Java - if (session.getBlockTranslator().isItemFrame(packet.getBlockRuntimeId()) && - session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) { - Vector3f vector = packet.getClickPosition(); - ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()), - InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking()); - ClientPlayerInteractEntityPacket interactAtPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()), - InteractAction.INTERACT_AT, vector.getX(), vector.getY(), vector.getZ(), Hand.MAIN_HAND, session.isSneaking()); - session.sendDownstreamPacket(interactPacket); - session.sendDownstreamPacket(interactAtPacket); - break; + if (session.getBlockTranslator().isItemFrame(packet.getBlockRuntimeId())) { + Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition()); + if (itemFrameEntity != null) { + int entityId = (int) itemFrameEntity.getEntityId(); + Vector3f vector = packet.getClickPosition(); + ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket(entityId, + InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking()); + ClientPlayerInteractEntityPacket interactAtPacket = new ClientPlayerInteractEntityPacket(entityId, + InteractAction.INTERACT_AT, vector.getX(), vector.getY(), vector.getZ(), Hand.MAIN_HAND, session.isSneaking()); + session.sendDownstreamPacket(interactPacket); + session.sendDownstreamPacket(interactAtPacket); + break; + } } Vector3i blockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getBlockFace()); @@ -288,9 +291,10 @@ else if (packet.getItemInHand() != null && ItemRegistry.BUCKETS.contains(packet. session.sendUpstreamPacket(blockBreakPacket); session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID); - long frameEntityId = ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()); - if (frameEntityId != -1 && session.getEntityCache().getEntityByJavaId(frameEntityId) != null) { - ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) frameEntityId, InteractAction.ATTACK, session.isSneaking()); + Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition()); + if (itemFrameEntity != null) { + ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) itemFrameEntity.getEntityId(), + InteractAction.ATTACK, session.isSneaking()); session.sendDownstreamPacket(attackPacket); break; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemFrameDropItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemFrameDropItemTranslator.java index 959d6dc291a..ac61f2f9db6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemFrameDropItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemFrameDropItemTranslator.java @@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket; import com.nukkitx.protocol.bedrock.packet.ItemFrameDropItemPacket; +import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.ItemFrameEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -44,9 +45,11 @@ public class BedrockItemFrameDropItemTranslator extends PacketTranslator