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.

This also adds utilities to aid in further preventing entity desyncs.

This also also fixes the bug causing cancelling PlayerInteractEvent to cause items to continue
to be used despite being cancelled on the server.

For example, items being consumed but never finishing, shields being put up, etc.
The underlying issue of this is that the client modifies their synced data values,
and so we have to (forcibly) resend them in order for the client to reset their using item state.

See: https://github.com/PaperMC/Paper/pull/1896

== AT ==
public net.minecraft.server.level.ChunkMap$TrackedEntity serverEntity
This commit is contained in:
Owen1212055 2022-12-07 17:25:19 -05:00
parent ea24e2c6aa
commit d300c94ec2
13 changed files with 358 additions and 246 deletions

View file

@ -1,10 +1,12 @@
--- a/net/minecraft/network/syncher/SynchedEntityData.java
+++ b/net/minecraft/network/syncher/SynchedEntityData.java
@@ -51,7 +51,7 @@
@@ -50,8 +50,8 @@
}
}
private <T> SynchedEntityData.DataItem<T> getItem(EntityDataAccessor<T> key) {
- private <T> SynchedEntityData.DataItem<T> getItem(EntityDataAccessor<T> key) {
- return this.itemsById[key.id()];
+ public <T> SynchedEntityData.DataItem<T> getItem(EntityDataAccessor<T> key) { // Paper - public
+ return (SynchedEntityData.DataItem<T>) this.itemsById[key.id()]; // CraftBukkit - decompile error
}
@ -23,7 +25,7 @@
public boolean isDirty() {
return this.isDirty;
}
@@ -140,7 +147,7 @@
@@ -140,10 +147,24 @@
if (!Objects.equals(from.serializer(), to.accessor.serializer())) {
throw new IllegalStateException(String.format(Locale.ROOT, "Invalid entity data item type for field %d on entity %s: old=%s(%s), new=%s(%s)", to.accessor.id(), this.entity, to.value, to.value.getClass(), from.value, from.value.getClass()));
} else {
@ -32,3 +34,20 @@
}
}
+ // 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
+ public List<SynchedEntityData.DataValue<?>> packAll() {
+ final List<SynchedEntityData.DataValue<?>> list = new ArrayList<>();
+ for (final DataItem<?> dataItem : this.itemsById) {
+ list.add(dataItem.value());
+ }
+
+ return list;
+ }
+ // Paper end
+
public static class DataItem<T> {
final EntityDataAccessor<T> accessor;

View file

@ -135,9 +135,9 @@
+ // Update any tile entity data for this block
+ capturedBlockEntity = true; // Paper - Send block entities after destroy prediction
+ // CraftBukkit end
+ return;
+ }
+
return;
}
+ // CraftBukkit start
+ PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, pos, direction, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND);
+ if (event.isCancelled()) {
@ -145,10 +145,10 @@
+ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync blocks
+ // Update any tile entity data for this block
+ capturedBlockEntity = true; // Paper - Send block entities after destroy prediction
return;
}
+ return;
+ }
+ // CraftBukkit end
+
if (this.isCreative()) {
this.destroyAndAck(pos, sequence, "creative destroy");
return;
@ -374,7 +374,7 @@
}
}
}
@@ -321,17 +514,62 @@
@@ -321,17 +514,63 @@
}
}
@ -431,6 +431,7 @@
+ }
+ // Paper end - extend Player Interact cancellation
+ player.getBukkitEntity().updateInventory(); // SPIGOT-2867
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
+ return (event.useItemInHand() != Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS;
+ } else if (this.gameModeForPlayer == GameType.SPECTATOR) {
+ MenuProvider itileinventory = iblockdata.getMenuProvider(world, blockposition);
@ -439,7 +440,7 @@
return InteractionResult.CONSUME;
} else {
return InteractionResult.PASS;
@@ -359,7 +597,7 @@
@@ -359,7 +598,7 @@
}
}
@ -448,3 +449,15 @@
UseOnContext itemactioncontext = new UseOnContext(player, hand, hitResult);
if (this.isCreative()) {
@@ -377,6 +616,11 @@
return enuminteractionresult;
} else {
+ // Paper start - Properly cancel usable items; Cancel only if cancelled + if the interact result is different from default response
+ if (this.interactResult && this.interactResult != cancelledItem) {
+ this.player.resyncUsingItem(this.player);
+ }
+ // Paper end - Properly cancel usable items
return InteractionResult.PASS;
}
}

View file

@ -48,7 +48,7 @@
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.Level;
@@ -192,12 +196,73 @@
@@ -192,11 +196,72 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
@ -59,7 +59,7 @@
import net.minecraft.world.phys.shapes.VoxelShape;
+import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
+
+// CraftBukkit start
+import io.papermc.paper.adventure.ChatProcessor; // Paper
+import io.papermc.paper.adventure.PaperAdventure; // Paper
@ -118,10 +118,9 @@
+import org.bukkit.inventory.InventoryView;
+import org.bukkit.inventory.SmithingInventory;
+// CraftBukkit end
+
public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl implements ServerGamePacketListener, ServerPlayerConnection, TickablePacketListener {
static final Logger LOGGER = LogUtils.getLogger();
@@ -212,7 +277,9 @@
private int tickCount;
private int ackBlockChangesUpTo = -1;
@ -339,7 +338,7 @@
boolean flag1 = entity.verticalCollisionBelow;
if (entity instanceof LivingEntity) {
@@ -449,20 +607,73 @@
@@ -449,19 +607,72 @@
d10 = d6 * d6 + d7 * d7 + d8 * d8;
boolean flag2 = false;
@ -358,8 +357,8 @@
+ this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
this.send(ClientboundMoveVehiclePacket.fromEntity(entity));
return;
}
+ }
+
+ // CraftBukkit start - fire PlayerMoveEvent
+ Player player = this.getCraftPlayer();
+ if (!this.hasMoved) {
@ -408,12 +407,11 @@
+ this.justTeleported = false;
+ return;
+ }
+ }
}
+ // CraftBukkit end
+
this.player.serverLevel().getChunkSource().move(this.player);
entity.recordMovementThroughBlocks(new Vec3(d0, d1, d2), entity.position());
Vec3 vec3d = new Vec3(entity.getX() - d0, entity.getY() - d1, entity.getZ() - d2);
@@ -489,16 +700,17 @@
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
if (packet.getId() == this.awaitingTeleport) {
@ -1264,7 +1262,7 @@
if (this.player.hasClientLoaded()) {
this.ackBlockChangesUpTo(packet.getSequence());
ServerLevel worldserver = this.player.serverLevel();
@@ -1296,6 +1993,47 @@
@@ -1296,6 +1993,48 @@
this.player.absRotateTo(f, f1);
}
@ -1301,6 +1299,7 @@
+ }
+
+ if (cancelled) {
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
+ this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524
+ return;
+ }
@ -1312,7 +1311,7 @@
InteractionResult enuminteractionresult = this.player.gameMode.useItem(this.player, worldserver, itemstack, enumhand);
if (enuminteractionresult instanceof InteractionResult.Success) {
@@ -1321,7 +2059,7 @@
@@ -1321,7 +2060,7 @@
Entity entity = packet.getEntity(worldserver);
if (entity != null) {
@ -1321,7 +1320,7 @@
return;
}
}
@@ -1342,22 +2080,52 @@
@@ -1342,22 +2081,52 @@
@Override
public void onDisconnect(DisconnectionDetails info) {
@ -1378,7 +1377,7 @@
throw new IllegalArgumentException("Expected packet sequence nr >= 0");
} else {
this.ackBlockChangesUpTo = Math.max(sequence, this.ackBlockChangesUpTo);
@@ -1367,7 +2135,17 @@
@@ -1367,7 +2136,17 @@
@Override
public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
@ -1396,7 +1395,7 @@
if (this.player.getInventory().selected != packet.getSlot() && this.player.getUsedItemHand() == InteractionHand.MAIN_HAND) {
this.player.stopUsingItem();
}
@@ -1376,11 +2154,18 @@
@@ -1376,11 +2155,18 @@
this.player.resetLastActionTime();
} else {
ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString());
@ -1415,7 +1414,7 @@
Optional<LastSeenMessages> optional = this.unpackAndApplyLastSeen(packet.lastSeenMessages());
if (!optional.isEmpty()) {
@@ -1394,27 +2179,46 @@
@@ -1394,27 +2180,46 @@
return;
}
@ -1469,7 +1468,7 @@
ParseResults<CommandSourceStack> parseresults = this.parseCommand(command);
if (this.server.enforceSecureProfile() && SignableCommand.hasSignableArguments(parseresults)) {
@@ -1431,30 +2235,58 @@
@@ -1431,30 +2236,58 @@
if (!optional.isEmpty()) {
this.tryHandleChat(packet.command(), () -> {
@ -1534,7 +1533,7 @@
}
private void handleMessageDecodeFailure(SignedMessageChain.DecodeException exception) {
@@ -1530,14 +2362,20 @@
@@ -1530,14 +2363,20 @@
return com_mojang_brigadier_commanddispatcher.parse(command, this.player.createCommandSourceStack());
}
@ -1560,7 +1559,7 @@
}
}
@@ -1549,7 +2387,7 @@
@@ -1549,7 +2388,7 @@
if (optional.isEmpty()) {
ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString());
@ -1569,7 +1568,7 @@
}
return optional;
@@ -1566,6 +2404,117 @@
@@ -1566,6 +2405,117 @@
return false;
}
@ -1687,7 +1686,7 @@
private PlayerChatMessage getSignedMessage(ServerboundChatPacket packet, LastSeenMessages lastSeenMessages) throws SignedMessageChain.DecodeException {
SignedMessageBody signedmessagebody = new SignedMessageBody(packet.message(), packet.timeStamp(), packet.salt(), lastSeenMessages);
@@ -1573,15 +2522,44 @@
@@ -1573,15 +2523,44 @@
}
private void broadcastChatMessage(PlayerChatMessage message) {
@ -1738,7 +1737,7 @@
}
@@ -1592,7 +2570,7 @@
@@ -1592,7 +2571,7 @@
synchronized (this.lastSeenMessages) {
if (!this.lastSeenMessages.applyOffset(packet.offset())) {
ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString());
@ -1747,7 +1746,7 @@
}
}
@@ -1601,7 +2579,40 @@
@@ -1601,7 +2580,40 @@
@Override
public void handleAnimate(ServerboundSwingPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
@ -1788,7 +1787,7 @@
this.player.swing(packet.getHand());
}
@@ -1609,6 +2620,29 @@
@@ -1609,6 +2621,29 @@
public void handlePlayerCommand(ServerboundPlayerCommandPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
if (this.player.hasClientLoaded()) {
@ -1818,7 +1817,7 @@
this.player.resetLastActionTime();
Entity entity;
PlayerRideableJumping ijumpable;
@@ -1616,6 +2650,11 @@
@@ -1616,6 +2651,11 @@
switch (packet.getAction()) {
case PRESS_SHIFT_KEY:
this.player.setShiftKeyDown(true);
@ -1830,7 +1829,7 @@
break;
case RELEASE_SHIFT_KEY:
this.player.setShiftKeyDown(false);
@@ -1684,15 +2723,25 @@
@@ -1684,15 +2724,25 @@
}
if (i > 4096) {
@ -1857,7 +1856,7 @@
}
public void sendDisguisedChatMessage(Component message, ChatType.Bound params) {
@@ -1703,6 +2752,18 @@
@@ -1703,6 +2753,18 @@
return this.connection.getRemoteAddress();
}
@ -1876,7 +1875,7 @@
public void switchToConfig() {
this.waitingForSwitchToConfig = true;
this.removePlayerFromWorld();
@@ -1718,9 +2779,17 @@
@@ -1718,9 +2780,17 @@
@Override
public void handleInteract(ServerboundInteractPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
@ -1894,7 +1893,7 @@
this.player.resetLastActionTime();
this.player.setShiftKeyDown(packet.isUsingSecondaryAction());
@@ -1731,22 +2800,61 @@
@@ -1731,22 +2801,61 @@
AABB axisalignedbb = entity.getBoundingBox();
@ -1918,7 +1917,7 @@
+
+ // 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)) {
+ entity.getBukkitEntity().update(ServerGamePacketListenerImpl.this.player);
+ entity.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it
+ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote();
+ }
+
@ -1961,7 +1960,7 @@
}
}
@@ -1755,19 +2863,20 @@
@@ -1755,19 +2864,20 @@
@Override
public void onInteraction(InteractionHand hand) {
@ -1985,7 +1984,7 @@
label23:
{
if (entity instanceof AbstractArrow) {
@@ -1785,17 +2894,41 @@
@@ -1785,17 +2895,41 @@
}
ServerGamePacketListenerImpl.this.player.attack(entity);
@ -2028,7 +2027,7 @@
}
}
@@ -1809,7 +2942,7 @@
@@ -1809,7 +2943,7 @@
case PERFORM_RESPAWN:
if (this.player.wonGame) {
this.player.wonGame = false;
@ -2037,7 +2036,7 @@
this.resetPosition();
CriteriaTriggers.CHANGED_DIMENSION.trigger(this.player, Level.END, Level.OVERWORLD);
} else {
@@ -1817,11 +2950,11 @@
@@ -1817,11 +2951,11 @@
return;
}
@ -2052,7 +2051,7 @@
}
}
break;
@@ -1833,16 +2966,27 @@
@@ -1833,16 +2967,27 @@
@Override
public void handleContainerClose(ServerboundContainerClosePacket packet) {
@ -2082,7 +2081,7 @@
this.player.containerMenu.sendAllDataToRemote();
} else if (!this.player.containerMenu.stillValid(this.player)) {
ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu);
@@ -1855,7 +2999,315 @@
@@ -1855,7 +3000,315 @@
boolean flag = packet.getStateId() != this.player.containerMenu.getStateId();
this.player.containerMenu.suppressRemoteUpdates();
@ -2399,7 +2398,7 @@
ObjectIterator objectiterator = Int2ObjectMaps.fastIterable(packet.getChangedSlots()).iterator();
while (objectiterator.hasNext()) {
@@ -1879,6 +3331,14 @@
@@ -1879,6 +3332,14 @@
@Override
public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) {
@ -2414,7 +2413,7 @@
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
this.player.resetLastActionTime();
if (!this.player.isSpectator() && this.player.containerMenu.containerId == packet.containerId()) {
@@ -1900,9 +3360,43 @@
@@ -1900,9 +3361,43 @@
ServerGamePacketListenerImpl.LOGGER.debug("Player {} tried to place impossible recipe {}", this.player, recipeholder.id().location());
return;
}
@ -2459,7 +2458,7 @@
if (containerrecipebook_a == RecipeBookMenu.PostPlaceAction.PLACE_GHOST_RECIPE) {
this.player.connection.send(new ClientboundPlaceGhostRecipePacket(this.player.containerMenu.containerId, craftingmanager_d.display().display()));
}
@@ -1917,6 +3411,7 @@
@@ -1917,6 +3412,7 @@
@Override
public void handleContainerButtonClick(ServerboundContainerButtonClickPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
@ -2467,7 +2466,7 @@
this.player.resetLastActionTime();
if (this.player.containerMenu.containerId == packet.containerId() && !this.player.isSpectator()) {
if (!this.player.containerMenu.stillValid(this.player)) {
@@ -1945,7 +3440,44 @@
@@ -1945,7 +3441,44 @@
boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45;
boolean flag2 = itemstack.isEmpty() || itemstack.getCount() <= itemstack.getMaxStackSize();
@ -2512,7 +2511,7 @@
if (flag1 && flag2) {
this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemstack);
this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemstack);
@@ -1964,7 +3496,19 @@
@@ -1964,7 +3497,19 @@
@Override
public void handleSignUpdate(ServerboundSignUpdatePacket packet) {
@ -2533,7 +2532,7 @@
this.filterTextPacket(list).thenAcceptAsync((list1) -> {
this.updateSignText(packet, list1);
@@ -1972,6 +3516,7 @@
@@ -1972,6 +3517,7 @@
}
private void updateSignText(ServerboundSignUpdatePacket packet, List<FilteredText> signText) {
@ -2541,7 +2540,7 @@
this.player.resetLastActionTime();
ServerLevel worldserver = this.player.serverLevel();
BlockPos blockposition = packet.getPos();
@@ -1993,15 +3538,33 @@
@@ -1993,15 +3539,33 @@
@Override
public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
@ -2576,7 +2575,7 @@
if (this.player.isModelPartShown(PlayerModelPart.HAT) != flag) {
this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT, this.player));
}
@@ -2012,7 +3575,7 @@
@@ -2012,7 +3576,7 @@
public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
if (this.player.hasPermissions(2) || this.isSingleplayerOwner()) {
@ -2585,7 +2584,7 @@
}
}
@@ -2033,7 +3596,7 @@
@@ -2033,7 +3597,7 @@
if (!Objects.equals(profilepublickey_a, profilepublickey_a1)) {
if (profilepublickey_a != null && profilepublickey_a1.expiresAt().isBefore(profilepublickey_a.expiresAt())) {
@ -2594,7 +2593,7 @@
} else {
try {
SignatureValidator signaturevalidator = this.server.getProfileKeySignatureValidator();
@@ -2045,8 +3608,8 @@
@@ -2045,8 +3609,8 @@
this.resetPlayerChatState(remotechatsession_a.validate(this.player.getGameProfile(), signaturevalidator));
} catch (ProfilePublicKey.ValidationException profilepublickey_b) {
@ -2605,7 +2604,7 @@
}
}
@@ -2058,7 +3621,7 @@
@@ -2058,7 +3622,7 @@
if (!this.waitingForSwitchToConfig) {
throw new IllegalStateException("Client acknowledged config, but none was requested");
} else {
@ -2614,7 +2613,7 @@
}
}
@@ -2076,15 +3639,18 @@
@@ -2076,15 +3640,18 @@
private void resetPlayerChatState(RemoteChatSession session) {
this.chatSession = session;
@ -2636,7 +2635,7 @@
@Override
public void handleClientTickEnd(ServerboundClientTickEndPacket packet) {
@@ -2115,4 +3681,17 @@
@@ -2115,4 +3682,17 @@
InteractionResult run(ServerPlayer player, Entity entity, InteractionHand hand);
}

View file

@ -313,7 +313,7 @@
+ ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now
+ // CraftBukkit end
+
+ player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
+ //player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn // Paper - THIS IS NOT NEEDED ANYMORE
+
+ this.sendLevelInfo(player, worldserver1);
+
@ -842,7 +842,24 @@
return entityplayer1;
}
@@ -516,15 +924,32 @@
@@ -505,26 +913,48 @@
}
public void sendActiveEffects(LivingEntity entity, ServerGamePacketListenerImpl networkHandler) {
+ // Paper start - collect packets
+ this.sendActiveEffects(entity, networkHandler::send);
+ }
+ public void sendActiveEffects(LivingEntity entity, java.util.function.Consumer<Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> packetConsumer) {
+ // Paper end - collect packets
Iterator iterator = entity.getActiveEffects().iterator();
while (iterator.hasNext()) {
MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
- networkHandler.send(new ClientboundUpdateMobEffectPacket(entity.getId(), mobeffect, false));
+ packetConsumer.accept(new ClientboundUpdateMobEffectPacket(entity.getId(), mobeffect, false)); // Paper - collect packets
}
}
public void sendPlayerPermissionLevel(ServerPlayer player) {
@ -877,14 +894,10 @@
this.sendAllPlayerInfoIn = 0;
}
@@ -537,9 +962,28 @@
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
@@ -541,6 +971,25 @@
}
entityplayer.connection.send(packet);
+ }
+
+ }
+
+ // CraftBukkit start - add a world/entity limited version
+ public void broadcastAll(Packet packet, net.minecraft.world.entity.player.Player entityhuman) {
+ for (int i = 0; i < this.players.size(); ++i) {
@ -899,14 +912,15 @@
+ public void broadcastAll(Packet packet, Level world) {
+ for (int i = 0; i < world.players().size(); ++i) {
+ ((ServerPlayer) world.players().get(i)).connection.send(packet);
}
}
+ }
+
+ }
+ // CraftBukkit end
+
public void broadcastAll(Packet<?> packet, ResourceKey<Level> dimension) {
Iterator iterator = this.players.iterator();
@@ -554,7 +998,7 @@
@@ -554,7 +1003,7 @@
}
@ -915,7 +929,7 @@
PlayerTeam scoreboardteam = source.getTeam();
if (scoreboardteam != null) {
@@ -573,7 +1017,7 @@
@@ -573,7 +1022,7 @@
}
}
@ -924,7 +938,7 @@
PlayerTeam scoreboardteam = source.getTeam();
if (scoreboardteam == null) {
@@ -619,7 +1063,7 @@
@@ -619,7 +1068,7 @@
}
public void deop(GameProfile profile) {
@ -933,7 +947,7 @@
ServerPlayer entityplayer = this.getPlayer(profile.getId());
if (entityplayer != null) {
@@ -629,6 +1073,11 @@
@@ -629,6 +1078,11 @@
}
private void sendPlayerPermissionLevel(ServerPlayer player, int permissionLevel) {
@ -945,7 +959,7 @@
if (player.connection != null) {
byte b0;
@@ -643,36 +1092,53 @@
@@ -643,36 +1097,53 @@
player.connection.send(new ClientboundEntityEventPacket(player, b0));
}
@ -1012,7 +1026,7 @@
if (entityplayer != player && entityplayer.level().dimension() == worldKey) {
double d4 = x - entityplayer.getX();
double d5 = y - entityplayer.getY();
@@ -687,10 +1153,12 @@
@@ -687,10 +1158,12 @@
}
public void saveAll() {
@ -1025,7 +1039,7 @@
}
public UserWhiteList getWhiteList() {
@@ -712,15 +1180,19 @@
@@ -712,15 +1185,19 @@
public void reloadWhiteList() {}
public void sendLevelInfo(ServerPlayer player, ServerLevel world) {
@ -1049,7 +1063,7 @@
}
player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LEVEL_CHUNKS_LOAD_START, 0.0F));
@@ -729,8 +1201,16 @@
@@ -729,8 +1206,16 @@
public void sendAllPlayerInfo(ServerPlayer player) {
player.inventoryMenu.sendAllDataToRemote();
@ -1067,7 +1081,7 @@
}
public int getPlayerCount() {
@@ -746,6 +1226,7 @@
@@ -746,6 +1231,7 @@
}
public void setUsingWhiteList(boolean whitelistEnabled) {
@ -1075,7 +1089,7 @@
this.doWhiteList = whitelistEnabled;
}
@@ -786,11 +1267,35 @@
@@ -786,11 +1272,35 @@
}
public void removeAll() {
@ -1113,7 +1127,7 @@
public void broadcastSystemMessage(Component message, boolean overlay) {
this.broadcastSystemMessage(message, (entityplayer) -> {
@@ -819,24 +1324,43 @@
@@ -819,24 +1329,43 @@
}
public void broadcastChatMessage(PlayerChatMessage message, ServerPlayer sender, ChatType.Bound params) {
@ -1160,7 +1174,7 @@
}
if (flag1 && sender != null) {
@@ -845,20 +1369,27 @@
@@ -845,20 +1374,27 @@
}
@ -1193,7 +1207,7 @@
Path path = file2.toPath();
if (FileUtil.isPathNormalized(path) && FileUtil.isPathPortable(path) && path.startsWith(file.getPath()) && file2.isFile()) {
@@ -867,7 +1398,7 @@
@@ -867,7 +1403,7 @@
}
serverstatisticmanager = new ServerStatsCounter(this.server, file1);
@ -1202,7 +1216,7 @@
}
return serverstatisticmanager;
@@ -875,13 +1406,13 @@
@@ -875,13 +1411,13 @@
public PlayerAdvancements getPlayerAdvancements(ServerPlayer player) {
UUID uuid = player.getUUID();
@ -1218,7 +1232,7 @@
}
advancementdataplayer.setPlayer(player);
@@ -932,15 +1463,39 @@
@@ -932,15 +1468,39 @@
}
public void reloadResources() {

View file

@ -302,7 +302,7 @@
}
public boolean removeTag(String tag) {
@@ -362,20 +576,36 @@
@@ -362,20 +576,68 @@
}
public void kill(ServerLevel world) {
@ -330,18 +330,50 @@
+ // CraftBukkit start
+ public void refreshEntityData(ServerPlayer to) {
+ List<SynchedEntityData.DataValue<?>> list = this.getEntityData().getNonDefaultValues();
+ List<SynchedEntityData.DataValue<?>> list = this.entityData.packAll(); // Paper - Update EVERYTHING not just not default
+
+ if (list != null) {
+ if (list != null && to.getBukkitEntity().canSee(this.getBukkitEntity())) { // Paper
+ to.connection.send(new ClientboundSetEntityDataPacket(this.getId(), list));
+ }
+ }
+ // CraftBukkit end
+ // Paper start
+ // This method should only be used if the data of an entity could have become desynced
+ // due to interactions on the client.
+ public void resendPossiblyDesyncedEntityData(net.minecraft.server.level.ServerPlayer player) {
+ if (player.getBukkitEntity().canSee(this.getBukkitEntity())) {
+ ServerLevel world = (net.minecraft.server.level.ServerLevel)this.level();
+ net.minecraft.server.level.ChunkMap.TrackedEntity tracker = world == null ? null : world.getChunkSource().chunkMap.entityMap.get(this.getId());
+ if (tracker == null) {
+ return;
+ }
+ final net.minecraft.server.level.ServerEntity serverEntity = tracker.serverEntity;
+ final List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> list = new java.util.ArrayList<>();
+ serverEntity.sendPairingData(player, list::add);
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(list));
+ }
+ }
+
+ // This method allows you to specifically resend certain data accessor keys to the client
+ public void resendPossiblyDesyncedDataValues(List<EntityDataAccessor<?>> keys, ServerPlayer to) {
+ if (!to.getBukkitEntity().canSee(this.getBukkitEntity())) {
+ return;
+ }
+
+ final List<SynchedEntityData.DataValue<?>> values = new java.util.ArrayList<>(keys.size());
+ for (final EntityDataAccessor<?> key : keys) {
+ final SynchedEntityData.DataItem<?> synchedValue = this.entityData.getItem(key);
+ values.add(synchedValue.value());
+ }
+
+ to.connection.send(new ClientboundSetEntityDataPacket(this.id, values));
+ }
+ // Paper end
+
public boolean equals(Object object) {
return object instanceof Entity ? ((Entity) object).id == this.id : false;
}
@@ -385,22 +615,39 @@
@@ -385,22 +647,39 @@
}
public void remove(Entity.RemovalReason reason) {
@ -386,7 +418,7 @@
return this.getPose() == pose;
}
@@ -417,6 +664,33 @@
@@ -417,6 +696,33 @@
}
public void setRot(float yaw, float pitch) {
@ -420,7 +452,7 @@
this.setYRot(yaw % 360.0F);
this.setXRot(pitch % 360.0F);
}
@@ -426,8 +700,8 @@
@@ -426,8 +732,8 @@
}
public void setPos(double x, double y, double z) {
@ -431,7 +463,7 @@
}
protected final AABB makeBoundingBox() {
@@ -459,13 +733,29 @@
@@ -459,13 +765,29 @@
}
public void tick() {
@ -461,7 +493,7 @@
this.inBlockState = null;
if (this.isPassenger() && this.getVehicle().isRemoved()) {
this.stopRiding();
@@ -475,7 +765,7 @@
@@ -475,7 +797,7 @@
--this.boardingCooldown;
}
@ -470,7 +502,7 @@
if (this.canSpawnSprintParticle()) {
this.spawnSprintParticle();
}
@@ -502,7 +792,7 @@
@@ -502,7 +824,7 @@
this.setRemainingFireTicks(this.remainingFireTicks - 1);
}
@ -479,7 +511,7 @@
this.setTicksFrozen(0);
this.level().levelEvent((Player) null, 1009, this.blockPosition, 1);
}
@@ -514,6 +804,10 @@
@@ -514,6 +836,10 @@
if (this.isInLava()) {
this.lavaHurt();
this.fallDistance *= 0.5F;
@ -490,7 +522,7 @@
}
this.checkBelowWorld();
@@ -525,7 +819,7 @@
@@ -525,7 +851,7 @@
world = this.level();
if (world instanceof ServerLevel worldserver) {
if (this instanceof Leashable) {
@ -499,7 +531,7 @@
}
}
@@ -537,7 +831,12 @@
@@ -537,7 +863,12 @@
}
public void checkBelowWorld() {
@ -513,7 +545,7 @@
this.onBelowWorld();
}
@@ -568,15 +867,32 @@
@@ -568,15 +899,32 @@
public void lavaHurt() {
if (!this.fireImmune()) {
@ -548,7 +580,7 @@
}
}
@@ -587,9 +903,25 @@
@@ -587,9 +935,25 @@
}
public final void igniteForSeconds(float seconds) {
@ -575,7 +607,7 @@
public void igniteForTicks(int ticks) {
if (this.remainingFireTicks < ticks) {
this.setRemainingFireTicks(ticks);
@@ -610,7 +942,7 @@
@@ -610,7 +974,7 @@
}
protected void onBelowWorld() {
@ -584,7 +616,7 @@
}
public boolean isFree(double offsetX, double offsetY, double offsetZ) {
@@ -672,6 +1004,7 @@
@@ -672,6 +1036,7 @@
}
public void move(MoverType type, Vec3 movement) {
@ -592,10 +624,13 @@
if (this.noPhysics) {
this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
} else {
@@ -750,6 +1083,28 @@
}
}
@@ -747,8 +1112,30 @@
if (movement.y != vec3d1.y) {
block.updateEntityMovementAfterFallOn(this.level(), this);
+ }
+ }
+
+ // CraftBukkit start
+ if (this.horizontalCollision && this.getBukkitEntity() instanceof Vehicle) {
+ Vehicle vehicle = (Vehicle) this.getBukkitEntity();
@ -614,14 +649,13 @@
+ if (!bl.getType().isAir()) {
+ VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl, org.bukkit.craftbukkit.util.CraftVector.toBukkit(originalMovement)); // Paper - Expose pre-collision velocity
+ this.level.getCraftServer().getPluginManager().callEvent(event);
+ }
+ }
}
}
+ // CraftBukkit end
+
if (!this.level().isClientSide() || this.isControlledByLocalInstance()) {
Entity.MovementEmission entity_movementemission = this.getMovementEmission();
@@ -913,7 +1268,7 @@
@@ -913,7 +1300,7 @@
}
protected BlockPos getOnPos(float offset) {
@ -630,12 +664,10 @@
BlockPos blockposition = (BlockPos) this.mainSupportingBlockPos.get();
if (offset <= 1.0E-5F) {
@@ -1131,7 +1486,21 @@
protected SoundEvent getSwimHighSpeedSplashSound() {
@@ -1133,6 +1520,20 @@
return SoundEvents.GENERIC_SPLASH;
+ }
+
}
+ // CraftBukkit start - Add delegate methods
+ public SoundEvent getSwimSound0() {
+ return this.getSwimSound();
@ -647,12 +679,13 @@
+
+ public SoundEvent getSwimHighSpeedSplashSound0() {
+ return this.getSwimHighSpeedSplashSound();
}
+ }
+ // CraftBukkit end
+
public void recordMovementThroughBlocks(Vec3 oldPos, Vec3 newPos) {
this.movementThisTick.add(new Entity.Movement(oldPos, newPos));
@@ -1599,6 +1968,7 @@
}
@@ -1599,6 +2000,7 @@
this.setXRot(Mth.clamp(pitch, -90.0F, 90.0F) % 360.0F);
this.yRotO = this.getYRot();
this.xRotO = this.getXRot();
@ -660,7 +693,7 @@
}
public void absMoveTo(double x, double y, double z) {
@@ -1609,6 +1979,7 @@
@@ -1609,6 +2011,7 @@
this.yo = y;
this.zo = d4;
this.setPos(d3, y, d4);
@ -668,7 +701,7 @@
}
public void moveTo(Vec3 pos) {
@@ -1628,11 +1999,19 @@
@@ -1628,11 +2031,19 @@
}
public void moveTo(double x, double y, double z, float yaw, float pitch) {
@ -688,7 +721,7 @@
}
public final void setOldPosAndRot() {
@@ -1701,6 +2080,7 @@
@@ -1701,6 +2112,7 @@
public void push(Entity entity) {
if (!this.isPassengerOfSameVehicle(entity)) {
if (!entity.noPhysics && !this.noPhysics) {
@ -696,7 +729,7 @@
double d0 = entity.getX() - this.getX();
double d1 = entity.getZ() - this.getZ();
double d2 = Mth.absMax(d0, d1);
@@ -1737,7 +2117,21 @@
@@ -1737,7 +2149,21 @@
}
public void push(double deltaX, double deltaY, double deltaZ) {
@ -719,7 +752,7 @@
this.hasImpulse = true;
}
@@ -1858,9 +2252,21 @@
@@ -1858,9 +2284,21 @@
}
public boolean isPushable() {
@ -741,7 +774,7 @@
public void awardKillScore(Entity entityKilled, DamageSource damageSource) {
if (entityKilled instanceof ServerPlayer) {
CriteriaTriggers.ENTITY_KILLED_PLAYER.trigger((ServerPlayer) entityKilled, this, damageSource);
@@ -1889,74 +2295,133 @@
@@ -1889,74 +2327,133 @@
}
public boolean saveAsPassenger(CompoundTag nbt) {
@ -898,7 +931,7 @@
}
ListTag nbttaglist;
@@ -1972,10 +2437,10 @@
@@ -1972,10 +2469,10 @@
nbttaglist.add(StringTag.valueOf(s));
}
@ -911,7 +944,7 @@
if (this.isVehicle()) {
nbttaglist = new ListTag();
iterator = this.getPassengers().iterator();
@@ -1984,17 +2449,44 @@
@@ -1984,17 +2481,44 @@
Entity entity = (Entity) iterator.next();
CompoundTag nbttagcompound1 = new CompoundTag();
@ -959,17 +992,16 @@
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being saved");
@@ -2079,7 +2571,72 @@
}
@@ -2080,6 +2604,71 @@
} else {
throw new IllegalStateException("Entity has invalid position");
+ }
}
+
+ // CraftBukkit start
+ // Spigot start
+ if (this instanceof net.minecraft.world.entity.LivingEntity) {
+ this.tickCount = nbt.getInt("Spigot.ticksLived");
}
+ }
+ // Spigot end
+ this.persist = !nbt.contains("Bukkit.persist") || nbt.getBoolean("Bukkit.persist");
+ this.visibleByDefault = !nbt.contains("Bukkit.visibleByDefault") || nbt.getBoolean("Bukkit.visibleByDefault");
@ -1032,20 +1064,21 @@
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being loaded");
@@ -2101,6 +2658,12 @@
return entitytypes.canSerialize() && minecraftkey != null ? minecraftkey.toString() : null;
}
@@ -2099,7 +2688,13 @@
ResourceLocation minecraftkey = EntityType.getKey(entitytypes);
return entitytypes.canSerialize() && minecraftkey != null ? minecraftkey.toString() : null;
+ }
+
+ // CraftBukkit start - allow excluding certain data when saving
+ protected void addAdditionalSaveData(CompoundTag nbttagcompound, boolean includeAll) {
+ this.addAdditionalSaveData(nbttagcompound);
+ }
}
+ // CraftBukkit end
+
protected abstract void readAdditionalSaveData(CompoundTag nbt);
protected abstract void addAdditionalSaveData(CompoundTag nbt);
@@ -2150,12 +2713,60 @@
@@ -2150,12 +2745,60 @@
@Nullable
public ItemEntity spawnAtLocation(ServerLevel world, ItemStack stack, float yOffset) {
@ -1108,7 +1141,7 @@
world.addFreshEntity(entityitem);
return entityitem;
}
@@ -2184,7 +2795,16 @@
@@ -2184,7 +2827,16 @@
if (this.isAlive() && this instanceof Leashable leashable) {
if (leashable.getLeashHolder() == player) {
if (!this.level().isClientSide()) {
@ -1126,7 +1159,7 @@
leashable.removeLeash();
} else {
leashable.dropLeash();
@@ -2200,6 +2820,14 @@
@@ -2200,6 +2852,14 @@
if (itemstack.is(Items.LEAD) && leashable.canHaveALeashAttachedToIt()) {
if (!this.level().isClientSide()) {
@ -1141,7 +1174,7 @@
leashable.setLeashedTo(player, true);
}
@@ -2265,15 +2893,15 @@
@@ -2265,15 +2925,15 @@
}
public boolean showVehicleHealth() {
@ -1160,7 +1193,7 @@
return false;
} else {
for (Entity entity1 = entity; entity1.vehicle != null; entity1 = entity1.vehicle) {
@@ -2285,11 +2913,32 @@
@@ -2285,11 +2945,32 @@
if (!force && (!this.canRide(entity) || !entity.canAddPassenger(this))) {
return false;
} else {
@ -1194,7 +1227,7 @@
this.vehicle = entity;
this.vehicle.addPassenger(this);
entity.getIndirectPassengersStream().filter((entity2) -> {
@@ -2314,19 +2963,30 @@
@@ -2314,19 +2995,30 @@
}
public void removeVehicle() {
@ -1227,7 +1260,7 @@
protected void addPassenger(Entity passenger) {
if (passenger.getVehicle() != this) {
throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)");
@@ -2349,21 +3009,53 @@
@@ -2349,21 +3041,53 @@
}
}
@ -1287,7 +1320,7 @@
}
protected boolean canAddPassenger(Entity passenger) {
@@ -2464,7 +3156,7 @@
@@ -2464,7 +3188,7 @@
if (teleporttransition != null) {
ServerLevel worldserver1 = teleporttransition.newLevel();
@ -1296,7 +1329,7 @@
this.teleport(teleporttransition);
}
}
@@ -2547,7 +3239,7 @@
@@ -2547,7 +3271,7 @@
}
public boolean isCrouching() {
@ -1305,7 +1338,7 @@
}
public boolean isSprinting() {
@@ -2563,7 +3255,7 @@
@@ -2563,7 +3287,7 @@
}
public boolean isVisuallySwimming() {
@ -1314,7 +1347,7 @@
}
public boolean isVisuallyCrawling() {
@@ -2571,6 +3263,13 @@
@@ -2571,6 +3295,13 @@
}
public void setSwimming(boolean swimming) {
@ -1328,7 +1361,7 @@
this.setSharedFlag(4, swimming);
}
@@ -2609,6 +3308,7 @@
@@ -2609,6 +3340,7 @@
@Nullable
public PlayerTeam getTeam() {
@ -1336,7 +1369,7 @@
return this.level().getScoreboard().getPlayersTeam(this.getScoreboardName());
}
@@ -2624,8 +3324,12 @@
@@ -2624,8 +3356,12 @@
return this.getTeam() != null ? this.getTeam().isAlliedTo(team) : false;
}
@ -1350,7 +1383,7 @@
}
public boolean getSharedFlag(int index) {
@@ -2644,7 +3348,7 @@
@@ -2644,7 +3380,7 @@
}
public int getMaxAirSupply() {
@ -1359,7 +1392,7 @@
}
public int getAirSupply() {
@@ -2652,7 +3356,18 @@
@@ -2652,7 +3388,18 @@
}
public void setAirSupply(int air) {
@ -1379,7 +1412,7 @@
}
public int getTicksFrozen() {
@@ -2679,11 +3394,44 @@
@@ -2679,11 +3426,44 @@
public void thunderHit(ServerLevel world, LightningBolt lightning) {
this.setRemainingFireTicks(this.remainingFireTicks + 1);
@ -1426,7 +1459,7 @@
}
public void onAboveBubbleCol(boolean drag) {
@@ -2713,7 +3461,7 @@
@@ -2713,7 +3493,7 @@
this.resetFallDistance();
}
@ -1435,7 +1468,7 @@
return true;
}
@@ -2818,7 +3566,7 @@
@@ -2818,7 +3598,7 @@
public String toString() {
String s = this.level() == null ? "~NULL~" : this.level().toString();
@ -1444,7 +1477,7 @@
}
public final boolean isInvulnerableToBase(DamageSource damageSource) {
@@ -2838,6 +3586,13 @@
@@ -2838,6 +3618,13 @@
}
public void restoreFrom(Entity original) {
@ -1458,7 +1491,7 @@
CompoundTag nbttagcompound = original.saveWithoutId(new CompoundTag());
nbttagcompound.remove("Dimension");
@@ -2850,8 +3605,57 @@
@@ -2850,8 +3637,57 @@
public Entity teleport(TeleportTransition teleportTarget) {
Level world = this.level();
@ -1516,7 +1549,7 @@
ServerLevel worldserver1 = teleportTarget.newLevel();
boolean flag = worldserver1.dimension() != worldserver.dimension();
@@ -2918,10 +3722,19 @@
@@ -2918,10 +3754,19 @@
gameprofilerfiller.pop();
return null;
} else {
@ -1537,7 +1570,7 @@
Iterator iterator1 = list1.iterator();
while (iterator1.hasNext()) {
@@ -2947,7 +3760,7 @@
@@ -2947,7 +3792,7 @@
}
private void sendTeleportTransitionToRidingPlayers(TeleportTransition teleportTarget) {
@ -1546,7 +1579,7 @@
Iterator iterator = this.getIndirectPassengers().iterator();
while (iterator.hasNext()) {
@@ -2995,9 +3808,17 @@
@@ -2995,9 +3840,17 @@
}
protected void removeAfterChangingDimensions() {
@ -1567,10 +1600,11 @@
}
}
@@ -3006,11 +3827,34 @@
@@ -3005,12 +3858,35 @@
public Vec3 getRelativePortalPosition(Direction.Axis portalAxis, BlockUtil.FoundRectangle portalRect) {
return PortalShape.getRelativePosition(portalRect, portalAxis, this.position(), this.getDimensions(this.getPose()));
}
+
+ // CraftBukkit start
+ public CraftPortalEvent callPortalEvent(Entity entity, Location exit, PlayerTeleportEvent.TeleportCause cause, int searchRadius, int creationRadius) {
+ org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity();
@ -1592,7 +1626,7 @@
+ return new CraftPortalEvent(event);
+ }
+ // CraftBukkit end
+
public boolean canUsePortal(boolean allowVehicles) {
return (allowVehicles || !this.isPassenger()) && this.isAlive();
}
@ -1602,7 +1636,7 @@
if (from.dimension() == Level.END && to.dimension() == Level.OVERWORLD) {
Iterator iterator = this.getPassengers().iterator();
@@ -3134,10 +3978,16 @@
@@ -3134,10 +4010,16 @@
return (Boolean) this.entityData.get(Entity.DATA_CUSTOM_NAME_VISIBLE);
}
@ -1622,7 +1656,7 @@
return entity != null;
}
@@ -3187,7 +4037,7 @@
@@ -3187,7 +4069,7 @@
/** @deprecated */
@Deprecated
protected void fixupDimensions() {
@ -1631,7 +1665,7 @@
EntityDimensions entitysize = this.getDimensions(entitypose);
this.dimensions = entitysize;
@@ -3196,7 +4046,7 @@
@@ -3196,7 +4078,7 @@
public void refreshDimensions() {
EntityDimensions entitysize = this.dimensions;
@ -1640,7 +1674,7 @@
EntityDimensions entitysize1 = this.getDimensions(entitypose);
this.dimensions = entitysize1;
@@ -3258,10 +4108,29 @@
@@ -3258,10 +4140,29 @@
}
public final void setBoundingBox(AABB boundingBox) {
@ -1672,7 +1706,7 @@
return this.getDimensions(pose).eyeHeight();
}
@@ -3300,7 +4169,14 @@
@@ -3300,7 +4201,14 @@
public void startSeenByPlayer(ServerPlayer player) {}
@ -1688,7 +1722,7 @@
public float rotate(Rotation rotation) {
float f = Mth.wrapDegrees(this.getYRot());
@@ -3335,7 +4211,7 @@
@@ -3335,7 +4243,7 @@
}
@Nullable
@ -1697,7 +1731,7 @@
return null;
}
@@ -3373,20 +4249,34 @@
@@ -3373,20 +4281,34 @@
}
private Stream<Entity> getIndirectPassengersStream() {
@ -1732,7 +1766,7 @@
return () -> {
return this.getIndirectPassengersStream().iterator();
};
@@ -3399,6 +4289,7 @@
@@ -3399,6 +4321,7 @@
}
public boolean hasExactlyOnePlayerPassenger() {
@ -1740,7 +1774,7 @@
return this.countPlayerPassengers() == 1;
}
@@ -3435,7 +4326,7 @@
@@ -3435,7 +4358,7 @@
}
public boolean isControlledByLocalInstance() {
@ -1749,7 +1783,7 @@
if (entityliving instanceof Player entityhuman) {
return entityhuman.isLocalPlayer();
@@ -3445,7 +4336,7 @@
@@ -3445,7 +4368,7 @@
}
public boolean isControlledByClient() {
@ -1758,7 +1792,7 @@
return entityliving != null && entityliving.isControlledByClient();
}
@@ -3463,7 +4354,7 @@
@@ -3463,7 +4386,7 @@
return new Vec3((double) f1 * d2 / (double) f3, 0.0D, (double) f2 * d2 / (double) f3);
}
@ -1767,7 +1801,7 @@
return new Vec3(this.getX(), this.getBoundingBox().maxY, this.getZ());
}
@@ -3488,9 +4379,38 @@
@@ -3488,9 +4411,38 @@
public int getFireImmuneTicks() {
return 1;
}
@ -1778,12 +1812,12 @@
+ @Override
+ public void sendSystemMessage(Component message) {
+ }
+
+ @Override
+ public CommandSender getBukkitSender(CommandSourceStack wrapper) {
+ return Entity.this.getBukkitEntity();
+ }
+
+ @Override
+ public boolean acceptsSuccess() {
+ return ((ServerLevel) Entity.this.level()).getGameRules().getBoolean(GameRules.RULE_SENDCOMMANDFEEDBACK);
@ -1807,7 +1841,7 @@
}
public void lookAt(EntityAnchorArgument.Anchor anchorPoint, Vec3 target) {
@@ -3551,6 +4471,11 @@
@@ -3551,6 +4503,11 @@
vec3d = vec3d.add(vec3d1);
++k1;
}
@ -1819,7 +1853,7 @@
}
}
}
@@ -3613,7 +4538,7 @@
@@ -3613,7 +4570,7 @@
return new ClientboundAddEntityPacket(this, entityTrackerEntry);
}
@ -1828,16 +1862,17 @@
return this.type.getDimensions();
}
@@ -3714,7 +4639,39 @@
@@ -3713,8 +4670,40 @@
public double getRandomZ(double widthScale) {
return this.getZ((2.0D * this.random.nextDouble() - 1.0D) * widthScale);
}
+
+ // Paper start - Block invalid positions and bounding box
+ public static boolean checkPosition(Entity entity, double newX, double newY, double newZ) {
+ if (Double.isFinite(newX) && Double.isFinite(newY) && Double.isFinite(newZ)) {
+ return true;
+ }
+
+ String entityInfo;
+ try {
+ entityInfo = entity.toString();
@ -1868,7 +1903,7 @@
if (this.position.x != x || this.position.y != y || this.position.z != z) {
this.position = new Vec3(x, y, z);
int i = Mth.floor(x);
@@ -3732,6 +4689,12 @@
@@ -3732,6 +4721,12 @@
this.levelCallback.onMove();
}
@ -1881,7 +1916,7 @@
}
public void checkDespawn() {}
@@ -3818,8 +4781,17 @@
@@ -3818,8 +4813,17 @@
@Override
public final void setRemoved(Entity.RemovalReason reason) {
@ -1900,7 +1935,7 @@
}
if (this.removalReason.shouldDestroy()) {
@@ -3827,14 +4799,30 @@
@@ -3827,14 +4831,30 @@
}
this.getPassengers().forEach(Entity::stopRiding);
@ -1933,7 +1968,7 @@
@Override
public void setLevelCallback(EntityInLevelCallback changeListener) {
this.levelCallback = changeListener;
@@ -3887,7 +4875,7 @@
@@ -3887,7 +4907,7 @@
}
public Vec3 getKnownMovement() {
@ -1942,7 +1977,7 @@
if (entityliving instanceof Player entityhuman) {
if (this.isAlive()) {
@@ -3962,4 +4950,14 @@
@@ -3962,4 +4982,14 @@
void accept(Entity entity, double x, double y, double z);
}

View file

@ -297,7 +297,7 @@
boolean flag = scoreboardteam != null && scoreboard.addPlayerToTeam(this.getStringUUID(), scoreboardteam);
if (!flag) {
@@ -806,22 +909,47 @@
@@ -806,11 +909,13 @@
if (nbt.contains("SleepingX", 99) && nbt.contains("SleepingY", 99) && nbt.contains("SleepingZ", 99)) {
BlockPos blockposition = new BlockPos(nbt.getInt("SleepingX"), nbt.getInt("SleepingY"), nbt.getInt("SleepingZ"));
@ -311,11 +311,10 @@
}
if (nbt.contains("Brain", 10)) {
this.brain = this.makeBrain(new Dynamic(NbtOps.INSTANCE, nbt.get("Brain")));
+ }
+
+ }
+
@@ -819,9 +924,32 @@
}
+ // CraftBukkit start
+ private boolean isTickingEffects = false;
+ private List<ProcessableEffect> effectsToProcess = Lists.newArrayList();
@ -329,15 +328,15 @@
+ private ProcessableEffect(MobEffectInstance effect, EntityPotionEffectEvent.Cause cause) {
+ this.effect = effect;
+ this.cause = cause;
}
+ }
+
+ private ProcessableEffect(Holder<MobEffect> type, EntityPotionEffectEvent.Cause cause) {
+ this.type = type;
+ this.cause = cause;
+ }
}
+ }
+ // CraftBukkit end
+
protected void tickEffects() {
Iterator<Holder<MobEffect>> iterator = this.activeEffects.keySet().iterator();
@ -765,12 +764,10 @@
this.lastHurtByPlayer = entityhuman1;
} else {
@@ -1356,14 +1658,26 @@
return null;
@@ -1358,12 +1660,24 @@
}
+ }
+
}
+ // Paper start - only call damage event when actuallyHurt will be called - move out amount computation logic
+ private float computeAmountFromEntityDamageEvent(final EntityDamageEvent event) {
+ // Taken from hurt()'s craftbukkit diff.
@ -780,9 +777,9 @@
+ amount += (float) event.getDamage(DamageModifier.FREEZING);
+ amount += (float) event.getDamage(DamageModifier.HARD_HAT);
+ return amount;
}
+ }
+ // Paper end - only call damage event when actuallyHurt will be called - move out amount computation logic
+
protected void blockUsingShield(LivingEntity attacker) {
attacker.blockedByShield(this);
}
@ -1157,7 +1154,7 @@
+ };
+ float freezingModifier = freezing.apply((double) f).floatValue();
+ f += freezingModifier;
+
+ com.google.common.base.Function<Double, Double> hardHat = new com.google.common.base.Function<Double, Double>() {
+ @Override
+ public Double apply(Double f) {
@ -1265,7 +1262,7 @@
+ if (damagesource.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
+ this.hurtHelmet(damagesource, f);
+ }
+
+ // Apply damage to armor
+ if (!damagesource.is(DamageTypeTags.BYPASSES_ARMOR)) {
+ float armorDamage = (float) (event.getDamage() + event.getDamage(DamageModifier.BLOCKING) + event.getDamage(DamageModifier.HARD_HAT));
@ -1352,27 +1349,26 @@
}
public CombatTracker getCombatTracker() {
@@ -1935,9 +2568,19 @@
@@ -1935,8 +2568,18 @@
}
public final void setArrowCount(int stuckArrowCount) {
- this.entityData.set(LivingEntity.DATA_ARROW_COUNT_ID, stuckArrowCount);
+ // CraftBukkit start
+ this.setArrowCount(stuckArrowCount, false);
}
+ }
+
+ public final void setArrowCount(int i, boolean flag) {
+ ArrowBodyCountChangeEvent event = CraftEventFactory.callArrowBodyCountChangeEvent(this, this.getArrowCount(), i, flag);
+ if (event.isCancelled()) {
+ return;
+ }
+ this.entityData.set(LivingEntity.DATA_ARROW_COUNT_ID, event.getNewAmount());
+ }
}
+ // CraftBukkit end
+
public final int getStingerCount() {
return (Integer) this.entityData.get(LivingEntity.DATA_STINGER_COUNT_ID);
}
@@ -1999,7 +2642,7 @@
this.playSound(soundeffect, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
}
@ -1515,13 +1511,13 @@
- while (this.getXRot() - this.xRotO < -180.0F) {
- this.xRotO -= 360.0F;
- }
+ this.yHeadRotO += Math.round((this.yHeadRot - this.yHeadRotO) / 360.0F) * 360.0F;
+ // Paper end
-
- while (this.getXRot() - this.xRotO >= 180.0F) {
- this.xRotO += 360.0F;
- }
-
+ this.yHeadRotO += Math.round((this.yHeadRot - this.yHeadRotO) / 360.0F) * 360.0F;
+ // Paper end
- while (this.yHeadRot - this.yHeadRotO < -180.0F) {
- this.yHeadRotO -= 360.0F;
- }
@ -1547,10 +1543,9 @@
}
- ItemStack itemstack2 = itemstack1;
-
- itemstack = this.getItemBySlot(enumitemslot);
+ ItemStack itemstack2 = itemstack1; final ItemStack oldEquipment = itemstack2; // Paper - PlayerArmorChangeEvent - obfhelper
+
- itemstack = this.getItemBySlot(enumitemslot);
+ itemstack = this.getItemBySlot(enumitemslot); final ItemStack newEquipment = itemstack;// Paper - PlayerArmorChangeEvent - obfhelper
if (this.equipmentHasChanged(itemstack2, itemstack)) {
+ // Paper start - PlayerArmorChangeEvent
@ -1761,7 +1756,19 @@
}
protected void internalSetAbsorptionAmount(float absorptionAmount) {
@@ -3410,9 +4110,14 @@
@@ -3367,6 +4067,11 @@
return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
}
+ // Paper start - Properly cancel usable items
+ public void resyncUsingItem(ServerPlayer serverPlayer) {
+ this.resendPossiblyDesyncedDataValues(java.util.List.of(DATA_LIVING_ENTITY_FLAGS), serverPlayer);
+ }
+ // Paper end - Properly cancel usable items
private void updatingUsingItem() {
if (this.isUsingItem()) {
if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) {
@@ -3410,9 +4115,14 @@
}
public void startUsingItem(InteractionHand hand) {
@ -1777,7 +1784,7 @@
this.useItem = itemstack;
this.useItemRemaining = itemstack.getUseDuration(this);
if (!this.level().isClientSide) {
@@ -3483,13 +4188,50 @@
@@ -3483,13 +4193,50 @@
this.releaseUsingItem();
} else {
if (!this.useItem.isEmpty() && this.isUsingItem()) {
@ -1791,7 +1798,7 @@
+ org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(enumhand);
+ event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem, hand); // Paper
+ this.level().getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ // Update client
+ Consumable consumable = this.useItem.get(DataComponents.CONSUMABLE);
@ -1803,7 +1810,7 @@
+ this.stopUsingItem(); // Paper - event is using an item, clear active item to reset its use
+ return;
+ }
+
+ itemstack = (craftItem.equals(event.getItem())) ? this.useItem.finishUsingItem(this.level(), this) : CraftItemStack.asNMSCopy(event.getItem()).finishUsingItem(this.level(), this);
+ } else {
+ itemstack = this.useItem.finishUsingItem(this.level(), this);
@ -1829,7 +1836,7 @@
}
}
@@ -3512,6 +4254,7 @@
@@ -3512,6 +4259,7 @@
public void releaseUsingItem() {
if (!this.useItem.isEmpty()) {
@ -1837,7 +1844,7 @@
this.useItem.releaseUsing(this.level(), this, this.getUseItemRemainingTicks());
if (this.useItem.useOnRelease()) {
this.updatingUsingItem();
@@ -3544,12 +4287,69 @@
@@ -3544,12 +4292,69 @@
if (this.isUsingItem() && !this.useItem.isEmpty()) {
Item item = this.useItem.getItem();
@ -1908,7 +1915,7 @@
public boolean isSuppressingSlidingDownLadder() {
return this.isShiftKeyDown();
}
@@ -3568,12 +4368,18 @@
@@ -3568,12 +4373,18 @@
}
public boolean randomTeleport(double x, double y, double z, boolean particleEffects) {
@ -1929,7 +1936,7 @@
Level world = this.level();
if (world.hasChunkAt(blockposition)) {
@@ -3592,18 +4398,43 @@
@@ -3592,18 +4403,43 @@
}
if (flag2) {
@ -1977,7 +1984,7 @@
world.broadcastEntityEvent(this, (byte) 46);
}
@@ -3613,7 +4444,7 @@
@@ -3613,7 +4449,7 @@
entitycreature.getNavigation().stop();
}
@ -1986,7 +1993,7 @@
}
}
@@ -3706,7 +4537,7 @@
@@ -3706,7 +4542,7 @@
}
public void stopSleeping() {
@ -1995,7 +2002,7 @@
Level world = this.level();
java.util.Objects.requireNonNull(world);
@@ -3718,9 +4549,9 @@
@@ -3718,9 +4554,9 @@
this.level().setBlock(blockposition, (BlockState) iblockdata.setValue(BedBlock.OCCUPIED, false), 3);
Vec3 vec3d = (Vec3) BedBlock.findStandUpPosition(this.getType(), this.level(), blockposition, enumdirection, this.getYRot()).orElseGet(() -> {
@ -2007,7 +2014,7 @@
});
Vec3 vec3d1 = Vec3.atBottomCenterOf(blockposition).subtract(vec3d).normalize();
float f = (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D);
@@ -3740,7 +4571,7 @@
@@ -3740,7 +4576,7 @@
@Nullable
public Direction getBedOrientation() {
@ -2016,7 +2023,7 @@
return blockposition != null ? BedBlock.getBedOrientation(this.level(), blockposition) : null;
}
@@ -3905,7 +4736,7 @@
@@ -3905,7 +4741,7 @@
public float maxUpStep() {
float f = (float) this.getAttributeValue(Attributes.STEP_HEIGHT);

View file

@ -12,7 +12,7 @@
public interface Bucketable {
@@ -93,10 +98,22 @@
@@ -93,10 +98,21 @@
ItemStack itemstack = player.getItemInHand(hand);
if (itemstack.getItem() == Items.WATER_BUCKET && entity.isAlive()) {
@ -27,8 +27,7 @@
+ itemstack1 = CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket());
+ if (playerBucketFishEvent.isCancelled()) {
+ ((ServerPlayer) player).containerMenu.sendAllDataToRemote(); // We need to update inventory to resync client's bucket
+ entity.getBukkitEntity().update((ServerPlayer) player); // We need to play out these packets as the client assumes the fish is gone
+ entity.refreshEntityData((ServerPlayer) player); // Need to send data such as the display name to client
+ entity.resendPossiblyDesyncedEntityData((ServerPlayer) player); // Paper
+ return Optional.of(InteractionResult.FAIL);
+ }
+ entity.playSound(((Bucketable) entity).getPickupSound(), 1.0F, 1.0F);
@ -36,7 +35,7 @@
ItemStack itemstack2 = ItemUtils.createFilledResult(itemstack, player, itemstack1, false);
player.setItemInHand(hand, itemstack2);
@@ -106,7 +123,7 @@
@@ -106,7 +122,7 @@
CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer) player, itemstack1);
}

View file

@ -33,16 +33,18 @@
});
}
@@ -79,6 +95,15 @@
@@ -79,6 +95,17 @@
return stack;
}
+ // CraftBukkit start
+ public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack) {
+ final java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> packets = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // Paper - properly resend entities - collect packets for bundle
+ itemstack.getAllOfType(ConsumableListener.class).forEach((consumablelistener) -> {
+ consumablelistener.cancelUsingItem(entityplayer, itemstack);
+ consumablelistener.cancelUsingItem(entityplayer, itemstack, packets); // Paper - properly resend entities - collect packets for bundle
+ });
+ entityplayer.server.getPlayerList().sendActivePlayerEffects(entityplayer);
+ entityplayer.server.getPlayerList().sendActiveEffects(entityplayer, packets::add); // Paper - properly resend entities - collect packets for bundle
+ entityplayer.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(packets));
+ }
+ // CraftBukkit end
+

View file

@ -5,5 +5,5 @@
void onConsume(Level world, LivingEntity user, ItemStack stack, Consumable consumable);
+
+ default void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack) {} // CraftBukkit
+ default void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack, java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> collectedPackets) {} // CraftBukkit // Paper - properly resend entities - collect packets for bundle
}

View file

@ -0,0 +1,18 @@
--- a/net/minecraft/world/item/component/OminousBottleAmplifier.java
+++ b/net/minecraft/world/item/component/OminousBottleAmplifier.java
@@ -28,8 +28,14 @@
@Override
public void onConsume(Level world, LivingEntity user, ItemStack stack, Consumable consumable) {
- user.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true));
+ user.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true)); // Paper - properly resend entities - diff on change for below
}
+ // Paper start - properly resend entities - collect packets for bundle
+ @Override
+ public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack, java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> collectedPackets) {
+ collectedPackets.add(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), MobEffects.BAD_OMEN));
+ }
+ // Paper end - properly resend entities - collect packets for bundle
@Override
public void addToTooltip(Item.TooltipContext context, Consumer<Component> tooltip, TooltipFlag type) {

View file

@ -15,9 +15,9 @@
+ // CraftBukkit start
@Override
+ public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack) {
+ public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack, java.util.List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> collectedPackets) { // Paper - properly resend entities - collect packets for bundle
+ for (SuspiciousStewEffects.Entry suspicioussteweffects_a : this.effects) {
+ entityplayer.connection.send(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), suspicioussteweffects_a.effect()));
+ collectedPackets.add(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), suspicioussteweffects_a.effect())); // Paper - bundlize packets
+ }
+ }
+ // CraftBukkit end

View file

@ -1008,7 +1008,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return;
}
entityTracker.broadcast(this.getHandle().getAddEntityPacket(entityTracker.serverEntity));
// Paper start - resend possibly desynced entity instead of add entity packet
for (final ServerPlayerConnection connection : entityTracker.seenBy) {
this.getHandle().resendPossiblyDesyncedEntityData(connection.getPlayer());
}
// Paper end - resend possibly desynced entity instead of add entity packet
}
public void update(ServerPlayer player) {

View file

@ -39,9 +39,11 @@ public class CraftItemFrame extends CraftHanging implements ItemFrame {
protected void update() {
super.update();
// Paper start, don't mark as dirty as this is handled in super.update()
// mark dirty, so that the client gets updated with item and rotation
this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ITEM);
this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ROTATION);
//this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ITEM);
//this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ROTATION);
// Paper end
// update redstone
if (!this.getHandle().generation) {