-
Bug
-
Resolution: Fixed
-
1.16.1, 20w29a, 20w30a, 1.16.2 Pre-release 1, 1.16.2 Pre-release 2, 1.16.2 Release Candidate 1, 1.16.2 Release Candidate 2, 1.16.2
-
None
-
Confirmed
-
Performance, Redstone
-
Normal
The bug
Comparators in compare mode can schedule tileticks when they shouldn't, creating unneeded lag from block updates and in some situations the comparator can be instant making for very confusing timings.
To reproduce
- Place a comparator down in compare mode
- Power the side of the comparator
- Power the back of the comparator with a signal strength less than the side
→ Comparator should do nothing
→ Comparator schedules a tiletick on itself and causes block updates afer 2gt
This can be most easily seen when placing a Block Update Detector after the comparator
It will detect the block updates that the scheduled tiletick produces
Instant Comparator
Due to this bug allowing comparators to schedule a tiletick seemly randomly, if in the right circumstances the comparator can appear instant, creating a very confusing time for the player as they try to find the timing issue
In the below picture both comparators turn on at the same time even tho the top line has an extra 1tick of delay
This is because when the first repeaters turn on, the comparator thinks it can turn on too (even tho it can't), so it schedules a tiletick on itself for the next tick
In the next tick, the side of the comparator turns off and the comparator instantly turns on afterwards in the same tick
Code analysis
Vanilla code:
private int calculateOutputSignal(Level level, BlockPos blockPos, BlockState blockState) { if (blockState.getValue(MODE) == ComparatorMode.SUBTRACT) { return Math.max(this.getInputSignal(level, blockPos, blockState) - this.getAlternateSignal(level, blockPos, blockState), 0); } return this.getInputSignal(level, blockPos, blockState); }
The first if statement for subtract mode works perfectly fine
But the compare mode doesn't take the side input into account, leading to the comparator thinking it can turn on even tho the side input is overpowering the back
Fixed code:
private int calculateOutputSignal(Level level, BlockPos blockPos, BlockState blockState) { if (blockState.getValue(MODE) == ComparatorMode.SUBTRACT) { return Math.max(this.getInputSignal(level, blockPos, blockState) - this.getAlternateSignal(level, blockPos, blockState), 0); } return this.getInputSignal(level, blockPos, blockState) >= this.getAlternateSignal(level, blockPos, blockState) ? this.getInputSignal(level, blockPos, blockState) : 0; }
Check if the side input is greater than the back and return 0
Optimized code:
private int calculateOutputSignal(Level level, BlockPos blockPos, BlockState blockState) { int i = this.getInputSignal(level, blockPos, blockState); if (i == 0) return 0; j = this.getAlternateSignal(level, blockPos, blockState); if (j > i) return 0; if (blockState.getValue(MODE) == ComparatorMode.SUBTRACT) { return i - j; } return j; }
If the back input is 0, no need to check the side or mode state and return 0
If the side input is greater than the back, no need to check the mode state and return 0
Note for technical players
This bug is not the cause nor affects scheduling a tiletick on a comparator by simply powering the back (without the side) with a 1tick pulse
As that is not a exception, but a rule on how comparators fundamentally work
Nor will this remove instant comparators
There are multiple ways of getting a comparator to schedule a tiletick
And you do not use this partiular technique