diff --git a/patches/server/Dont-resend-blocks-on-interactions.patch b/patches/server/Dont-resend-blocks-on-interactions.patch new file mode 100644 index 000000000..5e604b24e --- /dev/null +++ b/patches/server/Dont-resend-blocks-on-interactions.patch @@ -0,0 +1,171 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Tue, 27 Jun 2023 21:09:11 -0400 +Subject: [PATCH] Dont resend blocks on interactions + +In general, the client now has an acknowledgment system which will prevent block changes made by the client to be reverted correctly. + +It should be noted that this system does not yet support block entities, so those still need to resynced when needed. + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -0,0 +0,0 @@ public class ServerPlayerGameMode { + PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, pos, direction, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND); + if (event.isCancelled()) { + // Let the client know the block still exists +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ // 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 entity after predicting + return; +@@ -0,0 +0,0 @@ public class ServerPlayerGameMode { + // Spigot start - handle debug stick left click for non-creative + if (this.player.getMainHandItem().is(net.minecraft.world.item.Items.DEBUG_STICK) + && ((net.minecraft.world.item.DebugStickItem) net.minecraft.world.item.Items.DEBUG_STICK).handleInteraction(this.player, this.level.getBlockState(pos), this.level, pos, false, this.player.getMainHandItem())) { +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync block + return; + } + // Spigot end +@@ -0,0 +0,0 @@ public class ServerPlayerGameMode { + // CraftBukkit start - Swings at air do *NOT* exist. + if (event.useInteractedBlock() == Event.Result.DENY) { + // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door. +- BlockState data = this.level.getBlockState(pos); +- if (data.getBlock() instanceof DoorBlock) { +- // For some reason *BOTH* the bottom/top part have to be marked updated. +- boolean bottom = data.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, bottom ? pos.above() : pos.below())); +- } else if (data.getBlock() instanceof TrapDoorBlock) { +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); +- } ++ // Paper start - Don't resync blocks ++ //BlockState data = this.level.getBlockState(pos); ++ //if (data.getBlock() instanceof DoorBlock) { ++ // // For some reason *BOTH* the bottom/top part have to be marked updated. ++ // boolean bottom = data.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, bottom ? pos.above() : pos.below())); ++ //} else if (data.getBlock() instanceof TrapDoorBlock) { ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ //} ++ // Paper end + } else if (!iblockdata.isAir()) { + iblockdata.attack(this.level, pos, this.player); + f = iblockdata.getDestroyProgress(this.player, this.player.level(), pos); +@@ -0,0 +0,0 @@ public class ServerPlayerGameMode { + if (event.useItemInHand() == Event.Result.DENY) { + // If we 'insta destroyed' then the client needs to be informed. + if (f > 1.0f) { +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync blocks + } + return; + } +@@ -0,0 +0,0 @@ public class ServerPlayerGameMode { + + if (blockEvent.isCancelled()) { + // Let the client know the block still exists +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync block + return; + } + +@@ -0,0 +0,0 @@ public class ServerPlayerGameMode { + + // Tell client the block is gone immediately then process events + // Don't tell the client if its a creative sword break because its not broken! +- if (this.level.getBlockEntity(pos) == null && !isSwordNoBreak) { ++ if (false && this.level.getBlockEntity(pos) == null && !isSwordNoBreak) { // Paper - Don't resync block + ClientboundBlockUpdatePacket packet = new ClientboundBlockUpdatePacket(pos, Blocks.AIR.defaultBlockState()); + this.player.connection.send(packet); + } +@@ -0,0 +0,0 @@ public class ServerPlayerGameMode { + if (isSwordNoBreak) { + return false; + } ++ // Paper start - Dont resync blocks + // Let the client know the block still exists +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ //this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); + + // Brute force all possible updates +- for (Direction dir : Direction.values()) { +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos.relative(dir))); +- } ++ //for (Direction dir : Direction.values()) { ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos.relative(dir))); ++ //} ++ // Paper end + + // Update any tile entity data for this block + if (!captureSentBlockEntities) { // Paper - Toggle this location for capturing as this is used for api +@@ -0,0 +0,0 @@ public class ServerPlayerGameMode { + if (event.useInteractedBlock() == Event.Result.DENY) { + // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door. + if (iblockdata.getBlock() instanceof DoorBlock) { +- boolean bottom = iblockdata.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; +- player.connection.send(new ClientboundBlockUpdatePacket(world, bottom ? blockposition.above() : blockposition.below())); ++ // Paper start - Don't resync blocks ++ // boolean bottom = iblockdata.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; ++ // player.connection.send(new ClientboundBlockUpdatePacket(world, bottom ? blockposition.above() : blockposition.below())); ++ // Paper end + } else if (iblockdata.getBlock() instanceof CakeBlock) { + player.getBukkitEntity().sendHealthUpdate(); // SPIGOT-1341 - reset health for cake + } else if (this.interactItemStack.getItem() instanceof DoubleHighBlockItem) { + // send a correcting update to the client, as it already placed the upper half of the bisected item +- player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.relative(hitResult.getDirection()).above())); ++ //player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.relative(hitResult.getDirection()).above())); // Paper - don't resync blocks + + // send a correcting update to the client for the block above as well, this because of replaceable blocks (such as grass, sea grass etc) +- player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above())); ++ //player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above())); // Paper - don't resync blocks + // Paper start - extend Player Interact cancellation // TODO: consider merging this into the extracted method + } else if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.StructureBlock) { + player.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerClosePacket(this.player.containerMenu.containerId)); +diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/item/BucketItem.java ++++ b/src/main/java/net/minecraft/world/item/BucketItem.java +@@ -0,0 +0,0 @@ public class BucketItem extends Item implements DispensibleContainerItem { + PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) world, user, blockposition, blockposition, movingobjectpositionblock.getDirection(), itemstack, dummyFluid.getItem(), hand); + + if (event.isCancelled()) { +- ((ServerPlayer) user).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-5163 (see PlayerInteractManager) ++ // ((ServerPlayer) user).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-5163 (see PlayerInteractManager) // Paper - Don't resend blocks + ((ServerPlayer) user).getBukkitEntity().updateInventory(); // SPIGOT-4541 + return InteractionResultHolder.fail(itemstack); + } +@@ -0,0 +0,0 @@ public class BucketItem extends Item implements DispensibleContainerItem { + if (flag2 && entityhuman != null) { + PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent((ServerLevel) world, entityhuman, blockposition, clicked, enumdirection, itemstack, enumhand); + if (event.isCancelled()) { +- ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-4238: needed when looking through entity ++ // ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-4238: needed when looking through entity // Paper - Don't resend blocks + ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541 + return false; + } +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -0,0 +0,0 @@ public final class ItemStack { + world.preventPoiUpdated = false; + + // Brute force all possible updates +- BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition(); +- for (Direction dir : Direction.values()) { +- ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir))); +- } ++ // Paper start - don't resync blocks ++ // BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition(); ++ // for (Direction dir : Direction.values()) { ++ // ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir))); ++ // } ++ // Paper end + SignItem.openSign = null; // SPIGOT-6758 - Reset on early return + } else { + // Change the stack to its new contents if it hasn't been tampered with. diff --git a/patches/server/Extend-Player-Interact-cancellation.patch b/patches/server/Extend-Player-Interact-cancellation.patch index 87ca42f44..3a31b159a 100644 --- a/patches/server/Extend-Player-Interact-cancellation.patch +++ b/patches/server/Extend-Player-Interact-cancellation.patch @@ -16,18 +16,6 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -0,0 +0,0 @@ public class ServerPlayerGameMode { - PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, pos, direction, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND); - if (event.isCancelled()) { - // Let the client know the block still exists -+ // Paper start - brute force neighbor blocks for any attached blocks -+ for (Direction dir : Direction.values()) { -+ this.player.connection.send(new ClientboundBlockUpdatePacket(level, pos.relative(dir))); -+ } -+ // Paper end - this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); - // Update any tile entity data for this block - BlockEntity tileentity = this.level.getBlockEntity(pos); @@ -0,0 +0,0 @@ public class ServerPlayerGameMode { // send a correcting update to the client for the block above as well, this because of replaceable blocks (such as grass, sea grass etc) diff --git a/patches/server/Fix-cancelled-powdered-snow-bucket-placement.patch b/patches/server/Fix-cancelled-powdered-snow-bucket-placement.patch index 3203161a8..3fe5852fc 100644 --- a/patches/server/Fix-cancelled-powdered-snow-bucket-placement.patch +++ b/patches/server/Fix-cancelled-powdered-snow-bucket-placement.patch @@ -7,18 +7,6 @@ Cancelling the placement of powdered snow from the powdered snow bucket didn't revert grass that became snowy because of the placement. -diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/item/BlockItem.java -+++ b/src/main/java/net/minecraft/world/item/BlockItem.java -@@ -0,0 +0,0 @@ public class BlockItem extends Item { - blockstate.update(true, false); - - if (this instanceof SolidBucketItem) { -+ ((ServerPlayer) entityhuman).connection.send(new net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket(world, blockposition.below())); // Paper - update block below - ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541 - } - return InteractionResult.FAIL; diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/item/ItemStack.java diff --git a/patches/server/Fix-inventory-desync.patch b/patches/server/Fix-inventory-desync.patch index 2382dbf65..cba2f3634 100644 --- a/patches/server/Fix-inventory-desync.patch +++ b/patches/server/Fix-inventory-desync.patch @@ -14,6 +14,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (this instanceof SolidBucketItem) { + if (true) { // Paper - if the event is called here, the inventory should be updated - ((ServerPlayer) entityhuman).connection.send(new net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket(world, blockposition.below())); // Paper - update block below ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541 } + return InteractionResult.FAIL; diff --git a/patches/server/Implement-PlayerFlowerPotManipulateEvent.patch b/patches/server/Implement-PlayerFlowerPotManipulateEvent.patch index 0def07cf6..17abb0935 100644 --- a/patches/server/Implement-PlayerFlowerPotManipulateEvent.patch +++ b/patches/server/Implement-PlayerFlowerPotManipulateEvent.patch @@ -26,7 +26,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + if (event.isCancelled()) { + // Update client -+ player1.sendBlockChange(bukkitblock.getLocation(), bukkitblock.getBlockData()); + player1.updateInventory(); + + return InteractionResult.PASS; diff --git a/patches/server/Send-block-entities-after-destroy-prediction.patch b/patches/server/Send-block-entities-after-destroy-prediction.patch index 003929d2e..ae782933e 100644 --- a/patches/server/Send-block-entities-after-destroy-prediction.patch +++ b/patches/server/Send-block-entities-after-destroy-prediction.patch @@ -32,7 +32,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return; } @@ -0,0 +0,0 @@ public class ServerPlayerGameMode { - // Paper end + // Let the client know the block still exists this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Update any tile entity data for this block - BlockEntity tileentity = this.level.getBlockEntity(pos);