-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Description
Expected behavior
If damage post block is above 0 :
- Take knockback
- setDeltaMovement of player accordingly to knockback
- Play block_sound
- Deal remaining damage to player
If damage post block is 0 :
- Deal knockback to attacker
- Play block_sound
Observed/Actual behavior
If damage post block is above 0 :
- setDeltaMovement of player accordingly to knockback
- Play block_sound
- Deal remaining damage to player
If damage post block is 0 :
- setDeltaMovement of player accordingly to knockback
- Deal knockback to attacker
- Play block_sound
Steps/models to reproduce
If damage post block is above 0 :
/give @s diamond_sword[blocks_attacks={disable_cooldown_scale:0,damage_reductions:[{types: [mob_attack,arrow,explosion],base:0,factor:0.5}],block_sound:block.anvil.place}]
Block with that sword, facing an enemy attacking you, you'll take damage but not knockback, this is not the case in Vanilla, in Vanilla you still take knockback if attacks deal over 0 damage
If damage post block is 0 :
Block with a shield, when blocking a hit, the server will still set your delta movement based off knockback the player received yet knockback was never sent to client, you shouldn't do setDeltaMovement from knockback function in LivingEntity.java if no damage was dealt, it's useless and could cause desync between client and server, server's delta movement is used for arrow speed calculation for example, it wouldn't make sense to make your arrows go faster after blocking a hit
Plugin and Datapack List
None
Paper version
1.21.10-129
Other
Note 1 : The main issue would be caused by this in LivingEntity.java
if (!damageSource.is(DamageTypeTags.NO_IMPACT) && !flag) { // CraftBukkit - Prevent marking hurt if the damage is blocked
this.markHurt();
}flag is if damageBlocked is above 0 instead of if damage - damageBlocked is above 0, this.markHurt() sets this.hurtMarked to true which causes knockback to be sent to the client at the end of the tick, knockback equivalent to current deltaMovement value (which is properly set in this case by this.knockback function that is after that in note 2 but shouldn't be set if damage received is 0 or less)
Note 2 : The 2nd issue where it sets knockback even if damage is 0 is also there in LivingEntity.java
if (!damageSource.is(DamageTypeTags.NO_KNOCKBACK)) {
double d = 0.0;
double d1 = 0.0;
if (damageSource.getDirectEntity() instanceof Projectile projectile) {
DoubleDoubleImmutablePair doubleDoubleImmutablePair = projectile.calculateHorizontalHurtKnockbackDirection(this, damageSource);
d = -doubleDoubleImmutablePair.leftDouble();
d1 = -doubleDoubleImmutablePair.rightDouble();
} else if (damageSource.getSourcePosition() != null) {
d = damageSource.getSourcePosition().x() - this.getX();
d1 = damageSource.getSourcePosition().z() - this.getZ();
}
// Paper start - Check distance in entity interactions; see for loop in knockback method
if (Math.abs(d) > 200) {
d = Math.random() - Math.random();
}
if (Math.abs(d1) > 200) {
d1 = Math.random() - Math.random();
}
// Paper end - Check distance in entity interactions
this.knockback(0.4F, d, d1, damageSource.getDirectEntity(), damageSource.getDirectEntity() == 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(d, d1);
}
}This sets player's serveride speed to knockback even though knockback isn't dealt, also, once again
if (!flag) {
this.indicateDamage(d, d1);
}It is not indicatingDamage is flag is false and flag is false if blockedDamage is above 0 instead of checking if damage - damageBlocked is above 0
Note : If possible, add an option not to play shield sound if damage after block is above 0 and play the normal hurt sound normally