From 27979040fd9428069fce89e8b49d6b1923fd8321 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Mon, 12 Dec 2022 12:14:03 -0800 Subject: [PATCH] Properly track the changed item from dispense events --- .../dispenser/DispenseItemBehavior.java.patch | 73 +++++++++++-------- .../ProjectileDispenseBehavior.java.patch | 2 +- .../ShulkerBoxDispenseBehavior.java.patch | 12 ++- 3 files changed, 54 insertions(+), 33 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch index 5e26ba1183..6251abfb7e 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch @@ -36,7 +36,7 @@ public interface DispenseItemBehavior { -@@ -90,14 +104,42 @@ +@@ -90,14 +104,46 @@ Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING); EntityType entitytypes = ((SpawnEggItem) stack.getItem()).getType(pointer.level().registryAccess(), stack); @@ -65,10 +65,15 @@ + idispensebehavior.dispense(pointer, eventStack); + return stack; + } ++ // Paper start - track changed items in the dispense event ++ itemstack1 = CraftItemStack.unwrap(event.getItem()); // unwrap is safe because the stack won't be modified ++ entitytypes = ((SpawnEggItem) itemstack1.getItem()).getType(worldserver.registryAccess(), itemstack1); ++ // Paper end - track changed item from dispense event + } + try { - entitytypes.spawn(pointer.level(), stack, (Player) null, pointer.pos().relative(enumdirection), EntitySpawnReason.DISPENSER, enumdirection != Direction.UP, false); +- entitytypes.spawn(pointer.level(), stack, (Player) null, pointer.pos().relative(enumdirection), EntitySpawnReason.DISPENSER, enumdirection != Direction.UP, false); ++ entitytypes.spawn(pointer.level(), itemstack1, (Player) null, pointer.pos().relative(enumdirection), EntitySpawnReason.DISPENSER, enumdirection != Direction.UP, false); // Paper - track changed item in dispense event } catch (Exception exception) { - null.LOGGER.error("Error while dispensing spawn egg from dispenser at {}", pointer.pos(), exception); + DispenseItemBehavior.LOGGER.error("Error while dispensing spawn egg from dispenser at {}", pointer.pos(), exception); // CraftBukkit - decompile error @@ -81,7 +86,7 @@ pointer.level().gameEvent((Entity) null, (Holder) GameEvent.ENTITY_PLACE, pointer.pos()); return stack; } -@@ -116,13 +158,41 @@ +@@ -116,13 +162,42 @@ Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING); BlockPos blockposition = pointer.pos().relative(enumdirection); ServerLevel worldserver = pointer.level(); @@ -113,9 +118,11 @@ + } + // CraftBukkit end + ++ final ItemStack newStack = CraftItemStack.unwrap(event.getItem()); // Paper - use event itemstack (unwrap is fine here because the stack won't be modified) Consumer consumer = EntityType.appendDefaultStackConfig((entityarmorstand) -> { entityarmorstand.setYRot(enumdirection.toYRot()); - }, worldserver, stack, (Player) null); +- }, worldserver, stack, (Player) null); ++ }, worldserver, newStack, (Player) null); // Paper - track changed items in the dispense event ArmorStand entityarmorstand = (ArmorStand) EntityType.ARMOR_STAND.spawn(worldserver, consumer, blockposition, EntitySpawnReason.DISPENSER, false, false); if (entityarmorstand != null) { @@ -124,7 +131,7 @@ } return stack; -@@ -141,7 +211,34 @@ +@@ -141,7 +216,34 @@ }); if (!list.isEmpty()) { @@ -155,12 +162,12 @@ + return stack; + } + } -+ ((Saddleable) list.get(0)).equipSaddle(itemstack1, SoundSource.BLOCKS); ++ ((Saddleable) list.get(0)).equipSaddle(CraftItemStack.asNMSCopy(event.getItem()), SoundSource.BLOCKS); // Paper - track changed items in dispense event + // CraftBukkit end this.setSuccess(true); return stack; } else { -@@ -166,9 +263,35 @@ +@@ -166,9 +268,35 @@ } entityhorsechestedabstract = (AbstractChestedHorse) iterator1.next(); @@ -198,7 +205,7 @@ this.setSuccess(true); return stack; } -@@ -202,6 +325,44 @@ +@@ -202,8 +330,50 @@ BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); ServerLevel worldserver = pointer.level(); @@ -207,6 +214,7 @@ + int y = blockposition.getY(); + int z = blockposition.getZ(); + BlockState iblockdata = worldserver.getBlockState(blockposition); ++ ItemStack dispensedItem = stack; // Paper - track changed item from the dispense event + // Paper start - correctly check if the bucket place will succeed + /* Taken from SolidBucketItem#emptyContents */ + boolean willEmptyContentsSolidBucketItem = dispensiblecontaineritem instanceof net.minecraft.world.item.SolidBucketItem && worldserver.isInWorldBounds(blockposition) && iblockdata.isAir(); @@ -236,14 +244,20 @@ + } + } + -+ dispensiblecontaineritem = (DispensibleContainerItem) CraftItemStack.asNMSCopy(event.getItem()).getItem(); ++ // Paper start - track changed item from dispense event ++ dispensedItem = CraftItemStack.unwrap(event.getItem()); // unwrap is safe here as the stack isn't mutated ++ dispensiblecontaineritem = (DispensibleContainerItem) dispensedItem.getItem(); ++ // Paper end - track changed item from dispense event + } + // CraftBukkit end + if (dispensiblecontaineritem.emptyContents((Player) null, worldserver, blockposition, (BlockHitResult) null)) { - dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, stack, blockposition); +- dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, stack, blockposition); ++ dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, dispensedItem, blockposition); // Paper - track changed item from dispense event return this.consumeWithRemainder(pointer, stack, new ItemStack(Items.BUCKET)); -@@ -229,7 +390,7 @@ + } else { + return this.defaultDispenseItemBehavior.dispense(pointer, stack); +@@ -229,7 +399,7 @@ Block block = iblockdata.getBlock(); if (block instanceof BucketPickup ifluidsource) { @@ -252,7 +266,7 @@ if (itemstack1.isEmpty()) { return super.execute(pointer, stack); -@@ -237,6 +398,32 @@ +@@ -237,6 +407,32 @@ worldserver.gameEvent((Entity) null, (Holder) GameEvent.FLUID_PICKUP, blockposition); Item item = itemstack1.getItem(); @@ -285,11 +299,10 @@ return this.consumeWithRemainder(pointer, stack, new ItemStack(item)); } } else { -@@ -248,6 +435,30 @@ - @Override +@@ -249,16 +445,44 @@ protected ItemStack execute(BlockSource pointer, ItemStack stack) { ServerLevel worldserver = pointer.level(); -+ + + // CraftBukkit start + org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, pointer.pos()); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); @@ -313,10 +326,10 @@ + } + } + // CraftBukkit end - ++ this.setSuccess(true); Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING); -@@ -255,10 +466,14 @@ + BlockPos blockposition = pointer.pos().relative(enumdirection); BlockState iblockdata = worldserver.getBlockState(blockposition); if (BaseFireBlock.canBePlacedAt(worldserver, blockposition, enumdirection)) { @@ -334,7 +347,7 @@ TntBlock.explode(worldserver, blockposition); worldserver.removeBlock(blockposition, false); } else { -@@ -283,13 +498,64 @@ +@@ -283,13 +507,64 @@ this.setSuccess(true); ServerLevel worldserver = pointer.level(); BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); @@ -399,7 +412,7 @@ return stack; } }); -@@ -298,12 +564,41 @@ +@@ -298,12 +573,41 @@ protected ItemStack execute(BlockSource pointer, ItemStack stack) { ServerLevel worldserver = pointer.level(); BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); @@ -443,7 +456,7 @@ return stack; } }); -@@ -313,7 +608,31 @@ +@@ -313,7 +617,31 @@ ServerLevel worldserver = pointer.level(); Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING); BlockPos blockposition = pointer.pos().relative(enumdirection); @@ -456,11 +469,11 @@ + if (!DispenserBlock.eventFired) { + worldserver.getCraftServer().getPluginManager().callEvent(event); + } -+ + + if (event.isCancelled()) { + return stack; + } - ++ + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); @@ -475,7 +488,7 @@ if (worldserver.isEmptyBlock(blockposition) && WitherSkullBlock.canSpawnMob(worldserver, blockposition, stack)) { worldserver.setBlock(blockposition, (BlockState) Blocks.WITHER_SKELETON_SKULL.defaultBlockState().setValue(SkullBlock.ROTATION, RotationSegment.convertToSegment(enumdirection)), 3); worldserver.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_PLACE, blockposition); -@@ -326,7 +645,7 @@ +@@ -326,7 +654,7 @@ stack.shrink(1); this.setSuccess(true); } else { @@ -484,7 +497,7 @@ } return stack; -@@ -339,6 +658,30 @@ +@@ -339,6 +667,30 @@ BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); CarvedPumpkinBlock blockpumpkincarved = (CarvedPumpkinBlock) Blocks.CARVED_PUMPKIN; @@ -515,7 +528,7 @@ if (worldserver.isEmptyBlock(blockposition) && blockpumpkincarved.canSpawnGolem(worldserver, blockposition)) { if (!worldserver.isClientSide) { worldserver.setBlock(blockposition, blockpumpkincarved.defaultBlockState(), 3); -@@ -348,7 +691,7 @@ +@@ -348,7 +700,7 @@ stack.shrink(1); this.setSuccess(true); } else { @@ -524,7 +537,7 @@ } return stack; -@@ -377,6 +720,30 @@ +@@ -377,6 +729,30 @@ BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); BlockState iblockdata = worldserver.getBlockState(blockposition); @@ -555,7 +568,7 @@ if (iblockdata.is(BlockTags.BEEHIVES, (blockbase_blockdata) -> { return blockbase_blockdata.hasProperty(BeehiveBlock.HONEY_LEVEL) && blockbase_blockdata.getBlock() instanceof BeehiveBlock; }) && (Integer) iblockdata.getValue(BeehiveBlock.HONEY_LEVEL) >= 5) { -@@ -402,6 +769,13 @@ +@@ -402,6 +778,13 @@ this.setSuccess(true); if (iblockdata.is(Blocks.RESPAWN_ANCHOR)) { if ((Integer) iblockdata.getValue(RespawnAnchorBlock.CHARGE) != 4) { @@ -569,7 +582,7 @@ RespawnAnchorBlock.charge((Entity) null, worldserver, blockposition, iblockdata); stack.shrink(1); } else { -@@ -426,6 +800,31 @@ +@@ -426,6 +809,31 @@ this.setSuccess(false); return stack; } else { @@ -601,7 +614,7 @@ Iterator iterator1 = list.iterator(); Armadillo armadillo; -@@ -454,6 +853,13 @@ +@@ -454,6 +862,13 @@ Optional optional = HoneycombItem.getWaxed(iblockdata); if (optional.isPresent()) { @@ -615,7 +628,7 @@ worldserver.setBlockAndUpdate(blockposition, (BlockState) optional.get()); worldserver.levelEvent(3003, blockposition, 0); stack.shrink(1); -@@ -481,6 +887,12 @@ +@@ -481,6 +896,12 @@ if (!worldserver.getBlockState(blockposition1).is(BlockTags.CONVERTABLE_TO_MUD)) { return this.defaultDispenseItemBehavior.dispense(pointer, stack); } else { diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch index 8ba834ee20..6b228a3fea 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch @@ -47,7 +47,7 @@ + + // SPIGOT-7923: Avoid create projectiles with empty item + if (!itemstack1.isEmpty()) { -+ Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(worldserver, iposition, itemstack1, enumdirection), worldserver, itemstack1, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); ++ Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(worldserver, iposition, CraftItemStack.unwrap(event.getItem()), enumdirection), worldserver, itemstack1, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); // Paper - track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies + iprojectile.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(pointer.blockEntity()); + } + // itemstack.shrink(1); // CraftBukkit - Handled during event processing diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch index 95bd4507cc..3c544924c8 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch @@ -13,7 +13,7 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior { private static final Logger LOGGER = LogUtils.getLogger(); -@@ -26,6 +32,30 @@ +@@ -26,8 +32,37 @@ BlockPos blockposition = pointer.pos().relative(enumdirection); Direction enumdirection1 = pointer.level().isEmptyBlock(blockposition.below()) ? enumdirection : Direction.UP; @@ -42,5 +42,13 @@ + // CraftBukkit end + try { - this.setSuccess(((BlockItem) item).place(new DirectionalPlaceContext(pointer.level(), blockposition, enumdirection, stack, enumdirection1)).consumesAction()); +- this.setSuccess(((BlockItem) item).place(new DirectionalPlaceContext(pointer.level(), blockposition, enumdirection, stack, enumdirection1)).consumesAction()); ++ // Paper start - track changed items in the dispense event ++ this.setSuccess(((BlockItem) item).place(new DirectionalPlaceContext(pointer.level(), blockposition, enumdirection, CraftItemStack.asNMSCopy(event.getItem()), enumdirection1)).consumesAction()); ++ if (this.isSuccess()) { ++ stack.shrink(1); // vanilla shrink is in the place function above, manually handle it here ++ } ++ // Paper end - track changed items in the dispense event } catch (Exception exception) { + ShulkerBoxDispenseBehavior.LOGGER.error("Error trying to place shulker box at {}", blockposition, exception); + }