Fixup sendAllDataToRemote calls

Reduces unnecessary item copies by a lot
This commit is contained in:
Nassim Jahnke
2025-07-06 21:59:50 +02:00
parent b4466ec981
commit a939945148
34 changed files with 141 additions and 123 deletions

View File

@@ -143,7 +143,7 @@ public class InventoryDragEvent extends InventoryInteractEvent {
*/
@NotNull
public Set<Integer> getRawSlots() {
return this.addedItems.keySet();
return Collections.unmodifiableSet(this.addedItems.keySet());
}
/**

View File

@@ -23867,7 +23867,7 @@ index 46de98a6bbbae48c4837e1e588ba198a363d2dde..fd3553bdc1c3cdbf6aa3dc00e0a4987f
thread1 -> {
DedicatedServer dedicatedServer1 = new DedicatedServer(
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 03a616fc9b0325aa163fe4950ec4ce9ffdd3a9ea..b6aee251027cf124d6597137abefc7fd177358c9 100644
index 3527c39f3f95832d52aeda6205bbbb7161ecaf66..dc47259e40089a4793d950d4c3dc5bcc51ff680f 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -173,7 +173,7 @@ import net.minecraft.world.phys.Vec2;
@@ -27691,7 +27691,7 @@ index 49008b4cbaead8a66a93d2b0d4b50b335a6c3eed..f9c96bbdc54e68b9216b7f8662bfae03
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 6f7f92cc43c56a7453b289f205502d089474ef6d..b390ba657b8b880e431c84e9dd948ac9c84af2fd 100644
index 2f3b5164356e3a91e63054faac92981d7197d0fb..18439057b996a55833e1bfc60dc293de432d2902 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -193,7 +193,7 @@ import net.minecraft.world.scores.Team;
@@ -28728,7 +28728,7 @@ index 8cc5c0716392ba06501542ff5cbe71ee43979e5d..09fd99c9cbd23b5f3c899bfb00c9b896
+ // Paper end - block counting
}
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 06d07f93e42edcfdd7d69df0b52efe2a58e7dfc1..da880f52920b1101f23ef94f3fd0dbdea218c373 100644
index 7ece48c7c2e875eafa5a223b34b99c2ed9f3a8b8..813064b4d135c34cf76437a0f26546a8863abf85 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -147,7 +147,7 @@ import net.minecraft.world.waypoints.WaypointTransmitter;
@@ -29203,7 +29203,7 @@ index 06d07f93e42edcfdd7d69df0b52efe2a58e7dfc1..da880f52920b1101f23ef94f3fd0dbde
}
public InteractionResult interact(Player player, InteractionHand hand) {
@@ -4291,15 +4528,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4290,15 +4527,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public Iterable<Entity> getIndirectPassengers() {
@@ -29229,7 +29229,7 @@ index 06d07f93e42edcfdd7d69df0b52efe2a58e7dfc1..da880f52920b1101f23ef94f3fd0dbde
}
public int countPlayerPassengers() {
@@ -4442,77 +4681,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4441,77 +4680,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return Mth.lerp(partialTick, this.yRotO, this.yRot);
}
@@ -29420,7 +29420,7 @@ index 06d07f93e42edcfdd7d69df0b52efe2a58e7dfc1..da880f52920b1101f23ef94f3fd0dbde
public boolean touchingUnloadedChunk() {
AABB aabb = this.getBoundingBox().inflate(1.0);
@@ -4667,6 +4965,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4666,6 +4964,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
@@ -29436,7 +29436,7 @@ index 06d07f93e42edcfdd7d69df0b52efe2a58e7dfc1..da880f52920b1101f23ef94f3fd0dbde
if (!checkPosition(this, x, y, z)) {
return;
}
@@ -4818,6 +5125,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4817,6 +5124,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@Override
public final void setRemoved(Entity.RemovalReason removalReason, @Nullable org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { // CraftBukkit - add Bukkit remove cause
@@ -29449,7 +29449,7 @@ index 06d07f93e42edcfdd7d69df0b52efe2a58e7dfc1..da880f52920b1101f23ef94f3fd0dbde
org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit
final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers
if (this.removalReason == null) {
@@ -4828,7 +5141,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4827,7 +5140,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.stopRiding();
}
@@ -29458,7 +29458,7 @@ index 06d07f93e42edcfdd7d69df0b52efe2a58e7dfc1..da880f52920b1101f23ef94f3fd0dbde
this.levelCallback.onRemove(removalReason);
this.onRemoval(removalReason);
// Paper start - Folia schedulers
@@ -4862,7 +5175,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4861,7 +5174,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public boolean shouldBeSaved() {
return (this.removalReason == null || this.removalReason.shouldSave())
&& !this.isPassenger()

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Incremental chunk and player saving
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 338ef549efe82c250c74365c1c1071986920c8c9..39581095ccc69d113d954ed835bdfa32d25b5489 100644
index dc47259e40089a4793d950d4c3dc5bcc51ff680f..34b10db71d22cb7211dcfc5565e6833c8d4d2413 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -955,7 +955,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -83,7 +83,7 @@ index 34b7769663e235b93c6388ab0c92c00f0297e42f..dda8d38ef61672cc714d9e5a475f9b04
// Paper start - add close param
this.save(progress, flush, skipSave, false);
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index ff2f4a0fd221c0b632066cdc93719ec6d66c2ff7..9cbadb677d2ab3e9e3ee45df6647a1cbd28fcfd7 100644
index 18439057b996a55833e1bfc60dc293de432d2902..18c0a3de3fd04879f84306e09f5a30502a3d5077 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -195,6 +195,7 @@ import org.slf4j.Logger;
@@ -95,7 +95,7 @@ index ff2f4a0fd221c0b632066cdc93719ec6d66c2ff7..9cbadb677d2ab3e9e3ee45df6647a1cb
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
private static final int FLY_STAT_RECORDING_SPEED = 25;
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 18aaa9bfb08ce36177a5f357644093630ce91264..fe3f36b3cd90766f026c6383cfedc42fa7ae5508 100644
index 5a60527c9feb3606d85488b3cf215c451ca033de..dea72819f2933e5a806bb3a0603e4ebdf7f99456 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -489,6 +489,7 @@ public abstract class PlayerList {

View File

@@ -78,7 +78,7 @@ index 7c9a2eed4441f816723562e0012f918db265912e..cc8638a6dab16ffbdf6951fa10182bd5
profiler.popPush("tickSpawningChunks");
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 9cbadb677d2ab3e9e3ee45df6647a1cbd28fcfd7..d2e78e9e113c9b3e35ae401f2eb055a98df12c06 100644
index 18c0a3de3fd04879f84306e09f5a30502a3d5077..8b0d6efdc6daca8428cdbc8b984441806f7b1a4f 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -406,6 +406,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc

View File

@@ -60,7 +60,7 @@ index cc8638a6dab16ffbdf6951fa10182bd5763df90f..2882cd829d4d8e1f8615f085f6908efc
spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
} else {
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index d2e78e9e113c9b3e35ae401f2eb055a98df12c06..34e5cbb7eb58590f82510601e73c4e442a2addec 100644
index 8b0d6efdc6daca8428cdbc8b984441806f7b1a4f..1e28042457905f67ec965853bb1a0049b8b19330 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -410,6 +410,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc

View File

@@ -48,7 +48,7 @@ index 0000000000000000000000000000000000000000..24a2090e068ad3c0d08705050944abdf
+ }
+}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 41e24da7f0c120af96446603d234ddd417b0de60..7c5b6973769f6eda97f5a08a974b43a98f276ac7 100644
index 34b10db71d22cb7211dcfc5565e6833c8d4d2413..382d2b6b53bd144f4d56dccdc603ed0da8fe07a7 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1719,6 +1719,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -60,10 +60,10 @@ index 41e24da7f0c120af96446603d234ddd417b0de60..7c5b6973769f6eda97f5a08a974b43a9
/* Drop global time updates
if (this.tickCount % 20 == 0) {
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index fc91f7f5ca01f1afe6ceb21f12d1a6ec6f5b68f9..cf283389d9263ba29720bf296a778be9eaf308a7 100644
index c636dbc34b85687468317d1fa22a7073c3ed16e7..da16f4831c875e07c25d7ed041bed493db614658 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -811,10 +811,16 @@ public final class ItemStack implements DataComponentHolder {
@@ -807,10 +807,16 @@ public final class ItemStack implements DataComponentHolder {
}
public ItemStack copy() {

View File

@@ -67,10 +67,10 @@ index 382d2b6b53bd144f4d56dccdc603ed0da8fe07a7..7aac2a6889af3edaebfaf94deecbf00d
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.handleQueue(this.tickCount); // Paper
profilerFiller.push("commandFunctions");
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index da880f52920b1101f23ef94f3fd0dbdea218c373..3d2c0a4d3a1f9d3e5cc6cd0cdb988ae1205de821 100644
index 813064b4d135c34cf76437a0f26546a8863abf85..70b6ea8ab35e88989b5b1f5ffd64490a9d743b56 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -5165,6 +5165,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -5164,6 +5164,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.getBukkitEntity().taskScheduler.retire();
}
// Paper end - Folia schedulers

View File

@@ -17,7 +17,7 @@
+ // Paper start - Sync offhand slot in menus
+ @Override
+ public void sendOffHandSlotChange() {
+ ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(ServerPlayer.this.inventoryMenu.containerId, ServerPlayer.this.inventoryMenu.incrementStateId(), net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT, ServerPlayer.this.inventoryMenu.getSlot(net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT).getItem().copy()));
+ this.sendSlotChange(ServerPlayer.this.inventoryMenu, net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT, ServerPlayer.this.inventoryMenu.getSlot(net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT).getItem().copy());
+ }
+ // Paper end - Sync offhand slot in menus
+

View File

@@ -307,6 +307,15 @@
}
}
}
@@ -299,7 +_,7 @@
}
if (!player.isUsingItem()) {
- player.inventoryMenu.sendAllDataToRemote();
+ player.inventoryMenu.broadcastChanges(); // Paper - change to broadcastChanges, super old code that might not even be needed at all
}
return interactionResult;
@@ -307,15 +_,47 @@
}
}
@@ -348,7 +357,7 @@
+ } else if (blockState.is(net.minecraft.world.level.block.Blocks.JIGSAW) || blockState.is(net.minecraft.world.level.block.Blocks.STRUCTURE_BLOCK) || blockState.getBlock() instanceof net.minecraft.world.level.block.CommandBlock) {
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerClosePacket(this.player.containerMenu.containerId));
+ }
+ player.getBukkitEntity().updateInventory(); // SPIGOT-2867
+ player.containerMenu.forceHeldSlot(hand); // SPIGOT-2867
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
+ return (event.useItemInHand() != org.bukkit.event.Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS;
+ } else if (this.gameModeForPlayer == GameType.SPECTATOR) {

View File

@@ -1261,7 +1261,7 @@
this.player.swing(hand, true);
}
- }
+ } else { this.player.containerMenu.sendAllDataToRemote(); } // Paper - Fix inventory desync; MC-99075
+ } else { this.player.containerMenu.forceHeldSlot(hand); } // Paper - Fix inventory desync; MC-99075
} else {
Component component1 = Component.translatable("build.tooHigh", maxY).withStyle(ChatFormatting.RED);
this.player.sendSystemMessage(component1, true);
@@ -1327,7 +1327,7 @@
+
+ if (cancelled) {
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
+ this.player.containerMenu.sendAllDataToRemote(); // SPIGOT-2524
+ this.player.containerMenu.forceHeldSlotAndArmor(hand); // SPIGOT-2524
+ return;
+ }
+ itemInHand = this.player.getItemInHand(hand); // Update in case it was changed in the event
@@ -1812,7 +1812,7 @@
this.player.resetLastActionTime();
this.player.setShiftKeyDown(packet.isUsingSecondaryAction());
if (target != null) {
@@ -1703,16 +_,58 @@
@@ -1703,16 +_,53 @@
}
AABB boundingBox = target.getBoundingBox();
@@ -1834,7 +1834,7 @@
+
+ ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event);
+
+ // Entity in bucket - SPIGOT-4048 and SPIGOT-6859a
+ // Entity in bucket - SPIGOT-4048 and SPIGOT-6859
+ if ((target instanceof net.minecraft.world.entity.animal.Bucketable && target instanceof LivingEntity && origItem != null && origItem == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelectedItem().isEmpty() || !ServerGamePacketListenerImpl.this.player.getInventory().getSelectedItem().is(origItem))) {
+ target.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it
+ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote();
@@ -1854,9 +1854,10 @@
+ target.getId(), java.util.Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values())
+ .map((slot) -> com.mojang.datafixers.util.Pair.of(slot, ((LivingEntity) target).getItemBySlot(slot).copy()))
+ .collect(Collectors.toList()), true)); // Paper - sanitize
+ player.containerMenu.sendAllDataToRemote();
+ } else {
+ ServerGamePacketListenerImpl.this.player.containerMenu.forceHeldSlot(hand); // Paper - fix slot desync (is this needed?)
+ }
+
+ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); // Paper - fix slot desync - always refresh player inventory
+ }
+
+ if (event.isCancelled()) {
@@ -1865,12 +1866,6 @@
+ // CraftBukkit end
+ InteractionResult result = entityInteraction.run(ServerGamePacketListenerImpl.this.player, target, hand);
+
+ // CraftBukkit start
+ if (!itemInHand.isEmpty() && itemInHand.getCount() <= -1) {
+ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote();
+ }
+ // CraftBukkit end
+
+ if (result instanceof InteractionResult.Success success // CraftBukkit
+ ) {
ItemStack itemStack1 = success.wasItemInteraction() ? itemStack : ItemStack.EMPTY;
@@ -1892,7 +1887,7 @@
);
}
@@ -1738,14 +_,19 @@
@@ -1738,14 +_,14 @@
public void onAttack() {
if (!(target instanceof ItemEntity)
&& !(target instanceof ExperienceOrb)
@@ -1902,11 +1897,6 @@
ItemStack itemInHand = ServerGamePacketListenerImpl.this.player.getItemInHand(InteractionHand.MAIN_HAND);
if (itemInHand.isItemEnabled(serverLevel.enabledFeatures())) {
ServerGamePacketListenerImpl.this.player.attack(target);
+ // CraftBukkit start
+ if (!itemInHand.isEmpty() && itemInHand.getCount() <= -1) {
+ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote();
+ }
+ // CraftBukkit end
}
} else {
- ServerGamePacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.invalid_entity_attacked"));
@@ -1996,7 +1986,7 @@
this.player.containerMenu.sendAllDataToRemote();
} else if (!this.player.containerMenu.stillValid(this.player)) {
LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu);
@@ -1811,7 +_,340 @@
@@ -1811,7 +_,339 @@
} else {
boolean flag = packet.stateId() != this.player.containerMenu.getStateId();
this.player.containerMenu.suppressRemoteUpdates();
@@ -2298,7 +2288,6 @@
+ case HOTBAR_SWAP:
+ case COLLECT_TO_CURSOR:
+ case UNKNOWN:
+ this.player.containerMenu.sendAllDataToRemote();
+ break;
+ // Modified cursor and clicked
+ case PICKUP_SOME:

View File

@@ -1064,7 +1064,7 @@
this.gameEvent(GameEvent.ENTITY_INTERACT, player);
this.playSound(SoundEvents.LEAD_UNTIED);
@@ -2133,9 +_,23 @@
@@ -2133,9 +_,22 @@
if (itemInHand1.is(Items.LEAD) && !(leashable2.getLeashHolder() instanceof Player)) {
if (!this.level().isClientSide() && leashable2.canHaveALeashAttachedTo(player)) {
if (leashable2.isLeashed()) {
@@ -1082,7 +1082,6 @@
+ // Paper start - EntityLeashEvent
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLeashEntityEvent(this, player, player, hand).isCancelled()) {
+ ((ServerPlayer) player).connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket(this, leashable2.getLeashHolder()));
+ player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync
+ return InteractionResult.PASS;
+ }
+ // Paper end - EntityLeashEvent

View File

@@ -1703,7 +1703,7 @@
}
}
}
@@ -3264,12 +_,49 @@
@@ -3264,7 +_,38 @@
this.releaseUsingItem();
} else {
if (!this.useItem.isEmpty() && this.isUsingItem()) {
@@ -1719,12 +1719,11 @@
+ this.level().getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ // Update client
+ net.minecraft.world.item.component.Consumable consumable = this.useItem.get(DataComponents.CONSUMABLE);
+ if (consumable != null) {
+ consumable.cancelUsingItem(serverPlayer, this.useItem);
+ }
+ serverPlayer.containerMenu.sendAllDataToRemote();
+ serverPlayer.containerMenu.forceHeldSlot(this.getUsedItemHand());
+ serverPlayer.getBukkitEntity().updateScaledHealth();
+ this.stopUsingItem(); // Paper - event is using an item, clear active item to reset its use
+ return;
@@ -1744,16 +1743,6 @@
if (itemStack != this.useItem) {
this.setItemInHand(usedItemHand, itemStack);
}
this.stopUsingItem();
+ // Paper start
+ if (this instanceof Player player) {
+ player.containerMenu.sendAllDataToRemote();
+ }
+ // Paper end
}
}
}
@@ -3294,6 +_,7 @@
ItemStack itemInHand = this.getItemInHand(this.getUsedItemHand());
if (!this.useItem.isEmpty() && ItemStack.isSameItem(itemInHand, this.useItem)) {

View File

@@ -12,7 +12,7 @@
+ org.bukkit.event.player.PlayerBucketEntityEvent playerBucketFishEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerFishBucketEvent(entity, player, itemInHand, bucketItemStack, hand);
+ bucketItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket());
+ if (playerBucketFishEvent.isCancelled()) {
+ player.containerMenu.sendAllDataToRemote(); // We need to update inventory to resync client's bucket
+ player.containerMenu.forceHeldSlot(hand); // We need to update inventory to resync client's bucket
+ entity.resendPossiblyDesyncedEntityData((ServerPlayer) player); // Paper
+ return Optional.of(InteractionResult.FAIL);
+ }

View File

@@ -386,7 +386,7 @@
);
}
}
@@ -1264,10 +_,11 @@
@@ -1264,10 +_,10 @@
}
}
@@ -396,7 +396,6 @@
- this.level()
- .playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F);
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
+ this.containerMenu.sendAllDataToRemote(); // CraftBukkit - resync on cancelled event
+ // CraftBukkit end
}
}

View File

@@ -37,7 +37,7 @@
protected AbstractContainerMenu(@Nullable MenuType<?> menuType, int containerId) {
this.menuType = menuType;
@@ -176,8 +_,19 @@
@@ -176,8 +_,43 @@
if (this.synchronizer != null) {
this.synchronizer.sendInitialData(this, list, carried.copy(), this.remoteDataSlots.toIntArray());
@@ -47,6 +47,30 @@
+ }
+ }
+
+ // Paper start
+ public void forceHeldSlot(final net.minecraft.world.InteractionHand hand) {
+ this.sendAllDataToRemote();
+ }
+
+ public void forceHeldSlotAndArmor(final net.minecraft.world.InteractionHand hand) {
+ this.sendAllDataToRemote();
+ }
+
+ public void forceSlot(final Container container, final int slot) {
+ final int slotsIndex = this.findSlot(container, slot).orElse(-1);
+ if (slotsIndex == -1) {
+ return;
+ }
+
+ final ItemStack item = this.slots.get(slotsIndex).getItem();
+ this.remoteSlots.get(slotsIndex).force(item);
+
+ if (this.synchronizer != null) {
+ this.synchronizer.sendSlotChange(this, slotsIndex, item.copy());
+ }
+ }
+ // Paper end
+
+ // CraftBukkit start - from synchronizeCarriedToRemote
+ public void broadcastCarriedItem() {
+ ItemStack carried = this.getCarried();
@@ -80,11 +104,11 @@
}
int count = this.getCarried().getCount();
+ java.util.Map<Integer, ItemStack> draggedSlots = new java.util.HashMap<>(); // CraftBukkit - Store slots from drag in map (raw slot id -> new stack)
+ it.unimi.dsi.fastutil.ints.Int2ObjectMap<net.minecraft.world.item.ItemStack> draggedSlots = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(); // CraftBukkit - Store slots from drag in map (raw slot id -> new stack)
for (Slot slot1 : this.quickcraftSlots) {
ItemStack carried1 = this.getCarried();
@@ -387,12 +_,48 @@
@@ -387,12 +_,46 @@
int min = Math.min(itemStack.getMaxStackSize(), slot1.getMaxStackSize(itemStack));
int min1 = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots, this.quickcraftType, itemStack) + i2, min);
count -= min1 - i2;
@@ -101,39 +125,37 @@
+
+ // CraftBukkit start - InventoryDragEvent
+ org.bukkit.inventory.InventoryView view = this.getBukkitView();
+ org.bukkit.inventory.ItemStack newcursor = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
+ newcursor.setAmount(count);
+ java.util.Map<Integer, org.bukkit.inventory.ItemStack> eventmap = new java.util.HashMap<>();
+ for (java.util.Map.Entry<Integer, ItemStack> ditem : draggedSlots.entrySet()) {
+ eventmap.put(ditem.getKey(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(ditem.getValue()));
+ org.bukkit.inventory.ItemStack newCarried = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
+ newCarried.setAmount(count);
+ java.util.Map<Integer, org.bukkit.inventory.ItemStack> eventMap = new java.util.HashMap<>();
+ for (it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry<net.minecraft.world.item.ItemStack> entry : draggedSlots.int2ObjectEntrySet()) {
+ eventMap.put(entry.getIntKey(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(entry.getValue()));
+ }
+
+ // It's essential that we set the cursor to the new value here to prevent item duplication if a plugin closes the inventory.
+ ItemStack oldCursor = this.getCarried();
+ this.setCarried(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(newcursor));
+ ItemStack oldCarried = this.getCarried();
+ this.setCarried(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(newCarried));
+
+ org.bukkit.event.inventory.InventoryDragEvent event = new org.bukkit.event.inventory.InventoryDragEvent(view, (newcursor.getType() != org.bukkit.Material.AIR ? newcursor : null), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(oldCursor), this.quickcraftType == 1, eventmap);
+ org.bukkit.event.inventory.InventoryDragEvent event = new org.bukkit.event.inventory.InventoryDragEvent(
+ view,
+ newCarried,
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(oldCarried),
+ this.quickcraftType == QUICKCRAFT_TYPE_GREEDY,
+ eventMap
+ );
+ event.callEvent();
+
+ // Whether a change was made to the inventory that requires an update.
+ boolean needsUpdate = event.getResult() != org.bukkit.event.Event.Result.DEFAULT;
+
+ if (event.getResult() != org.bukkit.event.Event.Result.DENY) {
+ for (java.util.Map.Entry<Integer, ItemStack> dslot : draggedSlots.entrySet()) {
+ view.setItem(dslot.getKey(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(dslot.getValue()));
+ for (final it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry<net.minecraft.world.item.ItemStack> entry : draggedSlots.int2ObjectEntrySet()) {
+ view.setItem(entry.getIntKey(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(entry.getValue()));
+ }
+ // The only time the carried item will be set to null is if the inventory is closed by the server.
+ // The only time the carried item will be set to empty is if the inventory is closed by the server.
+ // If the inventory is closed by the server, then the cursor items are dropped. This is why we change the cursor early.
+ if (this.getCarried() != null) {
+ if (!this.getCarried().isEmpty()) {
+ this.setCarried(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getCursor()));
+ needsUpdate = true;
+ }
+ } else {
+ this.setCarried(oldCursor);
+ }
+
+ if (needsUpdate && player instanceof ServerPlayer) {
+ this.sendAllDataToRemote();
+ this.setCarried(oldCarried);
+ }
+ // CraftBukkit end
}

View File

@@ -15,7 +15,7 @@
this.active = active;
this.owner = owner;
this.addResultSlot(owner, 154, 28);
@@ -188,4 +_,17 @@
@@ -188,4 +_,38 @@
protected Player owner() {
return this.owner;
}
@@ -31,5 +31,26 @@
+ this.view = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.owner.getBukkitEntity(), inventory, this);
+ return this.view;
+ }
+
+ @Override
+ public void forceHeldSlot(final net.minecraft.world.InteractionHand hand) {
+ // If ever needed, a config option for instead synchronizing the full inventory can be added here to call this.sendAllDataToRemote();
+ // Otherwise, only resync the hand slot
+ final int slot = hand == net.minecraft.world.InteractionHand.MAIN_HAND ? this.owner.getInventory().getSelectedSlot() : Inventory.SLOT_OFFHAND;
+ this.forceSlot(this.owner.getInventory(), slot);
+ }
+
+ @Override
+ public void forceHeldSlotAndArmor(final net.minecraft.world.InteractionHand hand) {
+ this.forceHeldSlot(hand);
+
+ final int size = net.minecraft.world.entity.player.Inventory.INVENTORY_SIZE;
+ final net.minecraft.world.entity.player.Inventory inventory = this.owner.getInventory();
+ this.forceSlot(inventory, net.minecraft.world.entity.EquipmentSlot.FEET.getIndex(size));
+ this.forceSlot(inventory, net.minecraft.world.entity.EquipmentSlot.LEGS.getIndex(size));
+ this.forceSlot(inventory, net.minecraft.world.entity.EquipmentSlot.CHEST.getIndex(size));
+ this.forceSlot(inventory, net.minecraft.world.entity.EquipmentSlot.HEAD.getIndex(size));
+ }
+
+ // CraftBukkit end
}

View File

@@ -15,7 +15,7 @@
if (placementState == null) {
return InteractionResult.FAIL;
} else if (!this.placeBlock(blockPlaceContext, placementState)) {
@@ -69,15 +_,40 @@
@@ -69,15 +_,39 @@
BlockState blockState = level.getBlockState(clickedPos);
if (blockState.is(placementState.getBlock())) {
blockState = this.updateBlockStateFromTag(clickedPos, level, itemInHand, blockState);
@@ -40,8 +40,7 @@
+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
+ ((org.bukkit.craftbukkit.block.CraftBlockState) bukkitState).revertPlace();
+
+ // Paper - if the event is called here, the inventory should be updated
+ player.containerMenu.sendAllDataToRemote(); // SPIGOT-4541
+ player.containerMenu.forceHeldSlot(blockPlaceContext.getHand());
+ return InteractionResult.FAIL;
+ }
+ }

View File

@@ -39,7 +39,7 @@
if (shooter instanceof ServerPlayer serverPlayer) {
CriteriaTriggers.SHOT_CROSSBOW.trigger(serverPlayer, weapon);
serverPlayer.awardStat(Stats.ITEM_USED.get(weapon.getItem()));
@@ -211,7 +_,14 @@
@@ -211,7 +_,13 @@
);
}
@@ -48,7 +48,6 @@
+ // Paper start - Add EntityLoadCrossbowEvent
+ final io.papermc.paper.event.entity.EntityLoadCrossbowEvent event = new io.papermc.paper.event.entity.EntityLoadCrossbowEvent(livingEntity.getBukkitLivingEntity(), stack.asBukkitMirror(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(livingEntity.getUsedItemHand()));
+ if (!event.callEvent() || !tryLoadProjectiles(livingEntity, stack, event.shouldConsumeItem()) || !event.shouldConsumeItem()) {
+ if (livingEntity instanceof ServerPlayer player) player.containerMenu.sendAllDataToRemote();
+ return;
+ }
+ // Paper end - Add EntityLoadCrossbowEvent

View File

@@ -24,7 +24,7 @@
+ if (event.shouldConsume()) {
+ itemInHand.consume(1, player);
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ }
+ level.playSound(
+ // Paper end
@@ -44,7 +44,7 @@
+ player.awardStat(Stats.ITEM_USED.get(this));
+ // Paper start
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ return InteractionResult.FAIL;
+ }
+ // CraftBukkit end

View File

@@ -24,7 +24,7 @@
+ if (event.shouldConsume()) {
+ itemInHand.consume(1, player);
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ }
+
+ level.playSound(
@@ -44,7 +44,7 @@
+ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundCooldownPacket(player.getCooldowns().getCooldownGroup(itemInHand), 0)); // prevent visual desync of cooldown on the slot
+ }
+ // Paper end - PlayerLaunchProjectileEvent
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ return InteractionResult.FAIL;
+ }
}

View File

@@ -24,7 +24,7 @@
+ if (event.shouldConsume()) {
+ itemInHand.consume(1, player);
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ }
+
+ level.playSound(
@@ -38,7 +38,7 @@
+ 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F)
+ );
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ return InteractionResult.FAIL;
+ }
+ // Paper end - PlayerLaunchProjectileEvent

View File

@@ -21,7 +21,7 @@
+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Firework) fireworkRocketEntity.projectile().getBukkitEntity());
+ if (!event.callEvent() || !fireworkRocketEntity.attemptSpawn()) return InteractionResult.PASS;
+ if (event.shouldConsume() && !context.getPlayer().hasInfiniteMaterials()) itemInHand.shrink(1);
+ else context.getPlayer().containerMenu.sendAllDataToRemote();
+ else context.getPlayer().containerMenu.forceHeldSlot(context.getHand());
+ // Paper end - PlayerLaunchProjectileEvent
}
@@ -43,10 +43,10 @@
+ if (event.shouldConsume() && !player.hasInfiniteMaterials()) {
+ itemInHand.shrink(1); // Moved up from below
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ }
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
}
-
- Projectile.spawnProjectile(new FireworkRocketEntity(level, itemInHand, player), serverLevel, itemInHand);

View File

@@ -7,7 +7,7 @@
+ // Paper start - EntityChangeBlockEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, blockState1)) {
+ if (!player.isCreative()) {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(context.getHand());
+ }
+ return InteractionResult.PASS;
+ }

View File

@@ -101,7 +101,7 @@
+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
+ interactionResult = InteractionResult.FAIL; // cancel placement
+ // PAIL: Remove this when MC-99075 fixed
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ serverLevel.capturedTileEntities.clear(); // Paper - Allow chests to be placed with NBT data; clear out block entities as chests and such will pop loot
+ // revert back all captured blocks
+ for (org.bukkit.block.BlockState blockstate : blocks) {
@@ -192,7 +192,7 @@
return interactionResult;
}
@@ -449,31 +_,71 @@
@@ -449,31 +_,67 @@
return this.isDamageableItem() && this.getDamageValue() >= this.getMaxDamage() - 1;
}
@@ -212,10 +212,6 @@
+ if (i > 0 && player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent - limit to positive damage and run for player
+ org.bukkit.event.player.PlayerItemDamageEvent event = new org.bukkit.event.player.PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this), i, originalDamage); // Paper - Add EntityDamageItemEvent
+ event.getPlayer().getServer().getPluginManager().callEvent(event);
+
+ if (i != event.getDamage() || event.isCancelled()) {
+ serverPlayer.containerMenu.sendAllDataToRemote();
+ }
+ if (event.isCancelled()) {
+ return;
+ }

View File

@@ -7,7 +7,7 @@
- serverLevel.addFreshEntity(abstractMinecart);
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, abstractMinecart).isCancelled()) {
+ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync
+ if (context.getPlayer() != null) context.getPlayer().containerMenu.forceHeldSlot(context.getHand()); // Paper - Fix inventory desync
+ return InteractionResult.FAIL;
+ }
+ // CraftBukkit end

View File

@@ -6,7 +6,7 @@
if (context.getClickedFace() != Direction.DOWN && blockState.is(BlockTags.CONVERTABLE_TO_MUD) && potionContents.is(Potions.WATER)) {
+ // Paper start
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, Blocks.MUD.defaultBlockState())) {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(context.getHand());
+ return InteractionResult.PASS;
+ }
+ // Paper end

View File

@@ -8,7 +8,7 @@
) {
float f = EnchantmentHelper.processProjectileSpread(level, weapon, shooter, 0.0F);
float f1 = projectileItems.size() == 1 ? 0.0F : 2.0F * f / (projectileItems.size() - 1);
@@ -62,12 +_,29 @@
@@ -62,12 +_,26 @@
float f4 = f2 + f3 * ((i + 1) / 2) * f1;
f3 = -f3;
int i1 = i;
@@ -34,9 +34,6 @@
+ level,
+ itemStack
+ ).isRemoved()) {
+ if (shooter instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
+ serverPlayer.containerMenu.sendAllDataToRemote();
+ }
+ return;
+ }
+ }

View File

@@ -25,7 +25,7 @@
+ if (event.shouldConsume()) {
+ itemInHand.consume(1, player);
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ }
+ // Paper end - PlayerLaunchProjectileEvent
+
@@ -41,7 +41,7 @@
+ );
+ // Paper start - PlayerLaunchProjectileEvent - return fail
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ return InteractionResult.FAIL;
+ }
+ // Paper end- PlayerLaunchProjectileEvent - return fail

View File

@@ -12,10 +12,10 @@
+ if (event.shouldConsume()) {
+ itemInHand.consume(1, player);
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ }
+ } else {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ return InteractionResult.FAIL;
+ }
+ // Paper end - PlayerLaunchProjectileEvent

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/world/item/TridentItem.java
+++ b/net/minecraft/world/item/TridentItem.java
@@ -79,18 +_,39 @@
@@ -79,18 +_,38 @@
.orElse(SoundEvents.TRIDENT_THROW);
player.awardStat(Stats.ITEM_USED.get(this));
if (level instanceof ServerLevel serverLevel) {
@@ -18,7 +18,6 @@
+ if (!event.callEvent() || !tridentDelayed.attemptSpawn()) {
+ // CraftBukkit start
+ // Paper end - PlayerLaunchProjectileEvent
+ player.containerMenu.sendAllDataToRemote();
+ return false;
+ }
+ ThrownTrident thrownTrident = tridentDelayed.projectile(); // Paper - PlayerLaunchProjectileEvent

View File

@@ -16,7 +16,7 @@
+ // Paper start - PlayerLaunchProjectileEvent
+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) windCharge.projectile().getBukkitEntity());
+ if (!event.callEvent() || !windCharge.attemptSpawn()) {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
+ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundCooldownPacket(player.getCooldowns().getCooldownGroup(itemInHand), 0)); // prevent visual desync of cooldown on the slot
+ }
@@ -26,7 +26,7 @@
+ player.awardStat(Stats.ITEM_USED.get(this));
+ if (event.shouldConsume()) itemInHand.consume(1, player);
+ else if (!player.hasInfiniteMaterials()) {
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+ }
+ // Paper end - PlayerLaunchProjectileEvent
}

View File

@@ -6,7 +6,7 @@
if (stack.is(ItemTags.CANDLES) && state.getValue(BITES) == 0 && Block.byItem(item) instanceof CandleBlock candleBlock) {
+ // Paper start - call change block event
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, CandleCakeBlock.byCandle(candleBlock))) {
+ player.containerMenu.sendAllDataToRemote(); // update inv because candle could decrease
+ player.containerMenu.forceHeldSlot(hand); // update inv because candle could decrease
+ return InteractionResult.TRY_WITH_EMPTY_HAND;
+ }
+ // Paper end - call change block event

View File

@@ -11,7 +11,7 @@
+ io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent event = new io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent((org.bukkit.entity.Player) player.getBukkitEntity(), block, placedStack, true);
+ if (!event.callEvent()) {
+ // Update client
+ player.containerMenu.sendAllDataToRemote();
+ player.containerMenu.forceHeldSlot(hand);
+
+ return InteractionResult.CONSUME;
+ }

View File

@@ -1489,7 +1489,7 @@ public class CraftEventFactory {
BookMeta meta = editBookEvent.getNewBookMeta();
CraftItemStack.setItemMeta(itemInHand, meta);
} else {
player.containerMenu.sendAllDataToRemote(); // SPIGOT-7484
player.containerMenu.forceSlot(player.getInventory(), itemInHandIndex); // SPIGOT-7484
}
}