From 9704f1493c0180b77940f28fe016632756eb6b65 Mon Sep 17 00:00:00 2001 From: fullwall Date: Mon, 12 Jun 2023 21:20:51 +0800 Subject: [PATCH] Implement new push / knockback events --- .../java/net/citizensnpcs/EventListen.java | 89 +++++++++++++++++++ .../citizensnpcs/commands/NPCCommands.java | 4 +- .../main/java/net/citizensnpcs/util/NMS.java | 22 ++++- .../main/java/net/citizensnpcs/util/Util.java | 2 +- .../nms/v1_19_R3/entity/EntityHumanNPC.java | 9 +- .../nms/v1_20_R1/entity/EntityHumanNPC.java | 9 +- 6 files changed, 116 insertions(+), 19 deletions(-) diff --git a/main/src/main/java/net/citizensnpcs/EventListen.java b/main/src/main/java/net/citizensnpcs/EventListen.java index e5739e557..3d13483c1 100644 --- a/main/src/main/java/net/citizensnpcs/EventListen.java +++ b/main/src/main/java/net/citizensnpcs/EventListen.java @@ -1,5 +1,6 @@ package net.citizensnpcs; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -19,6 +20,7 @@ import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.block.EntityBlockFormEvent; import org.bukkit.event.entity.CreatureSpawnEvent; @@ -58,7 +60,9 @@ import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.RegisteredListener; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; import com.google.common.base.Joiner; import com.google.common.base.Predicates; @@ -84,7 +88,9 @@ import net.citizensnpcs.api.event.NPCDamageEntityEvent; import net.citizensnpcs.api.event.NPCDamageEvent; import net.citizensnpcs.api.event.NPCDeathEvent; import net.citizensnpcs.api.event.NPCDespawnEvent; +import net.citizensnpcs.api.event.NPCKnockbackEvent; import net.citizensnpcs.api.event.NPCLeftClickEvent; +import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.event.NPCRemoveEvent; import net.citizensnpcs.api.event.NPCRightClickEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; @@ -98,6 +104,7 @@ import net.citizensnpcs.api.trait.trait.Owner; import net.citizensnpcs.api.trait.trait.PlayerFilter; import net.citizensnpcs.api.util.Messaging; import net.citizensnpcs.editor.Editor; +import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.npc.skin.SkinUpdateTracker; import net.citizensnpcs.trait.ClickRedirectTrait; import net.citizensnpcs.trait.CommandTrait; @@ -150,6 +157,26 @@ public class EventListen implements Listener { }, CitizensAPI.getPlugin()); } catch (Throwable ex) { } + + Class kbc = null; + try { + kbc = Class.forName("com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent"); + } catch (ClassNotFoundException e) { + } + + if (kbc != null) { + registerKnockbackEvent(kbc); + } + + Class pbeac = null; + try { + pbeac = Class.forName("io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent"); + } catch (ClassNotFoundException e) { + } + + if (pbeac != null) { + registerPushEvent(pbeac); + } } private void checkCreationEvent(CommandSenderCreateNPCEvent event) { @@ -665,6 +692,68 @@ public class EventListen implements Listener { CitizensAPI.getLocationLookup().onWorldUnload(event); } + private void registerKnockbackEvent(Class kbc) { + try { + HandlerList handlers = (HandlerList) kbc.getMethod("getHandlerList").invoke(null); + Method getEntity = kbc.getMethod("getEntity"); + Method getHitBy = kbc.getMethod("getHitBy"); + Method getKnockbackStrength = kbc.getMethod("getKnockbackStrength"); + Method getAcceleration = kbc.getMethod("getAcceleration"); + handlers.register(new RegisteredListener(new Listener() { + }, (listener, event) -> { + if (NPCKnockbackEvent.getHandlerList().getRegisteredListeners().length == 0) + return; + try { + Entity entity = (Entity) getEntity.invoke(event); + if (!(entity instanceof NPCHolder)) + return; + NPC npc = ((NPCHolder) entity).getNPC(); + Entity hitBy = (Entity) getHitBy.invoke(event); + float strength = (float) getKnockbackStrength.invoke(event); + Vector vector = (Vector) getAcceleration.invoke(event); + NPCKnockbackEvent kb = new NPCKnockbackEvent(npc, strength, vector, hitBy); + Bukkit.getPluginManager().callEvent(kb); + ((Cancellable) event).setCancelled(kb.isCancelled()); + } catch (Throwable ex) { + ex.printStackTrace(); + } + }, EventPriority.NORMAL, CitizensAPI.getPlugin(), true)); + } catch (Throwable ex) { + Messaging.severe("Error registering knockback event forwarder"); + ex.printStackTrace(); + } + } + + private void registerPushEvent(Class clazz) { + try { + HandlerList handlers = (HandlerList) clazz.getMethod("getHandlerList").invoke(null); + Method getEntity = clazz.getMethod("getEntity"); + Method getPushedBy = clazz.getMethod("getPushedBy"); + Method getAcceleration = clazz.getMethod("getAcceleration"); + handlers.register(new RegisteredListener(new Listener() { + }, (listener, event) -> { + if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) + return; + try { + Entity entity = (Entity) getEntity.invoke(event); + if (!(entity instanceof NPCHolder)) + return; + NPC npc = ((NPCHolder) entity).getNPC(); + Entity pushedBy = (Entity) getPushedBy.invoke(event); + Vector vector = (Vector) getAcceleration.invoke(event); + NPCPushEvent push = new NPCPushEvent(npc, vector, pushedBy); + Bukkit.getPluginManager().callEvent(push); + ((Cancellable) event).setCancelled(push.isCancelled()); + } catch (Throwable ex) { + ex.printStackTrace(); + } + }, EventPriority.NORMAL, CitizensAPI.getPlugin(), true)); + } catch (Throwable ex) { + Messaging.severe("Error registering push event forwarder"); + ex.printStackTrace(); + } + } + private void respawnAllFromCoord(ChunkCoord coord, Event event) { List ids = Lists.newArrayList(toRespawn.get(coord)); if (ids.size() > 0) { diff --git a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java index f27ad4131..f14a7de21 100644 --- a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java +++ b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java @@ -680,7 +680,7 @@ public class NPCCommands { if (!sender.hasPermission("citizens.npc.create.*") && !sender.hasPermission("citizens.npc.createall") && !sender.hasPermission("citizens.npc.create." + type.name().toLowerCase().replace("_", ""))) throw new NoPermissionsException(); - + if ((at != null || registryName != null || traits != null || templateName != null) && !sender.hasPermission("citizens.npc.admin")) throw new NoPermissionsException(); @@ -764,8 +764,6 @@ public class NPCCommands { } if (at != null) { - if (!sender.hasPermission("citizens.npc.create-at-location")) - throw new NoPermissionsException(); spawnLoc = at; spawnLoc.getChunk().load(); } diff --git a/main/src/main/java/net/citizensnpcs/util/NMS.java b/main/src/main/java/net/citizensnpcs/util/NMS.java index 8429ae3d0..bba123caa 100644 --- a/main/src/main/java/net/citizensnpcs/util/NMS.java +++ b/main/src/main/java/net/citizensnpcs/util/NMS.java @@ -14,6 +14,8 @@ import java.util.stream.Collectors; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.Block; import org.bukkit.command.BlockCommandSender; import org.bukkit.entity.Enderman; @@ -107,7 +109,24 @@ public class NMS { public static void callKnockbackEvent(NPC npc, float strength, double dx, double dz, Consumer cb) { - NPCKnockbackEvent event = new NPCKnockbackEvent(npc, strength, dx, dz); + if (SUPPORT_KNOCKBACK_RESISTANCE && npc.getEntity() instanceof LivingEntity) { + try { + AttributeInstance attribute = ((LivingEntity) npc.getEntity()) + .getAttribute(Attribute.GENERIC_KNOCKBACK_RESISTANCE); + if (attribute != null) { + strength *= 1 - attribute.getValue(); + } + } catch (Throwable t) { + SUPPORT_KNOCKBACK_RESISTANCE = false; + } + } + Vector vector = npc.getEntity().getVelocity(); + Vector impulse = new Vector(dx, 0, dz).normalize().multiply(strength); + Vector delta = new Vector(vector.getX() / 2 - impulse.getX() - vector.getX(), + -vector.getY() + + (npc.getEntity().isOnGround() ? Math.min(0.4, vector.getY() / 2 + strength) : vector.getY()), + vector.getZ() / 2 - impulse.getZ() - vector.getZ()); + NPCKnockbackEvent event = new NPCKnockbackEvent(npc, strength, delta, null); Bukkit.getPluginManager().callEvent(event); if (!event.isCancelled()) { cb.accept(event); @@ -853,6 +872,7 @@ public class NMS { private static Method GET_MODULE; private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); private static Field MODIFIERS_FIELD; + private static boolean SUPPORT_KNOCKBACK_RESISTANCE = true; private static Object UNSAFE; private static MethodHandle UNSAFE_FIELD_OFFSET; private static MethodHandle UNSAFE_PUT_BOOLEAN; diff --git a/main/src/main/java/net/citizensnpcs/util/Util.java b/main/src/main/java/net/citizensnpcs/util/Util.java index ddd14f47a..45b0bfbc6 100644 --- a/main/src/main/java/net/citizensnpcs/util/Util.java +++ b/main/src/main/java/net/citizensnpcs/util/Util.java @@ -91,7 +91,7 @@ public class Util { // when another entity collides, this method is called to push the NPC so we prevent it from // doing anything if the event is cancelled. Vector vector = new Vector(x, y, z); - NPCPushEvent event = new NPCPushEvent(npc, vector); + NPCPushEvent event = new NPCPushEvent(npc, vector, null); event.setCancelled(!allowed); Bukkit.getPluginManager().callEvent(event); return !event.isCancelled() ? event.getCollisionVector() : null; diff --git a/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/entity/EntityHumanNPC.java b/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/entity/EntityHumanNPC.java index ab18a9fd3..d96068b63 100644 --- a/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/entity/EntityHumanNPC.java +++ b/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/entity/EntityHumanNPC.java @@ -18,7 +18,6 @@ import com.mojang.authlib.GameProfile; import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.api.CitizensAPI; -import net.citizensnpcs.api.event.NPCKnockbackEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC.NPCUpdate; import net.citizensnpcs.api.trait.trait.Inventory; @@ -273,12 +272,8 @@ public class EntityHumanNPC extends ServerPlayer implements NPCHolder, Skinnable @Override public void knockback(double strength, double dx, double dz) { - NPCKnockbackEvent event = new NPCKnockbackEvent(npc, strength, dx, dz); - Bukkit.getPluginManager().callEvent(event); - Vector kb = event.getKnockbackVector(); - if (!event.isCancelled()) { - super.knockback(event.getStrength(), kb.getX(), kb.getZ()); - } + NMS.callKnockbackEvent(npc, (float) strength, dx, dz, (evt) -> super.knockback((float) evt.getStrength(), + evt.getKnockbackVector().getX(), evt.getKnockbackVector().getZ())); } private void moveOnCurrentHeading() { diff --git a/v1_20_R1/src/main/java/net/citizensnpcs/nms/v1_20_R1/entity/EntityHumanNPC.java b/v1_20_R1/src/main/java/net/citizensnpcs/nms/v1_20_R1/entity/EntityHumanNPC.java index 64c41eef7..f33cd5e87 100644 --- a/v1_20_R1/src/main/java/net/citizensnpcs/nms/v1_20_R1/entity/EntityHumanNPC.java +++ b/v1_20_R1/src/main/java/net/citizensnpcs/nms/v1_20_R1/entity/EntityHumanNPC.java @@ -18,7 +18,6 @@ import com.mojang.authlib.GameProfile; import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.api.CitizensAPI; -import net.citizensnpcs.api.event.NPCKnockbackEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC.NPCUpdate; import net.citizensnpcs.api.trait.trait.Inventory; @@ -268,12 +267,8 @@ public class EntityHumanNPC extends ServerPlayer implements NPCHolder, Skinnable @Override public void knockback(double strength, double dx, double dz) { - NPCKnockbackEvent event = new NPCKnockbackEvent(npc, strength, dx, dz); - Bukkit.getPluginManager().callEvent(event); - Vector kb = event.getKnockbackVector(); - if (!event.isCancelled()) { - super.knockback(event.getStrength(), kb.getX(), kb.getZ()); - } + NMS.callKnockbackEvent(npc, (float) strength, dx, dz, (evt) -> super.knockback((float) evt.getStrength(), + evt.getKnockbackVector().getX(), evt.getKnockbackVector().getZ())); } private void moveOnCurrentHeading() {