From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> Date: Wed, 7 Dec 2022 17:25:19 -0500 Subject: [PATCH] Properly resend entities This resolves some issues which caused entities to not be resent correctly. Entities that are interacted with need to be resent to the client, so we resend all the entity data to the player whilst making sure not to clear dirty entries from the tracker. This makes sure that values will be correctly updated to other players. See: https://github.com/PaperMC/Paper/pull/1896 == AT == public net.minecraft.server.level.ChunkMap$TrackedEntity serverEntity diff --git a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java index d088479d160dbd2fc90b48a30553be141db8eef2..bf6a70a69bb695ec1a202cd1e863c468329f80fc 100644 --- a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java +++ b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java @@ -253,14 +253,46 @@ public class SynchedEntityData { // CraftBukkit start public void refresh(ServerPlayer to) { if (!this.isEmpty()) { - List> list = this.getNonDefaultValues(); + List> list = this.packAll(); // Paper - Update EVERYTHING not just not default if (list != null) { + if (to.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper to.connection.send(new ClientboundSetEntityDataPacket(this.entity.getId(), list)); + } // Paper } } } // CraftBukkit end + // Paper start + // We need to pack all as we cannot rely on "non default values" or "dirty" ones. + // Because these values can possibly be desynced on the client. + @Nullable + private List> packAll() { + if (this.isEmpty()) { + return null; + } + + List> list = new ArrayList<>(); + for (DataItem dataItem : this.itemsById.values()) { + list.add(dataItem.value()); + } + + return list; + } + + // This method should only be used if the data of an entity could have became desynced + // due to interactions on the client. + public void resendPossiblyDesyncedEntity(ServerPlayer player) { + if (this.entity.tracker == null) { + return; + } + + net.minecraft.server.level.ServerEntity serverEntity = this.entity.tracker.serverEntity; + if (player.getBukkitEntity().canSee(entity.getBukkitEntity())) { + serverEntity.sendPairingData(player, player.connection::send); + } + } + // Paper end public static class DataItem { diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 90c1cd80e0d3fd0d7d66541f3d17d71353e7f258..ab5b5e41017cd069903cee5394494352e7ff2adf 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -2799,7 +2799,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic // Entity in bucket - SPIGOT-4048 and SPIGOT-6859a if ((entity instanceof Bucketable && entity instanceof LivingEntity && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) { - ServerGamePacketListenerImpl.this.send(new ClientboundAddEntityPacket(entity)); + entity.getEntityData().resendPossiblyDesyncedEntity(player); // Paper - The entire mob gets deleted, so resend it. player.containerMenu.sendAllDataToRemote(); } diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java index 815eb218b6612b13c6deff636509bad35eeace62..490f2d6f7a43d0a5915a80960c1c7c48b3eea19f 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -371,7 +371,7 @@ public abstract class PlayerList { ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - track entity now // CraftBukkit end - player.getEntityData().refresh(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn + //player.getEntityData().refresh(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn Paper - THIS IS NOT NEEDED ANYMORE this.sendLevelInfo(player, worldserver1); diff --git a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java index 37596c7b65f280be00e8e59ae18bd1aceae21080..eca18540aeb0b0d4098477d73b14c78a7bf9f455 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java +++ b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java @@ -109,8 +109,7 @@ public interface Bucketable { itemstack1 = CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket()); if (playerBucketFishEvent.isCancelled()) { ((ServerPlayer) player).containerMenu.sendAllDataToRemote(); // We need to update inventory to resync client's bucket - ((ServerPlayer) player).connection.send(new ClientboundAddEntityPacket(entity)); // We need to play out these packets as the client assumes the fish is gone - entity.getEntityData().refresh((ServerPlayer) player); // Need to send data such as the display name to client + entity.getEntityData().resendPossiblyDesyncedEntity((ServerPlayer) player); // Paper return Optional.of(InteractionResult.FAIL); } entity.playSound(((Bucketable) entity).getPickupSound(), 1.0F, 1.0F);