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 {
@@ -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<ArmorStand> 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<BlockState> 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 {

View file

@ -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

View file

@ -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);
}