Complete redstone (static subset) specification
Scope
This specification completely describes redstone in minecraft java 1.18.2, with the following blocks:
| Name | ID |
|---|---|
| Air | 0 |
| Solid block | 1 |
| Glass | 2 |
| Slab (top) | 3 |
| Repeater | 4 |
| Comparator | 5 |
| Dust (wire) | 6 |
| Redstone Block | 7 |
| Redstone Torch | 8 |
| Redstone Lamp | 9 |
| Chest (contents static) | 10 |
| Barrel (contents static) | 11 |
Warning
This spec applies exclusively to 1.18.2.
Note
File paths are relative to /src/net/minecraft/ unless stated otherwise.
Types
Scheduled tick
A scheduled tick has five fields: block (the block type it targets), pos (the block position), triggerTick (the game tick it fires on, as a long), priority (a TickPriority value), and subTickOrder (a global sequence number assigned when the tick is scheduled).
Ordering within a chunk's queue (TRIGGER_TICK_COMPARATOR): sort by triggerTick ascending, then priority index ascending (lower index = higher priority), then subTickOrder ascending. This determines the order ticks fire within a chunk.
Ordering across chunks (BASIC_COMPARATOR): sort by priority index ascending, then subTickOrder ascending. Used to fairly interleave ticks from different chunks.
Deduplication key (identity): only (block, pos) - two ticks for the same block at the same position are considered duplicates regardless of their timing or priority.
Tick priority
| Index | Name |
|---|---|
| −3 | EXTREMELY_HIGH |
| −2 | VERY_HIGH |
| −1 | HIGH |
| 0 | NORMAL |
| 1 | LOW |
| 2 | VERY_LOW |
| 3 | EXTREMELY_LOW |
Lower index = fires first within the same game tick.
Block update flags (1)
| Name | Effect |
|---|---|
| NOTIFY_NEIGHBORS | call Notify neighbors on all 6 adjacent blocks |
| NOTIFY_LISTENERS | send state change to clients |
| FORCE_STATE | skip shape-update propagation (not used by redstone) |
| MOVED | block is moving (pistons; not used here) |
| SKIP_LIGHTING | skip lighting recalculation (not used by redstone) |
- Passed as the
flagsargument to Set block state
Flowchart
%%{init: {"themeVariables": {"fontSize": "80px"}}}%%
flowchart TD
START([Game tick]) --> CLOOP
subgraph COL ["1. Collect chunk schedulers"]
CLOOP{"Next entry in<br/>nextTriggerTickByChunkPos?"}
CLOOP -->|Yes| C1{"storedTriggerTick<br/><= now?"}
C1 -->|No| CLOOP
C1 -->|Yes| C3{Scheduler exists AND has pending tick?}
C3 -->|"No - remove entry"| CLOOP
C3 -->|Yes| C4{"tick.triggerTick<br/><= now?"}
C4 -->|"No - update stored time"| CLOOP
C4 -->|Yes| C5{Chunk loaded?}
C5 -->|No| CLOOP
C5 -->|"Yes - Remove and add to tickableChunkSchedulers"| CLOOP
end
CLOOP -->|"No more"| DLOOP
subgraph DRN ["2. Drain ticks"]
DLOOP{"tickableTicks.size < maxTicks<br/>AND schedulers not empty?"}
DLOOP -->|Yes| D1["Poll top scheduler<br/>Poll its next tick :fontawesome-solid-arrow-right: tickableTicks"]
D1 --> DSLOOP
DSLOOP{"tickableTicks.size < maxTicks AND<br/>candidate tick exists AND<br/>triggerTick <= now AND<br/>sorts before next scheduler's head?"}
DSLOOP -->|Yes| DS1["Poll candidate → tickableTicks"]
DS1 --> DSLOOP
DSLOOP -->|No| D2{Sched has more ticks?}
D2 -->|No| DLOOP
D2 -->|Yes| D3{"Next tick due AND<br/>below maxTicks?"}
D3 -->|"Yes - put back in queue"| DLOOP
D3 -->|"No - record trigger time"| DLOOP
end
DLOOP -->|No| DELAY["Delay remaining:<br/>For each leftover scheduler, record<br/>next triggerTick into nextTriggerTickByChunkPos"]
DELAY --> ELOOP
subgraph EXEC ["3. Execute ticks"]
ELOOP{tickableTicks empty?}
ELOOP -->|No| E1["Poll tick<br/>Remove from copiedList · Add to tickedTicks<br/>Call scheduledTick handler"]
E1 --> ELOOP
end
ELOOP -->|Yes| CLEAR["Clear all queues:<br/>tickableTicks · tickableChunkSchedulers<br/>tickedTicks · copiedList"]
CLEAR --> END([Done])
Procedures
BlockTick - entry point (1)
maxTicks = 65536 (hardcoded at the call site). (2)
- Collect chunk schedulers (3)
- Drain ticks (4)
- Delay remaining ticks (5)
- Loop through
tickableTicksuntil empty: (6) - Poll
tickfrom the front oftickableTicks(7) - Remove
tickfromcopiedTickableTicksListif present (8) - Append
ticktotickedTicks(9) - Tick the block at
tick.pospassing intick.type(10) - Clear
tickableTicks,tickableChunkTickSchedulers,tickedTicks,copiedTickableTicksList(11)
- world/tick/WorldTickScheduler.java:83-93
tick() - server/world/ServerWorld.java:301
- world/tick/WorldTickScheduler.java:96
- world/tick/WorldTickScheduler.java:98
- world/tick/WorldTickScheduler.java:99
- world/tick/WorldTickScheduler.java:181-189
tick(BiConsumer) - world/tick/WorldTickScheduler.java:182
- world/tick/WorldTickScheduler.java:183-185
- world/tick/WorldTickScheduler.java:187
- world/tick/WorldTickScheduler.java:188
- world/tick/WorldTickScheduler.java:193-196
clear()
Collect chunk schedulers (1)
For each entry (chunkKey storedTriggerTick) in nextTriggerTickByChunkPos: (2)
- If
storedTriggerTick> current time: skip this entry (3) - Look up
sched=chunkTickSchedulers[chunkKey]. If not found: remove entry and move on (4) - Peek at the next due tick in
sched. If there is none: remove entry and move on (5) - If that tick's
triggerTick> current time: update the entry's stored time totriggerTickand move on (6) - If the chunk is not loaded (
tickingFutureReadyPredicatereturns false): skip, leaving the entry unchanged (7) - Remove this entry from the map (8)
- Add
schedtotickableChunkTickSchedulers(a priority queue sorted byBASIC_COMPARATORon each scheduler's next-due tick) (9)
- world/tick/WorldTickScheduler.java:102-126
collectTickableChunkTickSchedulers() - world/tick/WorldTickScheduler.java:105
- world/tick/WorldTickScheduler.java:109
- world/tick/WorldTickScheduler.java:110-112
- world/tick/WorldTickScheduler.java:114-116
- world/tick/WorldTickScheduler.java:117-118
- world/tick/WorldTickScheduler.java:119
- world/tick/WorldTickScheduler.java:120
- world/tick/WorldTickScheduler.java:121
Drain ticks (1)
Repeat while tickableTicks has fewer than maxTicks entries and tickableChunkTickSchedulers is not empty: (2)
- Pull the highest-priority scheduler off
tickableChunkTickSchedulers(byBASIC_COMPARATOR). This will be referred to assched(3) - Take the next due tick from
schedand add it totickableTicks(4) - Drain same chunk (
sched) (5) - Peek at the next tick remaining in
sched. If there is none: go to the next iteration (6) - If that tick is due now and
tickableTicksis still belowmaxTicks: putschedback intotickableChunkTickSchedulers(7) - Otherwise: record
(chunkKey(next.pos) :fontawesome-solid-arrow-right: next.triggerTick)innextTriggerTickByChunkPos(8)
- world/tick/WorldTickScheduler.java:128-143
addTickableTicks()(outer) - world/tick/WorldTickScheduler.java:130
- world/tick/WorldTickScheduler.java:130
- world/tick/WorldTickScheduler.java:131-132
- world/tick/WorldTickScheduler.java:133
- world/tick/WorldTickScheduler.java:134-135
- world/tick/WorldTickScheduler.java:136-137
- world/tick/WorldTickScheduler.java:138-140
Drain same chunk (1)
- If
tickableTicksis already atmaxTicks: stop (2) - Peek at the next-due tick of the top scheduler in
tickableChunkTickSchedulers- call itheadTick(null if the queue is empty) (3) - Repeat while
tickableTicksis belowmaxTicks: (4) - Peek at the next tick of
sched- call itcandidate. If none: stop (5) - If
candidate.triggerTick> current time: stop (6) - If
headTickexists andcandidatesorts afterheadTickbyBASIC_COMPARATOR: stop (7) - Take
candidateoffschedand add it totickableTicks(8)
- world/tick/WorldTickScheduler.java:155-170
addTickableTicks()(inner overload) - world/tick/WorldTickScheduler.java:156
- world/tick/WorldTickScheduler.java:157-158
- world/tick/WorldTickScheduler.java:160
- world/tick/WorldTickScheduler.java:161-162
- world/tick/WorldTickScheduler.java:162
- world/tick/WorldTickScheduler.java:162
- world/tick/WorldTickScheduler.java:166-167
Delay remaining ticks (1)
For each scheduler still in tickableChunkTickSchedulers, record (chunkKey(tick.pos) :fontawesome-solid-arrow-right: tick.triggerTick) back into nextTriggerTickByChunkPos. (2)
- world/tick/WorldTickScheduler.java:145-149
delayAllTicks() - world/tick/WorldTickScheduler.java:146-148
Tick the block (1)
- Read the current block state at
pos(2) - If the block type no longer matches the tick's scheduled block type (it was replaced): do nothing and return (3)
- Otherwise run the block's scheduled-tick handler: (4)
- Repeater Repeater scheduled tick
- Comparator Comparator scheduled tick
- Redstone torch (floor) Torch scheduled tick
- Redstone torch (wall) Wall torch scheduled tick
- Redstone lamp Lamp scheduled tick
- Barrel animation update only, no redstone effect
- server/world/ServerWorld.java:654-659
tickBlock() - server/world/ServerWorld.java:655
- server/world/ServerWorld.java:656
- server/world/ServerWorld.java:657
Peek at next tick (1)
Return the tick at the front of the scheduler's tickQueue (lowest by TRIGGER_TICK_COMPARATOR) without removing it. (2) Return null if the queue is empty.
- world/tick/ChunkTickScheduler.java:45-47
peekNextTick() - world/tick/ChunkTickScheduler.java:46
Take next tick (1)
- Remove and return the tick at the front of
tickQueue(lowest byTRIGGER_TICK_COMPARATOR) (2) - If the result is non-null: also remove it from
queuedTicks(3) - Return null if the queue was empty (4)
- world/tick/ChunkTickScheduler.java:50-57
pollNextTick() - world/tick/ChunkTickScheduler.java:51
- world/tick/ChunkTickScheduler.java:52-54
- world/tick/ChunkTickScheduler.java:56
Schedule a tick (1)
ScheduleTick(pos, block, delay, priority = NORMAL)
- Compute
triggerTick= current time +delay(2) - Assign
subTickOrderfrom the world's global monotonic counter (incremented each call) (3) - Find the chunk scheduler for
pos. If the chunk is not loaded: error (4) - If
queuedTicksalready contains a tick for the same(pos, block)pair: return silently (deduplicated) (5) - Add the new tick to
queuedTicksand totickQueue(6) - Notify
WorldTickSchedulerto updatenextTriggerTickByChunkPos[chunkKey(pos)]tomin(stored, triggerTick)(7)
- world/WorldAccess.java:37 / world/tick/ChunkTickScheduler.java:60-71
- world/WorldAccess.java:37
- world/WorldAccess.java:37
- world/tick/WorldTickScheduler.java:73-81
- world/tick/ChunkTickScheduler.java:61
- world/tick/ChunkTickScheduler.java:61-62, 67
- world/tick/ChunkTickScheduler.java:68-70
Set block state (1)
SetBlockState(pos, newState, flags)
- Ask the chunk to store
newStateatpos. If the state did not actually change: return false (2) - As part of that chunk write, the following happen in order:
- The old state's On state replaced handler is called (3)
- The new state's On block added handler is called (4)
- If flag
NOTIFY_LISTENERS(2) is set: send the change to clients (5) - If flag
NOTIFY_NEIGHBORS(1) is set: - Notify neighbors of
pos, citing the old block as the source (6) - If the new state has a comparator output: Notify comparators at
pos(7) - Return true (8)
- world/World.java:189-248
setBlockState() - world/World.java:200-203
- world/chunk/WorldChunk.java:263
- world/chunk/WorldChunk.java:273
- world/World.java:224-228
- world/World.java:230-231
- world/World.java:232-234
- world/World.java:247
Notify neighbors (1)
NotifyNeighbors(pos, sourceBlock)
For each direction in [WEST, EAST, DOWN, UP, NORTH, SOUTH]: notify the block at pos.offset(dir), citing sourceBlock and pos as the origin. (2)
- world/World.java:296-303
updateNeighborsAlways() - world/World.java:297-302
Notify neighbors except one direction (1)
NotifyNeighborsExcept(pos, sourceBlock, exceptDir)
For each direction in [WEST, EAST, DOWN, UP, NORTH, SOUTH] where dir ≠ exceptDir: notify the block at pos.offset(dir). (2)
- world/World.java:305-329
updateNeighborsExcept() - world/World.java:306-328
Notify one neighbor (1)
NotifyNeighbor(pos, sourceBlock, fromPos)
- If running on the client: do nothing (2)
- Read the block state at
pos(3) - Call that block's neighbor-update handler: (4)
- Repeater Repeater neighbor update
- Comparator Comparator neighbor update
- Wire Wire neighbor update
- Redstone torch (floor) Torch neighbor update
- Redstone torch (wall) Wall torch neighbor update
- Redstone lamp Lamp neighbor update
- Any other block: no action within this spec's scope
- world/World.java:331-337
updateNeighbor() - world/World.java:332
- world/World.java:333
- world/World.java:336
Notify comparators (1)
NotifyComparators(pos, sourceBlock)
For each of the 4 horizontal directions [NORTH, EAST, SOUTH, WEST]: (2)
- Check the immediate neighbor in that direction. If it is a comparator: call its neighbor update handler (3)
- Otherwise, if the immediate neighbor is a solid block: check the position one step further in the same direction. If that position is a comparator: call its neighbor update handler (4)
- world/World.java:830-844
updateComparators() - world/World.java:831
- world/World.java:834-836
- world/World.java:837-843
On block added (1)
Called whenever a new block state is written into the chunk. Dispatches on the new block type: (2)
- Repeater Repeater on block added
- Comparator Repeater on block added (same inherited handler from
AbstractRedstoneGateBlock) - Wire Wire on block added
- Redstone torch (floor or wall) Torch on block added
- Any other block: no action within this spec's scope
- world/chunk/WorldChunk.java:272-274
- world/chunk/WorldChunk.java:273
On state replaced (1)
Called whenever a block state is overwritten. Dispatches on the old block type: (2)
- Repeater Repeater on state replaced
- Comparator Repeater on state replaced (same inherited handler)
- Wire Wire on state replaced
- Redstone torch (floor or wall) Torch on state replaced
- Any other block: default behavior (block entity cleanup; no redstone effect)
- world/chunk/WorldChunk.java:262-266
- world/chunk/WorldChunk.java:263
Notify the output side (1)
NotifyOutput(pos, state) - used by repeaters and comparators to push changes to whatever they power.
FACING points toward the input, so FACING.getOpposite() is the output direction.
- Compute
outputDir=state.FACING.getOpposite()andoutputPos=pos.offset(outputDir)(2) - Notify the block at
outputPos, citing this gate as the source (3) - Notify neighbors except one direction at
outputPos- all 5 neighbors of the output block, except the one pointing back toward this gate (directionstate.FACING) (4)
- block/AbstractRedstoneGateBlock.java:169-174
updateTarget() - block/AbstractRedstoneGateBlock.java:170-171
- block/AbstractRedstoneGateBlock.java:172
- block/AbstractRedstoneGateBlock.java:173
Power queries
Emitted power at a position (1)
EmittedPower(pos, dir) dir is the direction from the querying block toward pos.
- Read the block state at
pos(2) - Get the block's weak power output in direction
dir(3) - If the block at
posis a solid opaque block: return the maximum of that weak power and the strong power received atpos(4) - Otherwise: return the weak power directly (5)
A solid opaque block re-emits as weak power any strong power arriving from any face.
- world/World.java:680-684
getEmittedRedstonePower() - world/World.java:681
- world/World.java:682
- world/World.java:683
- world/World.java:683
Strong power received at a position (1)
StrongPowerReceived(pos)
For each direction in [DOWN, UP, NORTH, SOUTH, WEST, EAST]: get the strong power output of the neighbor in that direction, track the running maximum, and return 15 immediately if it is reached. (2) Return the maximum found.
- world/World.java:645-674
getReceivedStrongRedstonePower() - world/World.java:647-673
Weak power received at a position (1)
WeakPowerReceived(pos)
For each direction in [DOWN, UP, NORTH, SOUTH, WEST, EAST]: get the emitted power from the neighbor in that direction, track the running maximum, and return 15 immediately if it is reached. (2) Return the maximum found.
- world/World.java:700-715
getReceivedRedstonePower() - world/World.java:703-712
Is the position receiving any power? (1)
For each direction in [DOWN, UP, NORTH, SOUTH, WEST, EAST]: if the emitted power from the neighbor in that direction is > 0, return true. (2) Otherwise return false.
- world/World.java:686-698
isReceivingRedstonePower() - world/World.java:687-696
Is the position emitting power in a direction? (1)
Return true if EmittedPower(pos, dir) > 0. (2)
- world/World.java:676-678
isEmittingRedstonePower() - world/World.java:677
Weak power output (1)
WeakPower(state, pos, dir) - how much weak power this block emits in direction dir.
- Air (0), Solid block (1), Glass (2), Slab (3): 0
- Repeater (4): Repeater weak power
- Comparator (5): Comparator weak power
- Wire (6): Wire weak power
- Redstone block (7): 15 in all directions
- Redstone torch floor (8): Torch weak power
- Redstone torch wall (8w): Wall torch weak power
- Redstone lamp (9), Chest (10), Barrel (11): 0
BlockState.getWeakRedstonePower- dispatched by block type; see individual block sections
Strong power output (1)
StrongPower(state, pos, dir) - how much strong power this block emits in direction dir.
- Air (0), Solid block (1), Glass (2), Slab (3): 0
- Repeater (4): same as Repeater weak power
- Comparator (5): same as Comparator weak power
- Wire (6): Wire strong power
- Redstone block (7): 0 (does not override strong power)
- Redstone torch floor (8): Torch weak power if
dir== DOWN, else 0 (2) - Redstone torch wall (8w): Wall torch weak power if
dir== DOWN, else 0 (3) - Redstone lamp (9), Chest (10), Barrel (11): 0
BlockState.getStrongRedstonePower- dispatched by block type; see individual block sections- block/RedstoneTorchBlock.java:86-88
- block/RedstoneTorchBlock.java:86-88 (inherited by WallRedstoneTorchBlock)
Block 0 - Air
No behavior. Emits no power.
Block 1 - Solid block (opaque)
No redstone behavior of its own. Emits no weak or strong power. isSolidBlock = true, so it conducts strong power from neighboring emitters - handled automatically by Emitted power at a position.
Block 2 - Glass
No redstone behavior. Emits no power. isSolidBlock = false, so it does not conduct strong power.
Block 3 - Slab (top)
No redstone behavior. Emits no power. isSolidBlock = false. Wire can be placed on top of it.
Block 4 - Repeater
State: FACING (NORTH/EAST/SOUTH/WEST), DELAY (1-4 game ticks), LOCKED (bool), POWERED (bool)
FACING points toward the input block. The output block sits at pos.offset(FACING.getOpposite()). When placed, FACING = playerFacing.getOpposite().
Repeater weak power (1)
- If the repeater is not powered: return 0 (2)
- If
dir==FACING(the querying block is on the output side): return 15 (3) - Otherwise: return 0 (4)
- block/AbstractRedstoneGateBlock.java:59-65
getWeakRedstonePower() - block/AbstractRedstoneGateBlock.java:60-61
- block/AbstractRedstoneGateBlock.java:63
- block/AbstractRedstoneGateBlock.java:63
Repeater front input power (1)
- Get the emitted power of the block directly in front (
pos.offset(FACING)), measured in theFACINGdirection (2) - If that power is less than 15 and the block in front is wire: take the maximum of the emitted power and the wire's
POWERstate value (3) - Return the result (4)
- block/AbstractRedstoneGateBlock.java:107-117
getPower() - block/AbstractRedstoneGateBlock.java:108-110
- block/AbstractRedstoneGateBlock.java:111-116
- block/AbstractRedstoneGateBlock.java:116
Repeater side input power (1)
Check the two blocks perpendicular to FACING: left = FACING.rotateYClockwise(), right = FACING.rotateYCounterclockwise(). (2)
Return the maximum of repeater side input level for each side. (3)
- block/AbstractRedstoneGateBlock.java:119-124
getMaxInputLevelSides() - block/AbstractRedstoneGateBlock.java:120-122
- block/AbstractRedstoneGateBlock.java:123
Repeater side input level (1)
For repeaters, only another repeater or comparator on the side can contribute a locking signal.
- Read the block state at
sidePos(2) - If that block is not a repeater or comparator: return 0 (3)
- Return the strong power output of that block in
sideDir(4)
- block/AbstractRedstoneGateBlock.java:126-137
getInputLevel()(repeater variant,isValidInput=isRedstoneGate) - block/AbstractRedstoneGateBlock.java:127
- block/AbstractRedstoneGateBlock.java:128, 134-136
- block/AbstractRedstoneGateBlock.java:132
Repeater locked check (1)
Return true if repeater side input power > 0. (2)
- block/RepeaterBlock.java:60-62
isLocked() - block/RepeaterBlock.java:61
Does the repeater face a misaligned gate? (1)
- The output block sits at
pos.offset(FACING.getOpposite())(2) - Return true if that block is a repeater or comparator and its
FACINGis not pointing back toward this repeater (3)
- block/AbstractRedstoneGateBlock.java:188-192
isTargetNotAligned() - block/AbstractRedstoneGateBlock.java:189-190
- block/AbstractRedstoneGateBlock.java:191
Repeater neighbor update (1)
- If the repeater has no floor to stand on: drop as an item, remove the block, notify all 6 neighbors, and stop (2)
- Otherwise: check and schedule a state change (3)
- block/AbstractRedstoneGateBlock.java:68-80
neighborUpdate() - block/AbstractRedstoneGateBlock.java:71-79
- block/AbstractRedstoneGateBlock.java:70
Repeater check and schedule (1)
- If the repeater is locked: do nothing (2)
- If the current
POWEREDstate already matches whether front input power > 0, or a tick for this repeater is already being processed this game tick: do nothing (3) - Determine scheduling priority: (4)
- If the output target is misaligned: EXTREMELY_HIGH (5)
- Else if currently powered: VERY_HIGH (6)
- Otherwise: HIGH (7)
- Schedule a tick for this repeater at
DELAY × 2game ticks from now with that priority (8)
- block/AbstractRedstoneGateBlock.java:82-97
updatePowered() - block/AbstractRedstoneGateBlock.java:83
- block/AbstractRedstoneGateBlock.java:84-86
- block/AbstractRedstoneGateBlock.java:87-93
- block/AbstractRedstoneGateBlock.java:88-89
- block/AbstractRedstoneGateBlock.java:90-91
- block/AbstractRedstoneGateBlock.java:87
- block/AbstractRedstoneGateBlock.java:94
Repeater scheduled tick (1)
- If the repeater is locked: do nothing (2)
- Read current
POWEREDstate and whether front input power > 0 (call ithasPower) (3) - If powered and
hasPoweris false: set block state toPOWERED=false, flags 2 (4) - If not powered: (5)
- Set block state to
POWERED=true, flags 2 (6) - If
hasPoweris also false (input disappeared before this tick fired): schedule a tick atDELAY × 2ticks with priority VERY_HIGH to turn off again (7)
- block/AbstractRedstoneGateBlock.java:38-51
scheduledTick() - block/AbstractRedstoneGateBlock.java:39
- block/AbstractRedstoneGateBlock.java:40-41
- block/AbstractRedstoneGateBlock.java:42-43
- block/AbstractRedstoneGateBlock.java:44
- block/AbstractRedstoneGateBlock.java:45
- block/AbstractRedstoneGateBlock.java:46-48
Repeater on block added (1)
- block/AbstractRedstoneGateBlock.java:157-159
onBlockAdded() - block/AbstractRedstoneGateBlock.java:158
Repeater on state replaced (1)
- If the new block is the same type (e.g., a
POWEREDorDELAYchange): do nothing - the output was already notified via on block added (2) - Otherwise: notify the output side using the old state (3)
- block/AbstractRedstoneGateBlock.java:162-167
onStateReplaced() - block/AbstractRedstoneGateBlock.java:163
- block/AbstractRedstoneGateBlock.java:165
Block 5 - Comparator
State: FACING (NORTH/EAST/SOUTH/WEST), MODE (COMPARE/SUBTRACT), POWERED (bool)
FACING follows the same convention as the repeater - points toward the input, output at pos.offset(FACING.getOpposite()).
Block entity: ComparatorBlockEntity stores outputSignal (int 0-15) - the comparator's last computed output value.
Comparator weak power (1)
- If the comparator is not powered: return 0 (2)
- If
dir==FACING(the querying block is on the output side): returnComparatorBlockEntity(pos).outputSignal(3) - Otherwise: return 0 (4)
- block/AbstractRedstoneGateBlock.java:59-65 / block/ComparatorBlock.java:41-44
getWeakRedstonePower()/getOutputLevel() - block/AbstractRedstoneGateBlock.java:60-61
- block/AbstractRedstoneGateBlock.java:63 / block/ComparatorBlock.java:43
- block/AbstractRedstoneGateBlock.java:63
Comparator front input power (1)
- Start with the emitted power of the block directly in front (
pos.offset(FACING)), measured in theFACINGdirection (2) - Check the block directly in front: (3)
- If it outputs a comparator signal (e.g., a container): use that signal as the power value (4)
- Otherwise, if the current power is less than 15 and the front block is solid: look one step further behind it (
behindPos = frontPos.offset(FACING)): (5)- Check for an item frame at
behindPosfacingFACING(only counts if exactly one frame is present) (6) - Check if the block at
behindPosoutputs a comparator signal (7) - Use the larger of the two (if either exists) (8)
- Check for an item frame at
- Return the resulting power value (9)
- block/ComparatorBlock.java:72-92
getPower() - block/ComparatorBlock.java:73
- block/ComparatorBlock.java:74-76
- block/ComparatorBlock.java:77-78
- block/ComparatorBlock.java:79-88
- block/ComparatorBlock.java:82
- block/ComparatorBlock.java:84
- block/ComparatorBlock.java:83-87
- block/ComparatorBlock.java:91
Comparator side input power (1)
Check the two perpendicular neighbors (left and right of FACING). For comparators, any block that emits redstone power counts as a valid side input - not just repeaters and comparators. (2)
Return the maximum of comparator side input level for each side. (3)
- block/AbstractRedstoneGateBlock.java:119-124
getMaxInputLevelSides()(comparator variant) - block/AbstractRedstoneGateBlock.java:120-122
- block/AbstractRedstoneGateBlock.java:123
Comparator side input level (1)
- If the side block does not emit redstone power: return 0 (2)
- If it is a redstone block: return 15 (3)
- If it is wire: return the wire's
POWERstate value (4) - Otherwise: return its strong power output in
sideDir(5)
- block/AbstractRedstoneGateBlock.java:126-137
getInputLevel()(comparator variant,isValidInput=emitsRedstonePower) - block/AbstractRedstoneGateBlock.java:128, 134-136
- block/AbstractRedstoneGateBlock.java:129-130
- block/AbstractRedstoneGateBlock.java:132
- block/AbstractRedstoneGateBlock.java:132
Comparator output signal (1)
- Get front input power. If it is 0: return 0 (2)
- Get side input power (3)
- If side > front: return 0 (4)
- If mode is SUBTRACT: return
front − side. If mode is COMPARE: returnfront(5)
- block/ComparatorBlock.java:46-58
calculateOutputSignal() - block/ComparatorBlock.java:47-49
- block/ComparatorBlock.java:51
- block/ComparatorBlock.java:52-53
- block/ComparatorBlock.java:55
Does the comparator have power? (1)
- Get front input power. If 0: return false (2)
- Get side input power (3)
- Return true if
front > side, or iffront == sideand mode is COMPARE (4)
- block/ComparatorBlock.java:61-69
hasPower() - block/ComparatorBlock.java:62-65
- block/ComparatorBlock.java:67
- block/ComparatorBlock.java:68
Comparator neighbor update (1)
- If a tick for this comparator is already being processed this game tick: do nothing (2)
- Compute the new output signal and read the old one from the block entity (0 if absent) (3)
- If the output signal hasn't changed and the
POWEREDstate already matches whether it has power: do nothing (4) - Otherwise schedule a tick at 2 game ticks from now: (5)
- Priority HIGH if the output target is misaligned (6)
- Priority NORMAL otherwise (7)
- block/ComparatorBlock.java:119-129
updatePowered() - block/ComparatorBlock.java:120
- block/ComparatorBlock.java:121-123
- block/ComparatorBlock.java:124
- block/ComparatorBlock.java:126
- block/ComparatorBlock.java:125
- block/ComparatorBlock.java:125
Comparator scheduled tick (1)
- Compute the new output signal (2)
- Read the old
outputSignalfrom the block entity (0 if absent) (3) - Write the new value to the block entity (4)
- If the output signal didn't change and mode is not COMPARE: stop (no state update needed) (5)
- Check whether the comparator has power (6)
- If currently
POWEREDbut no longer has power: set block state toPOWERED=false, flags 2 (7) - If currently not
POWEREDbut now has power: set block state toPOWERED=true, flags 2 (8) - Notify the output side (9)
- block/ComparatorBlock.java:154-156
update()at 131-151 - block/ComparatorBlock.java:132
- block/ComparatorBlock.java:133-136
- block/ComparatorBlock.java:137
- block/ComparatorBlock.java:140
- block/ComparatorBlock.java:141
- block/ComparatorBlock.java:143-144
- block/ComparatorBlock.java:145-146
- block/ComparatorBlock.java:149
Block 6 - Wire (Redstone Dust)
State: WIRE_CONNECTION_{NORTH,EAST,SOUTH,WEST} (NONE/SIDE/UP), POWER (0-15)
wiresGivePower flag: a mutable boolean on the wire block singleton. Normally true; temporarily set to false during Wire received power to prevent circular power queries.
Wire weak power (1)
- If
wiresGivePoweris false, ordir== DOWN: return 0 (2) - If
POWER== 0: return 0 (3) - If
dir== UP, or the wire is connected toward the querying block (connection in directiondir.getOpposite()is SIDE or UP): returnPOWER(4) - Otherwise: return 0 (5)
- block/RedstoneWireBlock.java:404-418
getWeakRedstonePower() - block/RedstoneWireBlock.java:405
- block/RedstoneWireBlock.java:407-408
- block/RedstoneWireBlock.java:410-413
- block/RedstoneWireBlock.java:410-413
Wire strong power (1)
- If
wiresGivePoweris false: return 0 (2) - Otherwise: return wire weak power (3)
- block/RedstoneWireBlock.java:399-401
getStrongRedstonePower() - block/RedstoneWireBlock.java:400
- block/RedstoneWireBlock.java:400
Wire received power (1)
- Temporarily set
wiresGivePower= false (2) - Get weak power received at
pos- finds power from all non-wire sources on all 6 faces. Call thisdirect(3) - Restore
wiresGivePower= true (4) - If
direct< 15, also check adjacent wires: (5) - For each of [NORTH, EAST, SOUTH, WEST]: (6)
- Check the horizontal neighbor: if it is wire, note its
POWER(7) - If the neighbor is a solid block and the block directly above
posis not solid: also check the wire one step up from that neighbor (8) - If the neighbor is not solid: also check the wire one step down from that neighbor (9)
- Check the horizontal neighbor: if it is wire, note its
- Track the maximum wire
POWERseen; call thisadjacent(10) - Return
max(direct, adjacent − 1)(11)
- block/RedstoneWireBlock.java:307-327
getReceivedRedstonePower() - block/RedstoneWireBlock.java:308
- block/RedstoneWireBlock.java:309
- block/RedstoneWireBlock.java:310
- block/RedstoneWireBlock.java:312
- block/RedstoneWireBlock.java:313
- block/RedstoneWireBlock.java:316
- block/RedstoneWireBlock.java:318-319
- block/RedstoneWireBlock.java:320-321
- block/RedstoneWireBlock.java:316-321
- block/RedstoneWireBlock.java:326
Wire update (1)
- Compute wire received power (2)
- If
POWERalready equals the new value: do nothing (3) - If the block state at
posis still the same: set block state with the newPOWERvalue, flags 2 (4) - Build the set of positions to notify:
positself plus all 6 adjacent positions (5) - For each of those 7 positions: notify neighbors citing Wire as the source (6)
- block/RedstoneWireBlock.java:287-305
update() - block/RedstoneWireBlock.java:288
- block/RedstoneWireBlock.java:289
- block/RedstoneWireBlock.java:290-292
- block/RedstoneWireBlock.java:294-299
- block/RedstoneWireBlock.java:301-303
Wire neighbor update (1)
- If running on the client: do nothing (2)
- If the wire has no surface to sit on: drop as an item, remove the block, and stop (3)
- Otherwise: wire update (4)
- block/RedstoneWireBlock.java:387-396
neighborUpdate() - block/RedstoneWireBlock.java:388
- block/RedstoneWireBlock.java:392-394
- block/RedstoneWireBlock.java:390
Wire on block added (1)
- If running on the client: do nothing (2)
- Wire update (3)
- Notify neighbors of
pos.up()andpos.down(), citing Wire (4) - Notify wire offset neighbors at
pos(5)
- block/RedstoneWireBlock.java:344-354
onBlockAdded() - block/RedstoneWireBlock.java:345
- block/RedstoneWireBlock.java:346
- block/RedstoneWireBlock.java:348-350
- block/RedstoneWireBlock.java:352
Wire on state replaced (1)
- If the block is moving, or the new block is also wire: do nothing (2)
- If running on the client: do nothing (3)
- For each of the 6 directions: notify neighbors of
pos.offset(dir), citing Wire (4) - Wire update using the old state (5)
- Notify wire offset neighbors at
pos(6)
- block/RedstoneWireBlock.java:357-369
onStateReplaced() - block/RedstoneWireBlock.java:358
- block/RedstoneWireBlock.java:360
- block/RedstoneWireBlock.java:361-363
- block/RedstoneWireBlock.java:365
- block/RedstoneWireBlock.java:366
Notify wire offset neighbors (1)
For each horizontal direction [NORTH, EAST, SOUTH, WEST]: (2)
- If the immediate neighbor is wire: notify neighbors of that neighbor and all 6 of its own neighbors, citing Wire (3)
Then for each horizontal direction [NORTH, EAST, SOUTH, WEST]: (4)
- If the neighbor is a solid block, and the block one step above that neighbor is wire: notify neighbors of that wire and all 6 of its neighbors, citing Wire (5)
- If the neighbor is not a solid block, and the block one step below that neighbor is wire: notify neighbors of that wire and all 6 of its neighbors, citing Wire (6)
- block/RedstoneWireBlock.java:371-384
updateOffsetNeighbors() - block/RedstoneWireBlock.java:372
- block/RedstoneWireBlock.java:373-374
- block/RedstoneWireBlock.java:376
- block/RedstoneWireBlock.java:378-379
- block/RedstoneWireBlock.java:380-382
Block 7 - Redstone Block
No scheduled tick. No neighbor-update handler. Emits weak power 15 in all directions. Does not emit strong power (isSolidBlock = true but strong power is not overridden). emitsRedstonePower = true.
Block 8 - Redstone Torch (floor)
State: LIT (bool), default true
Torch weak power (1)
Return 15 if lit and dir ≠ UP, otherwise return 0. (2)
- block/RedstoneTorchBlock.java:48-50
getWeakRedstonePower() - block/RedstoneTorchBlock.java:49
Should the torch turn off? (1)
Return true if the block the torch is mounted on is emitting power downward - i.e., the mounting block is powered. (2)
- block/RedstoneTorchBlock.java:52-54
shouldUnpower() - block/RedstoneTorchBlock.java:53
Torch neighbor update (1)
If LIT == shouldUnpower (meaning a state change is needed: either lit and should turn off, or unlit and should turn on), and no tick is already scheduled for this torch: schedule a tick at 2 game ticks, priority NORMAL. (2)
- block/RedstoneTorchBlock.java:79-83
neighborUpdate() - block/RedstoneTorchBlock.java:80-82
Torch scheduled tick (1)
- Check whether the torch should turn off (2)
- Remove any burnout entries older than 60 game ticks from the burnout table (3)
- If lit and should turn off: (4)
- Set block state to
LIT=false, flags 3 (5) - If the torch is now burned out (recording this event): schedule a tick at 160 game ticks, NORMAL - prevents rapid relighting (6)
- If unlit and should turn on, and the torch is not burned out (not recording): set block state to
LIT=true, flags 3 (7)
- block/RedstoneTorchBlock.java:57-76
scheduledTick() - block/RedstoneTorchBlock.java:58
- block/RedstoneTorchBlock.java:59-63
- block/RedstoneTorchBlock.java:65-66
- block/RedstoneTorchBlock.java:67
- block/RedstoneTorchBlock.java:68-71
- block/RedstoneTorchBlock.java:73-75
Is the torch burned out? (1)
IsBurnedOut(pos, addNew) - tracks how many times this torch has turned off in the last 60 game ticks.
- Look up this position's entry list in the per-world burnout table (create it if absent) (2)
- If
addNewis true: append an entry with the current game tick (3) - Count entries for this position. If 8 or more: return true (burned out); otherwise false (4)
- block/RedstoneTorchBlock.java:110-128
isBurnedOut() - block/RedstoneTorchBlock.java:111
- block/RedstoneTorchBlock.java:112-114
- block/RedstoneTorchBlock.java:116-127
Torch on block added (1)
For each of the 6 directions: notify neighbors at pos.offset(dir), citing RedstoneTorch. (2)
- block/RedstoneTorchBlock.java:32-36
onBlockAdded() - block/RedstoneTorchBlock.java:33-35
Torch on state replaced (1)
If the block is not moving: for each of the 6 directions, notify neighbors at pos.offset(dir), citing RedstoneTorch. (2) (Fires for LIT changes as well as full block removal.)
- block/RedstoneTorchBlock.java:39-45
onStateReplaced() - block/RedstoneTorchBlock.java:40-44
Block 8w - Wall Redstone Torch
State: FACING (NORTH/EAST/SOUTH/WEST), LIT (bool), default true
FACING is the direction the torch points - away from the wall. The mounting block is at pos.offset(FACING.getOpposite()).
Wall torch weak power (1)
Return 15 if lit and dir ≠ FACING, otherwise return 0. (2)
- block/WallRedstoneTorchBlock.java:76-78
getWeakRedstonePower() - block/WallRedstoneTorchBlock.java:77
Should the wall torch turn off? (1)
mountDir=FACING.getOpposite()(2)- Return true if the mounting block at
pos.offset(mountDir)is emitting power in directionmountDir(3)
- block/WallRedstoneTorchBlock.java:70-73
shouldUnpower() - block/WallRedstoneTorchBlock.java:71
- block/WallRedstoneTorchBlock.java:72
Wall torch neighbor update
Same logic as Torch neighbor update but uses wall torch's should-turn-off check and schedules for WallRedstoneTorch. (Inherited from RedstoneTorchBlock.neighborUpdate - block/RedstoneTorchBlock.java:79-83.)
Wall torch scheduled tick
Same logic as Torch scheduled tick but uses wall torch's should-turn-off check and writes WallRedstoneTorch states. (Inherited from RedstoneTorchBlock.scheduledTick - block/RedstoneTorchBlock.java:57-76.)
Block 9 - Redstone Lamp
State: LIT (bool), default false. Never emits power.
Lamp neighbor update (1)
- If running on the client: do nothing (2)
- Read
lit=state.LITandreceiving= is the position receiving any power? (3) - If
lit==receiving: do nothing (state is already correct) (4) - If the lamp is lit and signal was lost: schedule a tick at 4 game ticks, priority NORMAL (5)
- If the lamp is unlit and signal arrived: set block state to
LIT=true, flags 2 (immediate, no delay) (6)
- block/RedstoneLampBlock.java:27-38
neighborUpdate() - block/RedstoneLampBlock.java:28
- block/RedstoneLampBlock.java:29-30
- block/RedstoneLampBlock.java:30
- block/RedstoneLampBlock.java:31-32
- block/RedstoneLampBlock.java:33-34
Lamp scheduled tick (1)
If lit and no longer receiving power: set block state to LIT=false, flags 2. (2)
- block/RedstoneLampBlock.java:41-45
scheduledTick() - block/RedstoneLampBlock.java:42-44
Block 10 - Chest
hasComparatorOutput = true. Otherwise passive (contents are static in this spec).
Chest comparator output (1)
Get the chest's inventory - for a double chest, this is the combined 54-slot inventory. Return the inventory fill signal. (2)
- block/ChestBlock.java:351-352
getComparatorOutput() - block/ChestBlock.java:352
Block 11 - Barrel
hasComparatorOutput = true. Otherwise passive.
Barrel comparator output (1)
Get the barrel's block entity and return the inventory fill signal. (2)
- block/BarrelBlock.java:103-104
getComparatorOutput() - block/BarrelBlock.java:104
Inventory fill signal (1)
- If the inventory is null: return 0 (2)
- For each slot: if not empty, add
(item count) / min(inventory max stack size, item's own max stack size)to a running total, and count one non-empty slot (3) - Divide the total by the number of slots to get a fill ratio (4)
- Return
floor(fillRatio × 14) + (1 if any slot was non-empty, else 0)(5)
Range: 0 (completely empty) to 15 (completely full). Single chest: 27 slots. Double chest: 54 slots. Barrel: 27 slots.
- screen/ScreenHandler.java:707-725
calculateComparatorOutput() - screen/ScreenHandler.java:708-710
- screen/ScreenHandler.java:715-721
- screen/ScreenHandler.java:723
- screen/ScreenHandler.java:724