Skip to content

Commit

Permalink
Add redstone relay block (#2002)
Browse files Browse the repository at this point in the history
 - Move redstone methods out of the IAPIEnvironment, and into a new
   RedstoneAccess. We similarly move the implementation from Environment
   into a new RedstoneState class.

   The interface is possibly a little redundant (interfaces with a
   single implementation are always a little suspect), but it's nice to
   keep the consumer/producer interfaces separate.

 - Abstract most redstone API methods into a separate shared class, that
   can be used by both the rs API and the new redstone relay.

 - Add the new redstone relay block.

The docs are probably a little lacking here, but I really struggled to
write anything which wasn't just "look, it's the same as the redstone
API".
  • Loading branch information
SquidDev authored Nov 12, 2024
1 parent ba6da3b commit 4f66ac7
Show file tree
Hide file tree
Showing 50 changed files with 1,610 additions and 353 deletions.
6 changes: 5 additions & 1 deletion doc/events/redstone.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
SPDX-License-Identifier: MPL-2.0
-->

The [`event!redstone`] event is fired whenever any redstone inputs on the computer change.
The [`event!redstone`] event is fired whenever any redstone inputs on the computer or [relay][`redstone_relay`] change.

## Return values
1. [`string`]: The event name.
Expand All @@ -21,3 +21,7 @@ while true do
print("A redstone input has changed!")
end
```

## See also
- [The `redstone` API on computers][`module!redstone`]
- [The `redstone_relay` peripheral][`redstone_relay`]
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ junit = "5.10.1"
jmh = "1.37"

# Build tools
cctJavadoc = "1.8.2"
cctJavadoc = "1.8.3"
checkstyle = "10.14.1"
curseForgeGradle = "1.0.14"
errorProne-core = "2.27.0"
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ public static void addBlockModels(BlockModelGenerators generators) {

registerCable(generators);

registerRedstoneControl(generators);

registerTurtleUpgrade(generators, "block/turtle_crafting_table", "block/turtle_crafty_face");
registerTurtleUpgrade(generators, "block/turtle_speaker", "block/turtle_speaker_face");
registerTurtleModem(generators, "block/turtle_modem_normal", "block/wireless_modem_normal_face");
Expand Down Expand Up @@ -355,6 +357,18 @@ private static void registerCable(BlockModelGenerators generators) {
generators.blockStateOutput.accept(generator);
}

private static void registerRedstoneControl(BlockModelGenerators generators) {
var redstoneControl = ModRegistry.Blocks.REDSTONE_RELAY.get();
var model = ModelTemplates.CUBE_ORIENTABLE_TOP_BOTTOM.create(
redstoneControl, TextureMapping.orientableCube(redstoneControl), generators.modelOutput
);
generators.blockStateOutput.accept(
MultiVariantGenerator.multiVariant(redstoneControl, Variant.variant().with(VariantProperties.MODEL, model))
.with(createHorizontalFacingDispatch())
);
}


private static final BooleanProperty[] CABLE_DIRECTIONS = { CableBlock.DOWN, CableBlock.UP, CableBlock.NORTH, CableBlock.SOUTH, CableBlock.WEST, CableBlock.EAST };
private static final boolean[] BOOLEANS = new boolean[]{ false, true };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ private void addTranslations() {
add(ModRegistry.Items.WIRED_MODEM.get(), "Wired Modem");
add(ModRegistry.Items.CABLE.get(), "Networking Cable");
add(ModRegistry.Items.WIRED_MODEM_FULL.get(), "Wired Modem");
add(ModRegistry.Items.REDSTONE_RELAY.get(), "Redstone Relay");

add(ModRegistry.Items.TURTLE_NORMAL.get(), "Turtle");
add(ModRegistry.Blocks.TURTLE_NORMAL.get().getDescriptionId() + ".upgraded", "%s Turtle");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ private static void registerBlocks(BiConsumer<ResourceLocation, LootTable.Builde
selfDrop(add, ModRegistry.Blocks.WIRED_MODEM_FULL);
selfDrop(add, ModRegistry.Blocks.WIRELESS_MODEM_NORMAL);
selfDrop(add, ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED);
selfDrop(add, ModRegistry.Blocks.REDSTONE_RELAY);

computerDrop(add, ModRegistry.Blocks.COMPUTER_NORMAL);
computerDrop(add, ModRegistry.Blocks.COMPUTER_ADVANCED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,17 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.requires(ingredients.string())
.unlockedBy("has_printer", inventoryChange(ModRegistry.Blocks.PRINTER.get()))
.save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.IMPOSTOR_SHAPELESS.get(), add));

ShapedRecipeBuilder
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.REDSTONE_RELAY.get())
.pattern("SRS")
.pattern("RCR")
.pattern("SRS")
.define('S', Items.STONE)
.define('R', ingredients.redstone())
.define('C', ModRegistry.Blocks.CABLE.get())
.unlockedBy("has_cable", inventoryChange(ModRegistry.Blocks.CABLE.get()))
.save(add);
}

private static DyeColor ofColour(Colour colour) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,12 @@ public static void blockTags(TagConsumer<Block> tags) {
ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get(),
ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get(),
ModRegistry.Blocks.WIRED_MODEM_FULL.get(),
ModRegistry.Blocks.CABLE.get()
ModRegistry.Blocks.CABLE.get(),
ModRegistry.Blocks.REDSTONE_RELAY.get()
);

tags.tag(BlockTags.MINEABLE_WITH_AXE).add(ModRegistry.Blocks.LECTERN.get());

tags.tag(BlockTags.WITHER_IMMUNE).add(ModRegistry.Blocks.COMPUTER_COMMAND.get());

tags.tag(ExternalModTags.Blocks.CREATE_BRITTLE).add(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
import dan200.computercraft.shared.peripheral.printer.PrinterBlock;
import dan200.computercraft.shared.peripheral.printer.PrinterBlockEntity;
import dan200.computercraft.shared.peripheral.printer.PrinterMenu;
import dan200.computercraft.shared.peripheral.redstone.RedstoneRelayBlock;
import dan200.computercraft.shared.peripheral.redstone.RedstoneRelayBlockEntity;
import dan200.computercraft.shared.peripheral.speaker.SpeakerBlock;
import dan200.computercraft.shared.peripheral.speaker.SpeakerBlockEntity;
import dan200.computercraft.shared.platform.PlatformHelper;
Expand Down Expand Up @@ -132,7 +134,7 @@ private static BlockBehaviour.Properties properties() {
return BlockBehaviour.Properties.of().strength(2);
}

private static BlockBehaviour.Properties computerProperties() {
private static BlockBehaviour.Properties redstoneConductor() {
// Computers shouldn't conduct redstone through them, so set isRedstoneConductor to false. This still allows
// redstone to connect to computers though as it's a signal source.
return properties().isRedstoneConductor((block, level, blockPos) -> false);
Expand All @@ -147,11 +149,11 @@ private static BlockBehaviour.Properties modemProperties() {
}

public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_NORMAL = REGISTRY.register("computer_normal",
() -> new ComputerBlock<>(computerProperties().mapColor(MapColor.STONE), BlockEntities.COMPUTER_NORMAL));
() -> new ComputerBlock<>(redstoneConductor().mapColor(MapColor.STONE), BlockEntities.COMPUTER_NORMAL));
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_ADVANCED = REGISTRY.register("computer_advanced",
() -> new ComputerBlock<>(computerProperties().mapColor(MapColor.GOLD), BlockEntities.COMPUTER_ADVANCED));
() -> new ComputerBlock<>(redstoneConductor().mapColor(MapColor.GOLD), BlockEntities.COMPUTER_ADVANCED));
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_COMMAND = REGISTRY.register("computer_command",
() -> new CommandComputerBlock<>(computerProperties().strength(-1, 6000000.0F), BlockEntities.COMPUTER_COMMAND));
() -> new CommandComputerBlock<>(redstoneConductor().strength(-1, 6000000.0F), BlockEntities.COMPUTER_COMMAND));

public static final RegistryEntry<TurtleBlock> TURTLE_NORMAL = REGISTRY.register("turtle_normal",
() -> new TurtleBlock(turtleProperties().mapColor(MapColor.STONE), BlockEntities.TURTLE_NORMAL));
Expand Down Expand Up @@ -179,6 +181,9 @@ private static BlockBehaviour.Properties modemProperties() {
public static final RegistryEntry<CustomLecternBlock> LECTERN = REGISTRY.register("lectern", () -> new CustomLecternBlock(
BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.5F).sound(SoundType.WOOD).ignitedByLava()
));

public static final RegistryEntry<RedstoneRelayBlock> REDSTONE_RELAY = REGISTRY.register("redstone_relay",
() -> new RedstoneRelayBlock(redstoneConductor().mapColor(MapColor.STONE)));
}

public static class BlockEntities {
Expand Down Expand Up @@ -222,6 +227,8 @@ private static <T extends BlockEntity> RegistryEntry<BlockEntityType<T>> ofBlock
ofBlock(Blocks.WIRELESS_MODEM_ADVANCED, (p, s) -> new WirelessModemBlockEntity(BlockEntities.WIRELESS_MODEM_ADVANCED.get(), p, s, true));

public static final RegistryEntry<BlockEntityType<CustomLecternBlockEntity>> LECTERN = ofBlock(Blocks.LECTERN, CustomLecternBlockEntity::new);

public static final RegistryEntry<BlockEntityType<RedstoneRelayBlockEntity>> REDSTONE_RELAY = ofBlock(Blocks.REDSTONE_RELAY, RedstoneRelayBlockEntity::new);
}

public static final class Items {
Expand Down Expand Up @@ -267,6 +274,7 @@ private static <B extends Block, I extends Item> RegistryEntry<I> ofBlock(Regist
public static final RegistryEntry<BlockItem> WIRELESS_MODEM_NORMAL = ofBlock(Blocks.WIRELESS_MODEM_NORMAL, BlockItem::new);
public static final RegistryEntry<BlockItem> WIRELESS_MODEM_ADVANCED = ofBlock(Blocks.WIRELESS_MODEM_ADVANCED, BlockItem::new);
public static final RegistryEntry<BlockItem> WIRED_MODEM_FULL = ofBlock(Blocks.WIRED_MODEM_FULL, BlockItem::new);
public static final RegistryEntry<BlockItem> REDSTONE_RELAY = ofBlock(Blocks.REDSTONE_RELAY, BlockItem::new);

public static final RegistryEntry<CableBlockItem.Cable> CABLE = REGISTRY.register("cable",
() -> new CableBlockItem.Cable(Blocks.CABLE.get(), properties()));
Expand Down Expand Up @@ -415,6 +423,7 @@ static class CreativeTabs {
out.accept(Items.CABLE.get());
out.accept(Items.WIRED_MODEM.get());
out.accept(Items.WIRED_MODEM_FULL.get());
out.accept(Items.REDSTONE_RELAY.get());

out.accept(Items.MONITOR_NORMAL.get());
out.accept(Items.MONITOR_ADVANCED.get());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ protected void serverTick() {
// Update the block state if needed.
updateBlockState(computer.getState());

var changes = computer.pollAndResetChanges();
var changes = computer.pollRedstoneChanges();
if (changes != 0) {
for (var direction : DirectionUtil.FACINGS) {
if ((changes & (1 << remapToLocalSide(direction).ordinal())) != 0) updateRedstoneTo(direction);
Expand Down Expand Up @@ -195,8 +195,10 @@ private void updateRedstoneInput(ServerComputer computer, Direction dir, BlockPo
var offsetSide = dir.getOpposite();
var localDir = remapToLocalSide(dir);

computer.setRedstoneInput(localDir, RedstoneUtil.getRedstoneInput(getLevel(), targetPos, dir));
computer.setBundledRedstoneInput(localDir, BundledRedstone.getOutput(getLevel(), targetPos, offsetSide));
computer.setRedstoneInput(localDir,
RedstoneUtil.getRedstoneInput(getLevel(), targetPos, dir),
BundledRedstone.getOutput(getLevel(), targetPos, offsetSide)
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ boolean hasTimedOut() {
*
* @return What sides on the computer have changed.
*/
public int pollAndResetChanges() {
return computer.pollAndResetChanges();
public int pollRedstoneChanges() {
return computer.pollRedstoneChanges();
}

public UUID register() {
Expand Down Expand Up @@ -222,19 +222,15 @@ public void queueEvent(String event, @Nullable Object[] arguments) {
}

public int getRedstoneOutput(ComputerSide side) {
return computer.getEnvironment().getExternalRedstoneOutput(side);
return computer.isOn() ? computer.getRedstone().getExternalOutput(side) : 0;
}

public void setRedstoneInput(ComputerSide side, int level) {
computer.getEnvironment().setRedstoneInput(side, level);
public void setRedstoneInput(ComputerSide side, int level, int bundledState) {
computer.getRedstone().setInput(side, level, bundledState);
}

public int getBundledRedstoneOutput(ComputerSide side) {
return computer.getEnvironment().getExternalBundledRedstoneOutput(side);
}

public void setBundledRedstoneInput(ComputerSide side, int combination) {
computer.getEnvironment().setBundledRedstoneInput(side, combination);
return computer.isOn() ? computer.getRedstone().getExternalBundledOutput(side) : 0;
}

public void setPeripheral(ComputerSide side, @Nullable IPeripheral peripheral) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.peripheral.redstone;

import dan200.computercraft.shared.common.IBundledRedstoneBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;

import javax.annotation.Nonnull;

/**
* The block for redstone relays. This mostly just forwards method calls to the {@linkplain RedstoneRelayBlockEntity
* block entity}.
*/
public final class RedstoneRelayBlock extends HorizontalDirectionalBlock implements EntityBlock, IBundledRedstoneBlock {
public RedstoneRelayBlock(Properties properties) {
super(properties);
registerDefaultState(defaultBlockState().setValue(FACING, Direction.NORTH));
}

@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> properties) {
properties.add(FACING);
}

@Override
public BlockState getStateForPlacement(BlockPlaceContext placement) {
return defaultBlockState().setValue(FACING, placement.getHorizontalDirection());
}

@Override
@Deprecated
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
super.tick(state, level, pos, random);

if (level.getBlockEntity(pos) instanceof RedstoneRelayBlockEntity relay) relay.update();
}

@Override
@Deprecated
public boolean isSignalSource(@Nonnull BlockState state) {
return true;
}

@Override
@Deprecated
public int getDirectSignal(@Nonnull BlockState state, BlockGetter level, @Nonnull BlockPos pos, @Nonnull Direction incomingSide) {
return level.getBlockEntity(pos) instanceof RedstoneRelayBlockEntity relay ? relay.getRedstoneOutput(incomingSide.getOpposite()) : 0;
}

@Override
@Deprecated
public int getSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return getDirectSignal(state, level, pos, direction);
}

@Override
public int getBundledRedstoneOutput(Level level, BlockPos pos, Direction side) {
return level.getBlockEntity(pos) instanceof RedstoneRelayBlockEntity relay ? relay.getBundledRedstoneOutput(side) : 0;
}

@Override
@Deprecated
public void neighborChanged(@Nonnull BlockState state, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Block neighbourBlock, @Nonnull BlockPos neighbourPos, boolean isMoving) {
if (world.getBlockEntity(pos) instanceof RedstoneRelayBlockEntity relay) relay.neighborChanged(neighbourPos);
}

@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new RedstoneRelayBlockEntity(pos, state);
}
}
Loading

0 comments on commit 4f66ac7

Please sign in to comment.