Redstone Mechanics
This page covers the redstone signal system, comparator logic, repeater delays, daylight detection, and powered rails as they’re implemented in the MinecraftConsoles codebase.
Signal constants
Section titled “Signal constants”The Redstone class (Redstone.h) defines the basic signal range used throughout the redstone system:
| Constant | Value | Purpose |
|---|---|---|
SIGNAL_NONE | 0 | No signal / off |
SIGNAL_MIN | 0 | Minimum signal strength |
SIGNAL_MAX | 15 | Maximum signal strength |
All redstone components clamp their output to this 0 to 15 range.
DiodeTile base class
Section titled “DiodeTile base class”Source files: DiodeTile.h/cpp, DirectionalTile.h/cpp
Both the comparator and repeater inherit from DiodeTile, which itself extends DirectionalTile. DiodeTile provides the shared logic for directional redstone components:
- Directionality uses a 2-bit
DIRECTION_MASKin the tile data to encode which way the component faces. TheDIRECTION_INV_MASKis the bitwise inverse, used by subclasses to extract non-direction bits. - On/off state is kept in a boolean
onfield (protected). Two tile IDs exist per component (one for powered, one for unpowered), returned by the pure-virtualgetOnTile()andgetOffTile()methods. - Input signal is read by
getInputSignal(), which grabs the redstone signal arriving from behind the component. - Alternate (side) signal is read by
getAlternateSignal()andgetAlternateSignalAt(), which check the signals from both sides. This is used for repeater locking and comparator subtract mode. - Output signal is provided by
getOutputSignal(), which reads the signal strength at the front. - Tick scheduling via
checkTickOnNeighbor()schedules a game tick when a neighbor changes, with optional priority support (shouldPrioritize()). - Locking via
isLocked()returns whether a side signal locks the component (base implementation always returnsfalse; the repeater overrides it).
Common methods
Section titled “Common methods”| Method | Purpose |
|---|---|
isDiode(int id) | Static helper that checks if a tile ID is any diode-type |
isSameDiode(int id) | Checks if a tile ID matches this specific diode type |
isMatching(int id) | Checks if a tile matches |
isOn(int data) | Checks if the component is powered from the tile data |
isSignalSource() | Returns true (all diodes produce redstone signal) |
isCubeShaped() | Returns false (diodes are flat) |
isSolidRender() | Returns false |
isAlternateInput(int tile) | Checks if a neighboring tile can provide side input |
updateNeighborsInFront() | Notifies blocks in front when the output changes |
mayPlace() | Checks if the component can be placed at a position |
canSurvive() | Checks if the component has support below |
updateDefaultShape() | 4J added this override for shape initialization |
shouldRenderFace() | Controls face rendering |
getRenderShape() | Returns the render shape ID |
getTexture(int face, int data) | Returns the texture icon for a given face |
Turn-off and turn-on delays
Section titled “Turn-off and turn-on delays”getTurnOffDelay(int data) returns the turn-off delay (base implementation uses turn-on delay).
getTurnOnDelay(int data) is pure virtual, implemented by each subclass.
Tick behavior
Section titled “Tick behavior”The base tick() method:
- Checks if the component needs to change state.
- If currently on but should be off, swaps to the off tile.
- If currently off but should be on, swaps to the on tile.
- Both transitions schedule a follow-up neighbor check.
Placement
Section titled “Placement”setPlacedBy() records the facing direction based on the placer’s rotation. onPlace() initializes the state and notifies neighbors. destroy() cleans up.
Comparator
Section titled “Comparator”Source files: ComparatorTile.h/cpp, ComparatorTileEntity.h/cpp
The comparator extends both DiodeTile and EntityTile, so it needs a tile entity to persist its output signal.
Data bits
Section titled “Data bits”| Bit | Mask | Purpose |
|---|---|---|
| Bits 0-1 | DIRECTION_MASK | Facing direction (inherited) |
| Bit 2 | 0x4 (BIT_OUTPUT_SUBTRACT) | Subtract mode enabled |
| Bit 3 | 0x8 (BIT_IS_LIT) | Comparator is visually lit |
The comparator has two modes, toggled by right-clicking (use()):
- Compare mode (default): Output equals the input signal, but only when the input is greater than or equal to the side (alternate) signal.
- Subtract mode (
BIT_OUTPUT_SUBTRACTset): Output equalsmax(input - alternate, 0).
The mode check is done by isReversedOutputSignal(), which tests (data & BIT_OUTPUT_SUBTRACT) == BIT_OUTPUT_SUBTRACT. Despite the name, “reversed” means subtract mode is active.
The use() method has a soundOnly parameter (4J addition) for tooltip prediction without side effects. TestUse() returns whether the comparator can be interacted with.
Signal calculation
Section titled “Signal calculation”calculateOutputSignal() has the core logic:
if not subtract mode: return input signalelse: return max(input - alternate, SIGNAL_NONE)shouldTurnOn() figures out whether the comparator should be lit:
- If the input signal is at maximum (15), always on.
- If the input signal is zero, always off.
- Otherwise, on when the input is greater than or equal to the alternate (side) signal.
Analog input detection
Section titled “Analog input detection”getInputSignal() goes beyond basic redstone signal reading. After getting the standard diode input, it checks whether the tile behind the comparator hasAnalogOutputSignal(). If so, it reads the analog output (used for containers like chests and hoppers). If the immediate tile is a solid block, it checks one tile further for an analog source. This lets you read through blocks.
Blocks that support analog output in MinecraftConsoles include:
- Hoppers (
HopperTile) - Dispensers (
DispenserTile) - Jukeboxes (
JukeboxTile) - Command blocks (
CommandBlock)
Turn-on delay
Section titled “Turn-on delay”The comparator has a fixed turn-on delay of 2 redstone ticks (returned by getTurnOnDelay()).
Tile entity
Section titled “Tile entity”ComparatorTileEntity stores a single int output field, saved in NBT as "OutputSignal". The tile entity is used by getOutputSignal() and setOutputSignal() to cache the comparator’s last computed output, so neighbors can read the signal without triggering a recalculation.
The entity type enum is eTYPE_COMPARATORTILEENTITY, and it has a static create() factory and a 4J-added clone() method.
Tick behavior
Section titled “Tick behavior”When tick() fires, the comparator cleans up legacy “on” tile IDs by converting them to the off tile with BIT_IS_LIT set, then calls refreshOutputState(). This method:
- Recalculates the output signal via
calculateOutputSignal(). - Updates the tile entity’s stored output via
setOutputSignal(). - Flips
BIT_IS_LITon or off as needed. - Notifies neighbors in front of the comparator via
updateNeighborsInFront().
Placement and removal
Section titled “Placement and removal”onPlace() calls the parent DiodeTile::onPlace() and creates a new ComparatorTileEntity. onRemove() removes the tile entity and updates front neighbors. triggerEvent() handles block events for state synchronization.
Other methods
Section titled “Other methods”getResource()returns the item drop IDcloneTileId()returns the tile ID for clone operationsgetRenderShape()returns the render shapegetTexture()returns the icon for a given face and datanewTileEntity()creates theComparatorTileEntity
Repeater
Section titled “Repeater”Source files: RepeaterTile.h/cpp
The repeater extends DiodeTile without needing a tile entity.
Delay system
Section titled “Delay system”The repeater supports four delay settings, stored in the upper bits of the tile data:
| Data bits | Mask | Purpose |
|---|---|---|
| Bits 0 to 1 | DIRECTION_MASK | Facing direction |
| Bits 2 to 3 | DELAY_MASK (same as DIRECTION_INV_MASK) | Delay index (0 to 3) |
The DELAY_SHIFT is 2, so the delay index is pulled out as (data & DELAY_MASK) >> 2.
The four delay values are stored in a static DELAYS[4] array:
| Index | Base delay | Actual delay (base * 2) | In seconds |
|---|---|---|---|
| 0 | 1 | 2 game ticks | 0.1s |
| 1 | 2 | 4 game ticks | 0.2s |
| 2 | 3 | 6 game ticks | 0.3s |
| 3 | 4 | 8 game ticks | 0.4s |
getTurnOnDelay() returns DELAYS[index] * 2.
Cycling delay
Section titled “Cycling delay”Right-clicking (use()) bumps the delay index by 1, wrapping around from index 3 back to 0. The operation preserves the direction bits and sets UPDATE_ALL for both client and server updates. Like the comparator, use() has a soundOnly parameter and TestUse() for tooltip support.
Locking
Section titled “Locking”The repeater overrides isLocked() to return true when getAlternateSignal() > SIGNAL_NONE, meaning a side signal from another diode locks the repeater’s current output state.
isAlternateInput() restricts side inputs to other diode tiles only (via isDiode()), so only repeaters and comparators can lock a repeater. Regular redstone dust or other signal sources can’t lock it.
Render offsets
Section titled “Render offsets”The four delay render offsets (DELAY_RENDER_OFFSETS[4]) position the movable torch visually:
{-1/16, 1/16, 3/16, 5/16}These are double values stored in a static array.
Particle effects
Section titled “Particle effects”When powered (on == true), animateTick() spawns reddust particles on either the receiver or transmitter end of the repeater, with the position offset based on the current delay setting and facing direction.
Removal
Section titled “Removal”onRemove() updates neighbors when the repeater is broken.
Other methods
Section titled “Other methods”getResource()returns the item drop IDcloneTileId()returns the tile ID for clone operationsgetRenderShape()returns the render shape
Daylight detector
Section titled “Daylight detector”Source files: DaylightDetectorTile.h/cpp, DaylightDetectorTileEntity.h/cpp
The daylight detector is a BaseEntityTile that outputs a redstone signal based on the sky light level.
The detector is a flat slab, 6/16 of a block tall. It’s not a full cube (isCubeShaped() returns false) and it’s not solid (isSolidRender() returns false). 4J added an updateDefaultShape() override and the standard updateShape() method.
Signal strength calculation
Section titled “Signal strength calculation”updateSignalStrength() computes the output signal:
- Skips entirely if the dimension has a ceiling (
dimension->hasCeiling). - Reads the sky brightness at the block’s position, minus the current sky darkening.
- Factors in the sun’s angle using
cos(sunAngle), with the angle tilted 20% toward zenith for a smoother day/night transition. - Clamps the result to
[0, SIGNAL_MAX]. - Updates the tile data only if the value changed, with
UPDATE_ALLpropagation.
getSignal() just reads and returns the stored tile data, so the data byte itself holds the signal strength (0 to 15). isSignalSource() returns true.
Tile entity tick
Section titled “Tile entity tick”DaylightDetectorTileEntity::tick() runs every second (getGameTime() % TICKS_PER_SECOND == 0) on the server side, calling updateSignalStrength() on its parent tile. So the signal updates once per second, not every game tick.
The entity type is eTYPE_DAYLIGHTDETECTORTILEENTITY with a static create() factory and 4J-added clone().
Event handling
Section titled “Event handling”neighborChanged() and onPlace() are overridden for initial setup and neighbor-based updates.
Textures
Section titled “Textures”Two textures are registered via registerIcons(): _top for the upper face and _side for all other faces, stored in an icons[2] array.
Powered rails
Section titled “Powered rails”Source files: PoweredRailTile.h/cpp, BaseRailTile.h/cpp
BaseRailTile foundation
Section titled “BaseRailTile foundation”All rail types inherit from BaseRailTile, which provides:
- Direction constants:
DIR_FLAT_Z(0),DIR_FLAT_X(1), plus slopes (2 to 5) and curves (6 to 9). - Data bit:
RAIL_DATA_BIT(0x8) is used by powered and detector rails to store their active state. Regular rails use the full data range for direction. - Direction mask:
RAIL_DIRECTION_MASK(0x7) pulls direction from tiles that use the data bit. - Rail detection:
isRail()checks if a tile ID is any rail type (normal rail, golden/powered rail, detector rail, or activator rail). Both static overloads are provided (by Level+position, and by raw ID). - Data bit flag:
usesDataBit(protected bool) marks whether this rail type uses bit 3. - Turn icon:
iconTurnstores the curved rail texture (only used by non-data-bit rails).
The inner Rail class handles connection logic:
- Each rail can connect to up to 2 neighboring rails.
- Rails auto-connect to neighbors during placement via
place(). - Slope detection checks one block above for rails in the X and Z directions.
- Curved directions (6 to 9) are only available to rails that don’t use the data bit (basically just normal rails).
- Piston push reaction is overridden to
PUSH_NORMALinstead of the decoration material default (viagetPistonPushReaction()). - 4J added a
m_bValidRailflag for additional validation.
Connection methods (all on the inner Rail class):
updateConnections()figures out connections based on directionremoveSoftConnections()cleans up invalid connectionshasRail()/hasNeighborRail()check for rails at positionsgetRail()gets aRailat aTilePosconnectsTo()/hasConnection()/canConnectTo()/connectTo()manage connectionscountPotentialConnections()counts possible neighbors
The neighborChanged() method checks structural validity: the rail pops off if the block below isn’t solid, or if a sloped rail loses its supporting block at the upper end.
Other BaseRailTile methods:
isUsesDataBit()public accessorgetAABB()returns the collision box (rails have no collision)blocksLight()returnsfalseisSolidRender()returnsfalseisCubeShaped()returnsfalseclip()handles ray tracingupdateShape()adjusts the bounding box shapegetRenderShape()returns the rail render shapegetResourceCount()returns 1mayPlace()checks placement validityonPlace()/onRemove()handle creation and cleanupupdateState()/updateDir()handle rail direction updates
PoweredRailTile
Section titled “PoweredRailTile”The powered rail extends BaseRailTile with usesDataBit = true. It uses bit 3 (RAIL_DATA_BIT) to store the powered/unpowered state.
Power propagation:
updateState() determines the powered state from three sources:
- Direct redstone neighbor signal (
hasNeighborSignal()). - Forward chain search (
findPoweredRailSignal(level, ..., true, 0)). - Backward chain search (
findPoweredRailSignal(level, ..., false, 0)).
The chain search (findPoweredRailSignal()) recursively follows connected powered rails up to a depth of 8 rails. At each step:
- It moves forward or backward along the rail’s axis, handling slopes by adjusting the Y coordinate.
isSameRailWithPower()verifies the neighbor is the same rail type, checks directional compatibility, and either confirms a direct redstone signal or recurses deeper.
When the powered state changes, the rail updates its data and notifies neighbors. For sloped rails (directions 2 to 5), it also updates neighbors at y + 1.
Textures:
Two textures are used: the default icon for unpowered and iconPowered (registered as _powered suffix) for the active state. Both are stored as Icon* pointers.
Related pages
Section titled “Related pages”- Hoppers and Droppers for hopper mechanics including analog output for comparators
- Minecart Variants for powered rail interaction with minecarts