diff --git a/patches/server/Properly-resend-entities.patch b/patches/server/Properly-resend-entities.patch new file mode 100644 index 0000000000..0c74b1418e --- /dev/null +++ b/patches/server/Properly-resend-entities.patch @@ -0,0 +1,147 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Fri, 22 Mar 2019 22:24:03 -0700 +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 + +Co-authored-by: AgentTroll <woodyc40@gmail.com>m + +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java +@@ -0,0 +0,0 @@ public class ClientboundSetEntityDataPacket implements Packet<ClientGamePacketLi + private final List<SynchedEntityData.DataItem<?>> packedItems; + + public ClientboundSetEntityDataPacket(int id, SynchedEntityData tracker, boolean forceUpdateAll) { ++ // Paper start ++ this(id, tracker, forceUpdateAll, true); ++ } ++ public ClientboundSetEntityDataPacket(int id, SynchedEntityData tracker, boolean forceUpdateAll, boolean clearDirty) { ++ // Paper end + this.id = id; + if (forceUpdateAll) { + this.packedItems = tracker.getAll(); +- tracker.clearDirty(); ++ if (clearDirty) tracker.clearDirty(); // Paper + } else { + this.packedItems = tracker.packDirty(); + } +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + } ++ // Paper start ++ // 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 (player.getBukkitEntity().canSee(entity.getBukkitEntity())) { ++ // This will prevent the entity data from being cleared, so that ONLY this player ++ // will have its entity data updated and it won't dirty the datatracker for other players. ++ this.serverEntity.clearDirtyEntityData = false; ++ this.serverEntity.sendPairingData(player.connection::send, player); ++ this.serverEntity.clearDirtyEntityData = true; ++ } ++ } ++ ++ public void resendPossiblyDesyncedEntityData(ServerPlayer player) { ++ if (player.getBukkitEntity().canSee(entity.getBukkitEntity())) { ++ player.connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket(entity.getId(), entity.getEntityData(), true, false)); ++ } ++ } ++ // Paper end + } + } +diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/level/ServerEntity.java ++++ b/src/main/java/net/minecraft/server/level/ServerEntity.java +@@ -0,0 +0,0 @@ public class ServerEntity { + private boolean wasOnGround; + // CraftBukkit start + final Set<ServerPlayerConnection> trackedPlayers; // Paper - private -> package ++ public boolean clearDirtyEntityData = true; // Paper + + public ServerEntity(ServerLevel worldserver, Entity entity, int i, boolean flag, Consumer<Packet<?>> consumer, Set<ServerPlayerConnection> trackedPlayers) { + this.trackedPlayers = trackedPlayers; +@@ -0,0 +0,0 @@ public class ServerEntity { + this.yHeadRotp = Mth.floor(this.entity.getYHeadRot() * 256.0F / 360.0F); + consumer.accept(packet); + if (!this.entity.getEntityData().isEmpty()) { +- consumer.accept(new ClientboundSetEntityDataPacket(this.entity.getId(), this.entity.getEntityData(), true)); ++ consumer.accept(new ClientboundSetEntityDataPacket(this.entity.getId(), this.entity.getEntityData(), true, this.clearDirtyEntityData)); // Paper + } + + boolean flag = this.trackDelta; +@@ -0,0 +0,0 @@ public class ServerEntity { + + } + ++ // Paper start - Add broadcast method ++ @Deprecated(forRemoval = true) ++ void broadcast(Packet<?> packet) { ++ this.broadcast.accept(packet); ++ } ++ // Paper end ++ + private void broadcastAndSend(Packet<?> packet) { + this.broadcast.accept(packet); + if (this.entity instanceof ServerPlayer) { +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + + // Entity in bucket - SPIGOT-4048 and SPIGOT-6859 + 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)); ++ // Paper start ++ if (entity.tracker != null) { ++ entity.tracker.resendPossiblyDesyncedEntity(((ServerPlayer) player)); // The entire mob gets deleted, so resend it. ++ } ++ // Paper end + player.containerMenu.sendAllDataToRemote(); + } + +@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + + if (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem) { + // Refresh the current entity metadata +- ServerGamePacketListenerImpl.this.send(new ClientboundSetEntityDataPacket(entity.getId(), entity.getEntityData(), true)); ++ // Paper start ++ if (entity.tracker != null) { ++ entity.tracker.resendPossiblyDesyncedEntityData(((ServerPlayer) player)); ++ } ++ // Paper end + // SPIGOT-7136 - Allays + if (entity instanceof Allay) { + ServerGamePacketListenerImpl.this.send(new ClientboundSetEquipmentPacket(entity.getId(), Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()).map((slot) -> Pair.of(slot, ((LivingEntity) entity).getItemBySlot(slot).copy())).collect(Collectors.toList()))); +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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java +@@ -0,0 +0,0 @@ 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 +- ((ServerPlayer) player).connection.send(new ClientboundSetEntityDataPacket(entity.getId(), entity.getEntityData(), true)); // Need to send data such as the display name to client ++ // Paper start ++ if (entity.tracker != null) { ++ entity.tracker.resendPossiblyDesyncedEntity(((ServerPlayer) player)); ++ } ++ // Paper end + return Optional.of(InteractionResult.FAIL); + } + entity.playSound(((Bucketable) entity).getPickupSound(), 1.0F, 1.0F); diff --git a/patches/server/Update-entity-Metadata-for-all-tracked-players.patch b/patches/server/Update-entity-Metadata-for-all-tracked-players.patch deleted file mode 100644 index deb7265929..0000000000 --- a/patches/server/Update-entity-Metadata-for-all-tracked-players.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: AgentTroll <woodyc40@gmail.com> -Date: Fri, 22 Mar 2019 22:24:03 -0700 -Subject: [PATCH] Update entity Metadata for all tracked players - - -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -0,0 +0,0 @@ public class ServerEntity { - - } - -+ // Paper start - Add broadcast method -+ void broadcast(Packet<?> packet) { -+ this.broadcast.accept(packet); -+ } -+ // Paper end -+ - private void broadcastAndSend(Packet<?> packet) { - this.broadcast.accept(packet); - if (this.entity instanceof ServerPlayer) { -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic - - if (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem) { - // Refresh the current entity metadata -- ServerGamePacketListenerImpl.this.send(new ClientboundSetEntityDataPacket(entity.getId(), entity.getEntityData(), true)); -+ // Paper start - update entity for all players -+ ClientboundSetEntityDataPacket entityDataPacket = new ClientboundSetEntityDataPacket(entity.getId(), entity.getEntityData(), true); -+ if (entity.tracker != null) { -+ entity.tracker.broadcast(entityDataPacket); -+ } else { -+ ServerGamePacketListenerImpl.this.send(entityDataPacket); -+ } -+ // Paper end - // SPIGOT-7136 - Allays - if (entity instanceof Allay) { - ServerGamePacketListenerImpl.this.send(new ClientboundSetEquipmentPacket(entity.getId(), Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()).map((slot) -> Pair.of(slot, ((LivingEntity) entity).getItemBySlot(slot).copy())).collect(Collectors.toList())));