mojira.dev
MC-255756

When the shield is broken between players, the attacking side has no shield breaking sound

Title
When the shield is broken between players, the attacking side has no shield breaking sound

What I expect to happen is...:
Shield breaking sound can be heard by nearby players

What actually happens is...:
The attacker can only hear the sound of the player being injured, even if the player holding the shield is not injured

Step:
Attacker hits defender's shield with an axe
When the defender's shield is disabled, only the defender will hear the sound of the broken shield
The attacker can only see that the defender is no longer raising the shield, and a sound effect of the player's injury is played once

Linked issues

Comments 2

Code analysis (using mojang mappings, 1.20.1):

 

The packet responsible for the shield block and shield break sounds is the ClientboundEntityEventPacket.

This packet is sent to the client successfully when a shield is blocking an attack or when the shield gets disabled by an axe.

 

When the client handles the entity event (29 for shield blocking and 30 for shield breaking), it uses the following playSound method:

Entity#playSound(SoundEvent, float, float)

which itself is overridden in the Player class, which makes a new call to the following method:

Level#playSound(Player, double, double, double, SoundEvent, SoundSource, float, float)

which ends up calling the following method (skipped one method call, which is straightforward by looking at the code)

@Override
public void playSeededSound(@Nullable Player player, double d, double e, double f, Holder<SoundEvent> holder, SoundSource soundSource, float g, float h, long l) {
    if (player == this.minecraft.player) {
        this.playSound(d, e, f, holder.value(), soundSource, g, h, false, l);
    }
}

The above method is the implementation in the ClientLevel class. As we can see, it checks if the given player is the player that this minecraft instance holds. Now when the shield breaking/blocking sounds arrive here, the player parameter is set to the player that's having its shield blocking/breaking.

 

A potential fix would be to use the Level#playLocalSound method, just like it's used for items that can be broken due to their durability:

@Override
    public void handleEntityEvent(byte b) {
        switch (b) {
            // ... previous entity events
            case 30: {
                this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.SHIELD_BREAK, 0.8f, 0.8f + this.level().random.nextFloat() * 0.4f, false);
                break;
            }
            case 29: {
                this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.SHIELD_BLOCK, 1.0f, 0.8f + this.level().random.nextFloat() * 0.4f, false);
                break;
            }
            // ... next entity events
        }
    }

Still occurs on 1.20.6

zChenX

(Unassigned)

Confirmed

Gameplay

Low

Networking, Sound

multiplayer, sound

1.19.2, 1.20.1, 1.20.6

25w04a

Retrieved