aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJake Potrebic <[email protected]>2024-05-30 11:54:30 -0700
committerJake Potrebic <[email protected]>2024-05-30 12:31:02 -0700
commit4df603b4da47ecd9a0085e82e81b6a425b888d8a (patch)
tree526ab8638486887e520632e7576b2bf3716dbccc
parent0fcf3e347f671ce6bdc9699cbe4c34567562dd2b (diff)
downloadPaper-4df603b4da47ecd9a0085e82e81b6a425b888d8a.tar.gz
Paper-4df603b4da47ecd9a0085e82e81b6a425b888d8a.zip
fix knockback events
-rw-r--r--patches/api/0484-temp.patch302
-rw-r--r--patches/server/1052-temp.patch217
2 files changed, 519 insertions, 0 deletions
diff --git a/patches/api/0484-temp.patch b/patches/api/0484-temp.patch
new file mode 100644
index 0000000000..fae4b0017b
--- /dev/null
+++ b/patches/api/0484-temp.patch
@@ -0,0 +1,302 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Thu, 30 May 2024 11:53:52 -0700
+Subject: [PATCH] temp
+
+
+diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java
+index e0ba692c9b107f2b042a9c06549185e1c4777e27..beb1715e30ec476e3031c247285d0d3219e8a8ea 100644
+--- a/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java
++++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java
+@@ -1,11 +1,12 @@
+ 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;
+-import org.jetbrains.annotations.NotNull;
+
+ /**
+ * Fired when an Entity is knocked back by the hit of another Entity. The acceleration
+@@ -16,32 +17,34 @@ public class EntityKnockbackByEntityEvent extends EntityPushedByEntityAttackEven
+ private final float knockbackStrength;
+
+ @ApiStatus.Internal
+- public EntityKnockbackByEntityEvent(@NotNull LivingEntity entity, @NotNull Entity hitBy, float knockbackStrength, @NotNull Vector acceleration) {
+- super(entity, hitBy, acceleration);
++ 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
+ */
+- @NotNull
+ @Override
+- public LivingEntity getEntity() {
++ 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
+ */
+- @NotNull
+- public Entity getHitBy() {
++ 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..8aaafa4ea837f54b32497010d121f02b103e03a6
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java
+@@ -0,0 +1,116 @@
++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
+index 404bec776244fd776566c81f671f1009830c6d6e..b9d2a7a5bc4e67d8c36047da616046cbedce1d4a 100644
+--- a/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java
++++ b/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java
+@@ -2,11 +2,9 @@ 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.checkerframework.checker.nullness.qual.NonNull;
+ 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
+@@ -15,19 +13,14 @@ import org.jetbrains.annotations.NotNull;
+ * 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 {
++public class EntityPushedByEntityAttackEvent extends EntityKnockbackEvent implements Cancellable {
+
+- private static final HandlerList HANDLER_LIST = new HandlerList();
+-
+- private final @NotNull Entity pushedBy;
+- private @NotNull Vector acceleration;
+- private boolean cancelled;
++ private final Entity pushedBy;
+
+ @ApiStatus.Internal
+- public EntityPushedByEntityAttackEvent(@NotNull Entity entity, @NotNull Entity pushedBy, @NotNull Vector acceleration) {
+- super(entity);
++ 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;
+- this.acceleration = acceleration;
+ }
+
+ /**
+@@ -35,8 +28,7 @@ public class EntityPushedByEntityAttackEvent extends EntityEvent implements Canc
+ *
+ * @return the pushing entity
+ */
+- @NotNull
+- public Entity getPushedBy() {
++ public @NonNull Entity getPushedBy() {
+ return this.pushedBy;
+ }
+
+@@ -44,39 +36,31 @@ public class EntityPushedByEntityAttackEvent extends EntityEvent implements Canc
+ * Gets the acceleration that will be applied to the affected entity.
+ *
+ * @return the acceleration vector
++ * @deprecated use {@link #getKnockback()}
+ */
+- @NotNull
+- public Vector getAcceleration() {
+- return this.acceleration; // TODO Clone in 1.21 to not instantly break what was technically already modifiable
++ @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)}
+ */
+- public void setAcceleration(final @NotNull Vector acceleration) {
+- this.acceleration = acceleration.clone();
++ @Deprecated(since = "1.20.6", forRemoval = true)
++ public void setAcceleration(final @NonNull Vector acceleration) {
++ super.setKnockback(acceleration);
+ }
+
+ @Override
+ public boolean isCancelled() {
+- return this.cancelled;
+- }
+-
+- @Override
+- public void setCancelled(boolean cancel) {
+- this.cancelled = cancel;
++ return super.isCancelled();
+ }
+
+- @NotNull
+ @Override
+- public HandlerList getHandlers() {
+- return HANDLER_LIST;
+- }
+-
+- @NotNull
+- public static HandlerList getHandlerList() {
+- return HANDLER_LIST;
++ public void setCancelled(final boolean cancel) {
++ super.setCancelled(cancel);
+ }
+ }
+diff --git a/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java b/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java
+index fe3374fbbfef728358e4a15bbf2deb238a1e0bfd..753e6f30da4f3dc9d5ed7d1b40d30b602b8c8c9e 100644
+--- a/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java
++++ b/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java
+@@ -12,7 +12,7 @@ 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 use {@link io.papermc.paper.event.entity.EntityKnockbackEvent}
+ */
+ @Deprecated(forRemoval = true) // Paper
+ public class EntityKnockbackEvent extends EntityEvent implements Cancellable {
diff --git a/patches/server/1052-temp.patch b/patches/server/1052-temp.patch
new file mode 100644
index 0000000000..ac3fbf1227
--- /dev/null
+++ b/patches/server/1052-temp.patch
@@ -0,0 +1,217 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Thu, 30 May 2024 11:53:47 -0700
+Subject: [PATCH] temp
+
+
+diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
+index 4ee843dfd826772c9157ca421d8fe1f36f814b51..6eef0e72af8c80a641c55914d7c18a411810e0b6 100644
+--- a/src/main/java/net/minecraft/world/entity/Entity.java
++++ b/src/main/java/net/minecraft/world/entity/Entity.java
+@@ -2220,11 +2220,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+ 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;
+diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+index 0ddf2e1a6d2ea836f8a140a435721e0ce96bd8d2..81278c04451a432439b6b391bee07b6af840c302 100644
+--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+@@ -1568,7 +1568,7 @@ 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);
+ }
+@@ -1622,7 +1622,7 @@ 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(), 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) {
+@@ -1936,37 +1936,26 @@ public abstract class LivingEntity extends Entity implements Attackable {
+
+ 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, @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
+ 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(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 9f42563699508fcb3d8a96cfdfc25a7bffd99759..8b612b772ca87c852d0b108c2afd6785c261c9b9 100644
+--- a/src/main/java/net/minecraft/world/entity/Mob.java
++++ b/src/main/java/net/minecraft/world/entity/Mob.java
+@@ -1832,7 +1832,7 @@ 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 0c63779af7e1c790160fb2ab86bf455219b3cc36..51fc1574d195b17fd1dc42907de3bb0e451af457 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/behavior/RamTarget.java
++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/RamTarget.java
+@@ -83,7 +83,7 @@ public class RamTarget extends Behavior<Goat> {
+ float f = 0.25F * (float)(i - j);
+ 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(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)) {
+diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
+index 686374e89e41b0917791264f3281f7384835bca8..25595bef64199c4ddbe69c65fd149eec33e778ad 100644
+--- a/src/main/java/net/minecraft/world/entity/player/Player.java
++++ b/src/main/java/net/minecraft/world/entity/player/Player.java
+@@ -1341,7 +1341,7 @@ 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, 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), this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
+ }
+@@ -1365,7 +1365,7 @@ 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().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/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
+index 082b804f4793f72e76361f5427f0358273454b3d..8611725989cff89d809e6b8837d8dbd7e4da2494 100644
+--- a/src/main/java/net/minecraft/world/level/Explosion.java
++++ b/src/main/java/net/minecraft/world/level/Explosion.java
+@@ -622,23 +622,10 @@ public class Explosion {
+
+ // 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 - 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
++ // 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 = 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 1a737167757891794b40575a5db48b0667e23a6b..dfbe0914ab2771ac632fd064719878ac47559e9f 100644
+--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+@@ -2070,19 +2070,33 @@ 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) {