Skip to content

Commit 39fd829

Browse files
EvtHarvestBlock (SkriptLang#7903)
* Initial Commit * Drops Addition * Update EvtHarvestBlock.java * Requested Changes * Update src/main/java/ch/njol/skript/events/EvtHarvestBlock.java Co-authored-by: Efnilite <35348263+Efnilite@users.noreply.github.com> * Update src/main/java/ch/njol/skript/effects/EffCancelDrops.java Co-authored-by: Efnilite <35348263+Efnilite@users.noreply.github.com> * Update src/main/java/ch/njol/skript/effects/EffCancelDrops.java Co-authored-by: Efnilite <35348263+Efnilite@users.noreply.github.com> * Update src/main/java/ch/njol/skript/expressions/ExprDrops.java Co-authored-by: Efnilite <35348263+Efnilite@users.noreply.github.com>
1 parent f5a595c commit 39fd829

6 files changed

Lines changed: 239 additions & 85 deletions

File tree

src/main/java/ch/njol/skript/effects/EffCancelDrops.java

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,59 @@
11
package ch.njol.skript.effects;
22

3+
import ch.njol.skript.doc.*;
4+
import ch.njol.skript.lang.EventRestrictedSyntax;
5+
import ch.njol.util.coll.CollectionUtils;
6+
import org.bukkit.entity.Item;
37
import org.bukkit.event.Event;
48
import org.bukkit.event.block.BlockBreakEvent;
9+
import org.bukkit.event.block.BlockDropItemEvent;
510
import org.bukkit.event.entity.EntityDeathEvent;
11+
import org.bukkit.event.player.PlayerHarvestBlockEvent;
612
import org.jetbrains.annotations.Nullable;
713

814
import ch.njol.skript.Skript;
9-
import ch.njol.skript.doc.Description;
10-
import ch.njol.skript.doc.Events;
11-
import ch.njol.skript.doc.Examples;
12-
import ch.njol.skript.doc.Name;
13-
import ch.njol.skript.doc.RequiredPlugins;
14-
import ch.njol.skript.doc.Since;
1515
import ch.njol.skript.lang.Effect;
1616
import ch.njol.skript.lang.Expression;
1717
import ch.njol.skript.lang.SkriptParser.ParseResult;
1818
import ch.njol.util.Kleenean;
1919

2020
@Name("Cancel Drops")
21-
@Description("Cancels drops of items or experiences in a death or block break event. " +
22-
"Please note that this doesn't keep items or experiences of a dead player. If you want to do that, " +
23-
"use the <a href='effects.html#EffKeepInventory'>Keep Inventory / Experience</a> effect.")
24-
@Examples({"on death of a zombie:",
25-
"\tif name of the entity is \"&cSpecial\":",
26-
"\t\tcancel drops of items",
27-
"",
28-
"on break of a coal ore:",
29-
"\tcancel the experience drops"})
30-
@Since("2.4")
21+
@Description({
22+
"Cancels drops of items in a death, block break, block drop, and block harvest events.",
23+
"The dropped experience can be cancelled in a death and block break events.",
24+
"Please note that using this in a death event doesn't keep items or experience of a dead player. If you want to do that, "
25+
+ "use the <a href='effects.html#EffKeepInventory'>Keep Inventory / Experience</a> effect."
26+
})
27+
@Example("""
28+
on death of a zombie:
29+
if name of the entity is "&cSpecial":
30+
cancel drops of items
31+
""")
32+
@Example("""
33+
on break of a coal ore:
34+
cancel the experience drops
35+
""")
36+
@Example("""
37+
on player block harvest:
38+
cancel the item drops
39+
""")
40+
@Since("2.4, INSERT VERSION (harvest event)")
3141
@RequiredPlugins("1.12.2 or newer (cancelling item drops of blocks)")
32-
@Events({"death", "break / mine"})
33-
public class EffCancelDrops extends Effect {
34-
35-
private static final boolean CAN_CANCEL_BLOCK_ITEM_DROPS = Skript.methodExists(BlockBreakEvent.class, "setDropItems", boolean.class);
42+
@Events({"death", "break / mine", "block drop", "harvest"})
43+
public class EffCancelDrops extends Effect implements EventRestrictedSyntax {
3644

3745
static {
3846
Skript.registerEffect(EffCancelDrops.class,
39-
"(cancel|clear|delete) [the] drops [of (items|2¦[e]xp[erience][s])]",
40-
"(cancel|clear|delete) [the] (item|[e]xp[erience]) drops");
47+
"(cancel|clear|delete) [the] drops [of (items:items|xp:[e]xp[erience][s])]",
48+
"(cancel|clear|delete) [the] (items:item|xp:[e]xp[erience]) drops");
4149
}
4250

4351
private boolean cancelItems, cancelExps;
4452

4553
@Override
4654
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
47-
cancelItems = parseResult.mark == 0 || parseResult.mark == 1;
48-
cancelExps = parseResult.mark == 0 || parseResult.mark == 2;
49-
if (getParser().isCurrentEvent(BlockBreakEvent.class)) {
50-
if (cancelItems && !CAN_CANCEL_BLOCK_ITEM_DROPS) {
51-
Skript.error("Cancelling drops of items in a block break event requires Minecraft 1.12 or newer");
52-
return false;
53-
}
54-
} else if (!getParser().isCurrentEvent(EntityDeathEvent.class)) {
55-
Skript.error("The cancel drops effect can't be used outside of a death" +
56-
(CAN_CANCEL_BLOCK_ITEM_DROPS ? " or block break" : "") + " event");
57-
return false;
58-
}
55+
cancelItems = !parseResult.hasTag("xp");
56+
cancelExps = !parseResult.hasTag("items");
5957
if (isDelayed.isTrue()) {
6058
Skript.error("Can't cancel the drops anymore after the event has already passed");
6159
return false;
@@ -64,24 +62,31 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
6462
}
6563

6664
@Override
67-
protected void execute(Event e) {
68-
if (e instanceof EntityDeathEvent) {
69-
EntityDeathEvent event = (EntityDeathEvent) e;
65+
public Class<? extends Event>[] supportedEvents() {
66+
return CollectionUtils.array(EntityDeathEvent.class, BlockBreakEvent.class, BlockDropItemEvent.class, PlayerHarvestBlockEvent.class);
67+
}
68+
69+
@Override
70+
protected void execute(Event event) {
71+
if (event instanceof EntityDeathEvent deathEvent) {
7072
if (cancelItems)
71-
event.getDrops().clear();
73+
deathEvent.getDrops().clear();
7274
if (cancelExps)
73-
event.setDroppedExp(0);
74-
} else if (e instanceof BlockBreakEvent) {
75-
BlockBreakEvent event = (BlockBreakEvent) e;
75+
deathEvent.setDroppedExp(0);
76+
} else if (event instanceof BlockBreakEvent breakEvent) {
7677
if (cancelItems)
77-
event.setDropItems(false);
78+
breakEvent.setDropItems(false);
7879
if (cancelExps)
79-
event.setExpToDrop(0);
80+
breakEvent.setExpToDrop(0);
81+
} else if (event instanceof BlockDropItemEvent dropItemEvent) {
82+
dropItemEvent.getItems().forEach(Item::remove);
83+
} else if (event instanceof PlayerHarvestBlockEvent harvestBlockEvent) {
84+
harvestBlockEvent.getItemsHarvested().clear();
8085
}
8186
}
8287

8388
@Override
84-
public String toString(@Nullable Event e, boolean debug) {
89+
public String toString(@Nullable Event event, boolean debug) {
8590
if (cancelItems && !cancelExps)
8691
return "cancel the drops of items";
8792
else if (cancelExps && !cancelItems)
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package ch.njol.skript.events;
2+
3+
import ch.njol.skript.Skript;
4+
import ch.njol.skript.aliases.ItemType;
5+
import ch.njol.skript.lang.Literal;
6+
import ch.njol.skript.lang.SkriptEvent;
7+
import ch.njol.skript.lang.SkriptParser.ParseResult;
8+
import ch.njol.skript.lang.SyntaxStringBuilder;
9+
import ch.njol.skript.lang.util.SimpleExpression;
10+
import ch.njol.skript.registrations.EventValues;
11+
import ch.njol.skript.util.slot.Slot;
12+
import org.bukkit.block.Block;
13+
import org.bukkit.block.data.BlockData;
14+
import org.bukkit.event.Event;
15+
import org.bukkit.event.player.PlayerHarvestBlockEvent;
16+
import org.bukkit.inventory.EquipmentSlot;
17+
import org.bukkit.inventory.ItemStack;
18+
import org.jetbrains.annotations.Nullable;
19+
20+
public class EvtHarvestBlock extends SkriptEvent {
21+
22+
static {
23+
Skript.registerEvent("Harvest Block", EvtHarvestBlock.class, PlayerHarvestBlockEvent.class,
24+
"[player] [block|crop] harvest[ing] [of %-itemtypes/blockdatas%]")
25+
.description("""
26+
Called when a player harvests a block.
27+
A block being harvested is when a block drops items and the state of the block is changed, but the block is not broken.
28+
An example is harvesting berries from a berry bush.
29+
""")
30+
.examples("""
31+
on player block harvest:
32+
send "You have harvested %event-block% that dropped %event-items% using your %item of event-slot% in your %event-equipment slot%"
33+
34+
on crop harvesting of sweet berry bush:
35+
chance 5%:
36+
set drops to a diamond
37+
chance 1%
38+
cancel the drops
39+
""")
40+
.since("INSERT VERSION");
41+
42+
EventValues.registerEventValue(PlayerHarvestBlockEvent.class, Block.class,
43+
PlayerHarvestBlockEvent::getHarvestedBlock);
44+
EventValues.registerEventValue(PlayerHarvestBlockEvent.class, ItemStack[].class,
45+
event -> event.getItemsHarvested().toArray(ItemStack[]::new));
46+
EventValues.registerEventValue(PlayerHarvestBlockEvent.class, EquipmentSlot.class,
47+
PlayerHarvestBlockEvent::getHand);
48+
EventValues.registerEventValue(PlayerHarvestBlockEvent.class, Slot.class,
49+
event -> new ch.njol.skript.util.slot.EquipmentSlot(event.getPlayer(), event.getHand()));
50+
}
51+
52+
private Literal<?> types = null;
53+
54+
@Override
55+
public boolean init(Literal<?>[] args, int matchedPattern, ParseResult parseResult) {
56+
types = args[0];
57+
return true;
58+
}
59+
60+
@Override
61+
public boolean check(Event event) {
62+
if (!(event instanceof PlayerHarvestBlockEvent harvestBlockEvent))
63+
return false;
64+
if (types == null)
65+
return true;
66+
67+
Block block = harvestBlockEvent.getHarvestedBlock();
68+
BlockData sourceData = block.getBlockData();
69+
return SimpleExpression.check(types.getAll(), object -> {
70+
if (object instanceof ItemType itemType) {
71+
return itemType.isOfType(block);
72+
} else if (object instanceof BlockData blockData) {
73+
return blockData.matches(sourceData);
74+
}
75+
return false;
76+
}, false, false);
77+
}
78+
79+
@Override
80+
public String toString(@Nullable Event event, boolean debug) {
81+
SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug);
82+
builder.append("player block harvest");
83+
if (types != null)
84+
builder.append("of", types);
85+
return builder.toString();
86+
}
87+
88+
}

src/main/java/ch/njol/skript/expressions/ExprDrops.java

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,36 @@
33
import ch.njol.skript.Skript;
44
import ch.njol.skript.aliases.ItemType;
55
import ch.njol.skript.classes.Changer.ChangeMode;
6-
import ch.njol.skript.doc.Description;
7-
import ch.njol.skript.doc.Events;
8-
import ch.njol.skript.doc.Examples;
9-
import ch.njol.skript.doc.Name;
10-
import ch.njol.skript.doc.Since;
6+
import ch.njol.skript.doc.*;
117
import ch.njol.skript.lang.EventRestrictedSyntax;
128
import ch.njol.skript.lang.Expression;
139
import ch.njol.skript.lang.ExpressionType;
1410
import ch.njol.skript.lang.SkriptParser.ParseResult;
1511
import ch.njol.skript.lang.util.SimpleExpression;
16-
import ch.njol.skript.log.ErrorQuality;
1712
import ch.njol.skript.util.Experience;
1813
import ch.njol.util.Kleenean;
1914
import ch.njol.util.coll.CollectionUtils;
20-
import org.bukkit.entity.Item;
2115
import org.bukkit.event.Event;
22-
import org.bukkit.event.block.BlockDropItemEvent;
23-
import org.bukkit.event.block.BlockEvent;
2416
import org.bukkit.event.entity.EntityDeathEvent;
17+
import org.bukkit.event.player.PlayerHarvestBlockEvent;
2518
import org.bukkit.inventory.Inventory;
2619
import org.bukkit.inventory.ItemStack;
2720
import org.jetbrains.annotations.Nullable;
2821

2922
import java.util.ArrayList;
3023
import java.util.List;
3124

32-
/**
33-
* @author Peter Güttinger
34-
*/
3525
@Name("Drops")
36-
@Description("Only works in death events. Holds the drops of the dying creature. Drops can be prevented by removing them with " +
37-
"\"remove ... from drops\", e.g. \"remove all pickaxes from the drops\", or \"clear drops\" if you don't want any drops at all.")
38-
@Examples({"clear drops",
39-
"remove 4 planks from the drops"})
26+
@Description({
27+
"This expression only works in death and harvest events.",
28+
"In a death event, will hold the drops of the dying creature.",
29+
"Drops can be prevented by removing them with \"remove ... from drops\", "
30+
+ "e.g. \"remove all pickaxes from the drops\", or \"clear drops\" if you don't want any drops at all."
31+
})
32+
@Examples({
33+
"clear drops",
34+
"remove 4 planks from the drops"
35+
})
4036
@Since("1.0")
4137
@Events("death")
4238
public class ExprDrops extends SimpleExpression<ItemType> implements EventRestrictedSyntax {
@@ -56,7 +52,7 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
5652

5753
@Override
5854
public Class<? extends Event>[] supportedEvents() {
59-
return CollectionUtils.array(EntityDeathEvent.class, BlockDropItemEvent.class);
55+
return CollectionUtils.array(EntityDeathEvent.class, PlayerHarvestBlockEvent.class);
6056
}
6157

6258
@Override
@@ -66,10 +62,9 @@ public Class<? extends Event>[] supportedEvents() {
6662
.stream()
6763
.map(ItemType::new)
6864
.toArray(ItemType[]::new);
69-
} else if (event instanceof BlockDropItemEvent blockDropItemEvent) {
70-
return blockDropItemEvent.getItems()
65+
} else if (event instanceof PlayerHarvestBlockEvent harvestBlockEvent) {
66+
return harvestBlockEvent.getItemsHarvested()
7167
.stream()
72-
.map(Item::getItemStack)
7368
.map(ItemType::new)
7469
.toArray(ItemType[]::new);
7570
}
@@ -83,19 +78,14 @@ public Class<? extends Event>[] supportedEvents() {
8378
Skript.error("Can't change the drops after the event has already passed");
8479
return null;
8580
}
86-
switch (mode) {
87-
case ADD:
88-
case REMOVE:
89-
case SET:
81+
return switch (mode) {
82+
case SET, ADD, REMOVE -> {
9083
if (isDeathEvent)
91-
return CollectionUtils.array(ItemType[].class, Inventory[].class, Experience[].class);
92-
else
93-
return CollectionUtils.array(ItemType[].class, Inventory[].class);
94-
case DELETE: // handled by EffClearDrops
95-
case RESET:
96-
default:
97-
return null;
98-
}
84+
yield CollectionUtils.array(ItemType[].class, Inventory[].class, Experience[].class);
85+
yield CollectionUtils.array(ItemType[].class, Inventory[].class);
86+
}
87+
default -> null;
88+
};
9989
}
10090

10191
@Override
@@ -105,11 +95,8 @@ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) {
10595
if (event instanceof EntityDeathEvent entityDeathEvent) {
10696
drops = entityDeathEvent.getDrops();
10797
originalExperience = entityDeathEvent.getDroppedExp();
108-
} else if (event instanceof BlockDropItemEvent blockDropItemEvent) {
109-
drops = blockDropItemEvent.getItems()
110-
.stream()
111-
.map(Item::getItemStack)
112-
.toList();
98+
} else if (event instanceof PlayerHarvestBlockEvent harvestBlockEvent) {
99+
drops = harvestBlockEvent.getItemsHarvested();
113100
} else {
114101
return;
115102
}
@@ -120,8 +107,8 @@ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) {
120107
int deltaExperience = -1; // Skript does not support negative experience, so -1 is a safe "unset" value
121108
boolean removeAllExperience = false;
122109
List<ItemType> deltaDrops = new ArrayList<>();
123-
for (Object o : delta) {
124-
if (o instanceof Experience experience) {
110+
for (Object object : delta) {
111+
if (object instanceof Experience experience) {
125112
// Special case for `remove xp from the drops`
126113
if ((experience.getInternalXP() == -1 && mode == ChangeMode.REMOVE) || mode == ChangeMode.REMOVE_ALL) {
127114
removeAllExperience = true;
@@ -132,13 +119,13 @@ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) {
132119
} else {
133120
deltaExperience += experience.getXP();
134121
}
135-
} else if (o instanceof Inventory inventory) {
122+
} else if (object instanceof Inventory inventory) {
136123
// inventories are unrolled into their contents
137124
for (ItemStack item : inventory.getContents()) {
138125
if (item != null)
139126
deltaDrops.add(new ItemType(item));
140127
}
141-
} else if (o instanceof ItemType itemType) {
128+
} else if (object instanceof ItemType itemType) {
142129
deltaDrops.add(itemType);
143130
} else {
144131
assert false;

src/main/java/ch/njol/skript/util/slot/EquipmentSlot.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ public EquipmentSlot(@NotNull HumanEntity holder, int index) {
178178
this(holder.getEquipment(), BukkitUtils.getEquipmentSlotFromIndex(index), true);
179179
}
180180

181+
public EquipmentSlot(@NotNull HumanEntity holder, @NotNull org.bukkit.inventory.EquipmentSlot bukkitSlot) {
182+
this(holder.getEquipment(), bukkitSlot, true);
183+
}
184+
181185
@Override
182186
public @Nullable ItemStack getItem() {
183187
if (skriptSlot != null)

0 commit comments

Comments
 (0)