Uploaded image for project: 'Minecraft: Java Edition'
  1. Minecraft: Java Edition
  2. MC-120986

Comparators do not update correctly in some cases


    • Icon: Bug Bug
    • Resolution: Unresolved
    • None
    • Minecraft 1.12.1, Minecraft 1.12.2 Pre-Release 1, Minecraft 1.12.2 Pre-Release 2, Minecraft 1.12.2, Minecraft 17w43a, Minecraft 17w43b, Minecraft 17w45b, Minecraft 17w46a, Minecraft 17w47a, Minecraft 17w47b, Minecraft 17w48a, Minecraft 17w49a, Minecraft 17w49b, Minecraft 17w50a, Minecraft 18w03b, Minecraft 18w05a, Minecraft 1.13-pre3, Minecraft 1.13-pre6, Minecraft 1.13-pre7, Minecraft 1.13, Minecraft 1.13.1, Minecraft 1.13.2, Minecraft 19w03b, Minecraft 19w03c, Minecraft 19w04b, Minecraft 19w05a, Minecraft 19w06a, Minecraft 1.14, 1.14.4, 1.15 Pre-release 1, 1.15.2, 20w09a, 20w19a, 20w21a, 1.16 Release Candidate 1, 1.16, 1.16.1, 1.16.4 Pre-release 2, 20w45a, 20w51a, 21w03a, 1.16.5, 21w07a, 1.17.1, 21w39a, 1.18 Release Candidate 4, 1.18, 1.19, 1.19.2, 1.19.3, 23w04a, 1.19.4 Pre-release 2, 1.20.2, 23w43a, 23w43b
    • Confirmed
    • Redstone
    • Normal
    • Platform

      This is a compilation of instances were comparators do not update their power level correctly when a block with a comparator input override changed.

      Affected blocks

      • beehive / bee nest
        • placed (behind block)
        • broken (behind block)
      • brewing stand
        • placed (behind block) using command /setblock x y z brewing_stand{Items:[{Slot:0b,id:"potion",Count:1b}]}
        • broken (behind block)
      • cake
        • placed (behind block) using command /setblock x y z cake (Does update if placed manually)
        • broken (behind block)
        • completely eaten up (behind block)
      • cauldron
        • placed (behind block) using command /setblock x y z cauldron[level=3]
        • removed (behind block)
        • filled by rain
      • chest
        • placed (behind block) using command /setblock x y z chest{Items:[{Slot:0b,id:"stone",Count:1b}]}
      • command block
        • placed (behind block) using command /setblock x y z command_block{SuccessCount:1}
        • broken (behind block)
      • compost
        • removed (behind block)
      • detector rail
        • broken (behind block)
      • dispenser
        • placed (behind block) using command /setblock x y z dispenser{Items:[{Slot:0b,id:"stone",Count:1b}]}
      • dropper
        • placed (behind block) using command /setblock x y z dropper{Items:[{Slot:0b,id:"stone",Count:1b}]}
      • end portal frame
        • placed (behind block) using command /setblock x y z end_portal_frame[eye=true]
        • broken (behind block)
      • furnace
        • placed (behind block) using command /setblock x y z furnace{Items:[{Slot:0b,id:"iron_ore",Count:1b}]}
      • hopper
        • placed (behind block) using command /setblock x y z hopper{Items:[{Slot:0b,id:"stone",Count:1b}]}
      • item frame
        • broken (by piston or command, left click would first remove the item)
        • In case MC-45619 is intended: If a block inside of the item frame is removed
      • jukebox
        • broken (behind block)
      • respawn anchors
        • explodes (behind block)
      • sculk sensors
      • (behind block): The comparator must detect the affected block through a solid block to not update in the described situation.
      • placed: Comparator does not update when the affected block is placed.
      • broken: Comparator does not update when the affected block is broken. Also applies for being moved away by a piston.
      • changed: Comparator does not update when the affected block changes its comparator input override.

      Here is a video with a few examples when this bug happens. Note that it doesn't make any difference whether a block is moved by a piston or removed by a player. Some blocks however cannot be moved by pistons.

      That's every block and issue I could find related to this. If I missed something, please let me know down below.

      Code Analysis

      This is based on a decompiled version of Minecraft 1.12 using mcp 980.

      Breaking/Moving block

      In net.minecraft.world.World.setBlockState(BlockPos, IBlockState, int) there is some code that is meant to update comparators when a block with a comparator input override is placed and the flag for block updates is set. In there, you could also cause updates if a block with comparator input override is removed, however there are some cases where the update flag is not set and instead the net.minecraft.world.World.notifyNeighborsOfStateChange(BlockPos, Block, boolean) method is called instead.
      So my proposed fix would be to remove the following

      net.minecraft.world.World.setBlockState(BlockPos, IBlockState, int)
      if (!this.isRemote && (flags & 1) != 0)
          this.notifyNeighborsRespectDebug(pos, iblockstate.getBlock(), true);
          //remove this
          if (newState.hasComparatorInputOverride())
              this.updateComparatorOutputLevel(pos, block);

      and instead add this to net.minecraft.world.World.notifyNeighborsOfStateChange(BlockPos, Block, boolean)

      net.minecraft.world.World.notifyNeighborsOfStateChange(BlockPos, Block, boolean)
      IBlockState newState = getBlockState(pos);
      if(blockType.getDefaultState().hasComparatorInputOverride() || newState.hasComparatorInputOverride())
      	updateComparatorOutputLevel(pos, newState.getBlock());

      Some code that becomes redundant after applying that fix also should be removed. That would be to remove worldIn.updateComparatorOutputLevel(pos, this); :in the following methodes

      • net.minecraft.block.BlockChest.breakBlock(World, BlockPos, IBlockState)
      • net.minecraft.block.BlockDispenser.breakBlock(World, BlockPos, IBlockState)
      • net.minecraft.block.BlockFurnace.breakBlock(World, BlockPos, IBlockState)
      • net.minecraft.block.BlockHopper.breakBlock(World, BlockPos, IBlockState)
      • net.minecraft.block.BlockShulkerBox.breakBlock(World, BlockPos, IBlockState)

      An alternative would be to override the net.minecraft.block.Block.breakBlock(World, BlockPos, IBlockState) in all the classes that have a comparator input override as proposed by marcono1234 in this comment. But it might be cleaner to apply the fix above since you don't need to remember to override the method when adding a new block with a comparator override.

      Another alternative might be to add a class that all blocks with a comparator input override need to extend in which the net.minecraft.block.Block.breakBlock(World, BlockPos, IBlockState) method is already overridden.

      Cauldron being filled by rain

      Code analysis by marcono1234 can be found in this comment

            Unassigned Unassigned
            Schortan [Mod] NeunEinser
            68 Vote for this issue
            30 Start watching this issue