PaperMC / PaperMC/Paper

minecraft:blocks_attacks non-vanilla behaviour

Open
#13,426 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: accepted version: 1.21.10 version: 1.21.11
Dominant language
Java
Stars
12.7k
Forks
3.5k
Avg merge
3d 13h
Merged PRs (30d)
11

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in LivingEntity.java at the damage-blocking and knockback logic shown in the report, then reproduce both cases with the provided sword command and shield blocking scenario. Compare the results with the stated vanilla behavior: apply knockback and hurt indication based on post-block damage, avoid movement changes when no damage is dealt, and preserve the expected block sound behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
game-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
70/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.