diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index 8b03eaca40b..b8259bc9402 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -96,6 +96,7 @@ import org.skriptlang.skript.bukkit.SkriptMetrics; import org.skriptlang.skript.bukkit.breeding.BreedingModule; import org.skriptlang.skript.bukkit.displays.DisplayModule; +import org.skriptlang.skript.bukkit.furnace.FurnaceModule; import org.skriptlang.skript.lang.comparator.Comparator; import org.skriptlang.skript.lang.comparator.Comparators; import org.skriptlang.skript.lang.converter.Converter; @@ -557,6 +558,7 @@ public void onEnable() { // todo: become proper module once registry api is merged DisplayModule.load(); BreedingModule.load(); + FurnaceModule.load(); } catch (final Exception e) { exception(e, "Could not load required .class files: " + e.getLocalizedMessage()); setEnabled(false); 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 f7cfcff0f11..3007eb0c2e5 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java @@ -126,18 +126,7 @@ import org.bukkit.event.hanging.HangingBreakEvent; import org.bukkit.event.hanging.HangingEvent; import org.bukkit.event.hanging.HangingPlaceEvent; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.event.inventory.CraftItemEvent; -import org.bukkit.event.inventory.DragType; -import org.bukkit.event.inventory.InventoryAction; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryCloseEvent; -import org.bukkit.event.inventory.InventoryDragEvent; -import org.bukkit.event.inventory.InventoryMoveItemEvent; -import org.bukkit.event.inventory.InventoryOpenEvent; -import org.bukkit.event.inventory.InventoryPickupItemEvent; -import org.bukkit.event.inventory.PrepareAnvilEvent; -import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.event.inventory.*; import org.bukkit.event.player.PlayerBedEnterEvent; import org.bukkit.event.player.PlayerBedLeaveEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent; @@ -1972,6 +1961,20 @@ public RegainReason get(EntityRegainHealthEvent event) { } }, EventValues.TIME_NOW); + // FurnaceExtractEvent + EventValues.registerEventValue(FurnaceExtractEvent.class, Player.class, new Getter() { + @Override + public Player get(FurnaceExtractEvent event) { + return event.getPlayer(); + } + }, EventValues.TIME_NOW); + EventValues.registerEventValue(FurnaceExtractEvent.class, ItemStack[].class, new Getter() { + @Override + public ItemStack[] get(FurnaceExtractEvent event) { + return new ItemStack[]{ItemStack.of(event.getItemType(), event.getItemAmount())}; + } + }, EventValues.TIME_NOW); + // BlockDropItemEvent EventValues.registerEventValue(BlockDropItemEvent.class, Block.class, new Getter() { @Override diff --git a/src/main/java/ch/njol/skript/events/SimpleEvents.java b/src/main/java/ch/njol/skript/events/SimpleEvents.java index 65d2c4eb4d4..50ddc0903f4 100644 --- a/src/main/java/ch/njol/skript/events/SimpleEvents.java +++ b/src/main/java/ch/njol/skript/events/SimpleEvents.java @@ -70,8 +70,6 @@ import org.bukkit.event.entity.SheepRegrowWoolEvent; import org.bukkit.event.entity.SlimeSplitEvent; import org.bukkit.event.entity.PiglinBarterEvent; -import org.bukkit.event.inventory.FurnaceBurnEvent; -import org.bukkit.event.inventory.FurnaceSmeltEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.inventory.InventoryOpenEvent; @@ -224,14 +222,6 @@ public class SimpleEvents { .description("Called when the hunger bar of a player changes, i.e. either increases by eating or decreases over time.") .examples("on food bar change:") .since("1.4.4"); - Skript.registerEvent("Fuel Burn", SimpleEvent.class, FurnaceBurnEvent.class, "fuel burn[ing]") - .description("Called when a furnace burns an item from its fuel slot.") - .examples("on fuel burning:") - .since("1.0"); - Skript.registerEvent("Smelt", SimpleEvent.class, FurnaceSmeltEvent.class, "[ore] smelt[ing]", "smelt[ing] of ore") //TODO SkriptEvent for "smelt[ing] of %itemtype%" - .description("Called when a furnace smelts an item in its ore slot.") - .examples("on smelt:") - .since("1.0"); Skript.registerEvent("Leaves Decay", SimpleEvent.class, LeavesDecayEvent.class, "leaves decay[ing]") .description("Called when a leaf block decays due to not being connected to a tree.") .examples("on leaves decay:") diff --git a/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java b/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java deleted file mode 100644 index 1777e73799f..00000000000 --- a/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java +++ /dev/null @@ -1,170 +0,0 @@ -/** - * This file is part of Skript. - * - * Skript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Skript is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Skript. If not, see . - * - * Copyright Peter Güttinger, SkriptLang team and contributors - */ -package ch.njol.skript.expressions; - -import java.util.Arrays; -import java.util.function.Function; - -import ch.njol.skript.classes.Changer.ChangeMode; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.Furnace; -import org.bukkit.event.Event; -import org.bukkit.event.inventory.FurnaceBurnEvent; -import org.jetbrains.annotations.Nullable; - -import ch.njol.skript.Skript; -import ch.njol.skript.aliases.Aliases; -import ch.njol.skript.aliases.ItemType; -import ch.njol.skript.classes.Changer; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.base.PropertyExpression; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.SkriptParser; -import ch.njol.skript.util.Timespan; -import ch.njol.util.Kleenean; -import ch.njol.util.coll.CollectionUtils; -import org.skriptlang.skript.lang.arithmetic.Operator; -import org.skriptlang.skript.lang.arithmetic.Arithmetics; - -@Name("Burn/Cook Time") -@Description({ - "The time a furnace takes to burn an item in a fuel burn event.", - "Can also be used to change the burn/cook time of a placed furnace." -}) -@Examples({ - "on fuel burn:", - "\tif fuel slot is coal:", - "\t\tset burning time to 1 tick" -}) -@Since("2.3") -public class ExprBurnCookTime extends PropertyExpression { - - static { - Skript.registerExpression(ExprBurnCookTime.class, Timespan.class, ExpressionType.PROPERTY, - "[the] burn[ing] time", - "[the] (burn|1:cook)[ing] time of %blocks%", - "%blocks%'[s] (burn|1:cook)[ing] time"); - } - - private boolean cookTime; - private boolean isEvent; - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - cookTime = parseResult.mark == 1; - isEvent = matchedPattern == 0; - if (isEvent && !getParser().isCurrentEvent(FurnaceBurnEvent.class)) { - Skript.error("Cannot use 'burning time' outside a fuel burn event."); - return false; - } - if (!isEvent) - setExpr((Expression) exprs[0]); - return true; - } - - @Override - protected Timespan[] get(Event event, Block[] source) { - if (isEvent) { - if (!(event instanceof FurnaceBurnEvent)) - return new Timespan[0]; - return CollectionUtils.array(Timespan.fromTicks(((FurnaceBurnEvent) event).getBurnTime())); - } else { - return Arrays.stream(source) - .map(Block::getState) - .filter(blockState -> blockState instanceof Furnace) - .map(state -> { - Furnace furnace = (Furnace) state; - return Timespan.fromTicks(cookTime ? furnace.getCookTime() : furnace.getBurnTime()); - }) - .toArray(Timespan[]::new); - } - } - @Override - @Nullable - public Class[] acceptChange(ChangeMode mode) { - if (mode == ChangeMode.ADD || mode == ChangeMode.REMOVE || mode == ChangeMode.SET) - return CollectionUtils.array(Timespan.class); - return null; - } - - @Override - public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { - if (delta == null) - return; - - Function value = null; - Timespan changed = (Timespan) delta[0]; - - switch (mode) { - case ADD: - value = (original) -> Arithmetics.calculate(Operator.ADDITION, original, changed, Timespan.class); - break; - case REMOVE: - value = (original) -> Arithmetics.difference(original, changed, Timespan.class); - break; - case SET: - value = (original) -> changed; - break; - default: - assert false; - break; - } - - if (isEvent) { - if (!(event instanceof FurnaceBurnEvent)) - return; - - FurnaceBurnEvent burnEvent = (FurnaceBurnEvent) event; - burnEvent.setBurnTime((int) value.apply(Timespan.fromTicks(burnEvent.getBurnTime())).getTicks()); - return; - } - - for (Block block : getExpr().getArray(event)) { - BlockState state = block.getState(); - if (!(state instanceof Furnace)) - continue; - Furnace furnace = (Furnace) block.getState(); - long time = value.apply(Timespan.fromTicks(cookTime ? furnace.getCookTime() : furnace.getBurnTime())).getTicks(); - - if (cookTime) { - furnace.setCookTime((short) time); - } else { - furnace.setBurnTime((short) time); - } - - furnace.update(); - } - } - - @Override - public Class getReturnType() { - return Timespan.class; - } - - @Override - public String toString(@Nullable Event event, boolean debug) { - return isEvent ? "the burning time" : String.format("the %sing time of %s", cookTime ? "cook" : "burn", getExpr().toString(event, debug)); - } - -} diff --git a/src/main/java/ch/njol/skript/expressions/ExprFireTicks.java b/src/main/java/ch/njol/skript/expressions/ExprFireTicks.java index e12c124c1c1..84fb243127e 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFireTicks.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFireTicks.java @@ -41,21 +41,19 @@ public class ExprFireTicks extends SimplePropertyExpression { } @Override - @Nullable - public Timespan convert(Entity entity) { - return Timespan.fromTicks(Math.max(entity.getFireTicks(), 0)); + public @Nullable Timespan convert(Entity entity) { + return new Timespan(Timespan.TimePeriod.TICK, Math.max(entity.getFireTicks(), 0)); } @Override - @Nullable - public Class[] acceptChange(ChangeMode mode) { + public Class @Nullable [] acceptChange(ChangeMode mode) { return (mode != ChangeMode.REMOVE_ALL) ? CollectionUtils.array(Timespan.class) : null; } @Override public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { Entity[] entities = getExpr().getArray(event); - int change = delta == null ? 0 : (int) ((Timespan) delta[0]).getTicks(); + int change = delta == null ? 0 : (int) ((Timespan) delta[0]).getAs(Timespan.TimePeriod.TICK); switch (mode) { case REMOVE: change = -change; @@ -75,7 +73,7 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { } @Override - public Class getReturnType() { + public Class getReturnType() { return Timespan.class; } diff --git a/src/main/java/ch/njol/skript/expressions/ExprFurnaceSlot.java b/src/main/java/ch/njol/skript/expressions/ExprFurnaceSlot.java deleted file mode 100644 index b43652b7ae4..00000000000 --- a/src/main/java/ch/njol/skript/expressions/ExprFurnaceSlot.java +++ /dev/null @@ -1,259 +0,0 @@ -/** - * This file is part of Skript. - * - * Skript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Skript is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Skript. If not, see . - * - * Copyright Peter Güttinger, SkriptLang team and contributors - */ -package ch.njol.skript.expressions; - -import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Events; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.effects.Delay; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.lang.util.SimpleExpression; -import ch.njol.skript.registrations.EventValues; -import ch.njol.skript.util.slot.InventorySlot; -import ch.njol.skript.util.slot.Slot; -import ch.njol.util.Kleenean; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.Furnace; -import org.bukkit.event.Event; -import org.bukkit.event.inventory.FurnaceBurnEvent; -import org.bukkit.event.inventory.FurnaceSmeltEvent; -import org.bukkit.inventory.FurnaceInventory; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -@Name("Furnace Slot") -@Description({ - "A slot of a furnace, i.e. either the ore, fuel or result slot.", - "Remember to use 'block' and not furnace, as furnace is not an existing expression.", - "Note that the result and the result slot refer to separate things. the result is the product in a smelt event " + - "and the result slot is the output slot of a furnace (where the result will end up).", - "Note that if the result in a smelt event is changed to an item that differs in type from the items currently in " + - "the result slot, the smelting will fail to complete (the item will attempt to smelt itself again).", - "Note that if values other than the result are changed, event values may not accurately reflect the actual items in a furnace.", - "Thus you may wish to use the event block in this case (e.g. the fuel slot of the event-block) to get accurate values if needed." -}) -@Examples({ - "set the fuel slot of the clicked block to a lava bucket", - "set the block's ore slot to 64 iron ore", - "give the result of the block to the player", - "clear the result slot of the block" -}) -@Events({"smelt", "fuel burn"}) -@Since("1.0, 2.8.0 (syntax rework)") -public class ExprFurnaceSlot extends SimpleExpression { - - private static final int ORE = 0, FUEL = 1, RESULT = 2; - - static { - Skript.registerExpression(ExprFurnaceSlot.class, Slot.class, ExpressionType.PROPERTY, - "[the] (0:ore slot|1:fuel slot|2:result [5:slot])", - "[the] (0:ore|1:fuel|2:result) slot[s] of %blocks%", - "%blocks%'[s] (0:ore|1:fuel|2:result) slot[s]" - ); - } - - @Nullable - private Expression blocks; - private boolean isEvent; - private boolean isResultSlot; - private int slot; - - @Override - @SuppressWarnings("unchecked") - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - isEvent = matchedPattern == 0; - if (!isEvent) - blocks = (Expression) exprs[0]; - - slot = parseResult.mark; - isResultSlot = slot == 7; - if (isResultSlot) - slot = RESULT; - - if (isEvent && (slot == ORE || slot == RESULT) && !getParser().isCurrentEvent(FurnaceSmeltEvent.class)) { - Skript.error("Cannot use 'result slot' or 'ore slot' outside an ore smelt event."); - return false; - } else if (isEvent && slot == FUEL && !getParser().isCurrentEvent(FurnaceBurnEvent.class)) { - Skript.error("Cannot use 'fuel slot' outside a fuel burn event."); - return false; - } - - return true; - } - - @Override - @Nullable - protected Slot[] get(Event event) { - Block[] blocks; - if (isEvent) { - blocks = new Block[1]; - if (event instanceof FurnaceSmeltEvent) { - blocks[0] = ((FurnaceSmeltEvent) event).getBlock(); - } else if (event instanceof FurnaceBurnEvent) { - blocks[0] = ((FurnaceBurnEvent) event).getBlock(); - } else { - return new Slot[0]; - } - } else { - assert this.blocks != null; - blocks = this.blocks.getArray(event); - } - - List slots = new ArrayList<>(); - for (Block block : blocks) { - BlockState state = block.getState(); - if (!(state instanceof Furnace)) - continue; - FurnaceInventory furnaceInventory = ((Furnace) state).getInventory(); - if (isEvent && !Delay.isDelayed(event)) { - slots.add(new FurnaceEventSlot(event, furnaceInventory)); - } else { // Normal inventory slot is fine since the time will always be in the present - slots.add(new InventorySlot(furnaceInventory, slot)); - } - } - return slots.toArray(new Slot[0]); - } - - @Override - public boolean isSingle() { - if (isEvent) - return true; - assert blocks != null; - return blocks.isSingle(); - } - - @Override - public Class getReturnType() { - return InventorySlot.class; - } - - @Override - public String toString(@Nullable Event event, boolean debug) { - String time = (getTime() == -1) ? "past " : (getTime() == 1) ? "future " : ""; - String slotName = (slot == ORE) ? "ore" : (slot == FUEL) ? "fuel" : "result"; - if (isEvent) { - return "the " + time + slotName + (isResultSlot ? " slot" : ""); - } else { - assert blocks != null; - return "the " + time + slotName + " slot of " + blocks.toString(event, debug); - } - } - - @Override - public boolean setTime(int time) { - if (isEvent) { // getExpr will be null - if (slot == RESULT && !isResultSlot) { // 'the past/future result' - doesn't make sense, don't allow it - return false; - } else if (slot == FUEL) { - return setTime(time, FurnaceBurnEvent.class); - } else { - return setTime(time, FurnaceSmeltEvent.class); - } - } - return false; - } - - private final class FurnaceEventSlot extends InventorySlot { - - private final Event event; - - public FurnaceEventSlot(Event event, FurnaceInventory furnaceInventory) { - super(furnaceInventory, slot); - this.event = event; - } - - @Override - @Nullable - public ItemStack getItem() { - switch (slot) { - case ORE: - if (event instanceof FurnaceSmeltEvent) { - ItemStack source = ((FurnaceSmeltEvent) event).getSource().clone(); - if (getTime() != EventValues.TIME_FUTURE) - return source; - source.setAmount(source.getAmount() - 1); - return source; - } - return super.getItem(); - case FUEL: - if (event instanceof FurnaceBurnEvent) { - ItemStack fuel = ((FurnaceBurnEvent) event).getFuel().clone(); - if (getTime() != EventValues.TIME_FUTURE) - return fuel; - // a single lava bucket becomes an empty bucket - // see https://minecraft.wiki/w/Smelting#Fuel - // this is declared here because setting the amount to 0 may cause the ItemStack to become AIR - Material newMaterial = fuel.getType() == Material.LAVA_BUCKET ? Material.BUCKET : Material.AIR; - fuel.setAmount(fuel.getAmount() - 1); - if (fuel.getAmount() == 0) - fuel = new ItemStack(newMaterial); - return fuel; - } - return super.getItem(); - case RESULT: - if (event instanceof FurnaceSmeltEvent) { - ItemStack result = ((FurnaceSmeltEvent) event).getResult().clone(); - if (isResultSlot) { // Special handling for getting the result slot - ItemStack currentResult = ((FurnaceInventory) getInventory()).getResult(); - if (currentResult != null) - currentResult = currentResult.clone(); - if (getTime() != EventValues.TIME_FUTURE) { // 'past result slot' and 'result slot' - return currentResult; - } else if (currentResult != null && currentResult.isSimilar(result)) { // 'future result slot' - currentResult.setAmount(currentResult.getAmount() + result.getAmount()); - return currentResult; - } else { - return result; - } - } - // 'the result' - return result; - } - return super.getItem(); - } - return null; - } - - @Override - public void setItem(@Nullable ItemStack item) { - if (slot == RESULT && !isResultSlot && event instanceof FurnaceSmeltEvent) { - ((FurnaceSmeltEvent) event).setResult(item != null ? item : new ItemStack(Material.AIR)); - } else { - if (getTime() == EventValues.TIME_FUTURE) { // Since this is a future expression, run it AFTER the event - Bukkit.getScheduler().scheduleSyncDelayedTask(Skript.getInstance(), () -> FurnaceEventSlot.super.setItem(item)); - } else { - super.setItem(item); - } - } - } - - } - -} diff --git a/src/main/java/org/skriptlang/skript/bukkit/furnace/FurnaceModule.java b/src/main/java/org/skriptlang/skript/bukkit/furnace/FurnaceModule.java new file mode 100644 index 00000000000..0a1f50286ff --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/furnace/FurnaceModule.java @@ -0,0 +1,12 @@ +package org.skriptlang.skript.bukkit.furnace; + +import ch.njol.skript.Skript; +import java.io.IOException; + +public class FurnaceModule { + + public static void load() throws IOException{ + Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit.furnace", "elements"); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/EvtFurnace.java b/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/EvtFurnace.java new file mode 100644 index 00000000000..2703ea482e7 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/EvtFurnace.java @@ -0,0 +1,113 @@ +package org.skriptlang.skript.bukkit.furnace.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptEvent; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.registrations.Classes; +import org.bukkit.event.Event; +import org.bukkit.event.inventory.FurnaceBurnEvent; +import org.bukkit.event.inventory.FurnaceExtractEvent; +import org.bukkit.event.inventory.FurnaceSmeltEvent; +import org.bukkit.event.inventory.FurnaceStartSmeltEvent; +import org.jetbrains.annotations.Nullable; + +public class EvtFurnace extends SkriptEvent { + + static { + Skript.registerEvent("Smelt", EvtFurnace.class, FurnaceSmeltEvent.class, + "[furnace] [ore] smelt[ed|ing] [of %-itemtypes%]", + "[furnace] smelt[ed|ing] of ore") + .description("Called when a furnace smelts an item in its input slot.") + .examples( + "on smelt:", + "\tclear the smelted item", + "on smelt of raw iron:", + "\tbroadcast smelted item", + "\tset the smelted item to iron block" + ) + .since("1.0, INSERT VERSION (specific item)"); + + Skript.registerEvent("Fuel Burn", EvtFurnace.class, FurnaceBurnEvent.class, "[furnace] fuel burn[ing] [of %-itemtypes%]") + .description("Called when a furnace burns an item from its fuel slot.") + .examples( + "on fuel burning:", + "\tbroadcast fuel burned", + "\tif burned fuel is coal:", + "\t\tadd 20 seconds to burn time" + ) + .since("1.0, INSERT VERSION (specific item)"); + + Skript.registerEvent("Furnace Item Extract", EvtFurnace.class, FurnaceExtractEvent.class, "furnace [item] extract[ion] [of %-itemtypes%]") + .description("Called when a player takes any item out of the furnace.") + .examples( + "on furnace extract:", + "\tif event-items is an iron ingot:", + "\t\tremove event-items from event-player's inventory" + ) + .since("INSERT VERSION"); + + Skript.registerEvent("Start Smelt", EvtFurnace.class, FurnaceStartSmeltEvent.class, + "[furnace] start [of] smelt[ing] [[of] %-itemtypes%]", + "[furnace] smelt[ing] start [of %-itemtypes%]") + .description("Called when a furnace starts smelting an item in its ore slot.") + .examples( + "on smelting start:", + "\tif the smelting item is raw iron:", + "\t\tset total cook time to 1 second", + "on smelting start of raw iron:", + "\tadd 20 seconds to total cook time" + ) + .since("INSERT VERSION"); + } + + private @Nullable Literal types; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Literal[] exprs, int matchedPattern, ParseResult parseResult) { + if (exprs[0] != null) + types = (Literal) exprs[0]; + return true; + } + + @Override + public boolean check(Event event) { + if (types == null) + return true; + + ItemType item; + + if (event instanceof FurnaceSmeltEvent smeltEvent) { + item = new ItemType(smeltEvent.getSource()); + } else if (event instanceof FurnaceBurnEvent burnEvent) { + item = new ItemType(burnEvent.getFuel()); + } else if (event instanceof FurnaceExtractEvent extractEvent) { + item = new ItemType(extractEvent.getItemType()); + } else if (event instanceof FurnaceStartSmeltEvent startEvent) { + item = new ItemType(startEvent.getSource()); + } else { + assert false; + return false; + } + + return types.check(event, itemType -> itemType.isSupertypeOf(item)); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + String result = ""; + if (event instanceof FurnaceSmeltEvent) { + result = "smelt"; + } else if (event instanceof FurnaceBurnEvent) { + result = "burn"; + } else if (event instanceof FurnaceExtractEvent) { + result = "extract"; + } else if (event instanceof FurnaceStartSmeltEvent) { + result = "start smelt"; + } + return result + " of " + Classes.toString(types); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/ExprFurnaceEventItems.java b/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/ExprFurnaceEventItems.java new file mode 100644 index 00000000000..8419b998b15 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/ExprFurnaceEventItems.java @@ -0,0 +1,149 @@ +package org.skriptlang.skript.bukkit.furnace.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Events; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.EventValueExpression; +import ch.njol.skript.expressions.base.PropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.Event; +import org.bukkit.event.inventory.FurnaceBurnEvent; +import org.bukkit.event.inventory.FurnaceExtractEvent; +import org.bukkit.event.inventory.FurnaceSmeltEvent; +import org.bukkit.event.inventory.FurnaceStartSmeltEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; + +@Name("Furnace Event Items") +@Description({ + "Represents the different items in furnace events.", + "Only 'smelting item' can be changed." +}) +@Examples({ + "on furnace smelt:", + "\tbroadcast smelted item", + "\t# Or 'result'", + "on furnace extract:", + "\tbroadcast extracted item", + "on fuel burn:", + "\tbroadcast burned fuel", + "on smelting start:", + "\tbroadcast smelting item", + "\tclear smelting item" +}) +@Events({"smelt", "fuel burn", "smelting start", "furnace extract"}) +@Since("INSERT VERSION") +public class ExprFurnaceEventItems extends PropertyExpression { + + enum FurnaceValues { + SMELTED("(smelted item|result[ item])", "smelted item", FurnaceSmeltEvent.class, "'smelted item' can only be used in a smelting event."), + EXTRACTED("extracted item[s]", "extracted item", FurnaceExtractEvent.class, "'extracted item' can only be used in a furnace extract event."), + SMELTING("smelting item", "smelting item", FurnaceStartSmeltEvent.class, "'smelting item' can only be used in a start smelting event"), + BURNED("burned (fuel|item)", "burned fuel item", FurnaceBurnEvent.class, "'burned fuel' can only be used in a fuel burning event."); + + private String pattern, error, toString; + private Class clazz; + + FurnaceValues(String pattern, String toString, Class clazz, String error) { + this.pattern = "[the] " + pattern; + this.clazz = clazz; + this.error = error; + this.toString = toString; + } + + } + + private static final FurnaceValues[] FURNACE_VALUES = FurnaceValues.values(); + + static { + int size = FURNACE_VALUES.length; + String[] patterns = new String[size]; + for (FurnaceValues value : FURNACE_VALUES) { + patterns[value.ordinal()] = value.pattern; + } + + Skript.registerExpression(ExprFurnaceEventItems.class, ItemStack.class, ExpressionType.PROPERTY, patterns); + } + + private FurnaceValues type; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + type = FURNACE_VALUES[matchedPattern]; + if (!getParser().isCurrentEvent(type.clazz)) { + Skript.error(type.error); + return false; + } + setExpr(new EventValueExpression<>(Block.class)); + return true; + } + + @Override + protected ItemStack @Nullable [] get(Event event, Block[] source) { + ItemStack stack = null; + switch (type) { + case SMELTING -> { + stack = ((FurnaceStartSmeltEvent) event).getSource(); + } + case BURNED -> { + stack = ((FurnaceBurnEvent) event).getFuel(); + } + case SMELTED -> { + stack = ((FurnaceSmeltEvent) event).getResult(); + } + case EXTRACTED -> { + FurnaceExtractEvent extractEvent = (FurnaceExtractEvent) event; + stack = new ItemStack(extractEvent.getItemType(), extractEvent.getItemAmount()); + } + }; + return new ItemStack[]{stack}; + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (type != FurnaceValues.SMELTED) + return null; + if (mode != ChangeMode.SET && mode != ChangeMode.DELETE) + return null; + return CollectionUtils.array(ItemStack.class); + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + if (!(event instanceof FurnaceSmeltEvent smeltEvent)) + return; + + if (mode == ChangeMode.SET) { + smeltEvent.setResult((ItemStack) delta[0]); + } else if (mode == ChangeMode.DELETE) { + smeltEvent.setResult(ItemStack.of(Material.AIR)); + } + + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return ItemStack.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return type.toString; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/ExprFurnaceSlot.java b/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/ExprFurnaceSlot.java new file mode 100644 index 00000000000..8fd42c23d0c --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/ExprFurnaceSlot.java @@ -0,0 +1,229 @@ +package org.skriptlang.skript.bukkit.furnace.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Events; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.effects.Delay; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.skript.registrations.EventValues; +import ch.njol.skript.util.slot.InventorySlot; +import ch.njol.skript.util.slot.Slot; +import ch.njol.util.Kleenean; +import ch.njol.util.Math2; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.Furnace; +import org.bukkit.event.Event; +import org.bukkit.event.block.BlockEvent; +import org.bukkit.event.inventory.FurnaceBurnEvent; +import org.bukkit.event.inventory.FurnaceExtractEvent; +import org.bukkit.event.inventory.FurnaceSmeltEvent; +import org.bukkit.event.inventory.FurnaceStartSmeltEvent; +import org.bukkit.inventory.FurnaceInventory; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +@Name("Furnace Slot") +@Description({ + "A slot of a furnace, i.e. either the ore, fuel or result slot." +}) +@Examples({ + "set the fuel slot of the clicked block to a lava bucket", + "set the block's ore slot to 64 iron ore", + "clear the result slot of the block", + "on smelt:", + "\tif the fuel slot is charcoal:", + "\t\tadd 5 seconds to the burn time" +}) +@Events({"smelt", "fuel burn"}) +@Since("1.0, 2.8.0 (syntax rework)") +public class ExprFurnaceSlot extends SimpleExpression { + + private enum FurnaceSlot { + INPUT("(ore|input)", "input"), + FUEL("fuel", "fuel"), + OUTPUT("(result|output)", "output"); + + private String pattern, toString; + + FurnaceSlot(String pattern, String toString) { + this.pattern = pattern; + this.toString = toString; + } + } + + private static final FurnaceSlot[] furnaceSlots = FurnaceSlot.values(); + + static { + String[] patterns = new String[furnaceSlots.length * 2]; + for (FurnaceSlot slot : furnaceSlots) { + patterns[2 * slot.ordinal()] = "[the] " + slot.pattern + " slot[s] [of %blocks%]"; + patterns[2 * slot.ordinal() + 1] = "%blocks%'[s] " + slot.pattern + " slot[s]"; + } + Skript.registerExpression(ExprFurnaceSlot.class, Slot.class, ExpressionType.PROPERTY, patterns); + } + + + private @Nullable Expression blocks; + private FurnaceSlot selectedSlot; + private boolean isEvent; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + selectedSlot = furnaceSlots[(int) Math2.floor(matchedPattern / 2)]; + if (exprs[0] != null) { + //noinspection unchecked + blocks = (Expression) exprs[0]; + } else { + if (!getParser().isCurrentEvent(FurnaceBurnEvent.class, FurnaceStartSmeltEvent.class, FurnaceExtractEvent.class, FurnaceSmeltEvent.class)) { + Skript.error("There's no furnace in a " + getParser().getCurrentEventName() + " event."); + return false; + } + isEvent = true; + } + return true; + } + + @Override + protected Slot @Nullable [] get(Event event) { + Block[] blocks; + if (isEvent) { + blocks = new Block[1]; + if (event instanceof BlockEvent blockEvent) { + blocks[0] = blockEvent.getBlock(); + } else { + return new Slot[0]; + } + } else { + assert this.blocks != null; + blocks = this.blocks.getArray(event); + } + + List slots = new ArrayList<>(); + for (Block block : blocks) { + BlockState state = block.getState(); + if (!(state instanceof Furnace)) + continue; + FurnaceInventory furnaceInventory = ((Furnace) state).getInventory(); + if (isEvent && !Delay.isDelayed(event)) { + slots.add(new FurnaceEventSlot(event, furnaceInventory)); + } else { + slots.add(new InventorySlot(furnaceInventory, selectedSlot.ordinal())); + } + } + return slots.toArray(new Slot[0]); + } + + @Override + public boolean isSingle() { + if (isEvent) + return true; + assert blocks != null; + return blocks.isSingle(); + } + + @Override + public Class getReturnType() { + return InventorySlot.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return selectedSlot.toString + " slot of " + (isEvent ? event.getEventName() : blocks.toString(event, debug)); + } + + @Override + public boolean setTime(int time) { + if (isEvent) { // getExpr will be null + if (selectedSlot == FurnaceSlot.FUEL) + return setTime(time, FurnaceBurnEvent.class); + return setTime(time, FurnaceSmeltEvent.class); + } + return false; + } + + private final class FurnaceEventSlot extends InventorySlot { + + private final Event event; + + public FurnaceEventSlot(Event event, FurnaceInventory furnaceInventory) { + super(furnaceInventory, selectedSlot.ordinal()); + this.event = event; + } + + @Override + public @Nullable ItemStack getItem() { + return switch (selectedSlot) { + case INPUT -> { + if (event instanceof FurnaceSmeltEvent furnaceSmeltEvent) { + ItemStack source = furnaceSmeltEvent.getSource().clone(); + if (getTime() != EventValues.TIME_FUTURE) + yield source; + source.setAmount(source.getAmount() - 1); + yield source; + } + yield super.getItem(); + } + case FUEL -> { + if (event instanceof FurnaceBurnEvent furnaceBurnEvent) { + ItemStack fuel = furnaceBurnEvent.getFuel().clone(); + if (getTime() != EventValues.TIME_FUTURE) + yield fuel; + // a single lava bucket becomes an empty bucket + // see https://minecraft.wiki/w/Smelting#Fuel + // this is declared here because setting the amount to 0 may cause the ItemStack to become AIR + Material newMaterial = fuel.getType() == Material.LAVA_BUCKET ? Material.BUCKET : Material.AIR; + fuel.setAmount(fuel.getAmount() - 1); + if (fuel.getAmount() == 0) + fuel = new ItemStack(newMaterial); + yield fuel; + } + yield super.getItem(); + } + case OUTPUT -> { + if (event instanceof FurnaceSmeltEvent furnaceSmeltEvent) { + ItemStack result = furnaceSmeltEvent.getResult().clone(); + ItemStack currentResult = ((FurnaceInventory) getInventory()).getResult(); + if (currentResult != null) + currentResult = currentResult.clone(); + if (getTime() != EventValues.TIME_FUTURE) { // 'past result slot' and 'result slot' + yield currentResult; + } else if (currentResult != null && currentResult.isSimilar(result)) { // 'future result slot' + currentResult.setAmount(currentResult.getAmount() + result.getAmount()); + yield currentResult; + } else { + yield result; // 'the result' + } + } + yield super.getItem(); + } + }; + } + + @Override + public void setItem(@Nullable ItemStack item) { + if (selectedSlot == FurnaceSlot.OUTPUT && event instanceof FurnaceSmeltEvent furnaceSmeltEvent) { + furnaceSmeltEvent.setResult(item != null ? item : new ItemStack(Material.AIR)); + } else { + if (getTime() == EventValues.TIME_FUTURE) { // Since this is a future expression, run it AFTER the event + Bukkit.getScheduler().scheduleSyncDelayedTask(Skript.getInstance(), () -> FurnaceEventSlot.super.setItem(item)); + } else { + super.setItem(item); + } + } + } + + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/ExprFurnaceTime.java b/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/ExprFurnaceTime.java new file mode 100644 index 00000000000..4df5078f2b3 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/furnace/elements/ExprFurnaceTime.java @@ -0,0 +1,206 @@ +package org.skriptlang.skript.bukkit.furnace.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.*; +import ch.njol.skript.expressions.base.EventValueExpression; +import ch.njol.skript.expressions.base.PropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.Timespan; +import ch.njol.util.Kleenean; +import ch.njol.util.Math2; +import ch.njol.util.coll.CollectionUtils; +import org.bukkit.block.Block; +import org.bukkit.block.Furnace; +import org.bukkit.event.Event; +import org.bukkit.event.inventory.FurnaceBurnEvent; +import org.bukkit.event.inventory.FurnaceExtractEvent; +import org.bukkit.event.inventory.FurnaceSmeltEvent; +import org.bukkit.event.inventory.FurnaceStartSmeltEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +@Name("Furnace Times") +@Description({ + "The cook time, total cook time, and burn time of a furnace. Can be changed.", + "
    ", + "
  • cook time: The amount of time an item has been smelting for.
  • ", + "
  • total cook time: The amount of time required to finish smelting an item.
  • ", + "
  • burn time: The amount of time left for the current fuel until consumption of another fuel item.
  • ", + "
" +}) +@Examples({ + "set the cooking time of {_block} to 10", + "set the total cooking time of {_block} to 50", + "set the fuel burning time of {_block} to 100", + "on smelt:", + "\tif the fuel slot is charcoal:", + "\t\tadd 5 seconds to the fuel burn time" +}) +@Since("INSERT VERSION") +public class ExprFurnaceTime extends PropertyExpression { + + enum FurnaceExpressions { + COOKTIME("cook[ing] time", "cook time"), + TOTALCOOKTIME("total cook[ing] time", "total cook time"), + BURNTIME("fuel burn[ing] time", "fuel burn time"); + + private String pattern, toString; + + FurnaceExpressions(String pattern, String toString) { + this.pattern = pattern; + this.toString = toString; + } + + } + + private static final FurnaceExpressions[] furnaceExprs = FurnaceExpressions.values(); + + static { + + int size = furnaceExprs.length; + String[] patterns = new String[size * 2]; + for (FurnaceExpressions value : furnaceExprs) { + patterns[2 * value.ordinal()] = "[the] [furnace] " + value.pattern + " [of %blocks%]"; + patterns[2 * value.ordinal() + 1] = "%blocks%'[s]" + value.pattern; + } + + Skript.registerExpression(ExprFurnaceTime.class, Timespan.class, ExpressionType.PROPERTY, patterns); + } + + private FurnaceExpressions type; + private boolean explicitlyBlock = false; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + type = furnaceExprs[(int) Math2.floor( matchedPattern / 2)]; + if (exprs[0] != null) { + explicitlyBlock = true; + //noinspection unchecked + setExpr((Expression) exprs[0]); + } else { + if (!getParser().isCurrentEvent(FurnaceBurnEvent.class, FurnaceStartSmeltEvent.class, FurnaceExtractEvent.class, FurnaceSmeltEvent.class)) { + Skript.error("There's no furnace in a " + getParser().getCurrentEventName() + " event."); + return false; + } + explicitlyBlock = false; + setExpr(new EventValueExpression<>(Block.class)); + } + return true; + } + + @Override + protected Timespan @Nullable [] get(Event event, Block[] source) { + return get(source, block -> { + Furnace furnace = (block != null && block.getState() instanceof Furnace furnaceCheck) ? furnaceCheck : null; + switch (type) { + case COOKTIME -> { + return new Timespan(Timespan.TimePeriod.TICK, (int) furnace.getCookTime()); + } + case TOTALCOOKTIME -> { + if (event instanceof FurnaceStartSmeltEvent startEvent && block.equals(startEvent.getBlock())) { + return new Timespan(Timespan.TimePeriod.TICK, startEvent.getTotalCookTime()); + } else { + return new Timespan(Timespan.TimePeriod.TICK, furnace.getCookTimeTotal()); + } + } + case BURNTIME -> { + if (event instanceof FurnaceBurnEvent burnEvent && block.equals(burnEvent.getBlock())) { + return new Timespan(Timespan.TimePeriod.TICK, burnEvent.getBurnTime()); + } else { + return new Timespan(Timespan.TimePeriod.TICK, (int) furnace.getBurnTime()); + } + } + } + return null; + }); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.REMOVE_ALL || mode == ChangeMode.RESET) + return null; + + return CollectionUtils.array(Timespan.class); + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + int providedTime = 0; + if (delta != null && delta[0] instanceof Timespan span) + providedTime = (int) span.get(Timespan.TimePeriod.TICK); + int finalTime = providedTime; + + Function calculateTime = switch (mode) { + case SET -> time -> finalTime; + case ADD -> time -> Math2.fit(0, time + finalTime, Integer.MAX_VALUE); + case REMOVE -> time -> Math2.fit(0, time - finalTime, Integer.MAX_VALUE); + case DELETE -> time -> 0; + default -> throw new IllegalStateException("Unexpected value: " + mode); + }; + Function calculateTimeShort = switch (mode) { + case SET -> time -> (short) finalTime; + case ADD -> time -> (short) Math2.fit(0, time + finalTime, Short.MAX_VALUE); + case REMOVE -> time -> (short) Math2.fit(0, time - finalTime, Short.MAX_VALUE); + case DELETE -> time -> (short) 0; + default -> throw new IllegalStateException("Unexpected value: " + mode); + }; + + switch (type) { + case COOKTIME -> changeFurnaces(event, furnace -> change(furnace::setCookTime, furnace::getCookTime, calculateTimeShort)); + case TOTALCOOKTIME -> { + if (!explicitlyBlock && event instanceof FurnaceStartSmeltEvent smeltEvent) { + change(smeltEvent::setTotalCookTime, smeltEvent::getTotalCookTime, calculateTime); + } else { + changeFurnaces(event, furnace -> change(furnace::setCookTimeTotal, furnace::getCookTimeTotal, calculateTime)); + } + } + case BURNTIME -> { + if (!explicitlyBlock && event instanceof FurnaceBurnEvent burnEvent) { + change(burnEvent::setBurnTime, burnEvent::getBurnTime, calculateTime); + } else { + changeFurnaces(event, furnace -> change(furnace::setBurnTime, furnace::getBurnTime, calculateTimeShort)); + } + } + } + } + + /** + * Handler for setting data of furnace blocks + * @param event Event + * @param changer The consumer used to apply to the furnace blocks + */ + private void changeFurnaces(Event event, Consumer changer) { + for (Block block : getExpr().getArray(event)) { + Furnace furnace = (Furnace) block.getState(); + changer.accept(furnace); + furnace.update(true); + } + } + + private static void change(@NotNull Consumer set, @NotNull Supplier get, @NotNull Function calculateTime) { + set.accept(calculateTime.apply(get.get())); + } + + @Override + public boolean isSingle() { + return getExpr().isSingle(); + } + + @Override + public Class getReturnType() { + return Timespan.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return type.toString + " of " + getExpr().toString(event, debug); + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/syntaxes/events/EvtFurnaceTest.java b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/events/EvtFurnaceTest.java new file mode 100644 index 00000000000..45e0c678ad2 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/events/EvtFurnaceTest.java @@ -0,0 +1,59 @@ +package org.skriptlang.skript.test.tests.syntaxes.events; + +import ch.njol.skript.test.runner.SkriptJUnitTest; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.FurnaceBurnEvent; +import org.bukkit.event.inventory.FurnaceExtractEvent; +import org.bukkit.event.inventory.FurnaceSmeltEvent; +import org.bukkit.event.inventory.FurnaceStartSmeltEvent; +import org.bukkit.inventory.CookingRecipe; +import org.bukkit.inventory.FurnaceRecipe; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class EvtFurnaceTest extends SkriptJUnitTest { + + private Block furnace; + private CookingRecipe recipe; + private Player easyMockPlayer; + + @Before + public void setUp() { + furnace = setBlock(Material.FURNACE); + furnace.setType(Material.FURNACE); + for (Recipe goldIngotRecipe : Bukkit.getRecipesFor(new ItemStack(Material.GOLD_INGOT))) { + if (goldIngotRecipe instanceof FurnaceRecipe furnaceRecipe) { + recipe = furnaceRecipe; + break; + } + } + easyMockPlayer = EasyMock.niceMock(Player.class); + } + + @Test + public void callEvents() { + FurnaceBurnEvent burnEvent = new FurnaceBurnEvent(furnace, new ItemStack(Material.LAVA_BUCKET), 10); + FurnaceSmeltEvent smeltEvent = new FurnaceSmeltEvent(furnace, new ItemStack(Material.RAW_IRON), new ItemStack(Material.IRON_INGOT)); + FurnaceStartSmeltEvent startEvent = new FurnaceStartSmeltEvent(furnace, new ItemStack(Material.RAW_GOLD), recipe); + FurnaceExtractEvent extractEvent = new FurnaceExtractEvent(easyMockPlayer, furnace, Material.COPPER_INGOT, 10, 20); + + Bukkit.getPluginManager().callEvent(burnEvent); + Bukkit.getPluginManager().callEvent(smeltEvent); + Bukkit.getPluginManager().callEvent(startEvent); + Bukkit.getPluginManager().callEvent(extractEvent); + } + + @After + public void cleanUp() { + furnace.setType(Material.AIR); + } + +} diff --git a/src/test/skript/junit/EvtFurnaceTest.sk b/src/test/skript/junit/EvtFurnaceTest.sk new file mode 100644 index 00000000000..f65a04135ea --- /dev/null +++ b/src/test/skript/junit/EvtFurnaceTest.sk @@ -0,0 +1,42 @@ +options: + EvtFurnaceTest: "org.skriptlang.skript.test.tests.syntaxes.events.EvtFurnaceTest" + +on load: + set {_tests::1} to "smelt event" + set {_tests::2} to "smelt - got smelted item" + set {_tests::3} to "start smelt event" + set {_tests::4} to "start smelt - got smelting item" + set {_tests::5} to "fuel burn event" + set {_tests::6} to "fuel burn - got burned fuel item" + set {_tests::7} to "extract event" + set {_tests::8} to "extract - got extracted item" + set {_tests::9} to "extract - got player" + + ensure junit test {@EvtFurnaceTest} completes {_tests::*} + +on smelt: + junit test is {@EvtFurnaceTest} + complete objective "smelt event" for junit test {@EvtFurnaceTest} + broadcast "%smelted item%" + if smelted item is an iron ingot: + complete objective "smelt - got smelted item" for junit test {@EvtFurnaceTest} + +on start smelt: + junit test is {@EvtFurnaceTest} + complete objective "start smelt event" for junit test {@EvtFurnaceTest} + if smelting item is a raw gold: + complete objective "start smelt - got smelting item" for junit test {@EvtFurnaceTest} + +on fuel burn: + junit test is {@EvtFurnaceTest} + complete objective "fuel burn event" for junit test {@EvtFurnaceTest} + if burned fuel is a lava bucket: + complete objective "fuel burn - got burned fuel item" for junit test {@EvtFurnaceTest} + +on furnace extract: + junit test is {@EvtFurnaceTest} + complete objective "extract event" for junit test {@EvtFurnaceTest} + if extracted item is a copper ingot: + complete objective "extract - got extracted item" for junit test {@EvtFurnaceTest} + if event-player is set: + complete objective "extract - got player" for junit test {@EvtFurnaceTest} diff --git a/src/test/skript/tests/syntaxes/expressions/ExprFurnaceSlot.sk b/src/test/skript/tests/syntaxes/expressions/ExprFurnace.sk similarity index 64% rename from src/test/skript/tests/syntaxes/expressions/ExprFurnaceSlot.sk rename to src/test/skript/tests/syntaxes/expressions/ExprFurnace.sk index b7bf3a27e1a..111dbfcd714 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprFurnaceSlot.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprFurnace.sk @@ -29,3 +29,26 @@ test "furnace slot": # cleanup set test-block to air + +test "furnace expressions": + set {_loc} to location(0, 0, 0, world) + set block at {_loc} to furnace + set block at location(0, 0, 0, world) to furnace + set {_furnace} to block at location(0, 0, 0, world) + + set the cook time of {_furnace} to 10 seconds + assert the cook time of {_furnace} is 10 seconds with "Set furnace cook time to 10" + clear the cook time of {_furnace} + assert the cook time of {_furnace} is 0 seconds with "Clear furnace cook time" + + set the total cook time of {_furnace} to 20 seconds + assert the total cook time of {_furnace} is 20 seconds with "Set furnace total cook time to 20" + clear the total cook time of {_furnace} + assert the total cook time of {_furnace} is 0 seconds with "Clear furnace total cook time" + + set the fuel burn time of {_furnace} to 50 seconds + assert the fuel burn time of {_furnace} is 50 seconds with "Set furnace fuel burn time to 50" + clear the fuel burn time of {_furnace} + assert the fuel burn time of {_furnace} is 0 seconds with "Clear furnace fuel burn time" + + set block at location(0, 0, 0, world) to air