From ea9c42406e793d83bb20bbebd542c65ead5d67c0 Mon Sep 17 00:00:00 2001 From: Jake Potrebic <jake.m.potrebic@gmail.com> Date: Thu, 30 May 2024 13:17:16 -0700 Subject: [PATCH] fix knockback events (#10831) * fix knockback events * squash * handle cancelled event for explosions --- ...ackByEntityEvent-and-EntityPushedByE.patch | 180 ----------- patches/api/Add-entity-knockback-events.patch | 293 ++++++++++++++++++ patches/server/Add-critical-damage-API.patch | 2 +- ...atch => Add-entity-knockback-events.patch} | 166 +++++++--- 4 files changed, 417 insertions(+), 224 deletions(-) delete mode 100644 patches/api/Add-EntityKnockbackByEntityEvent-and-EntityPushedByE.patch create mode 100644 patches/api/Add-entity-knockback-events.patch rename patches/server/{Add-EntityKnockbackByEntityEvent-and-EntityPushedByE.patch => Add-entity-knockback-events.patch} (57%) diff --git a/patches/api/Add-EntityKnockbackByEntityEvent-and-EntityPushedByE.patch b/patches/api/Add-EntityKnockbackByEntityEvent-and-EntityPushedByE.patch deleted file mode 100644 index 2be77ecfa7..0000000000 --- a/patches/api/Add-EntityKnockbackByEntityEvent-and-EntityPushedByE.patch +++ /dev/null @@ -1,180 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brokkonaut <hannos17@gmx.de> -Date: Mon, 18 Jun 2018 15:40:39 +0200 -Subject: [PATCH] Add EntityKnockbackByEntityEvent and - EntityPushedByEntityAttackEvent - -Co-authored-by: aerulion <aerulion@gmail.com> - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java -@@ -0,0 +0,0 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent; -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.util.Vector; -+import org.jetbrains.annotations.ApiStatus; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when an Entity is knocked back by the hit of another Entity. The acceleration -+ * vector can be modified. If this event is cancelled, the entity is not knocked back. -+ */ -+public class EntityKnockbackByEntityEvent extends EntityPushedByEntityAttackEvent { -+ -+ private final float knockbackStrength; -+ -+ @ApiStatus.Internal -+ public EntityKnockbackByEntityEvent(@NotNull LivingEntity entity, @NotNull Entity hitBy, float knockbackStrength, @NotNull Vector acceleration) { -+ super(entity, hitBy, acceleration); -+ this.knockbackStrength = knockbackStrength; -+ } -+ -+ /** -+ * @return the entity which was knocked back -+ */ -+ @NotNull -+ @Override -+ public LivingEntity getEntity() { -+ return (LivingEntity) super.getEntity(); -+ } -+ -+ /** -+ * @return the original knockback strength. -+ */ -+ public float getKnockbackStrength() { -+ return this.knockbackStrength; -+ } -+ -+ /** -+ * @return the Entity which hit -+ */ -+ @NotNull -+ public Entity getHitBy() { -+ return super.getPushedBy(); -+ } -+ -+} -diff --git a/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java -@@ -0,0 +0,0 @@ -+package io.papermc.paper.event.entity; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.bukkit.util.Vector; -+import org.jetbrains.annotations.ApiStatus; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when an entity is pushed by another entity's attack. The acceleration vector can be -+ * modified. If this event is cancelled, the entity will not get pushed. -+ * <p> -+ * Note: Some entities might trigger this multiple times on the same entity -+ * as multiple acceleration calculations are done. -+ */ -+public class EntityPushedByEntityAttackEvent extends EntityEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private final @NotNull Entity pushedBy; -+ private @NotNull Vector acceleration; -+ private boolean cancelled; -+ -+ @ApiStatus.Internal -+ public EntityPushedByEntityAttackEvent(@NotNull Entity entity, @NotNull Entity pushedBy, @NotNull Vector acceleration) { -+ super(entity); -+ this.pushedBy = pushedBy; -+ this.acceleration = acceleration; -+ } -+ -+ /** -+ * Gets the entity which pushed the affected entity. -+ * -+ * @return the pushing entity -+ */ -+ @NotNull -+ public Entity getPushedBy() { -+ return this.pushedBy; -+ } -+ -+ /** -+ * Gets the acceleration that will be applied to the affected entity. -+ * -+ * @return the acceleration vector -+ */ -+ @NotNull -+ public Vector getAcceleration() { -+ return this.acceleration; // TODO Clone in 1.21 to not instantly break what was technically already modifiable -+ } -+ -+ /** -+ * Sets the relative acceleration that will be applied to the affected entity. -+ * -+ * @param acceleration the new acceleration vector -+ */ -+ public void setAcceleration(final @NotNull Vector acceleration) { -+ this.acceleration = acceleration.clone(); -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} -diff --git a/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java -+++ b/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java -@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull; - - /** - * Called when an entity receives knockback from another entity. -+ * -+ * @deprecated use {@link com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent} - */ -+@Deprecated(forRemoval = true) // Paper - public class EntityKnockbackByEntityEvent extends EntityKnockbackEvent { - - private final Entity source; -diff --git a/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java b/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java -+++ b/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java -@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull; - - /** - * Called when a living entity receives knockback. -+ * -+ * @deprecated use {@link com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent} or {@link io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent} - */ -+@Deprecated(forRemoval = true) // Paper - public class EntityKnockbackEvent extends EntityEvent implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); diff --git a/patches/api/Add-entity-knockback-events.patch b/patches/api/Add-entity-knockback-events.patch new file mode 100644 index 0000000000..a7fc30b7e3 --- /dev/null +++ b/patches/api/Add-entity-knockback-events.patch @@ -0,0 +1,293 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brokkonaut <hannos17@gmx.de> +Date: Mon, 18 Jun 2018 15:40:39 +0200 +Subject: [PATCH] Add entity knockback events + +- EntityKnockbackEvent +- EntityPushedByEntityAttackEvent +- EntityKnockbackByEntityEvent + +Co-authored-by: aerulion <aerulion@gmail.com> +Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com> + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java +@@ -0,0 +0,0 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import io.papermc.paper.event.entity.EntityKnockbackEvent; ++import io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.util.Vector; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Fired when an Entity is knocked back by the hit of another Entity. The acceleration ++ * vector can be modified. If this event is cancelled, the entity is not knocked back. ++ */ ++public class EntityKnockbackByEntityEvent extends EntityPushedByEntityAttackEvent { ++ ++ private final float knockbackStrength; ++ ++ @ApiStatus.Internal ++ public EntityKnockbackByEntityEvent(final @NonNull LivingEntity entity, final @NonNull Entity hitBy, final EntityKnockbackEvent.@NonNull Cause cause, final float knockbackStrength, final @NonNull Vector knockback) { ++ super(entity, cause, hitBy, knockback); ++ this.knockbackStrength = knockbackStrength; ++ } ++ ++ /** ++ * @return the entity which was knocked back ++ */ ++ @Override ++ public @NonNull LivingEntity getEntity() { ++ return (LivingEntity) super.getEntity(); ++ } ++ ++ /** ++ * @return the original knockback strength. ++ * @apiNote this value doesn't necessarily relate to {@link #getKnockback()}. ++ */ ++ @ApiStatus.Obsolete(since = "1.20.6") ++ public float getKnockbackStrength() { ++ return this.knockbackStrength; ++ } ++ ++ /** ++ * Gets the causing entity. Same as {@link #getPushedBy()}. ++ * ++ * @return the Entity which hit ++ */ ++ public @NonNull Entity getHitBy() { ++ return super.getPushedBy(); ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.event.entity; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.entity.Entity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.util.Vector; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Called when an entity receives knockback. ++ * @see EntityPushedByEntityAttackEvent ++ * @see com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent ++ */ ++public class EntityKnockbackEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Cause cause; ++ protected Vector knockback; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityKnockbackEvent(final @NonNull Entity entity, final EntityKnockbackEvent.@NonNull Cause cause, final @NonNull Vector knockback) { ++ super(entity); ++ this.cause = cause; ++ this.knockback = knockback; ++ } ++ ++ /** ++ * Gets the cause of the knockback. ++ * ++ * @return the cause of the knockback ++ */ ++ public EntityKnockbackEvent.@NonNull Cause getCause() { ++ return this.cause; ++ } ++ ++ /** ++ * Gets the knockback force that will be applied to the entity. <br> ++ * This value is read-only, changes made to it <b>will not</b> have any ++ * effect on the final knockback received. Use {@link #setKnockback(Vector)} ++ * to make changes. ++ * ++ * @return the knockback ++ */ ++ public @NonNull Vector getKnockback() { ++ return this.knockback.clone(); ++ } ++ ++ /** ++ * Sets the knockback force that will be applied to the entity. ++ * ++ * @param knockback the knockback ++ */ ++ public void setKnockback(final @NonNull Vector knockback) { ++ Preconditions.checkArgument(knockback != null, "knockback"); ++ this.knockback = knockback.clone(); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public @NonNull HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static @NonNull HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ /** ++ * An enum to specify the cause of the knockback. ++ */ ++ public enum Cause { ++ ++ /** ++ * Knockback caused by non-entity damage. ++ */ ++ DAMAGE, ++ /** ++ * Knockback caused by an attacking entity. ++ */ ++ ENTITY_ATTACK, ++ /** ++ * Knockback caused by an explosion. ++ */ ++ EXPLOSION, ++ /** ++ * Knockback caused by the target blocking with a shield. ++ */ ++ SHIELD_BLOCK, ++ /** ++ * Knockback caused by a sweeping attack. ++ */ ++ SWEEP_ATTACK, ++ /** ++ * A generic push. ++ */ ++ PUSH, ++ /** ++ * Knockback with an unknown cause. ++ */ ++ UNKNOWN ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.util.Vector; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Fired when an entity is pushed by another entity's attack. The acceleration vector can be ++ * modified. If this event is cancelled, the entity will not get pushed. ++ * <p> ++ * Note: Some entities might trigger this multiple times on the same entity ++ * as multiple acceleration calculations are done. ++ */ ++public class EntityPushedByEntityAttackEvent extends EntityKnockbackEvent implements Cancellable { ++ ++ private final Entity pushedBy; ++ ++ @ApiStatus.Internal ++ public EntityPushedByEntityAttackEvent(final @NonNull Entity entity, final EntityKnockbackEvent.@NonNull Cause cause, final @NonNull Entity pushedBy, final @NonNull Vector knockback) { ++ super(entity, cause, knockback); ++ this.pushedBy = pushedBy; ++ } ++ ++ /** ++ * Gets the entity which pushed the affected entity. ++ * ++ * @return the pushing entity ++ */ ++ public @NonNull Entity getPushedBy() { ++ return this.pushedBy; ++ } ++ ++ /** ++ * Gets the acceleration that will be applied to the affected entity. ++ * ++ * @return the acceleration vector ++ * @deprecated use {@link #getKnockback()} ++ */ ++ @Deprecated(since = "1.20.6", forRemoval = true) ++ public @NonNull Vector getAcceleration() { ++ return this.knockback; // TODO Clone in 1.21 to not instantly break what was technically already modifiable (call super.getKnockback()) ++ } ++ ++ /** ++ * Sets the relative acceleration that will be applied to the affected entity. ++ * ++ * @param acceleration the new acceleration vector ++ * @deprecated use {@link #setKnockback(Vector)} ++ */ ++ @Deprecated(since = "1.20.6", forRemoval = true) ++ public void setAcceleration(final @NonNull Vector acceleration) { ++ super.setKnockback(acceleration); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return super.isCancelled(); ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ super.setCancelled(cancel); ++ } ++} +diff --git a/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java +@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull; + + /** + * Called when an entity receives knockback from another entity. ++ * ++ * @deprecated use {@link com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent} + */ ++@Deprecated(forRemoval = true) // Paper + public class EntityKnockbackByEntityEvent extends EntityKnockbackEvent { + + private final Entity source; +diff --git a/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java b/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java +@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull; + + /** + * Called when a living entity receives knockback. ++ * ++ * @deprecated use {@link io.papermc.paper.event.entity.EntityKnockbackEvent} + */ ++@Deprecated(forRemoval = true) // Paper + public class EntityKnockbackEvent extends EntityEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); diff --git a/patches/server/Add-critical-damage-API.patch b/patches/server/Add-critical-damage-API.patch index b828c22b21..6a3a2dda1b 100644 --- a/patches/server/Add-critical-damage-API.patch +++ b/patches/server/Add-critical-damage-API.patch @@ -55,7 +55,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start - Only apply knockback if the damage hits - if (entityliving.hurt(this.damageSources().playerAttack(this).sweep(), f4)) { + if (entityliving.hurt(this.damageSources().playerAttack(this).sweep().critical(flag2), f4)) { // Paper - add critical damage API - entityliving.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, EntityKnockbackEvent.KnockbackCause.SWEEP_ATTACK); // CraftBukkit + entityliving.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SWEEP_ATTACK); // CraftBukkit // Paper - knockback events } // CraftBukkit end diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java diff --git a/patches/server/Add-EntityKnockbackByEntityEvent-and-EntityPushedByE.patch b/patches/server/Add-entity-knockback-events.patch similarity index 57% rename from patches/server/Add-EntityKnockbackByEntityEvent-and-EntityPushedByE.patch rename to patches/server/Add-entity-knockback-events.patch index 470e500c87..c09c7f205d 100644 --- a/patches/server/Add-EntityKnockbackByEntityEvent-and-EntityPushedByE.patch +++ b/patches/server/Add-entity-knockback-events.patch @@ -1,12 +1,14 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Brokkonaut <hannos17@gmx.de> Date: Mon, 18 Jun 2018 15:46:23 +0200 -Subject: [PATCH] Add EntityKnockbackByEntityEvent and - EntityPushedByEntityAttackEvent +Subject: [PATCH] Add entity knockback events + +- EntityKnockbackEvent +- EntityPushedByEntityAttackEvent +- EntityKnockbackByEntityEvent Co-authored-by: aerulion <aerulion@gmail.com> - -This event is called when an entity receives knockback by another entity. +Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com> diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -26,64 +28,84 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public void push(double deltaX, double deltaY, double deltaZ, @org.jetbrains.annotations.Nullable Entity pushingEntity) { + org.bukkit.util.Vector delta = new org.bukkit.util.Vector(deltaX, deltaY, deltaZ); + if (pushingEntity != null) { -+ io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent event = new io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent(getBukkitEntity(), pushingEntity.getBukkitEntity(), delta); ++ io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent event = new io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent(this.getBukkitEntity(), io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.PUSH, pushingEntity.getBukkitEntity(), delta); + if (!event.callEvent()) { + return; + } -+ delta = event.getAcceleration(); ++ delta = event.getKnockback(); + } + this.setDeltaMovement(this.getDeltaMovement().add(delta.getX(), delta.getY(), delta.getZ())); - this.hasImpulse = true; + // Paper end - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent + this.hasImpulse = true; } - protected void markHurt() { diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable { + d0 = (Math.random() - Math.random()) * 0.01D; + } + +- this.knockback(0.4000000059604645D, d0, d1, entity1, entity1 == null ? EntityKnockbackEvent.KnockbackCause.DAMAGE : EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit ++ this.knockback(0.4000000059604645D, d0, d1, entity1, entity1 == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events + if (!flag) { + this.indicateDamage(d0, d1); + } @@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable { } protected void blockedByShield(LivingEntity target) { - target.knockback(0.5D, target.getX() - this.getX(), target.getZ() - this.getZ(), null, EntityKnockbackEvent.KnockbackCause.SHIELD_BLOCK); // CraftBukkit -+ target.knockback(0.5D, target.getX() - this.getX(), target.getZ() - this.getZ(), this, EntityKnockbackEvent.KnockbackCause.SHIELD_BLOCK); // CraftBukkit // Paper - fix attacker ++ target.knockback(0.5D, target.getX() - this.getX(), target.getZ() - this.getZ(), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SHIELD_BLOCK); // CraftBukkit // Paper - fix attacker & knockback events } private boolean checkTotemDeathProtection(DamageSource source) { @@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.knockback(strength, x, z, null, EntityKnockbackEvent.KnockbackCause.UNKNOWN); + + public void knockback(double strength, double x, double z) { + // CraftBukkit start - EntityKnockbackEvent +- this.knockback(strength, x, z, null, EntityKnockbackEvent.KnockbackCause.UNKNOWN); ++ this.knockback(strength, x, z, null, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.UNKNOWN); // Paper - knockback events } - public void knockback(double d0, double d1, double d2, Entity attacker, EntityKnockbackEvent.KnockbackCause cause) { -+ public void knockback(double d0, double d1, double d2, @Nullable Entity attacker, EntityKnockbackEvent.KnockbackCause cause) { // Paper - add nullable to attacker param ++ public void knockback(double d0, double d1, double d2, @Nullable Entity attacker, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause cause) { // Paper - knockback events d0 *= 1.0D - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE); if (true || d0 > 0.0D) { // CraftBukkit - Call event even when force is 0 //this.hasImpulse = true; // CraftBukkit - Move down -@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable { + Vec3 vec3d = this.getDeltaMovement(); + Vec3 vec3d1 = (new Vec3(d1, 0.0D, d2)).normalize().scale(d0); + +- EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) this.getBukkitEntity(), attacker, cause, d0, vec3d1, vec3d.x / 2.0D - vec3d1.x, this.onGround() ? Math.min(0.4D, vec3d.y / 2.0D + d0) : vec3d.y, vec3d.z / 2.0D - vec3d1.z); ++ // Paper start - knockback events ++ Vec3 finalVelocity = new Vec3(vec3d.x / 2.0D - vec3d1.x, this.onGround() ? Math.min(0.4D, vec3d.y / 2.0D + d0) : vec3d.y, vec3d.z / 2.0D - vec3d1.z); ++ Vec3 diff = finalVelocity.subtract(vec3d); ++ io.papermc.paper.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) this.getBukkitEntity(), attacker, cause, d0, diff); ++ // Paper end - knockback events + if (event.isCancelled()) { return; } -+ // Paper start - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent -+ final org.bukkit.util.Vector currentMovement = this.getBukkitEntity().getVelocity(); -+ org.bukkit.util.Vector resultingMovement = event.getFinalKnockback(); -+ final org.bukkit.util.Vector deltaMovement = resultingMovement.clone().subtract(currentMovement); -+ if (attacker != null) { -+ final com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent knockbackEvent = new com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent(this.getBukkitLivingEntity(), attacker.getBukkitEntity(), (float) event.getForce(), deltaMovement); -+ if (!knockbackEvent.callEvent()) { -+ return; -+ } -+ -+ // Back from delta to the absolute vector -+ resultingMovement = currentMovement.add(knockbackEvent.getAcceleration()); -+ } this.hasImpulse = true; - this.setDeltaMovement(event.getFinalKnockback().getX(), event.getFinalKnockback().getY(), event.getFinalKnockback().getZ()); -+ this.setDeltaMovement(resultingMovement.getX(), resultingMovement.getY(), resultingMovement.getZ()); -+ // Paper end - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent ++ this.setDeltaMovement(vec3d.add(event.getKnockback().getX(), event.getKnockback().getY(), event.getKnockback().getZ())); // Paper - knockback events // CraftBukkit end } } +diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/entity/Mob.java ++++ b/src/main/java/net/minecraft/world/entity/Mob.java +@@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti + + if (flag) { + if (f1 > 0.0F && target instanceof LivingEntity) { +- ((LivingEntity) target).knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot())) * 0.017453292F, this, org.bukkit.event.entity.EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit ++ ((LivingEntity) target).knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot())) * 0.017453292F, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events + this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D)); + } + diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/RamTarget.java b/src/main/java/net/minecraft/world/entity/ai/behavior/RamTarget.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/RamTarget.java @@ -93,7 +115,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 float g = Mth.clamp(entity.getSpeed() * 1.65F, 0.2F, 3.0F) + f; float h = livingEntity.isDamageSourceBlocked(world.damageSources().mobAttack(entity)) ? 0.5F : 1.0F; - livingEntity.knockback((double)(h * g) * this.getKnockbackForce.applyAsDouble(entity), this.ramDirection.x(), this.ramDirection.z()); -+ livingEntity.knockback(h * g * this.getKnockbackForce.applyAsDouble(entity), this.ramDirection.x(), this.ramDirection.z(), entity, org.bukkit.event.entity.EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent ++ livingEntity.knockback(h * g * this.getKnockbackForce.applyAsDouble(entity), this.ramDirection.x(), this.ramDirection.z(), entity, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent this.finishRam(world, entity); world.playSound(null, entity, this.getImpactSound.apply(entity), SoundSource.NEUTRAL, 1.0F, 1.0F); } else if (this.hasRammedHornBreakingBlock(world, entity)) { @@ -183,14 +205,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -0,0 +0,0 @@ public abstract class Player extends LivingEntity { + if (flag5) { + if (i > 0) { if (target instanceof LivingEntity) { - ((LivingEntity) target).knockback((double) ((float) i * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit +- ((LivingEntity) target).knockback((double) ((float) i * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit ++ ((LivingEntity) target).knockback((double) ((float) i * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events } else { - target.push((double) (-Mth.sin(this.getYRot() * 0.017453292F) * (float) i * 0.5F), 0.1D, (double) (Mth.cos(this.getYRot() * 0.017453292F) * (float) i * 0.5F)); + target.push((double) (-Mth.sin(this.getYRot() * 0.017453292F) * (float) i * 0.5F), 0.1D, (double) (Mth.cos(this.getYRot() * 0.017453292F) * (float) i * 0.5F), this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent } this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D)); +@@ -0,0 +0,0 @@ public abstract class Player extends LivingEntity { + if (entityliving != this && entityliving != target && !this.isAlliedTo((Entity) entityliving) && (!(entityliving instanceof ArmorStand) || !((ArmorStand) entityliving).isMarker()) && this.distanceToSqr((Entity) entityliving) < 9.0D) { + // CraftBukkit start - Only apply knockback if the damage hits + if (entityliving.hurt(this.damageSources().playerAttack(this).sweep(), f4)) { +- entityliving.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, EntityKnockbackEvent.KnockbackCause.SWEEP_ATTACK); // CraftBukkit ++ entityliving.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SWEEP_ATTACK); // CraftBukkit // Paper - knockback events + } + // CraftBukkit end + } diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java @@ -200,7 +234,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (vec3d.lengthSqr() > 0.0D) { - entityliving.push(vec3d.x, 0.1D, vec3d.z); -+ entityliving.push(vec3d.x, 0.1D, vec3d.z, this); // Paper ++ entityliving.push(vec3d.x, 0.1D, vec3d.z, this); // Paper - pass causing entity for knockback events } } @@ -222,19 +256,65 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/Explosion.java +++ b/src/main/java/net/minecraft/world/level/Explosion.java @@ -0,0 +0,0 @@ public class Explosion { - // since the code below (the setDeltaMovement call as well as the hitPlayers map) - // want the vector to be the relative velocity will the event provides the absolute velocity - vec3d1 = (event.isCancelled()) ? Vec3.ZERO : new Vec3(event.getFinalKnockback().getX(), event.getFinalKnockback().getY(), event.getFinalKnockback().getZ()).subtract(entity.getDeltaMovement()); -+ // Paper start - call EntityKnockbackByEntityEvent for explosions -+ if (this.damageSource.getEntity() != null || this.source != null) { -+ final org.bukkit.entity.Entity hitBy = this.damageSource.getEntity() != null ? this.damageSource.getEntity().getBukkitEntity() : this.source.getBukkitEntity(); -+ com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent paperEvent = new com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent(((LivingEntity) entity).getBukkitLivingEntity(), hitBy, (float) event.getForce(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(vec3d1)); -+ if (!paperEvent.callEvent()) { -+ continue; -+ } -+ vec3d1 = org.bukkit.craftbukkit.util.CraftVector.toNMS(paperEvent.getAcceleration()); -+ } -+ // Paper end - call EntityKnockbackByEntityEvent for explosions + + // CraftBukkit start - Call EntityKnockbackEvent + if (entity instanceof LivingEntity) { +- Vec3 result = entity.getDeltaMovement().add(vec3d1); +- org.bukkit.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) entity.getBukkitEntity(), this.source, org.bukkit.event.entity.EntityKnockbackEvent.KnockbackCause.EXPLOSION, d13, vec3d1, result.x, result.y, result.z); +- +- // SPIGOT-7640: Need to subtract entity movement from the event result, +- // since the code below (the setDeltaMovement call as well as the hitPlayers map) +- // want the vector to be the relative velocity will the event provides the absolute velocity +- vec3d1 = (event.isCancelled()) ? Vec3.ZERO : new Vec3(event.getFinalKnockback().getX(), event.getFinalKnockback().getY(), event.getFinalKnockback().getZ()).subtract(entity.getDeltaMovement()); ++ // Paper start - knockback events ++ io.papermc.paper.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) entity.getBukkitEntity(), this.damageSource.getEntity() != null ? this.damageSource.getEntity() : this.source, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.EXPLOSION, d13, vec3d1); ++ vec3d1 = event.isCancelled() ? Vec3.ZERO : org.bukkit.craftbukkit.util.CraftVector.toNMS(event.getKnockback()); ++ // Paper end - knockback events } // CraftBukkit end entity.setDeltaMovement(entity.getDeltaMovement().add(vec3d1)); +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -0,0 +0,0 @@ public class CraftEventFactory { + return event; + } + +- public static EntityKnockbackEvent callEntityKnockbackEvent(CraftLivingEntity entity, Entity attacker, EntityKnockbackEvent.KnockbackCause cause, double force, Vec3 raw, double x, double y, double z) { +- Vector bukkitRaw = new Vector(-raw.x, raw.y, -raw.z); // Due to how the knockback calculation works, we need to invert x and z. +- +- EntityKnockbackEvent event; ++ // Paper start - replace knockback events ++ public static io.papermc.paper.event.entity.EntityKnockbackEvent callEntityKnockbackEvent(CraftLivingEntity entity, Entity attacker, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause cause, double force, Vec3 knockback) { ++ Vector apiKnockback = CraftVector.toBukkit(knockback); ++ ++ final Vector currentVelocity = entity.getVelocity(); ++ final Vector legacyFinalKnockback = currentVelocity.clone().add(apiKnockback); ++ final org.bukkit.event.entity.EntityKnockbackEvent.KnockbackCause legacyCause = org.bukkit.event.entity.EntityKnockbackEvent.KnockbackCause.valueOf(cause.name()); ++ EntityKnockbackEvent legacyEvent; + if (attacker != null) { +- event = new EntityKnockbackByEntityEvent(entity, attacker.getBukkitEntity(), cause, force, new Vector(-raw.x, raw.y, -raw.z), new Vector(x, y, z)); ++ legacyEvent = new EntityKnockbackByEntityEvent(entity, attacker.getBukkitEntity(), legacyCause, force, apiKnockback, legacyFinalKnockback); + } else { +- event = new EntityKnockbackEvent(entity, cause, force, new Vector(-raw.x, raw.y, -raw.z), new Vector(x, y, z)); ++ legacyEvent = new EntityKnockbackEvent(entity, legacyCause, force, apiKnockback, legacyFinalKnockback); + } ++ legacyEvent.callEvent(); + +- Bukkit.getPluginManager().callEvent(event); ++ final io.papermc.paper.event.entity.EntityKnockbackEvent event; ++ apiKnockback = legacyEvent.getFinalKnockback().subtract(currentVelocity); ++ if (attacker != null) { ++ event = new com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent(entity, attacker.getBukkitEntity(), cause, (float) force, apiKnockback); ++ } else { ++ event = new io.papermc.paper.event.entity.EntityKnockbackEvent(entity, cause, apiKnockback); ++ } ++ event.setCancelled(legacyEvent.isCancelled()); ++ event.callEvent(); + return event; + } ++ // Paper end - replace knockback events + + public static void callEntityRemoveEvent(Entity entity, EntityRemoveEvent.Cause cause) { + if (entity instanceof ServerPlayer) {