From 790c779fe911f9b0271923c7f4ab5b59997888b5 Mon Sep 17 00:00:00 2001 From: SirSmurfy2 <82696841+TheAbsolutionism@users.noreply.github.com> Date: Sun, 13 Oct 2024 02:09:12 -0400 Subject: [PATCH] BlockDropItemEvent (#7075) * Starter Commit * Test Variations Logging for a copy, will be removed * PR Ready * Stuff Forgot to add back the return if none of the events in ExprDrops * ; * Requested Changes * Requested Changes * Requested Changes * Requested Changes * Requested Changes * Requested Change --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../classes/data/BukkitEventValues.java | 27 ++++++ .../java/ch/njol/skript/events/EvtBlock.java | 56 ++++++++---- .../ch/njol/skript/expressions/ExprDrops.java | 87 ++++++++++++------- 3 files changed, 120 insertions(+), 50 deletions(-) diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java index c53810d5d69..189cbab9de7 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java @@ -62,6 +62,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; +import org.bukkit.event.block.BlockDropItemEvent; import org.bukkit.command.CommandSender; import org.bukkit.entity.AbstractVillager; import org.bukkit.entity.AreaEffectCloud; @@ -1964,5 +1965,31 @@ public RegainReason get(EntityRegainHealthEvent event) { return event.getRegainReason(); } }, EventValues.TIME_NOW); + + // BlockDropItemEvent + EventValues.registerEventValue(BlockDropItemEvent.class, Block.class, new Getter() { + @Override + public Block get(BlockDropItemEvent event) { + return new BlockStateBlock(event.getBlockState()); + } + }, EventValues.TIME_PAST); + EventValues.registerEventValue(BlockDropItemEvent.class, Player.class, new Getter() { + @Override + public Player get(BlockDropItemEvent event) { + return event.getPlayer(); + } + }, EventValues.TIME_NOW); + EventValues.registerEventValue(BlockDropItemEvent.class, ItemStack[].class, new Getter() { + @Override + public ItemStack[] get(BlockDropItemEvent event) { + return event.getItems().stream().map(Item::getItemStack).toArray(ItemStack[]::new); + } + }, EventValues.TIME_NOW); + EventValues.registerEventValue(BlockDropItemEvent.class, Entity[].class, new Getter() { + @Override + public Entity[] get(BlockDropItemEvent event) { + return event.getItems().toArray(Entity[]::new); + } + }, EventValues.TIME_NOW); } } diff --git a/src/main/java/ch/njol/skript/events/EvtBlock.java b/src/main/java/ch/njol/skript/events/EvtBlock.java index ddfdc512552..33fef59ea7f 100644 --- a/src/main/java/ch/njol/skript/events/EvtBlock.java +++ b/src/main/java/ch/njol/skript/events/EvtBlock.java @@ -22,12 +22,7 @@ import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.bukkit.event.Event; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockBurnEvent; -import org.bukkit.event.block.BlockEvent; -import org.bukkit.event.block.BlockFadeEvent; -import org.bukkit.event.block.BlockFormEvent; -import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.*; import org.bukkit.event.hanging.HangingBreakEvent; import org.bukkit.event.hanging.HangingEvent; import org.bukkit.event.hanging.HangingPlaceEvent; @@ -37,6 +32,7 @@ import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; +import org.jetbrains.annotations.NotNull; import org.skriptlang.skript.lang.comparator.Relation; import ch.njol.skript.classes.data.DefaultComparators; import ch.njol.skript.entity.EntityData; @@ -74,6 +70,30 @@ public class EvtBlock extends SkriptEvent { .description("Called when a block is created, but not by a player, e.g. snow forms due to snowfall, water freezes in cold biomes. This isn't called when block spreads (mushroom growth, water physics etc.), as it has its own event (see spread event).") .examples("on form of snow:", "on form of a mushroom:") .since("1.0, 2.6 (BlockData support)"); + Skript.registerEvent("Block Drop", EvtBlock.class, BlockDropItemEvent.class, "block drop[ping] [[of] %-itemtypes/blockdatas%]") + .description( + "Called when a block broken by a player drops something.", + "
    ", + "
  • event-player: The player that broke the block
  • ", + "
  • past event-block: The block that was broken
  • ", + "
  • event-block: The block after being broken
  • ", + "
  • event-items (or drops): The drops of the block
  • ", + "
  • event-entities: The entities of the dropped items
  • ", + "
", + "", + "If the breaking of the block leads to others being broken, such as torches, they will appear" + + "in \"event-items\" and \"event-entities\"." + ) + .examples( + "on block drop:", + "\tbroadcast event-player", + "\tbroadcast past event-block", + "\tbroadcast event-block", + "\tbroadcast event-items", + "\tbroadcast event-entities", + "on block drop of oak log:" + ) + .since("INSERT VERSION"); } @Nullable @@ -101,26 +121,26 @@ public boolean check(final Event event) { ItemType item; BlockData blockData = null; - if (event instanceof BlockFormEvent) { - BlockFormEvent blockFormEvent = (BlockFormEvent) event; + if (event instanceof BlockFormEvent blockFormEvent) { BlockState newState = blockFormEvent.getNewState(); item = new ItemType(newState.getBlockData()); blockData = newState.getBlockData(); - } else if (event instanceof BlockEvent) { - BlockEvent blockEvent = (BlockEvent) event; + } else if (event instanceof BlockDropItemEvent blockDropItemEvent) { + Block block = blockDropItemEvent.getBlock(); + item = new ItemType(block); + blockData = block.getBlockData(); + } else if (event instanceof BlockEvent blockEvent) { Block block = blockEvent.getBlock(); item = new ItemType(block); blockData = block.getBlockData(); - } else if (event instanceof PlayerBucketFillEvent) { - PlayerBucketFillEvent playerBucketFillEvent = ((PlayerBucketFillEvent) event); + } else if (event instanceof PlayerBucketFillEvent playerBucketFillEvent) { Block block = playerBucketFillEvent.getBlockClicked(); item = new ItemType(block); blockData = block.getBlockData(); - } else if (event instanceof PlayerBucketEmptyEvent) { - PlayerBucketEmptyEvent playerBucketEmptyEvent = ((PlayerBucketEmptyEvent) event); + } else if (event instanceof PlayerBucketEmptyEvent playerBucketEmptyEvent) { item = new ItemType(playerBucketEmptyEvent.getItemStack()); - } else if (event instanceof HangingEvent) { - final EntityData d = EntityData.fromEntity(((HangingEvent) event).getEntity()); + } else if (event instanceof HangingEvent hangingEvent) { + final EntityData d = EntityData.fromEntity((hangingEvent.getEntity())); return types.check(event, o -> { if (o instanceof ItemType) return Relation.EQUAL.isImpliedBy(DefaultComparators.entityItemComparator.compare(d, ((ItemType) o))); @@ -144,8 +164,8 @@ else if (o instanceof BlockData && finalBlockData != null) } @Override - public String toString(final @Nullable Event e, final boolean debug) { - return "break/place/burn/fade/form of " + Classes.toString(types); + public String toString(@Nullable Event event, boolean debug) { + return "break/place/burn/fade/form/drop of " + Classes.toString(types); } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprDrops.java b/src/main/java/ch/njol/skript/expressions/ExprDrops.java index 5c94dd50c06..2528df6c5d0 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprDrops.java +++ b/src/main/java/ch/njol/skript/expressions/ExprDrops.java @@ -34,7 +34,10 @@ import ch.njol.skript.util.Experience; import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; +import org.bukkit.entity.Item; import org.bukkit.event.Event; +import org.bukkit.event.block.BlockDropItemEvent; +import org.bukkit.event.block.BlockEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -59,30 +62,39 @@ public class ExprDrops extends SimpleExpression { Skript.registerExpression(ExprDrops.class, ItemType.class, ExpressionType.SIMPLE, "[the] drops"); } + private boolean isDeathEvent; + @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - if (!getParser().isCurrentEvent(EntityDeathEvent.class)) { - Skript.error("The expression 'drops' can only be used in death events", ErrorQuality.SEMANTIC_ERROR); + if (!getParser().isCurrentEvent(EntityDeathEvent.class, BlockDropItemEvent.class)) { + Skript.error("The expression 'drops' can only be used in death events and block drop events"); return false; } + if (getParser().isCurrentEvent(EntityDeathEvent.class)) + isDeathEvent = true; return true; } @Override - @Nullable - protected ItemType[] get(Event e) { - if (!(e instanceof EntityDeathEvent)) - return null; - - return ((EntityDeathEvent) e).getDrops() - .stream() - .map(ItemType::new) - .toArray(ItemType[]::new); + protected ItemType @Nullable [] get(Event event) { + if (event instanceof EntityDeathEvent entityDeathEvent) { + return entityDeathEvent.getDrops() + .stream() + .map(ItemType::new) + .toArray(ItemType[]::new); + } else if (event instanceof BlockDropItemEvent blockDropItemEvent) { + return blockDropItemEvent.getItems() + .stream() + .map(Item::getItemStack) + .map(ItemType::new) + .toArray(ItemType[]::new); + } + assert false; + return new ItemType[0]; } @Override - @Nullable - public Class[] acceptChange(ChangeMode mode) { + public Class @Nullable [] acceptChange(ChangeMode mode) { if (getParser().getHasDelayBefore().isTrue()) { Skript.error("Can't change the drops after the event has already passed"); return null; @@ -90,9 +102,11 @@ public Class[] acceptChange(ChangeMode mode) { switch (mode) { case ADD: case REMOVE: - case REMOVE_ALL: case SET: - return CollectionUtils.array(ItemType[].class, Inventory[].class, Experience[].class); + if (isDeathEvent) + return CollectionUtils.array(ItemType[].class, Inventory[].class, Experience[].class); + else + return CollectionUtils.array(ItemType[].class, Inventory[].class); case DELETE: // handled by EffClearDrops case RESET: default: @@ -101,12 +115,21 @@ public Class[] acceptChange(ChangeMode mode) { } @Override - public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { - if (!(event instanceof EntityDeathEvent)) + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + List drops = null; + int originalExperience = 0; + if (event instanceof EntityDeathEvent entityDeathEvent) { + drops = entityDeathEvent.getDrops(); + originalExperience = entityDeathEvent.getDroppedExp(); + } else if (event instanceof BlockDropItemEvent blockDropItemEvent) { + drops = blockDropItemEvent.getItems() + .stream() + .map(Item::getItemStack) + .toList(); + } else { return; + } - List drops = ((EntityDeathEvent) event).getDrops(); - int originalExperience = ((EntityDeathEvent) event).getDroppedExp(); assert delta != null; // separate the delta into experience and drops to make it easier to handle @@ -114,25 +137,25 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { boolean removeAllExperience = false; List deltaDrops = new ArrayList<>(); for (Object o : delta) { - if (o instanceof Experience) { + if (o instanceof Experience experience) { // Special case for `remove xp from the drops` - if ((((Experience) o).getInternalXP() == -1 && mode == ChangeMode.REMOVE) || mode == ChangeMode.REMOVE_ALL) { + if ((experience.getInternalXP() == -1 && mode == ChangeMode.REMOVE) || mode == ChangeMode.REMOVE_ALL) { removeAllExperience = true; } // add the value even if we're removing all experience, just so we know that experience was changed if (deltaExperience == -1) { - deltaExperience = ((Experience) o).getXP(); + deltaExperience = experience.getXP(); } else { - deltaExperience += ((Experience) o).getXP(); + deltaExperience += experience.getXP(); } - } else if (o instanceof Inventory) { + } else if (o instanceof Inventory inventory) { // inventories are unrolled into their contents - for (ItemStack item : ((Inventory) o).getContents()) { + for (ItemStack item : inventory.getContents()) { if (item != null) deltaDrops.add(new ItemType(item)); } - } else if (o instanceof ItemType) { - deltaDrops.add((ItemType) o); + } else if (o instanceof ItemType itemType) { + deltaDrops.add(itemType); } else { assert false; } @@ -144,20 +167,20 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { // todo: All the experience stuff should be removed from this class for 2.8 and given to ExprExperience // handle experience - if (deltaExperience > -1) { + if (deltaExperience > -1 && event instanceof EntityDeathEvent entityDeathEvent) { switch (mode) { case SET: - ((EntityDeathEvent) event).setDroppedExp(deltaExperience); + entityDeathEvent.setDroppedExp(deltaExperience); break; case ADD: - ((EntityDeathEvent) event).setDroppedExp(originalExperience + deltaExperience); + entityDeathEvent.setDroppedExp(originalExperience + deltaExperience); break; case REMOVE: - ((EntityDeathEvent) event).setDroppedExp(originalExperience - deltaExperience); + entityDeathEvent.setDroppedExp(originalExperience - deltaExperience); // fallthrough to check for removeAllExperience case REMOVE_ALL: if (removeAllExperience) - ((EntityDeathEvent) event).setDroppedExp(0); + entityDeathEvent.setDroppedExp(0); break; case DELETE: case RESET: