diff --git a/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch b/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch index 98be950605..d2519790c5 100644 --- a/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch @@ -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 SynchedEntityData.DataItem getItem(EntityDataAccessor key) { +- private SynchedEntityData.DataItem getItem(EntityDataAccessor key) { - return this.itemsById[key.id()]; ++ public SynchedEntityData.DataItem getItem(EntityDataAccessor key) { // Paper - public + return (SynchedEntityData.DataItem) 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> packAll() { ++ final List> list = new ArrayList<>(); ++ for (final DataItem dataItem : this.itemsById) { ++ list.add(dataItem.value()); ++ } ++ ++ return list; ++ } ++ // Paper end ++ + public static class DataItem { + + final EntityDataAccessor accessor; diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch index 6f36548255..aba7ebeae1 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch @@ -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; + } + } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index b39c68012f..6c1745ae43 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -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 optional = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); if (!optional.isEmpty()) { -@@ -1394,27 +2179,46 @@ +@@ -1394,27 +2180,46 @@ return; } @@ -1469,7 +1468,7 @@ ParseResults 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 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); } diff --git a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch index 93555e74c6..06288fc4a0 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -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> 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 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() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch index f288f27212..a274089f56 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -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> list = this.getEntityData().getNonDefaultValues(); ++ List> 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> 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> keys, ServerPlayer to) { ++ if (!to.getBukkitEntity().canSee(this.getBukkitEntity())) { ++ return; ++ } ++ ++ final List> 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 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); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index ac25e7f770..c1e602ad26 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -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 effectsToProcess = Lists.newArrayList(); @@ -329,15 +328,15 @@ + private ProcessableEffect(MobEffectInstance effect, EntityPotionEffectEvent.Cause cause) { + this.effect = effect; + this.cause = cause; - } - ++ } ++ + private ProcessableEffect(Holder type, EntityPotionEffectEvent.Cause cause) { + this.type = type; + this.cause = cause; + } - } ++ } + // CraftBukkit end - ++ protected void tickEffects() { Iterator> 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 hardHat = new com.google.common.base.Function() { + @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); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/Bucketable.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/Bucketable.java.patch index 0776d6fecd..804bc3e693 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/Bucketable.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/Bucketable.java.patch @@ -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); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch index 8420f1012f..a163ec68c0 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch @@ -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> 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 + diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/ConsumableListener.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/ConsumableListener.java.patch index 5d14084425..2e31354cba 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/ConsumableListener.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/ConsumableListener.java.patch @@ -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> collectedPackets) {} // CraftBukkit // Paper - properly resend entities - collect packets for bundle } diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/OminousBottleAmplifier.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/OminousBottleAmplifier.java.patch new file mode 100644 index 0000000000..57338edcbf --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/item/component/OminousBottleAmplifier.java.patch @@ -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> 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 tooltip, TooltipFlag type) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/SuspiciousStewEffects.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/SuspiciousStewEffects.java.patch index 3578ba2d3a..2836856f9c 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/SuspiciousStewEffects.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/SuspiciousStewEffects.java.patch @@ -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> 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 diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 7142319f67..b25b10c24a 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -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) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java index f3a9b33802..350ad61ab3 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java @@ -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) {