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) {