-
Bug
-
Resolution: Unresolved
-
None
-
1.20.4, 24w14a
-
None
-
Community Consensus
-
Particles
The normal behaviour can be observed when breaking a bed in survival or adventure mode. When you break a bed, the block breaking effects are played for both halves no matter in which orientation or order you break it in.
Compare that to creative mode, where if you break the bed's top half, it behaves normally, however when you break the bottom half, the particle effects are played twice for the head, and no times for the foot.
Doing my own investigations, the problem appears to come from this method in the bed block class (cleaned up a bit for readability) (using yarn mappings):
@Override public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) { BedPart part = state.get(PART); BlockPos otherHalfPos = pos.offset(getDirectionTowardsOtherPart(part, state.get(FACING))); BlockState otherHalfState = world.getBlockState(otherHalfPos); if (!world.isClient && player.isCreative() && part == BedPart.FOOT && otherHalfState.isOf(this) && otherHalfState.get(PART) == BedPart.HEAD) { world.setBlockState(otherHalfPos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL | Block.SKIP_DROPS); world.syncWorldEvent(player, WorldEvents.BLOCK_BROKEN, otherHalfPos, Block.getRawIdFromState(otherHalfState)); } return super.onBreak(world, pos, state, player); }
The purpose of this code appears to be to remove the head of the bed when the foot is broken so it doesn't drop and item. At first it seemed like the problem was entirely here, but after digging ruther it seems a little more complicated than that.
The problem seems t be in two parts:
1. The effect for the head of the block isn't being played (world.syncWorldEvent does nothing here)
2. Breaking the head of the block here somehow triggers getStateForNeighborUpdate to be called on the foot of the bed, which does its validation and causes the foot to break and play its effects, then its effects are repeated by the onBreak method.
After some trial and error, I landed on this that should patch both issues.
The significant changes are:
1. move the client check down so spawnBreakParticles is called for the head on both client and server
2. skip the call to spawnBreakParticles for the foot to avoid doubling up with the call that comes from elsewhere.
@Override public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) { BedPart part = state.get(PART); BlockPos otherHalfPos = pos.offset(getDirectionTowardsOtherPart(part, state.get(FACING))); BlockState otherHalfState = world.getBlockState(otherHalfPos); // moved client side check down as we need this to run on both sides if (/*!world.isClient &&*/ player.isCreative() && part == BedPart.FOOT && otherHalfState.isOf(this) && otherHalfState.get(PART) == BedPart.HEAD) { if (!world.isClient) { world.setBlockState(otherHalfPos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL | Block.SKIP_DROPS); } spawnBreakParticles(world, player, otherHalfPos, otherHalfState); // contents of the super method (to preserve previous behaviour - would be good to have a way to call this without the spawnBreakParticles call) if (state.isIn(BlockTags.GUARDED_BY_PIGLINS)) { PiglinBrain.onGuardedBlockInteracted(player, false); } world.emitGameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Emitter.of(player, state)); return state; } else { // moved super call to an else condition return super.onBreak(world, pos, state, player); } }
- is duplicated by
-
MC-270333 Breaking the foot half of a bed does not emit particles at the head half
- Resolved