PaperMC/patches/server/Properly-resend-entities.patch
2022-11-05 14:50:16 -04:00

147 lines
9.2 KiB
Diff

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);