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 0c3175247b1..148e0609171 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java @@ -84,6 +84,8 @@ import org.bukkit.event.block.BlockIgniteEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.block.BellRingEvent; +import org.bukkit.event.block.BellResonateEvent; import org.bukkit.event.enchantment.EnchantItemEvent; import org.bukkit.event.enchantment.PrepareItemEnchantEvent; import org.bukkit.event.entity.AreaEffectCloudApplyEvent; @@ -1799,6 +1801,44 @@ public TransformReason get(EntityTransformEvent event) { } }, EventValues.TIME_NOW); + // BellRingEvent - these are BlockEvents and not EntityEvents, so they have declared methods for getEntity() + if (Skript.classExists("org.bukkit.event.block.BellRingEvent")) { + EventValues.registerEventValue(BellRingEvent.class, Entity.class, new Getter() { + @Override + @Nullable + public Entity get(BellRingEvent event) { + return event.getEntity(); + } + }, EventValues.TIME_NOW); + + EventValues.registerEventValue(BellRingEvent.class, Direction.class, new Getter() { + @Override + public Direction get(BellRingEvent event) { + return new Direction(event.getDirection(), 1); + } + }, EventValues.TIME_NOW); + } else if (Skript.classExists("io.papermc.paper.event.block.BellRingEvent")) { + EventValues.registerEventValue( + io.papermc.paper.event.block.BellRingEvent.class, Entity.class, + new Getter() { + @Override + @Nullable + public Entity get(io.papermc.paper.event.block.BellRingEvent event) { + return event.getEntity(); + } + }, EventValues.TIME_NOW); + } + + if (Skript.classExists("org.bukkit.event.block.BellResonateEvent")) { + EventValues.registerEventValue(BellResonateEvent.class, Entity[].class, new Getter() { + @Override + @Nullable + public Entity[] get(BellResonateEvent event) { + return event.getResonatedEntities().toArray(new LivingEntity[0]); + } + }, EventValues.TIME_NOW); + } + // InventoryMoveItemEvent EventValues.registerEventValue(InventoryMoveItemEvent.class, Inventory.class, new Getter() { @Override @@ -1830,7 +1870,5 @@ public ItemStack get(InventoryMoveItemEvent event) { return event.getItem(); } }, EventValues.TIME_NOW); - } - } diff --git a/src/main/java/ch/njol/skript/conditions/CondIsResonating.java b/src/main/java/ch/njol/skript/conditions/CondIsResonating.java new file mode 100644 index 00000000000..c2614aaead1 --- /dev/null +++ b/src/main/java/ch/njol/skript/conditions/CondIsResonating.java @@ -0,0 +1,58 @@ +/** + * 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.conditions; + +import ch.njol.skript.Skript; +import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import org.bukkit.block.Bell; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; + +@Name("Bell Is Resonating") +@Description({ + "Checks to see if a bell is currently resonating.", + "A bell will start resonating five game ticks after being rung, and will continue to resonate for 40 game ticks." +}) +@Examples("target block is resonating") +@RequiredPlugins("Spigot 1.19.4+") +@Since("INSERT VERSION") +public class CondIsResonating extends PropertyCondition { + + static { + if (Skript.classExists("org.bukkit.block.Bell") && Skript.methodExists(Bell.class, "isResonating")) + register(CondIsResonating.class, "resonating", "blocks"); + } + + @Override + public boolean check(Block value) { + BlockState state = value.getState(false); + return state instanceof Bell && ((Bell) state).isResonating(); + } + + @Override + protected String getPropertyName() { + return "resonating"; + } + +} diff --git a/src/main/java/ch/njol/skript/conditions/CondIsRinging.java b/src/main/java/ch/njol/skript/conditions/CondIsRinging.java new file mode 100644 index 00000000000..c7ddca50b1a --- /dev/null +++ b/src/main/java/ch/njol/skript/conditions/CondIsRinging.java @@ -0,0 +1,55 @@ +/** + * 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.conditions; + +import ch.njol.skript.Skript; +import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import org.bukkit.block.Bell; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; + +@Name("Bell Is Ringing") +@Description("Checks to see if a bell is currently ringing. A bell typically rings for 50 game ticks.") +@Examples("target block is ringing") +@RequiredPlugins("Spigot 1.19.4+") +@Since("INSERT VERSION") +public class CondIsRinging extends PropertyCondition { + + static { + if (Skript.classExists("org.bukkit.block.Bell") && Skript.methodExists(Bell.class, "isShaking")) + register(CondIsRinging.class, "ringing", "blocks"); + } + + @Override + public boolean check(Block value) { + BlockState state = value.getState(false); + return state instanceof Bell && ((Bell) state).isShaking(); + } + + @Override + protected String getPropertyName() { + return "ringing"; + } + +} diff --git a/src/main/java/ch/njol/skript/effects/EffRing.java b/src/main/java/ch/njol/skript/effects/EffRing.java new file mode 100644 index 00000000000..8b66e1ce488 --- /dev/null +++ b/src/main/java/ch/njol/skript/effects/EffRing.java @@ -0,0 +1,110 @@ +/** + * 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.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.Direction; +import ch.njol.util.Kleenean; +import org.bukkit.block.Bell; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Entity; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +@Name("Ring Bell") +@Description({ + "Causes a bell to ring.", + "Optionally, the entity that rang the bell and the direction the bell should ring can be specified.", + "A bell can only ring in two directions, and the direction is determined by which way the bell is facing.", + "By default, the bell will ring in the direction it is facing.", +}) +@Examples({"make player ring target-block"}) +@RequiredPlugins("Spigot 1.19.4+") +@Since("INSERT VERSION") +public class EffRing extends Effect { + + static { + if (Skript.classExists("org.bukkit.block.Bell") && Skript.methodExists(Bell.class, "ring", Entity.class, BlockFace.class)) + Skript.registerEffect(EffRing.class, + "ring %blocks% [from [the]] [%-direction%]", + "(make|let) %entity% ring %blocks% [from [the]] [%-direction%]" + ); + } + + @Nullable + private Expression entity; + + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression blocks; + + @Nullable + private Expression direction; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + entity = matchedPattern == 0 ? null : (Expression) exprs[0]; + blocks = (Expression) exprs[matchedPattern]; + direction = (Expression) exprs[matchedPattern + 1]; + return true; + } + + @Nullable + private BlockFace getBlockFace(Event event) { + if (this.direction == null) + return null; + + Direction direction = this.direction.getSingle(event); + if (direction == null) + return null; + + return Direction.getFacing(direction.getDirection(), true); + } + + @Override + protected void execute(Event event) { + BlockFace blockFace = getBlockFace(event); + Entity actualEntity = entity == null ? null : entity.getSingle(event); + + for (Block block : blocks.getArray(event)) { + BlockState state = block.getState(false); + if (state instanceof Bell) { + Bell bell = (Bell) state; + bell.ring(actualEntity, blockFace); + } + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return (entity != null ? "make " + entity.toString(event, debug) + " " : "") + + "ring " + blocks.toString(event, debug) + " from " + (direction != null ? direction.toString(event, debug) : ""); + } + +} diff --git a/src/main/java/ch/njol/skript/events/SimpleEvents.java b/src/main/java/ch/njol/skript/events/SimpleEvents.java index 4a7b7300430..1e2d6847050 100644 --- a/src/main/java/ch/njol/skript/events/SimpleEvents.java +++ b/src/main/java/ch/njol/skript/events/SimpleEvents.java @@ -32,6 +32,7 @@ import io.papermc.paper.event.player.PlayerDeepSleepEvent; import io.papermc.paper.event.player.PlayerInventorySlotChangeEvent; import io.papermc.paper.event.player.PlayerTradeEvent; +import org.bukkit.event.Event; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockDamageEvent; import org.bukkit.event.block.BlockFertilizeEvent; @@ -740,6 +741,45 @@ public class SimpleEvents { ) .since("2.7"); + { + final Class eventClass; + if (Skript.classExists("org.bukkit.event.block.BellRingEvent")) { + eventClass = org.bukkit.event.block.BellRingEvent.class; + } else if (Skript.classExists("io.papermc.paper.event.block.BellRingEvent")) { + //noinspection deprecation + eventClass = io.papermc.paper.event.block.BellRingEvent.class; + } else { + eventClass = null; + } + + if (eventClass != null) { + Skript.registerEvent("Bell Ring", SimpleEvent.class, eventClass, "bell ring[ing]") + .description("Called when a bell is rung.") + .examples( + "on bell ring:", + "\tsend \"Ding-dong!\" to all players in radius 10 of event-block" + ) + .since("INSERT VERSION") + .requiredPlugins("Spigot 1.19.4+ or Paper 1.16.5+ (no event-direction)"); + } + } + + /* + * Paper supported this in 1.16.5 via io.papermc.paper.event.block.BellRevealRaiderEvent. + * The Paper event, however, is called for each raider, while the Spigot event is called once for all raiders. + * Supporting both would cause confusing behaviour, with the event being triggered in different ways depending + * on the server software and version, so we're only supporting the Spigot event. + */ + if (Skript.classExists("org.bukkit.event.block.BellResonateEvent")) { + Skript.registerEvent("Bell Resonate", SimpleEvent.class, org.bukkit.event.block.BellResonateEvent.class, "bell resonat(e|ing)") + .description("Called when a bell resonates, highlighting nearby raiders.") + .examples( + "on bell resonate:", + "\tsend \"Raiders are nearby!\" to all players in radius 32 around event-block" + ) + .since("INSERT VERSION") + .requiredPlugins("Spigot 1.19.4+"); + } } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprResonatingTime.java b/src/main/java/ch/njol/skript/expressions/ExprResonatingTime.java new file mode 100644 index 00000000000..58426835823 --- /dev/null +++ b/src/main/java/ch/njol/skript/expressions/ExprResonatingTime.java @@ -0,0 +1,69 @@ +/** + * 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.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.Timespan; +import org.bukkit.block.Bell; +import org.bukkit.block.Block; +import org.eclipse.jdt.annotation.Nullable; + +@Name("Resonating Time") +@Description({ + "Returns the resonating time of a bell.", + "A bell will start resonating five game ticks after being rung, and will continue to resonate for 40 game ticks." +}) +@Examples("broadcast \"The bell has been resonating for %resonating time of target block%\"") +@RequiredPlugins("Spigot 1.19.4+") +@Since("INSERT VERSION") +public class ExprResonatingTime extends SimplePropertyExpression { + + static { + if (Skript.classExists("org.bukkit.block.Bell") && Skript.methodExists(Bell.class, "getResonatingTicks")) { + register(ExprResonatingTime.class, Timespan.class, "resonat(e|ing) time", "block"); + } + } + + @Override + @Nullable + public Timespan convert(Block from) { + if (from.getState() instanceof Bell) { + int resonatingTicks = ((Bell) from.getState(false)).getResonatingTicks(); + return resonatingTicks == 0 ? null : Timespan.fromTicks(resonatingTicks); + } + return null; + } + + @Override + protected String getPropertyName() { + return "resonating time"; + } + + @Override + public Class getReturnType() { + return Timespan.class; + } + +} diff --git a/src/main/java/ch/njol/skript/expressions/ExprRingingTime.java b/src/main/java/ch/njol/skript/expressions/ExprRingingTime.java new file mode 100644 index 00000000000..482f7e0c2cf --- /dev/null +++ b/src/main/java/ch/njol/skript/expressions/ExprRingingTime.java @@ -0,0 +1,67 @@ +/** + * 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.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.Timespan; +import org.bukkit.block.Bell; +import org.bukkit.block.Block; +import org.eclipse.jdt.annotation.Nullable; + +@Name("Ringing Time") +@Description({ + "Returns the ringing time of a bell.", + "A bell typically rings for 50 game ticks." +}) +@Examples("broadcast \"The bell has been ringing for %ringing time of target block%\"") +@RequiredPlugins("Spigot 1.19.4+") +@Since("INSERT VERSION") +public class ExprRingingTime extends SimplePropertyExpression { + + static { + if (Skript.classExists("org.bukkit.block.Bell") && Skript.methodExists(Bell.class, "getShakingTicks")) + register(ExprRingingTime.class, Timespan.class, "ring[ing] time", "block"); + } + + @Override + public @Nullable Timespan convert(Block from) { + if (from.getState() instanceof Bell) { + int shakingTicks = ((Bell) from.getState(false)).getShakingTicks(); + return shakingTicks == 0 ? null : Timespan.fromTicks(shakingTicks); + } + return null; + } + + @Override + protected String getPropertyName() { + return "ringing time"; + } + + @Override + public Class getReturnType() { + return Timespan.class; + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/syntaxes/events/BellEventsTest.java b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/events/BellEventsTest.java new file mode 100644 index 00000000000..07163771783 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/events/BellEventsTest.java @@ -0,0 +1,81 @@ +/** + * 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 org.skriptlang.skript.test.tests.syntaxes.events; + +import ch.njol.skript.Skript; +import ch.njol.skript.test.runner.SkriptJUnitTest; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Pillager; +import org.bukkit.event.Event; +import org.bukkit.event.block.BellResonateEvent; +import org.bukkit.event.block.BellRingEvent; +import org.junit.Before; +import org.junit.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class BellEventsTest extends SkriptJUnitTest { + + private static final boolean canRun = Skript.classExists("org.bukkit.block.Bell"); + + private Block bell; + private LivingEntity pillager; + + @Before + public void setUp() { + if (!canRun) + return; + this.bell = setBlock(Material.BELL); + this.pillager = getTestWorld().spawn(bell.getLocation().add(0, 1, 0), Pillager.class); + setShutdownDelay(1); + } + + @Test + public void testEvents() { + if (!canRun) + return; + Set events = new HashSet<>(); + if (Skript.classExists("org.bukkit.event.block.BellRingEvent")) { + events.add(new BellRingEvent(this.bell, BlockFace.EAST, null)); + } else if (Skript.classExists("io.papermc.paper.event.block.BellRingEvent")) { + try { + events.add(io.papermc.paper.event.block.BellRingEvent.class.getConstructor(Block.class, Entity.class) + .newInstance(this.bell, null)); + } catch (ReflectiveOperationException ignored) { + } + + } + + if (Skript.classExists("org.bukkit.event.block.BellResonateEvent")) + events.add(new BellResonateEvent(this.bell, Collections.singletonList(this.pillager))); + + for (Event event : events) + Bukkit.getPluginManager().callEvent(event); + } + +} diff --git a/src/test/skript/junit/-BellEventsPaper.sk b/src/test/skript/junit/-BellEventsPaper.sk new file mode 100644 index 00000000000..61afbd566f5 --- /dev/null +++ b/src/test/skript/junit/-BellEventsPaper.sk @@ -0,0 +1,5 @@ +# This file contains events we can run on Paper 1.16.5+ + +on bell ringing: + junit test is "org.skriptlang.skript.test.tests.syntaxes.events.BellEventsTest" + complete objective "bell rings" for junit test "org.skriptlang.skript.test.tests.syntaxes.events.BellEventsTest" diff --git a/src/test/skript/junit/-BellEventsSpigot.sk b/src/test/skript/junit/-BellEventsSpigot.sk new file mode 100644 index 00000000000..cf33b09aff5 --- /dev/null +++ b/src/test/skript/junit/-BellEventsSpigot.sk @@ -0,0 +1,10 @@ +# This file contains tests we can run on Spigot 1.19.4+ + +on bell ringing: + junit test is "org.skriptlang.skript.test.tests.syntaxes.events.BellEventsTest" + complete objective "bell rings" for junit test "org.skriptlang.skript.test.tests.syntaxes.events.BellEventsTest" + +on bell resonating: + junit test is "org.skriptlang.skript.test.tests.syntaxes.events.BellEventsTest" + complete objective "bell resonates" for junit test "org.skriptlang.skript.test.tests.syntaxes.events.BellEventsTest" + assert size of event-entities is greater than or equal to 1 with "bell did not reveal the pillager" diff --git a/src/test/skript/junit/BellEvents.sk b/src/test/skript/junit/BellEvents.sk new file mode 100644 index 00000000000..7a502fdddbd --- /dev/null +++ b/src/test/skript/junit/BellEvents.sk @@ -0,0 +1,21 @@ +test "BellEventsTest" when running JUnit: + set {_slashIndex} to last index of "/" in "%script%.sk" + set {_parent} to substring of "%script%.sk" from 0 to {_slashIndex} + + if running below minecraft "1.19.4": + complete objective "bell resonates" for junit test "org.skriptlang.skript.test.tests.syntaxes.events.BellEventsTest" + if running below minecraft "1.16.5": + complete objective "bell rings" for junit test "org.skriptlang.skript.test.tests.syntaxes.events.BellEventsTest" + else: + load script "%{_parent}%-BellEventsPaper.sk" + else: + load script "%{_parent}%-BellEventsSpigot.sk" + + ensure junit test "org.skriptlang.skript.test.tests.syntaxes.events.BellEventsTest" completes "bell resonates" + ensure junit test "org.skriptlang.skript.test.tests.syntaxes.events.BellEventsTest" completes "bell rings" + +on script unload: + set {_slashIndex} to last index of "/" in "%script%.sk" + set {_parent} to substring of "%script%.sk" from 0 to {_slashIndex} + disable script "%{_parent}%BellEventsSpigot.sk" + disable script "%{_parent}%BellEventsPaper.sk"