mojira.dev
MC-193925

Ice does not produce water when broken in creative

Inconsistent with survival behavior

Code Analysis:

Code analysis by @unknown can be found in this comment.

Linked issues

Attachments

Comments 18

Hi there!

This is more than likely intended, as otherwise, there would be no way (except for commands) to remove ice in creative mode without it flooding an area.

Say you were building on a creative world with cheats disabled. You start placing down ice blocks in an item transporting system, but then realize that it is packed ice you should be using. You start breaking the ice blocks (the only thing you can do), but then your complex redstone contraption beneath it is now flooded.

Creative players should not have to use silk touch tools to be able to remove ice without creating water.

Can confirm for 1.16.2

Can confirm for 20w46a.

Can confirm in 20w49a.

Can confirm in 20w51a.

8 more comments

Can confirm in 1.18.1.

Can confirm in 1.18.2.

Can confirm in 1.19.

Can confirm in 1.19.2.

Code Analysis:

The following is based on a decompiled version of Minecraft 1.20.1 using MCP-Reborn.

net.minecraft.server.level.ServerPlayerGameMode.java // Original

public class ServerPlayerGameMode {
    ...
    public boolean destroyBlock(BlockPos p_9281_) {
       BlockState blockstate = this.level.getBlockState(p_9281_);
       if (!this.player.getMainHandItem().getItem().canAttackBlock(blockstate, this.level, p_9281_, this.player)) {
          return false;
       } else {
          BlockEntity blockentity = this.level.getBlockEntity(p_9281_);
          Block block = blockstate.getBlock();
          if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) {
             this.level.sendBlockUpdated(p_9281_, blockstate, blockstate, 3);
             return false;
          } else if (this.player.blockActionRestricted(this.level, p_9281_, this.gameModeForPlayer)) {
                    return false;
                } else {
                    block.playerWillDestroy(this.level, p_9281_, blockstate, this.player);
                    boolean flag = this.level.removeBlock(p_9281_, false);
                    if (flag) {
                        block.destroy(this.level, p_9281_, blockstate);
                    }                    

                    if (this.isCreative()) {
                        return true;
                    } else {
                        ItemStack itemstack = this.player.getMainHandItem();
                        ItemStack itemstack1 = itemstack.copy();
                        boolean flag1 = this.player.hasCorrectToolForDrops(blockstate);
                        itemstack.mineBlock(this.level, blockstate, p_9281_, this.player);
                        if (flag && flag1) {
                            block.playerDestroy(this.level, this.player, p_9281_, blockstate, blockentity, itemstack1);
                        }
    
                        return true;
                    }
                }
            }
        }
        ...
}

As you can see, there is a piece of code that checks if the player is in creative (this.isCreative()), if they are, then we return and do nothing about the block's state. Therefore this looks pretty intentional as a "feature" for Minecraft.
But, it looks like this bug report seems to be an official Mojang bug, so I will write a code analysis and fix to solve this problem.

Temporary Fix:

net.minecraft.server.level.ServerPlayerGameMode.java // Updated

public class ServerPlayerGameMode {
    ...
    public boolean destroyBlock(BlockPos p_9281_) {
            BlockState blockstate = this.level.getBlockState(p_9281_);
            if (!this.player.getMainHandItem().getItem().canAttackBlock(blockstate, this.level, p_9281_, this.player)) {
                return false;
            } else {
                BlockEntity blockentity = this.level.getBlockEntity(p_9281_);
                Block block = blockstate.getBlock();
                if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) {
                    this.level.sendBlockUpdated(p_9281_, blockstate, blockstate, 3);
                    return false;
                } else if (this.player.blockActionRestricted(this.level, p_9281_, this.gameModeForPlayer)) {
                    return false;
                } else {
                    block.playerWillDestroy(this.level, p_9281_, blockstate, this.player);
                    boolean flag = this.level.removeBlock(p_9281_, false);
                    if (flag) {
                        block.destroy(this.level, p_9281_, blockstate);
                    }                    

                    ItemStack itemstack = this.player.getMainHandItem();
                    ItemStack itemstack1 = itemstack.copy();
                    boolean flag1 = this.player.hasCorrectToolForDrops(blockstate);
                    itemstack.mineBlock(this.level, blockstate, p_9281_, this.player);
                    if (flag && flag1) {
                       block.playerDestroy(this.level, this.player, p_9281_, blockstate, blockentity, itemstack1);
                    }                        
                    
                    return true;
                }
            }
        }
        ...
}

In the code structure above, we simply remove the this.isCreative() check so logic of the block's state will update even in creative.

WARNING: This code analysis and fix will allow creative players to drop item(s) upon breaking the block.

muzikbike

(Unassigned)

Confirmed

Block states

1.16.1, 20w27a, 1.16.2, 1.16.3 Release Candidate 1, 1.16.3, ..., 1.19, 1.19.2, 1.19.4, 23w14a, 1.20.1

Retrieved