Properly track the changed item from dispense events

This commit is contained in:
Jake Potrebic 2022-12-12 12:14:03 -08:00
parent 193d6ee2ca
commit 27979040fd
3 changed files with 54 additions and 33 deletions

View file

@ -36,7 +36,7 @@
public interface DispenseItemBehavior { public interface DispenseItemBehavior {
@@ -90,14 +104,42 @@ @@ -90,14 +104,46 @@
Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING); Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING);
EntityType<?> entitytypes = ((SpawnEggItem) stack.getItem()).getType(pointer.level().registryAccess(), stack); EntityType<?> entitytypes = ((SpawnEggItem) stack.getItem()).getType(pointer.level().registryAccess(), stack);
@ -65,10 +65,15 @@
+ idispensebehavior.dispense(pointer, eventStack); + idispensebehavior.dispense(pointer, eventStack);
+ return stack; + 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 { 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) { } catch (Exception exception) {
- null.LOGGER.error("Error while dispensing spawn egg from dispenser at {}", pointer.pos(), 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 + 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()); pointer.level().gameEvent((Entity) null, (Holder) GameEvent.ENTITY_PLACE, pointer.pos());
return stack; return stack;
} }
@@ -116,13 +158,41 @@ @@ -116,13 +162,42 @@
Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING); Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING);
BlockPos blockposition = pointer.pos().relative(enumdirection); BlockPos blockposition = pointer.pos().relative(enumdirection);
ServerLevel worldserver = pointer.level(); ServerLevel worldserver = pointer.level();
@ -113,9 +118,11 @@
+ } + }
+ // CraftBukkit end + // 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<ArmorStand> consumer = EntityType.appendDefaultStackConfig((entityarmorstand) -> { Consumer<ArmorStand> consumer = EntityType.appendDefaultStackConfig((entityarmorstand) -> {
entityarmorstand.setYRot(enumdirection.toYRot()); 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); ArmorStand entityarmorstand = (ArmorStand) EntityType.ARMOR_STAND.spawn(worldserver, consumer, blockposition, EntitySpawnReason.DISPENSER, false, false);
if (entityarmorstand != null) { if (entityarmorstand != null) {
@ -124,7 +131,7 @@
} }
return stack; return stack;
@@ -141,7 +211,34 @@ @@ -141,7 +216,34 @@
}); });
if (!list.isEmpty()) { if (!list.isEmpty()) {
@ -155,12 +162,12 @@
+ return stack; + 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 + // CraftBukkit end
this.setSuccess(true); this.setSuccess(true);
return stack; return stack;
} else { } else {
@@ -166,9 +263,35 @@ @@ -166,9 +268,35 @@
} }
entityhorsechestedabstract = (AbstractChestedHorse) iterator1.next(); entityhorsechestedabstract = (AbstractChestedHorse) iterator1.next();
@ -198,7 +205,7 @@
this.setSuccess(true); this.setSuccess(true);
return stack; return stack;
} }
@@ -202,6 +325,44 @@ @@ -202,8 +330,50 @@
BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
ServerLevel worldserver = pointer.level(); ServerLevel worldserver = pointer.level();
@ -207,6 +214,7 @@
+ int y = blockposition.getY(); + int y = blockposition.getY();
+ int z = blockposition.getZ(); + int z = blockposition.getZ();
+ BlockState iblockdata = worldserver.getBlockState(blockposition); + 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 + // Paper start - correctly check if the bucket place will succeed
+ /* Taken from SolidBucketItem#emptyContents */ + /* Taken from SolidBucketItem#emptyContents */
+ boolean willEmptyContentsSolidBucketItem = dispensiblecontaineritem instanceof net.minecraft.world.item.SolidBucketItem && worldserver.isInWorldBounds(blockposition) && iblockdata.isAir(); + 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 + // CraftBukkit end
+ +
if (dispensiblecontaineritem.emptyContents((Player) null, worldserver, blockposition, (BlockHitResult) null)) { 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)); 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(); Block block = iblockdata.getBlock();
if (block instanceof BucketPickup ifluidsource) { if (block instanceof BucketPickup ifluidsource) {
@ -252,7 +266,7 @@
if (itemstack1.isEmpty()) { if (itemstack1.isEmpty()) {
return super.execute(pointer, stack); return super.execute(pointer, stack);
@@ -237,6 +398,32 @@ @@ -237,6 +407,32 @@
worldserver.gameEvent((Entity) null, (Holder) GameEvent.FLUID_PICKUP, blockposition); worldserver.gameEvent((Entity) null, (Holder) GameEvent.FLUID_PICKUP, blockposition);
Item item = itemstack1.getItem(); Item item = itemstack1.getItem();
@ -285,11 +299,10 @@
return this.consumeWithRemainder(pointer, stack, new ItemStack(item)); return this.consumeWithRemainder(pointer, stack, new ItemStack(item));
} }
} else { } else {
@@ -248,6 +435,30 @@ @@ -249,16 +445,44 @@
@Override
protected ItemStack execute(BlockSource pointer, ItemStack stack) { protected ItemStack execute(BlockSource pointer, ItemStack stack) {
ServerLevel worldserver = pointer.level(); ServerLevel worldserver = pointer.level();
+
+ // CraftBukkit start + // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, pointer.pos()); + org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, pointer.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack);
@ -313,10 +326,10 @@
+ } + }
+ } + }
+ // CraftBukkit end + // CraftBukkit end
+
this.setSuccess(true); this.setSuccess(true);
Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING); Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING);
@@ -255,10 +466,14 @@ BlockPos blockposition = pointer.pos().relative(enumdirection);
BlockState iblockdata = worldserver.getBlockState(blockposition); BlockState iblockdata = worldserver.getBlockState(blockposition);
if (BaseFireBlock.canBePlacedAt(worldserver, blockposition, enumdirection)) { if (BaseFireBlock.canBePlacedAt(worldserver, blockposition, enumdirection)) {
@ -334,7 +347,7 @@
TntBlock.explode(worldserver, blockposition); TntBlock.explode(worldserver, blockposition);
worldserver.removeBlock(blockposition, false); worldserver.removeBlock(blockposition, false);
} else { } else {
@@ -283,13 +498,64 @@ @@ -283,13 +507,64 @@
this.setSuccess(true); this.setSuccess(true);
ServerLevel worldserver = pointer.level(); ServerLevel worldserver = pointer.level();
BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
@ -399,7 +412,7 @@
return stack; return stack;
} }
}); });
@@ -298,12 +564,41 @@ @@ -298,12 +573,41 @@
protected ItemStack execute(BlockSource pointer, ItemStack stack) { protected ItemStack execute(BlockSource pointer, ItemStack stack) {
ServerLevel worldserver = pointer.level(); ServerLevel worldserver = pointer.level();
BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
@ -443,7 +456,7 @@
return stack; return stack;
} }
}); });
@@ -313,7 +608,31 @@ @@ -313,7 +617,31 @@
ServerLevel worldserver = pointer.level(); ServerLevel worldserver = pointer.level();
Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING); Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING);
BlockPos blockposition = pointer.pos().relative(enumdirection); BlockPos blockposition = pointer.pos().relative(enumdirection);
@ -456,11 +469,11 @@
+ if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event); + worldserver.getCraftServer().getPluginManager().callEvent(event);
+ } + }
+
+ if (event.isCancelled()) { + if (event.isCancelled()) {
+ return stack; + return stack;
+ } + }
+
+ if (!event.getItem().equals(craftItem)) { + if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item + // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
@ -475,7 +488,7 @@
if (worldserver.isEmptyBlock(blockposition) && WitherSkullBlock.canSpawnMob(worldserver, blockposition, stack)) { 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.setBlock(blockposition, (BlockState) Blocks.WITHER_SKELETON_SKULL.defaultBlockState().setValue(SkullBlock.ROTATION, RotationSegment.convertToSegment(enumdirection)), 3);
worldserver.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_PLACE, blockposition); worldserver.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_PLACE, blockposition);
@@ -326,7 +645,7 @@ @@ -326,7 +654,7 @@
stack.shrink(1); stack.shrink(1);
this.setSuccess(true); this.setSuccess(true);
} else { } else {
@ -484,7 +497,7 @@
} }
return stack; return stack;
@@ -339,6 +658,30 @@ @@ -339,6 +667,30 @@
BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
CarvedPumpkinBlock blockpumpkincarved = (CarvedPumpkinBlock) Blocks.CARVED_PUMPKIN; CarvedPumpkinBlock blockpumpkincarved = (CarvedPumpkinBlock) Blocks.CARVED_PUMPKIN;
@ -515,7 +528,7 @@
if (worldserver.isEmptyBlock(blockposition) && blockpumpkincarved.canSpawnGolem(worldserver, blockposition)) { if (worldserver.isEmptyBlock(blockposition) && blockpumpkincarved.canSpawnGolem(worldserver, blockposition)) {
if (!worldserver.isClientSide) { if (!worldserver.isClientSide) {
worldserver.setBlock(blockposition, blockpumpkincarved.defaultBlockState(), 3); worldserver.setBlock(blockposition, blockpumpkincarved.defaultBlockState(), 3);
@@ -348,7 +691,7 @@ @@ -348,7 +700,7 @@
stack.shrink(1); stack.shrink(1);
this.setSuccess(true); this.setSuccess(true);
} else { } else {
@ -524,7 +537,7 @@
} }
return stack; return stack;
@@ -377,6 +720,30 @@ @@ -377,6 +729,30 @@
BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
BlockState iblockdata = worldserver.getBlockState(blockposition); BlockState iblockdata = worldserver.getBlockState(blockposition);
@ -555,7 +568,7 @@
if (iblockdata.is(BlockTags.BEEHIVES, (blockbase_blockdata) -> { if (iblockdata.is(BlockTags.BEEHIVES, (blockbase_blockdata) -> {
return blockbase_blockdata.hasProperty(BeehiveBlock.HONEY_LEVEL) && blockbase_blockdata.getBlock() instanceof BeehiveBlock; return blockbase_blockdata.hasProperty(BeehiveBlock.HONEY_LEVEL) && blockbase_blockdata.getBlock() instanceof BeehiveBlock;
}) && (Integer) iblockdata.getValue(BeehiveBlock.HONEY_LEVEL) >= 5) { }) && (Integer) iblockdata.getValue(BeehiveBlock.HONEY_LEVEL) >= 5) {
@@ -402,6 +769,13 @@ @@ -402,6 +778,13 @@
this.setSuccess(true); this.setSuccess(true);
if (iblockdata.is(Blocks.RESPAWN_ANCHOR)) { if (iblockdata.is(Blocks.RESPAWN_ANCHOR)) {
if ((Integer) iblockdata.getValue(RespawnAnchorBlock.CHARGE) != 4) { if ((Integer) iblockdata.getValue(RespawnAnchorBlock.CHARGE) != 4) {
@ -569,7 +582,7 @@
RespawnAnchorBlock.charge((Entity) null, worldserver, blockposition, iblockdata); RespawnAnchorBlock.charge((Entity) null, worldserver, blockposition, iblockdata);
stack.shrink(1); stack.shrink(1);
} else { } else {
@@ -426,6 +800,31 @@ @@ -426,6 +809,31 @@
this.setSuccess(false); this.setSuccess(false);
return stack; return stack;
} else { } else {
@ -601,7 +614,7 @@
Iterator iterator1 = list.iterator(); Iterator iterator1 = list.iterator();
Armadillo armadillo; Armadillo armadillo;
@@ -454,6 +853,13 @@ @@ -454,6 +862,13 @@
Optional<BlockState> optional = HoneycombItem.getWaxed(iblockdata); Optional<BlockState> optional = HoneycombItem.getWaxed(iblockdata);
if (optional.isPresent()) { if (optional.isPresent()) {
@ -615,7 +628,7 @@
worldserver.setBlockAndUpdate(blockposition, (BlockState) optional.get()); worldserver.setBlockAndUpdate(blockposition, (BlockState) optional.get());
worldserver.levelEvent(3003, blockposition, 0); worldserver.levelEvent(3003, blockposition, 0);
stack.shrink(1); stack.shrink(1);
@@ -481,6 +887,12 @@ @@ -481,6 +896,12 @@
if (!worldserver.getBlockState(blockposition1).is(BlockTags.CONVERTABLE_TO_MUD)) { if (!worldserver.getBlockState(blockposition1).is(BlockTags.CONVERTABLE_TO_MUD)) {
return this.defaultDispenseItemBehavior.dispense(pointer, stack); return this.defaultDispenseItemBehavior.dispense(pointer, stack);
} else { } else {

View file

@ -47,7 +47,7 @@
+ +
+ // SPIGOT-7923: Avoid create projectiles with empty item + // SPIGOT-7923: Avoid create projectiles with empty item
+ if (!itemstack1.isEmpty()) { + 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()); + iprojectile.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(pointer.blockEntity());
+ } + }
+ // itemstack.shrink(1); // CraftBukkit - Handled during event processing + // itemstack.shrink(1); // CraftBukkit - Handled during event processing

View file

@ -13,7 +13,7 @@
public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior { public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior {
private static final Logger LOGGER = LogUtils.getLogger(); private static final Logger LOGGER = LogUtils.getLogger();
@@ -26,6 +32,30 @@ @@ -26,8 +32,37 @@
BlockPos blockposition = pointer.pos().relative(enumdirection); BlockPos blockposition = pointer.pos().relative(enumdirection);
Direction enumdirection1 = pointer.level().isEmptyBlock(blockposition.below()) ? enumdirection : Direction.UP; Direction enumdirection1 = pointer.level().isEmptyBlock(blockposition.below()) ? enumdirection : Direction.UP;
@ -42,5 +42,13 @@
+ // CraftBukkit end + // CraftBukkit end
+ +
try { 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) { } catch (Exception exception) {
ShulkerBoxDispenseBehavior.LOGGER.error("Error trying to place shulker box at {}", blockposition, exception);
}