diff --git a/src/main/java/ch/njol/skript/effects/EffFireworkLaunch.java b/src/main/java/ch/njol/skript/effects/EffFireworkLaunch.java deleted file mode 100644 index 6f610ad6e4b..00000000000 --- a/src/main/java/ch/njol/skript/effects/EffFireworkLaunch.java +++ /dev/null @@ -1,94 +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.effects; - -import org.bukkit.FireworkEffect; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Firework; -import org.bukkit.event.Event; -import org.bukkit.inventory.meta.FireworkMeta; -import org.eclipse.jdt.annotation.Nullable; - -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.Since; -import ch.njol.skript.lang.Effect; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.util.Kleenean; - -@Name("Launch firework") -@Description("Launch firework effects at the given location(s).") -@Examples("launch ball large colored red, purple and white fading to light green and black at player's location with duration 1") -@Since("2.4") -public class EffFireworkLaunch extends Effect { - - static { - Skript.registerEffect(EffFireworkLaunch.class, "(launch|deploy) [[a] firework [with effect[s]]] %fireworkeffects% at %locations% [([with] (duration|power)|timed) %number%]"); - } - - @Nullable - public static Entity lastSpawned = null; - - @SuppressWarnings("NotNullFieldNotInitialized") - private Expression effects; - @SuppressWarnings("NotNullFieldNotInitialized") - private Expression locations; - @SuppressWarnings("NotNullFieldNotInitialized") - private Expression lifetime; - - @Override - @SuppressWarnings("unchecked") - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - effects = (Expression) exprs[0]; - locations = (Expression) exprs[1]; - lifetime = (Expression) exprs[2]; - return true; - } - - @Override - protected void execute(Event event) { - FireworkEffect[] effects = this.effects.getArray(event); - int power = lifetime.getOptionalSingle(event).orElse(1).intValue(); - power = Math.min(127, Math.max(0, power)); - for (Location location : locations.getArray(event)) { - World world = location.getWorld(); - if (world == null) - continue; - Firework firework = world.spawn(location, Firework.class); - FireworkMeta meta = firework.getFireworkMeta(); - meta.addEffects(effects); - meta.setPower(power); - firework.setFireworkMeta(meta); - lastSpawned = firework; - } - } - - @Override - public String toString(@Nullable Event event, boolean debug) { - return "Launch firework(s) " + effects.toString(event, debug) + - " at location(s) " + locations.toString(event, debug) + - " timed " + lifetime.toString(event, debug); - } - -} diff --git a/src/main/java/ch/njol/skript/entity/EntityData.java b/src/main/java/ch/njol/skript/entity/EntityData.java index 8d6bf363440..c52d841bd75 100644 --- a/src/main/java/ch/njol/skript/entity/EntityData.java +++ b/src/main/java/ch/njol/skript/entity/EntityData.java @@ -40,6 +40,7 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.eclipse.jdt.annotation.Nullable; +import org.jetbrains.annotations.ApiStatus.ScheduledForRemoval; import ch.njol.skript.Skript; import ch.njol.skript.SkriptAPIException; @@ -674,8 +675,14 @@ protected boolean deserialize(final String s) { return false; } - @SuppressWarnings({"unchecked", "deprecation"}) - protected static @Nullable E spawn(Location location, Class type, Consumer consumer) { + /** + * Utility method to handle Bukkit changing from org.bukkit.util.Consumer to java Consumer. + * Subject to removal in the future, when some older versions get dropped. + */ + @Deprecated + @ScheduledForRemoval + @SuppressWarnings("unchecked") + public static @Nullable E spawn(Location location, Class type, Consumer consumer) { World world = location.getWorld(); if (world == null) return null; diff --git a/src/main/java/ch/njol/skript/expressions/ExprLastSpawnedEntity.java b/src/main/java/ch/njol/skript/expressions/ExprLastSpawnedEntity.java index 92bd4ea8e35..2de4f5e3f45 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprLastSpawnedEntity.java +++ b/src/main/java/ch/njol/skript/expressions/ExprLastSpawnedEntity.java @@ -20,9 +20,6 @@ import java.lang.reflect.Array; -import ch.njol.skript.effects.EffFireworkLaunch; -import ch.njol.skript.sections.EffSecSpawn; -import ch.njol.util.coll.CollectionUtils; import org.bukkit.entity.Entity; import org.bukkit.entity.Firework; import org.bukkit.entity.Item; @@ -44,12 +41,18 @@ import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.skript.sections.EffSecFireworkLaunch; +import ch.njol.skript.sections.EffSecSpawn; import ch.njol.util.Kleenean; @Name("Last Spawned Entity") -@Description("Holds the entity that was spawned most recently with the spawn effect (section), dropped with the drop effect, shot with the shoot effect or created with the lightning effect. " + - "Please note that even though you can spawn multiple mobs simultaneously (e.g. with 'spawn 5 creepers'), only the last spawned mob is saved and can be used. " + - "If you spawn an entity, shoot a projectile and drop an item you can however access all them together.") +@Description({ + "Holds the entity that was spawned most recently with the spawn effect (section), dropped with the drop effect,", + "shot with the shoot effect, launched firework firework launch effect section,", + "or created with the lightning effect.", + "Please note that even though you can spawn multiple mobs simultaneously (e.g. with 'spawn 5 creepers'), only the last spawned mob is saved and can be used.", + "If you spawn an entity, shoot a projectile and drop an item you can however access all them together." +}) @Examples({ "spawn a priest", "set {healer::%spawned priest%} to true", @@ -62,16 +65,15 @@ }) @Since("1.3 (spawned entity), 2.0 (shot entity), 2.2-dev26 (dropped item), 2.7 (struck lightning, firework)") public class ExprLastSpawnedEntity extends SimpleExpression { - + static { Skript.registerExpression(ExprLastSpawnedEntity.class, Entity.class, ExpressionType.SIMPLE, - "[the] [last[ly]] (0:spawned|1:shot) %*entitydata%", - "[the] [last[ly]] dropped (2:item)", - "[the] [last[ly]] (created|struck) (3:lightning)", - "[the] [last[ly]] (launched|deployed) (4:firework)"); + "[the] [last[ly]] (0:spawned|1:shot) %*entitydata%", + "[the] [last[ly]] dropped (2:item)", + "[the] [last[ly]] (created|struck) (3:lightning)", + "[the] [last[ly]] (launched|deployed) (4:firework)"); } - - @SuppressWarnings("NotNullFieldNotInitialized") + private EntityData type; private int from; @@ -90,51 +92,51 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye } return true; } - + @Override @Nullable protected Entity[] get(Event event) { - Entity en; + Entity entity; switch (from) { case 0: - en = EffSecSpawn.lastSpawned; + entity = EffSecSpawn.lastSpawned; break; case 1: - en = EffShoot.lastSpawned; + entity = EffShoot.lastSpawned; break; case 2: - en = EffDrop.lastSpawned; + entity = EffDrop.lastSpawned; break; case 3: - en = EffLightning.lastSpawned; + entity = EffLightning.lastSpawned; break; case 4: - en = EffFireworkLaunch.lastSpawned; + entity = EffSecFireworkLaunch.lastSpawned; break; default: - en = null; + entity = null; } - if (en == null) + if (entity == null) return null; - if (!type.isInstance(en)) + if (!type.isInstance(entity)) return null; Entity[] one = (Entity[]) Array.newInstance(type.getType(), 1); - one[0] = en; + one[0] = entity; return one; } - + @Override public boolean isSingle() { return true; } - + @Override public Class getReturnType() { return type.getType(); } - + @Override public String toString(@Nullable Event event, boolean debug) { String word = ""; @@ -157,7 +159,7 @@ public String toString(@Nullable Event event, boolean debug) { default: assert false; } - return "the last " + word + " " + type; + return "last " + word + " " + type; } - + } diff --git a/src/main/java/ch/njol/skript/sections/EffSecFireworkLaunch.java b/src/main/java/ch/njol/skript/sections/EffSecFireworkLaunch.java new file mode 100644 index 00000000000..1327756be6a --- /dev/null +++ b/src/main/java/ch/njol/skript/sections/EffSecFireworkLaunch.java @@ -0,0 +1,175 @@ +/** + * 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.sections; + +import java.util.List; +import java.util.function.Consumer; + +import org.bukkit.FireworkEffect; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Firework; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.meta.FireworkMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import ch.njol.skript.Skript; +import ch.njol.skript.config.SectionNode; +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.entity.EntityData; +import ch.njol.skript.lang.EffectSection; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.Trigger; +import ch.njol.skript.lang.TriggerItem; +import ch.njol.skript.registrations.EventValues; +import ch.njol.skript.util.Getter; +import ch.njol.skript.variables.Variables; +import ch.njol.util.Kleenean; + +@Name("Launch Firework") +@Description({ + "Launch firework effects at the given location(s).", + "This can be used as an effect and as a section.", + "If it is used as a section, the section is run before the entity is added to the world.", + "You can modify the firework in this section, using for example event-entity.", + "Do note that other event values, such as player, won't work in this section." +}) +@Examples({ + "launch ball large coloured red, purple and white fading to light green and black at player's location with duration 1", + "", + "command /firework:", + "\ttrigger:", + "\t\tlaunch a firework with effects ball large coloured red at player:", + "\t\t\tset metadata value \"cancel damage\" of event-entity to true", + "", + "# Firework launch section example", + "on damage:", + "\tdamage cause is entity explosion", + "\tmetadata value \"cancel damage\" of event-projectile is true", + "\tcancel event", +}) +@Since("2.4, INSERT VERSION (section)") +public class EffSecFireworkLaunch extends EffectSection { + + public static class FireworkSectionLaunchEvent extends Event { + + private final Firework firework; + + public FireworkSectionLaunchEvent(Firework firework) { + this.firework = firework; + } + + public Firework getFirework() { + return firework; + } + + @Override + @NotNull + public HandlerList getHandlers() { + throw new IllegalStateException(); + } + + } + + static { + Skript.registerSection(EffSecFireworkLaunch.class, "(launch|deploy) [[a] firework [with effect[s]]] %fireworkeffects% at %locations% [([with] (duration|power)|timed) %-number%]"); + EventValues.registerEventValue(FireworkSectionLaunchEvent.class, Firework.class, new Getter() { + @Override + public Firework get(FireworkSectionLaunchEvent fireworkLaunchEvent) { + return fireworkLaunchEvent.getFirework(); + } + }, EventValues.TIME_NOW); + } + + private Expression effects; + private Expression locations; + + @Nullable + public static Entity lastSpawned; + + @Nullable + private Expression power; + + @Nullable + private Trigger trigger; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult, + @Nullable SectionNode sectionNode, @Nullable List triggerItems) { + + effects = (Expression) exprs[0]; + locations = (Expression) exprs[1]; + power = (Expression) exprs[2]; + + if (sectionNode != null) + trigger = loadCode(sectionNode, "firework launch", FireworkSectionLaunchEvent.class); + + return true; + } + + @Override + @Nullable + protected TriggerItem walk(Event event) { + FireworkEffect[] effects = this.effects.getArray(event); + // Uses org.bukkit consumer for older versions support. If newer, bukkit maps this class to java utils. + Consumer consumer = null; + if (trigger != null) { + consumer = firework -> { + FireworkSectionLaunchEvent fireworkLaunchEvent = new FireworkSectionLaunchEvent(firework); + Variables.setLocalVariables(fireworkLaunchEvent, Variables.copyLocalVariables(event)); + TriggerItem.walk(trigger, fireworkLaunchEvent); + Variables.setLocalVariables(event, Variables.copyLocalVariables(fireworkLaunchEvent)); + Variables.removeLocals(fireworkLaunchEvent); + }; + } + + int power = this.power != null ? this.power.getOptionalSingle(event).orElse(1).intValue() : 1; + for (Location location : locations.getArray(event)) { + World world = location.getWorld(); + if (world == null) + continue; + @SuppressWarnings("deprecation") + Firework firework = EntityData.spawn(location, Firework.class, consumer); + FireworkMeta meta = firework.getFireworkMeta(); + meta.addEffects(effects); + meta.setPower(power); + firework.setFireworkMeta(meta); + lastSpawned = firework; + } + + return super.walk(event, false); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "launch fireworks " + effects.toString(event, debug) + + " at " + locations.toString(event, debug) + + " timed " + (power != null ? power.toString(event, debug) : "1"); + } + +} diff --git a/src/test/skript/tests/syntaxes/sections/EffSecFireworkLaunch.sk b/src/test/skript/tests/syntaxes/sections/EffSecFireworkLaunch.sk new file mode 100644 index 00000000000..08977631b1b --- /dev/null +++ b/src/test/skript/tests/syntaxes/sections/EffSecFireworkLaunch.sk @@ -0,0 +1,10 @@ +test "firework launch section": + set {_foo} to true + launch a firework with effects ball large coloured red at spawn of "world": + assert {_foo} is true with "variables from previous section wasn't carried over" + set {_foo} to false + assert event-entity is a firework with "entity should be a firework but is %event-entity%" + assert location of event-entity is set with "location of firework is not set" + set metadata value "test" of event-entity to true + assert metadata value "test" of event-entity is true with "metadata value not true (check from section)" + assert {_foo} is false with "variables from launch section wasn't carried over"