From 4439ccded2abbe359baa799e2a86316f02a7de52 Mon Sep 17 00:00:00 2001 From: Yager400 <176045997+Yager400@users.noreply.github.com> Date: Fri, 7 Aug 2026 15:21:23 +0200 Subject: [PATCH 1/3] Fix duplicate EntityKnockbackEvent for sprint attacks and add ENTITY_SPRINT_ATTACK cause --- .../event/entity/EntityKnockbackEvent.java | 4 ++ .../event/entity/EntityKnockbackEvent.java | 4 ++ .../world/entity/LivingEntity.java.patch | 47 ++++++++++++++----- .../world/entity/player/Player.java.patch | 17 +++++-- 4 files changed, 55 insertions(+), 17 deletions(-) diff --git a/paper-api/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java b/paper-api/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java index 44db373eebb3..2be0c7c05449 100644 --- a/paper-api/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java +++ b/paper-api/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java @@ -94,6 +94,10 @@ public enum Cause { * Knockback caused by an attacking entity. */ ENTITY_ATTACK, + /** + * Knockback caused by the sprint bonus applied during an entity attack. + */ + ENTITY_SPRINT_ATTACK, /** * Knockback caused by an explosion. */ diff --git a/paper-api/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java b/paper-api/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java index c19fe417db05..f71d2e54a69f 100644 --- a/paper-api/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java @@ -141,6 +141,10 @@ public enum KnockbackCause { * Knockback caused by an attacking entity. */ ENTITY_ATTACK, + /** + * Knockback caused by the sprint bonus applied during an entity attack. + */ + ENTITY_SPRINT_ATTACK, /** * Knockback caused by an explosion. */ diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index dd7bcd5582d9..3a03c670a089 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -597,7 +597,7 @@ if (success) { this.lastDamageSource = source; this.lastDamageStamp = this.level().getGameTime(); -@@ -1300,13 +_,28 @@ +@@ -1300,13 +_,36 @@ zd = source.getSourcePosition().z() - this.getZ(); } @@ -611,7 +611,15 @@ + } + // Paper end - Check distance in entity interactions + -+ this.knockback(0.4F, xd, zd, source, damage, source.getDirectEntity(), source.getDirectEntity() == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events ++ io.papermc.paper.event.entity.EntityKnockbackEvent.Cause cause; ++ if (source.getDirectEntity() instanceof LivingEntity living && living.isSprinting()) { ++ cause = io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_SPRINT_ATTACK; ++ } else if (source.getDirectEntity() == null) { ++ cause = io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE; ++ } else { ++ cause = io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK; ++ } ++ this.knockback(0.4F, xd, zd, source, damage, source.getDirectEntity(), cause); // CraftBukkit // Paper - knockback events if (!blocked) { this.indicateDamage(xd, zd); } @@ -902,7 +910,7 @@ Vec3 deltaMovement = this.getDeltaMovement(); while (xd * xd + zd * zd < 1.0E-5F) { -@@ -1651,16 +_,32 @@ +@@ -1651,16 +_,34 @@ } Vec3 deltaVector = new Vec3(xd, 0.0, zd).normalize().scale(power); @@ -914,13 +922,15 @@ ); + // Paper start - knockback events + Vec3 knockback = targetMovement.subtract(deltaMovement); -+ io.papermc.paper.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) this.getBukkitEntity(), attacker, attacker, eventCause, power, knockback); -+ if (event.isCancelled()) { -+ return; -+ } ++ if (!comesFromEffect) { ++ io.papermc.paper.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) this.getBukkitEntity(), attacker, attacker, eventCause, power, knockback); ++ if (event.isCancelled()) { ++ return; ++ } + -+ this.needsSync = true; -+ this.setDeltaMovement(deltaMovement.add(event.getKnockback().getX(), event.getKnockback().getY(), event.getKnockback().getZ())); ++ this.needsSync = true; ++ } ++ this.setDeltaMovement(deltaMovement.add(knockback.x, knockback.y, knockback.z)); + // Paper end - knockback events } } @@ -1271,15 +1281,26 @@ } private Vec3 updateFallFlyingMovement(Vec3 movement) { -@@ -2749,7 +_,7 @@ +@@ -2748,9 +_,16 @@ + final Entity target, final float knockback, final Vec3 oldMovement, final DamageSource damageSource, final float damage, final boolean comesFromEffect ) { if (knockback > 0.0F && target instanceof LivingEntity livingTarget) { - livingTarget.knockback( +- livingTarget.knockback( - knockback, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect -+ knockback, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK // Paper - knockback events - ); +- ); ++ if (this.isSprinting()) { ++ livingTarget.knockback( ++ knockback, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_SPRINT_ATTACK // Paper - knockback events ++ ); ++ } ++ else { ++ livingTarget.knockback( ++ knockback, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK // Paper - knockback events ++ ); ++ } this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 1.0, 0.6)); } + } @@ -2826,37 +_,15 @@ profiler.pop(); profiler.push("rangeChecks"); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch index fb7007df9e5c..4bd2168fb578 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch @@ -290,13 +290,22 @@ return true; } else { return false; -@@ -1127,20 +_,41 @@ +@@ -1126,21 +_,48 @@ + ) { if (knockbackAmount > 0.0F) { if (entity instanceof LivingEntity livingTarget) { - livingTarget.knockback( +- livingTarget.knockback( - knockbackAmount, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect -+ knockbackAmount, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK // Paper - knockback events - ); +- ); ++ if (livingTarget.isSprinting()) { ++ livingTarget.knockback( ++ knockbackAmount, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_SPRINT_ATTACK // Paper - knockback events ++ ); ++ } else { ++ livingTarget.knockback( ++ knockbackAmount, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK // Paper - knockback events ++ ); ++ } } else { - entity.push(-Mth.sin(this.getYRot() * Mth.DEG_TO_RAD) * knockbackAmount, 0.1, Mth.cos(this.getYRot() * Mth.DEG_TO_RAD) * knockbackAmount); + entity.push(-Mth.sin(this.getYRot() * Mth.DEG_TO_RAD) * knockbackAmount, 0.1, Mth.cos(this.getYRot() * Mth.DEG_TO_RAD) * knockbackAmount, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent From 4960351b37855bf537c08d3d3fa0414f2eed69b3 Mon Sep 17 00:00:00 2001 From: Yager400 <176045997+Yager400@users.noreply.github.com> Date: Fri, 7 Aug 2026 16:52:01 +0200 Subject: [PATCH 2/3] Address style review comments --- .../world/entity/LivingEntity.java.patch | 29 ++++++++----------- .../world/entity/player/Player.java.patch | 18 ++++-------- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index 3a03c670a089..9a9d07d884b2 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -609,8 +609,8 @@ + if (Math.abs(zd) > 200) { + zd = Math.random() - Math.random(); + } -+ // Paper end - Check distance in entity interactions + ++ // Paper start - knockback events + io.papermc.paper.event.entity.EntityKnockbackEvent.Cause cause; + if (source.getDirectEntity() instanceof LivingEntity living && living.isSprinting()) { + cause = io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_SPRINT_ATTACK; @@ -619,7 +619,7 @@ + } else { + cause = io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK; + } -+ this.knockback(0.4F, xd, zd, source, damage, source.getDirectEntity(), cause); // CraftBukkit // Paper - knockback events ++ this.knockback(0.4F, xd, zd, source, damage, source.getDirectEntity(), cause); // Paper end - knockback events if (!blocked) { this.indicateDamage(xd, zd); } @@ -910,7 +910,7 @@ Vec3 deltaMovement = this.getDeltaMovement(); while (xd * xd + zd * zd < 1.0E-5F) { -@@ -1651,16 +_,34 @@ +@@ -1651,16 +_,33 @@ } Vec3 deltaVector = new Vec3(xd, 0.0, zd).normalize().scale(power); @@ -927,9 +927,8 @@ + if (event.isCancelled()) { + return; + } -+ -+ this.needsSync = true; + } ++ this.needsSync = true; + this.setDeltaMovement(deltaMovement.add(knockback.x, knockback.y, knockback.z)); + // Paper end - knockback events } @@ -1281,23 +1280,19 @@ } private Vec3 updateFallFlyingMovement(Vec3 movement) { -@@ -2748,9 +_,16 @@ +@@ -2748,9 +_,13 @@ final Entity target, final float knockback, final Vec3 oldMovement, final DamageSource damageSource, final float damage, final boolean comesFromEffect ) { if (knockback > 0.0F && target instanceof LivingEntity livingTarget) { -- livingTarget.knockback( ++ // Paper start - knockback events ++ io.papermc.paper.event.entity.EntityKnockbackEvent.Cause cause = this.isSprinting() ++ ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_SPRINT_ATTACK ++ : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK; + livingTarget.knockback( - knockback, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect - ); -+ if (this.isSprinting()) { -+ livingTarget.knockback( -+ knockback, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_SPRINT_ATTACK // Paper - knockback events -+ ); -+ } -+ else { -+ livingTarget.knockback( -+ knockback, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK // Paper - knockback events -+ ); -+ } ++ knockback, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, cause ++ ); // Paper end - knockback events this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 1.0, 0.6)); } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch index 4bd2168fb578..e16b9442c4fe 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch @@ -290,22 +290,14 @@ return true; } else { return false; -@@ -1126,21 +_,48 @@ - ) { +@@ -1127,20 +_,42 @@ if (knockbackAmount > 0.0F) { if (entity instanceof LivingEntity livingTarget) { -- livingTarget.knockback( + livingTarget.knockback( - knockbackAmount, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect -- ); -+ if (livingTarget.isSprinting()) { -+ livingTarget.knockback( -+ knockbackAmount, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_SPRINT_ATTACK // Paper - knockback events -+ ); -+ } else { -+ livingTarget.knockback( -+ knockbackAmount, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK // Paper - knockback events -+ ); -+ } ++ knockbackAmount, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, ++ livingTarget.isSprinting() ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_SPRINT_ATTACK : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK // Paper - knockback events + ); } else { - entity.push(-Mth.sin(this.getYRot() * Mth.DEG_TO_RAD) * knockbackAmount, 0.1, Mth.cos(this.getYRot() * Mth.DEG_TO_RAD) * knockbackAmount); + entity.push(-Mth.sin(this.getYRot() * Mth.DEG_TO_RAD) * knockbackAmount, 0.1, Mth.cos(this.getYRot() * Mth.DEG_TO_RAD) * knockbackAmount, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent From 3d7a6be1e7fe89056caac0b36fa7eee55d625619 Mon Sep 17 00:00:00 2001 From: Yager400 <176045997+Yager400@users.noreply.github.com> Date: Sat, 8 Aug 2026 20:49:16 +0200 Subject: [PATCH 3/3] Fix comment formatting in patches --- .../minecraft/world/entity/LivingEntity.java.patch | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index 9a9d07d884b2..48f275dd5b80 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -597,7 +597,7 @@ if (success) { this.lastDamageSource = source; this.lastDamageStamp = this.level().getGameTime(); -@@ -1300,13 +_,36 @@ +@@ -1300,13 +_,37 @@ zd = source.getSourcePosition().z() - this.getZ(); } @@ -619,7 +619,8 @@ + } else { + cause = io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK; + } -+ this.knockback(0.4F, xd, zd, source, damage, source.getDirectEntity(), cause); // Paper end - knockback events ++ this.knockback(0.4F, xd, zd, source, damage, source.getDirectEntity(), cause); ++ // Paper end - knockback events if (!blocked) { this.indicateDamage(xd, zd); } @@ -1280,7 +1281,7 @@ } private Vec3 updateFallFlyingMovement(Vec3 movement) { -@@ -2748,9 +_,13 @@ +@@ -2748,9 +_,14 @@ final Entity target, final float knockback, final Vec3 oldMovement, final DamageSource damageSource, final float damage, final boolean comesFromEffect ) { if (knockback > 0.0F && target instanceof LivingEntity livingTarget) { @@ -1290,9 +1291,9 @@ + : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK; livingTarget.knockback( - knockback, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect -- ); + knockback, Mth.sin(this.getYRot() * Mth.DEG_TO_RAD), -Mth.cos(this.getYRot() * Mth.DEG_TO_RAD), damageSource, damage, comesFromEffect, this, cause -+ ); // Paper end - knockback events + ); ++ // Paper end - knockback events this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 1.0, 0.6)); } }