Skip to content

Commit

Permalink
Cleanup projectile events (#2426)
Browse files Browse the repository at this point in the history
* Initial work on `ProjectileHitScriptEvent`

* Deprecate `ProjectileCollideScriptEvent`

* Finish meta docs

* Remove old versions

* Only deprecated on 1.19+

* Cleanup `couldMatch`, check for edge cases

* Add version note to deprecation notice

* Cleanup deprecation messages

* Fixes from review

* Add note to `collides` event deprecation
  • Loading branch information
tal5 committed Jan 15, 2023
1 parent c31f472 commit 7841434
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 303 deletions.
@@ -1,7 +1,10 @@
package com.denizenscript.denizen.paper.events;

import com.denizenscript.denizen.events.BukkitScriptEvent;
import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.nms.NMSVersion;
import com.denizenscript.denizen.objects.EntityTag;
import com.denizenscript.denizen.utilities.BukkitImplDeprecations;
import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.scripts.ScriptEntryData;
Expand Down Expand Up @@ -32,12 +35,25 @@ public class ProjectileCollideScriptEvent extends BukkitScriptEvent implements L
// @Player When the entity collided with is a player.
// @NPC When the entity collided with is a NPC.
//
// @deprecated Use <@link event projectile hits> with the 'entity' switch on versions above 1.19.
//
// -->

public ProjectileCollideScriptEvent() {
registerCouldMatcher("<projectile> collides with <entity>");
}

@Override
public boolean couldMatch(ScriptPath path) {
if (!super.couldMatch(path)) {
return false;
}
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_19)) {
BukkitImplDeprecations.projectileCollideEvent.warn(path.container);
}
return true;
}

public ProjectileCollideEvent event;
public EntityTag projectile;
public EntityTag collidedWith;
Expand All @@ -63,13 +79,11 @@ public ScriptEntryData getScriptEntryData() {

@Override
public ObjectTag getContext(String name) {
if (name.equals("entity")) {
return collidedWith.getDenizenObject();
}
else if (name.equals("projectile")) {
return projectile;
}
return super.getContext(name);
return switch (name) {
case "entity" -> collidedWith.getDenizenObject();
case "projectile" -> projectile;
default -> super.getContext(name);
};
}

@EventHandler
Expand Down
Expand Up @@ -132,8 +132,7 @@ public static void registerMainEvents() {
ScriptEvent.registerScriptEvent(HorseJumpsScriptEvent.class);
ScriptEvent.registerScriptEvent(PiglinBarterScriptEvent.class);
ScriptEvent.registerScriptEvent(PigZappedScriptEvent.class);
ScriptEvent.registerScriptEvent(ProjectileHitsBlockScriptEvent.class);
ScriptEvent.registerScriptEvent(ProjectileHitsEntityScriptEvent.class);
ScriptEvent.registerScriptEvent(ProjectileHitScriptEvent.class);
ScriptEvent.registerScriptEvent(ProjectileLaunchedScriptEvent.class);
ScriptEvent.registerScriptEvent(SheepDyedScriptEvent.class);
ScriptEvent.registerScriptEvent(SheepRegrowsScriptEvent.class);
Expand Down
@@ -0,0 +1,157 @@
package com.denizenscript.denizen.events.entity;

import com.denizenscript.denizen.events.BukkitScriptEvent;
import com.denizenscript.denizen.objects.EntityTag;
import com.denizenscript.denizen.objects.LocationTag;
import com.denizenscript.denizen.objects.MaterialTag;
import com.denizenscript.denizen.utilities.BukkitImplDeprecations;
import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.scripts.ScriptEntryData;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.ProjectileHitEvent;

public class ProjectileHitScriptEvent extends BukkitScriptEvent implements Listener {

// <--[event]
// @Events
// <projectile> hits
//
// @Synonyms entity shoots
//
// @Switch entity:<entity> to only process the event if an entity got hit, and it matches the specified EntityTag matcher.
// @Switch block:<block> to only process the event if a block got hit, and it matches the specified LocationTag matcher.
// @Switch shooter:<entity> to only process the event if the projectile was shot by an entity, and it matches the specified EntityTag matcher.
//
// @Group Entity
//
// @Location true
//
// @Cancellable true
//
// @Triggers When a projectile hits a block or an entity.
//
// @Context
// <context.projectile> returns an EntityTag of the projectile.
// <context.hit_entity> returns an EntityTag of the entity that was hit, if any.
// <context.hit_block> returns a LocationTag of the block that was hit, if any.
// <context.hit_face> returns a LocationTag vector of the hit normal (like '0,1,0' if the projectile hit the top of a block).
// <context.shooter> returns an EntityTag of the entity that shot the projectile, if any.
//
// @Player when the entity that was hit is a player, or when the shooter is a player if no entity was hit.
//
// @NPC when the entity that was hit is a npc, or when the shooter is a npc if no entity was hit.
//
// -->

public ProjectileHitScriptEvent() {
registerCouldMatcher("<projectile> hits (<material>)");
registerCouldMatcher("<projectile> hits <entity>");
registerCouldMatcher("<entity> shoots <material> (with <projectile>)");
registerSwitches("entity", "block", "shooter", "with");
}

public ProjectileHitEvent event;
public LocationTag hitBlock;
public EntityTag hitEntity;
public EntityTag projectile;
public EntityTag shooter;

@Override
public boolean couldMatch(ScriptPath path) {
if (!super.couldMatch(path)) {
return false;
}
if (path.eventArgLowerAt(1).equals("shoots")) {
BukkitImplDeprecations.entityShootsMaterialEvent.warn(path.container);
}
else {
if (path.switches.containsKey("with")) { // 'with' is only valid for the deprecated 'entity shoots material' event
addPossibleCouldMatchFailReason("unrecognized switch name", "with");
return false;
}
if (path.eventArgs.length > 2) {
BukkitImplDeprecations.projectileHitsEventMatchers.warn(path.container);
}
}
return true;
}

@Override
public boolean matches(ScriptPath path) {
if (!path.tryObjectSwitch("entity", hitEntity)) {
return false;
}
if (!path.tryObjectSwitch("block", hitBlock)) {
return false;
}
if (!path.tryObjectSwitch("shooter", shooter)) {
return false;
}
if (path.eventArgLowerAt(1).equals("hits")) {
if (!path.tryArgObject(0, projectile)) {
return false;
}
if (path.eventArgs.length > 2 && !path.tryArgObject(2, hitEntity) && !path.tryArgObject(2, hitBlock)) {
return false;
}
}
else {
if (event.getHitBlock() == null || !path.tryArgObject(2, new MaterialTag(event.getHitBlock()))) {
return false;
}
if (!path.tryArgObject(0, shooter)) {
return false;
}
if (!path.tryObjectSwitch("with", projectile)) {
return false;
}
if (path.eventArgLowerAt(3).equals("with") && !path.tryArgObject(4, projectile)) {
return false;
}
}
if (!runInCheck(path, hitEntity != null ? hitEntity.getLocation() : hitBlock)) {
return false;
}
return super.matches(path);
}

@Override
public ObjectTag getContext(String name) {
return switch (name) {
case "projectile" -> projectile.getDenizenObject();
case "hit_entity" -> hitEntity != null ? hitEntity.getDenizenObject() : null;
case "hit_block" -> hitBlock;
case "hit_face" -> event.getHitBlockFace() != null ? new LocationTag(event.getHitBlockFace().getDirection()) : null;
case "shooter" -> shooter != null ? shooter.getDenizenObject() : null;
case "location" -> {
BukkitImplDeprecations.projectileHitsBlockLocationContext.warn();
yield hitBlock;
}
default -> super.getContext(name);
};
}

@Override
public ScriptEntryData getScriptEntryData() {
return new BukkitScriptEntryData(hitEntity != null ? hitEntity : shooter);
}

@EventHandler
public void onProjectileHit(ProjectileHitEvent event) {
this.event = event;
projectile = new EntityTag(event.getEntity());
// Additional checks for some rare edge-cases
if (projectile.getLocation() == null) {
return;
}
if (Double.isNaN(projectile.getLocation().getDirection().normalize().getX())) {
return;
}
hitBlock = event.getHitBlock() != null ? new LocationTag(event.getHitBlock().getLocation()) : null;
hitEntity = event.getHitEntity() != null ? new EntityTag(event.getHitEntity()) : null;
shooter = projectile.getShooter();
fire(event);
}
}

This file was deleted.

0 comments on commit 7841434

Please sign in to comment.