In general, there are two types of redstone blocks:
- power providers, such as redstone blocks (RedstoneBlock), buttons, levers, daylight sensors
- power consumers, such as redstone lamp (RedstoneLampBlock), DoorBlock, NoteBlock
Power providersPower providers can provide power to other blocks in two ways:
- “Weak power” – every block adjacent to the power provider is powered. For example – in the picture below, when the lever is on, all adjacent lamps (south, north, west, east, up, down) will turn on.
- “Strong power” – when the power provider is attached to a suitable block, it causes that block to provide weak power to all of its neighbours. For example – the button provides strong power to the stone block, and the stone block provides weak power to the adjacent lamps.
|Weak power - when activated, the lever provides weak power to the adjacent lamps (in this case north, south, east, west)|
|Strong power - when activated, the button provides strong power to the stone it's attached to. The stone then provides weak power to the adjacent lamps.|
The amount of power provided is from 0 (no power) to 15 (max power), using the following Block methods:
getWeakPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
For the example in the picture below:
RedstoneBlock.isProvidingWeakPower(minecraft:redstone_block, world, redstone blockpos, EAST)
When this method is called for the redstone, it returns the weak power level (i.e. 15) it is providing to the adjacent lamp.
EAST means that the redstone is to the EAST of the lamp.
pos and state are the position and state of the redstone, not the adjacent lamp.
|Redstone block provides weak power to the lamp|
getStrongPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
button blockpos, EAST)
When this method is called for the button, it returns the strong power level (i.e. 15) it is providing to the adjacent stone block.
EAST means that the button is to the EAST of the stone
pos and state are the position and state of the button, not the adjacent stone.
|Button provides strong power to the stone. This will cause the stone to provide weak power to all of the stone's neighbours.|
– return true!
Optional methods that can help you tweak your block’s behaviourcanConnectRedstone(side)
- this side is a power output and redstone wire will connect to it. (Note- the Javadoc for the method says "input or output" but actually it's strictly for output only).
shouldCheckWeakPower(IBlockAccess world, BlockPos pos, EnumFacing side)
This method is called when Forge wants to know the power level of this block Actually it is named backwards! A block which can be strongly powered (eg by an attached lever or button) should return true here. This lets you override the vanilla assumption that a block can be strongly powered if (and only if) it isNormalCube().
- If you return true: Forge checks whether this block is being strongly powered by any of its neighbours. If not, the power level is zero.
- If you return false: Forge instead checks whether this block itself is generating weak power.
Power consumersA power consumer is a block which reacts to nearby power providers. The propagation of power is by “pull”, not push – i.e. The consumer is responsible for requesting information from its neighbouring providers, not the other way around. It usually does this in one of two ways-
- For non-direction blocks such as Redstone Lamp-
a. World.isBlockPowered(pos) for an on/off answer; or
b. World.getRedstonePowerFromNeighbors(pos) if they need to know the strength [0 – 15]
- For directional blocks such as Redstone Torch or redstone repeater-
a. World.isSidePowered(side) for an on/off answer; or
b. World.getRedstonePower(side) if they need to know the strength [0-15]
The typical sequence is as follows, with example picture below.
- An event occurs which means the redstone power needs to be recalculated. In many cases, this is caused by a change in the power provider – for example the user pushes the BlockLever -> onBlockActivated(), or the user smashes the BlockLever -> breakBlock() or similar. The block method will typically then call world.notifyNeighborsOfStateChange().
- All neighbouring consumers (such as the Redstone Lamp) will then call world.isBlockPowered(BlockPos) with their own blockpos to discover whether they are being powered, either weakly or strongly. This check usually happens in onBlockAdded, onNeighbourBlockChange, and updateTick
- The call to World.isBlockPowered for RedstoneLampBlock will then check its neighbours one by one (in this case- the unattached lever, and the stone):
a. Check if the neighbour is providing weak power (the unattached lever).
b. Check if the neighbour can be strongly powered (yes - the stone), and if so, check if the stone has any adjacent blocks which are strongly powering it (the button attached to the stone).
- The RedstoneLampBlock will then change its state/ perform some action as appropriate depending on whether it is being powered or not.
If the block needs to know the strength of the signal, it will use getRedstonePowerFromNeighbors() instead of isBlockPowered().
|The glowstone can be powered by weak power from the lever, or alternatively the strong power from the button can make the stone emit weak power to the glowstone.|
ComparatorsComparators function slightly differently from other redstone. The input to a comparator might be from a block that is two positions away with an isNormalCube() in between – for example the comparator senses the level of water in the cauldron, with a stone block inbetween.
|The comparator senses the cauldron water level from two blocks away.|
To create your own comparator (ComparatorBlock is the only vanilla example), you should implement
- return true. This ensures that your comparator will be informed of a change two blocks away, instead of only for adjacent blocks.
Blocks which can be used as the input for a redstone comparator (eg CauldronBlock) should implement the following methods·
getComparatorInputOverride(World worldIn, BlockPos pos)
return the value [0..15] to be used by the comparator
Some notes about server/client and IBlockReader
- You may have noticed that the most important redstone methods (eg isProvidingWeakPower() and isProvidingStrongPower()) give you an IBlockReader instead of a World. This poses a few restrictions on the methods you can run in there. Most importantly, it generally means that you must rely on stored power level information rather than trying to calculate it from adjacent block power levels. Vanilla usually stores the power level in the blockstate, for this reason. The major exception is the comparator, which uses a TileEntity to store the power level (and retrieves this information during the call to isProvidingWeakPower()). I think this is probably done for a good reason, eg to stop infinite loops from two adjacent blocks calling each other recursively, or perhaps to make sure that the redstone propagates the same way regardless of which order the neighbour blocks update in.
- Most of the methods relevant to redstone run on the server only - for example updateTick(), onNeighbourBlockChange() - calculation of signal strengths and propagation of power is done on the server only.
- If your client side needs to know about redstone signal strength for rendering your block correctly, you need to use some way of communicating it to the client. Vanilla usually does this by storing the power level as metadata (RedstoneWireBlock), or sometimes by changing the block (eg RedstoneLampBlock). These are automatically synchronised from server to client.
- You might think that you could change the block's appearance during render using getModelData to query the redstone power based on the block's neighbours. Unfortunately this doesn't work. The reason is that this methods is provided with an ILightReader instead of a World; block rendering is multithreaded and is performed on a cached copy of the world, which only stores some of the information. This cached copy is accessed through ILightReader and gives no direct access to weak power methods. You need to store the power level in blockstate property instead.
- As an alternative, you can attach a TileEntity to the block - the TileEntity is rendered every frame in the client thread - it has a reference to World which you can use to access all the redstone power methods also on the client side. Although you could use this trick to access World during a call to getModelData I wouldn't recommend it, because this might lead to the rendering thread accessing the same objects as the client thread without any synchronisation, which is usually a recipe for disaster (i.e. crashes and other weird glitches that are very hard to debug).
Further informationFor some more useful background information about redstone devices, see here. (NB the terminology he uses for "weak" and "strong", "powered", "indirect" doesn't really match the Forge conventions).
Some working examples to illustrate these concepts.