From 683ac1c763f9082f9847ac2a71262941cc729b24 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 19 Jun 2021 20:33:07 -0400 Subject: [PATCH] Fix spawn egg triggering twice in water --- ...BedrockInventoryTransactionTranslator.java | 60 ++++++++++++------- .../translators/item/ItemRegistry.java | 15 +++-- 2 files changed, 48 insertions(+), 27 deletions(-) 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 6378c0ba956..bb23257855a 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 @@ -183,6 +183,17 @@ public void translate(InventoryTransactionPacket packet, GeyserSession session) Block place checks end - client is good to go */ + if (packet.getItemInHand() != null && ItemRegistry.SPAWN_EGGS.contains(packet.getItemInHand().getId())) { + int blockState = session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition()); + if (blockState == BlockTranslator.JAVA_WATER_ID) { + // Otherwise causes multiple mobs to spawn - just send a use item packet + // TODO when we fix mobile bucket rotation, use it for this, too + ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); + session.sendDownstreamPacket(itemPacket); + break; + } + } + ClientPlayerPlaceBlockPacket blockPacket = new ClientPlayerPlaceBlockPacket( new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), BlockFace.values()[packet.getBlockFace()], @@ -191,25 +202,27 @@ public void translate(InventoryTransactionPacket packet, GeyserSession session) false); session.sendDownstreamPacket(blockPacket); - // Otherwise boats will not be able to be placed in survival and buckets won't work on mobile - if (packet.getItemInHand() != null && ItemRegistry.BOATS.contains(packet.getItemInHand().getId())) { - ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); - session.sendDownstreamPacket(itemPacket); - } - // Check actions, otherwise buckets may be activated when block inventories are accessed - else if (packet.getItemInHand() != null && ItemRegistry.BUCKETS.contains(packet.getItemInHand().getId())) { - // Let the server decide if the bucket item should change, not the client, and revert the changes the client made - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.INVENTORY); - slotPacket.setSlot(packet.getHotbarSlot()); - slotPacket.setItem(packet.getItemInHand()); - session.sendUpstreamPacket(slotPacket); - // Delay the interaction in case the client doesn't intend to actually use the bucket - // See BedrockActionTranslator.java - session.setBucketScheduledFuture(session.getConnector().getGeneralThreadPool().schedule(() -> { + if (packet.getItemInHand() != null) { + // Otherwise boats will not be able to be placed in survival and buckets won't work on mobile + if (ItemRegistry.BOATS.contains(packet.getItemInHand().getId())) { ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); session.sendDownstreamPacket(itemPacket); - }, 5, TimeUnit.MILLISECONDS)); + } + // Check actions, otherwise buckets may be activated when block inventories are accessed + else if (ItemRegistry.BUCKETS.contains(packet.getItemInHand().getId())) { + // Let the server decide if the bucket item should change, not the client, and revert the changes the client made + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.INVENTORY); + slotPacket.setSlot(packet.getHotbarSlot()); + slotPacket.setItem(packet.getItemInHand()); + session.sendUpstreamPacket(slotPacket); + // Delay the interaction in case the client doesn't intend to actually use the bucket + // See BedrockActionTranslator.java + session.setBucketScheduledFuture(session.getConnector().getGeneralThreadPool().schedule(() -> { + ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); + session.sendDownstreamPacket(itemPacket); + }, 5, TimeUnit.MILLISECONDS)); + } } if (packet.getActions().isEmpty()) { @@ -253,10 +266,15 @@ else if (packet.getItemInHand() != null && ItemRegistry.BUCKETS.contains(packet. break; } - // Handled in ITEM_USE if the item is not milk - if (packet.getItemInHand() != null && ItemRegistry.BUCKETS.contains(packet.getItemInHand().getId()) && - packet.getItemInHand().getId() != ItemRegistry.MILK_BUCKET.getBedrockId()) { - break; + if (packet.getItemInHand() != null) { + if (ItemRegistry.BUCKETS.contains(packet.getItemInHand().getId()) && + packet.getItemInHand().getId() != ItemRegistry.MILK_BUCKET.getBedrockId()) { + // Handled in case 0 if the item is not milk + break; + } else if (ItemRegistry.SPAWN_EGGS.contains(packet.getItemInHand().getId())) { + // Handled in case 0 + break; + } } ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index 0e5fc5819de..1288930f55e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -37,10 +37,7 @@ import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntArraySet; -import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -113,6 +110,10 @@ public class ItemRegistry { * Shield item entry, used in Entity.java and LivingEntity.java */ public static ItemEntry SHIELD; + /** + * A list of all spawn eggs by their Bedrock IDs. Used in BedrockInventoryTransactionTranslator.java + */ + public static final IntSet SPAWN_EGGS = new IntArraySet(); /** * Wheat item entry, used in AbstractHorseEntity.java */ @@ -457,9 +458,9 @@ public static void init() { } if (entry.getKey().contains("boat")) { - BOATS.add(entry.getValue().get("bedrock_id").intValue()); + BOATS.add(itemEntry.getBedrockId()); } else if (entry.getKey().contains("bucket") && !entry.getKey().contains("milk")) { - BUCKETS.add(entry.getValue().get("bedrock_id").intValue()); + BUCKETS.add(itemEntry.getBedrockId()); } else if (entry.getKey().contains("_carpet") && !entry.getKey().contains("moss")) { // This should be the numerical order Java sends as an integer value for llamas CARPETS.add(ItemData.builder() @@ -471,6 +472,8 @@ public static void init() { // The Java record level event uses the item ID as the "key" to play the record EffectRegistry.RECORDS.put(itemIndex, SoundEvent.valueOf("RECORD_" + entry.getKey().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH))); + } else if (entry.getKey().endsWith("_spawn_egg")) { + SPAWN_EGGS.add(itemEntry.getBedrockId()); } itemNames.add(entry.getKey());