From 11f048a065c38e4eb38717d9dfad5d0f4b6a8346 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Thu, 22 Jul 2021 09:16:19 -0400
Subject: [PATCH] Better logic for item updating on item entities

Specifically created to address InteractionVisualizer updating all metadata properties when updating the nametag - this commit prevents the item from jumping on updating. It also prevents the entity from being respawned if just the stack size updated.
---
 .../geysermc/connector/entity/ItemEntity.java | 25 ++++++++++++++++---
 .../translators/item/ItemTranslator.java      |  2 ++
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java
index 3dcfb0d93..ba354c525 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java
@@ -29,9 +29,11 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
 import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
 import com.nukkitx.math.vector.Vector3f;
 import com.nukkitx.math.vector.Vector3i;
+import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
 import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
 import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
 import com.nukkitx.protocol.bedrock.packet.AddItemEntityPacket;
+import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
 import org.geysermc.connector.entity.type.EntityType;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.translators.item.ItemTranslator;
@@ -115,9 +117,26 @@ public class ItemEntity extends ThrowableEntity {
     @Override
     public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
         if (entityMetadata.getId() == 8) {
-            item = ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue());
-            despawnEntity(session);
-            spawnEntity(session);
+            ItemData item = ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue());
+            if (this.item == null) {
+                this.item = item;
+                spawnEntity(session);
+            } else if (item.equals(this.item, false, true, true)) {
+                // Don't bother respawning the entity if items are equal
+                if (this.item.getCount() != item.getCount()) {
+                    // Just item count updated; let's make this easy
+                    this.item = item;
+                    EntityEventPacket packet = new EntityEventPacket();
+                    packet.setRuntimeEntityId(geyserId);
+                    packet.setType(EntityEventType.UPDATE_ITEM_STACK_SIZE);
+                    packet.setData(this.item.getCount());
+                    session.sendUpstreamPacket(packet);
+                }
+            } else {
+                this.item = item;
+                despawnEntity(session);
+                spawnEntity(session);
+            }
         }
 
         super.updateBedrockMetadata(entityMetadata, session);
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java
index 0fdfc3cc7..497ef831f 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java
@@ -44,6 +44,7 @@ import org.geysermc.connector.registry.type.ItemMappings;
 import org.geysermc.connector.utils.FileUtils;
 import org.geysermc.connector.utils.LocaleUtils;
 
+import javax.annotation.Nonnull;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -125,6 +126,7 @@ public abstract class ItemTranslator {
         return itemStack;
     }
 
+    @Nonnull
     public static ItemData translateToBedrock(GeyserSession session, ItemStack stack) {
         if (stack == null) {
             return ItemData.AIR;