From 2441110d40c08c7f06111a0aa9133421f0e8a3cc Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 5 Mar 2023 10:49:03 +0000 Subject: [PATCH] Add `entity teleported by portal` Paper-only event (#2441) * Add `entity teleported by portal` event * Properly handle null target world in switch --- .../denizen/paper/PaperModule.java | 3 + .../EntityTeleportedByPortalScriptEvent.java | 101 ++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 paper/src/main/java/com/denizenscript/denizen/paper/events/EntityTeleportedByPortalScriptEvent.java diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java index c1c6fed7d7..f8aa8ff2f8 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java @@ -38,6 +38,9 @@ public static void init() { ScriptEvent.registerScriptEvent(EntityPathfindScriptEvent.class); ScriptEvent.registerScriptEvent(EntityRemoveFromWorldScriptEvent.class); ScriptEvent.registerScriptEvent(EntityStepsOnScriptEvent.class); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19)) { + ScriptEvent.registerScriptEvent(EntityTeleportedByPortalScriptEvent.class); + } ScriptEvent.registerScriptEvent(ExperienceOrbMergeScriptEvent.class); ScriptEvent.registerScriptEvent(PlayerAbsorbsExperienceScriptEvent.class); ScriptEvent.registerScriptEvent(PlayerBeaconEffectScriptEvent.class); diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/EntityTeleportedByPortalScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/EntityTeleportedByPortalScriptEvent.java new file mode 100644 index 0000000000..1a1d30162b --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/EntityTeleportedByPortalScriptEvent.java @@ -0,0 +1,101 @@ +package com.denizenscript.denizen.paper.events; + +import com.denizenscript.denizen.events.BukkitScriptEvent; +import com.denizenscript.denizen.objects.EntityTag; +import com.denizenscript.denizen.objects.WorldTag; +import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import io.papermc.paper.event.entity.EntityPortalReadyEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class EntityTeleportedByPortalScriptEvent extends BukkitScriptEvent implements Listener { + + // <--[event] + // @Events + // teleported by portal + // + // @Switch to: to only process the event if the world the entity is being teleported to matches the specified WorldTag matcher. + // @Switch portal_type: to only process the event if the portal's type matches the specified portal type. + // + // @Plugin Paper + // + // @Group Paper + // + // @Location true + // + // @Cancellable true + // + // @Triggers When an entity is about to be teleported by a portal (currently only fires for nether portals). + // + // @Context + // returns an EntityTag of the entity being teleported. + // returns a WorldTag of the world the entity is being teleported to. + // returns an ElementTag of the portal's type. Will be one of <@link url https://jd.papermc.io/paper/1.19/org/bukkit/PortalType.html>. + // + // @Determine + // "TARGET_WORLD:" + WorldTag to set the world the entity will be teleported to. + // "REMOVE_TARGET_WORLD" to remove the target world. Should usually cancel the event instead of using this. + // + // --> + + public EntityTeleportedByPortalScriptEvent() { + registerCouldMatcher(" teleported by portal"); + registerSwitches("to", "portal_type"); + } + + EntityPortalReadyEvent event; + + @Override + public boolean matches(ScriptPath path) { + if (!path.tryObjectSwitch("to", WorldTag.mirrorBukkitWorld(event.getTargetWorld()))) { + return false; + } + if (!runGenericSwitchCheck(path, "portal_type", event.getPortalType().name())) { + return false; + } + if (!path.tryArgObject(0, new EntityTag(event.getEntity()))) { + return false; + } + if (!runInCheck(path, event.getEntity().getLocation())) { + return false; + } + return super.matches(path); + } + + @Override + public ObjectTag getContext(String name) { + return switch (name) { + case "entity" -> new EntityTag(event.getEntity()); + case "target_world" -> event.getTargetWorld() != null ? new WorldTag(event.getTargetWorld()) : null; + case "portal_type" -> new ElementTag(event.getPortalType()); + default -> super.getContext(name); + }; + } + + @Override + public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) { + if (determinationObj instanceof ElementTag) { + String determination = CoreUtilities.toLowerCase(determinationObj.toString()); + if (determination.startsWith("target_world:")) { + WorldTag world = WorldTag.valueOf(determination.substring("target_world:".length()), getTagContext(path)); + if (world != null) { + event.setTargetWorld(world.getWorld()); + return true; + } + } + else if (determination.equals("remove_target_world")) { + event.setTargetWorld(null); + return true; + } + } + return super.applyDetermination(path, determinationObj); + } + + @EventHandler + public void onEntityPortalReady(EntityPortalReadyEvent event) { + this.event = event; + fire(event); + } +}