Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ComputerCraft integrations to more devices #6849

Open
wants to merge 7 commits into
base: mc1.18/dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add ComputerCraft integration to Nixie Tubes
- Makes computer-controlled Nixie Tubes unable to be changed by external
  factors (but can still be used as a Display Link source)
- Add CC setText(text[, colour]) function
- Add CC setTextColour(colour) function
- Add CC setSignal(first, second) function taking 2 tables describing
  the appearance of the first and second tube as custom train signals
  • Loading branch information
ElementW committed Aug 24, 2024
commit 96a325c03b2d47a21c6a7d7c5e4b17b12c138368
4 changes: 4 additions & 0 deletions src/main/java/com/simibubi/create/AllPartialModels.java
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ public class AllPartialModels {
SIGNAL_RED_CUBE = block("track_signal/red_cube"), SIGNAL_RED_GLOW = block("track_signal/red_glow"),
SIGNAL_RED = block("track_signal/red_tube"), SIGNAL_YELLOW_CUBE = block("track_signal/yellow_cube"),
SIGNAL_YELLOW_GLOW = block("track_signal/yellow_glow"), SIGNAL_YELLOW = block("track_signal/yellow_tube"),
SIGNAL_COMPUTER_WHITE_CUBE = block("track_signal/computer_white_cube"),
SIGNAL_COMPUTER_WHITE_GLOW = block("track_signal/computer_white_glow"),
SIGNAL_COMPUTER_WHITE = block("track_signal/computer_white_tube"),
SIGNAL_COMPUTER_WHITE_BASE = block("track_signal/computer_white_tube_base"),

BLAZE_INERT = block("blaze_burner/blaze/inert"), BLAZE_SUPER_ACTIVE = block("blaze_burner/blaze/super_active"),
BLAZE_GOGGLES = block("blaze_burner/goggles"), BLAZE_GOGGLES_SMALL = block("blaze_burner/goggles_small"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour;
import com.simibubi.create.compat.computercraft.implementation.peripherals.DisplayLinkPeripheral;
import com.simibubi.create.compat.computercraft.implementation.peripherals.NixieTubePeripheral;
import com.simibubi.create.compat.computercraft.implementation.peripherals.SequencedGearshiftPeripheral;
import com.simibubi.create.compat.computercraft.implementation.peripherals.SpeedControllerPeripheral;
import com.simibubi.create.compat.computercraft.implementation.peripherals.SpeedGaugePeripheral;
Expand All @@ -12,6 +13,7 @@
import com.simibubi.create.content.kinetics.speedController.SpeedControllerBlockEntity;
import com.simibubi.create.content.kinetics.transmission.sequencer.SequencedGearshiftBlockEntity;
import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockEntity;
import com.simibubi.create.content.redstone.nixieTube.NixieTubeBlockEntity;
import com.simibubi.create.content.trains.station.StationBlockEntity;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;

Expand Down Expand Up @@ -40,6 +42,8 @@ public static NonNullSupplier<IPeripheral> getPeripheralFor(SmartBlockEntity be)
return () -> new SpeedControllerPeripheral(scbe, scbe.targetSpeed);
if (be instanceof DisplayLinkBlockEntity dlbe)
return () -> new DisplayLinkPeripheral(dlbe);
if (be instanceof NixieTubeBlockEntity ntbe)
return () -> new NixieTubePeripheral(ntbe);
if (be instanceof SequencedGearshiftBlockEntity sgbe)
return () -> new SequencedGearshiftPeripheral(sgbe);
if (be instanceof SpeedGaugeBlockEntity sgbe)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package com.simibubi.create.compat.computercraft.implementation.peripherals;

import java.util.Map;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;


import com.simibubi.create.content.redstone.nixieTube.NixieTubeBlock;
import com.simibubi.create.content.redstone.nixieTube.NixieTubeBlockEntity;
import com.simibubi.create.foundation.utility.Components;

import dan200.computercraft.api.lua.IArguments;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.lua.LuaValues;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;

public class NixieTubePeripheral extends SyncedPeripheral<NixieTubeBlockEntity> {

private static final String EMPTY_COMPONENT_JSON = Component.Serializer.toJson(Components.literal(""));

public NixieTubePeripheral(NixieTubeBlockEntity blockEntity) {
super(blockEntity);
}

@Override
protected void onFirstAttach() {
// When first attaching to a computer, clear out the entire nixie tube row.
super.onFirstAttach();
Level world = blockEntity.getLevel();
if (world == null)
return;
NixieTubeBlock.walkNixies(world, blockEntity.getBlockPos(), true,
(currentPos, rowPosition) -> {
if (world.getBlockEntity(currentPos) instanceof NixieTubeBlockEntity ntbe)
ntbe.displayCustomText(EMPTY_COMPONENT_JSON, rowPosition);
});
}

@Override
protected void onLastDetach() {
// When detaching from the last computer, reset the entire nixie tube row back to redstone display,
// except if it's still being controlled from some other tube. onLastDetach runs after the
// hasAttachedComputer flag is reset, so we can use walkNixies()'s computer control rejection for that.
super.onLastDetach();
Level world = blockEntity.getLevel();
if (world == null)
return;
// Check if the nixie tube block is still there; if it isn't then the nixie was removed/destroyed
// and the row reset is handled in NixieTubeBlock::remove.
BlockState state = world.getBlockState(blockEntity.getBlockPos());
if (!(state.getBlock() instanceof NixieTubeBlock))
return;
NixieTubeBlock.walkNixies(world, blockEntity.getBlockPos(), false,
(currentPos, rowPosition) -> {
if (world.getBlockEntity(currentPos) instanceof NixieTubeBlockEntity ntbe) {
NixieTubeBlock.updateDisplayedRedstoneValue(ntbe, true);
}
});
}

@LuaFunction(mainThread = true)
public void setText(IArguments arguments) throws LuaException {
Level world = blockEntity.getLevel();
if (world == null)
return;
blockEntity.computerSignal = null;

String tagElement = Component.Serializer.toJson(Components.literal(arguments.getString(0)));

@Nullable String colour = arguments.optString(1, null);
BlockState state = null;
DyeColor dye = null;
if (colour != null) {
state = blockEntity.getLevel().getBlockState(blockEntity.getBlockPos());
dye = LuaValues.checkEnum(1, DyeColor.class, colour.equals("grey") ? "gray" : colour);
}

changeTextNixie(tagElement, state, dye);
}

@LuaFunction(mainThread = true)
public void setTextColour(String colour) throws LuaException {
Level world = blockEntity.getLevel();
if (world == null)
return;
BlockState state = blockEntity.getLevel().getBlockState(blockEntity.getBlockPos());
DyeColor dye = LuaValues.checkEnum(1, DyeColor.class, colour.equals("grey") ? "gray" : colour);
changeTextNixie(null, state, dye);
}

@LuaFunction(mainThread = true)
public void setTextColor(String color) throws LuaException {
setTextColour(color);
}

private void changeTextNixie(@Nullable String tagElement, @Nullable BlockState state, @Nullable DyeColor dye) {
Level world = blockEntity.getLevel();
if (world == null)
return;
NixieTubeBlock.walkNixies(world, blockEntity.getBlockPos(), true, (currentPos, rowPosition) -> {
if (tagElement != null)
((NixieTubeBlock) blockEntity.getBlockState().getBlock()).withBlockEntityDo(
world, currentPos, be -> be.displayCustomText(tagElement, rowPosition));
if (state != null && dye != null)
world.setBlockAndUpdate(currentPos, NixieTubeBlock.withColor(state, dye));
});
}

@LuaFunction(mainThread = true)
public void setSignal(IArguments arguments) throws LuaException {
if (arguments.optTable(0).isPresent())
setSignal(signal().first, arguments.getTable(0));
if (arguments.optTable(1).isPresent())
setSignal(signal().second, arguments.getTable(1));
}

private void setSignal(NixieTubeBlockEntity.ComputerSignal.TubeDisplay display, @NotNull Map<?, ?> attrs)
throws LuaException {
if (attrs.containsKey("r"))
display.r = constrainByte("r", 0, 255, attrs.get("r"));
if (attrs.containsKey("g"))
display.g = constrainByte("g", 0, 255, attrs.get("g"));
if (attrs.containsKey("b"))
display.b = constrainByte("r", 0, 255, attrs.get("b"));
if (attrs.containsKey("glowWidth"))
display.glowWidth = constrainByte("glowWidth", 1, 4, attrs.get("glowWidth"));
if (attrs.containsKey("glowHeight"))
display.glowHeight = constrainByte("glowHeight", 1, 4, attrs.get("glowHeight"));
if (attrs.containsKey("blinkPeriod"))
display.blinkPeriod = constrainByte("blinkPeriod", 0, 255, attrs.get("blinkPeriod"));
if (attrs.containsKey("blinkOffTime"))
display.blinkOffTime = constrainByte("blinkOffTime", 0, 255, attrs.get("blinkOffTime"));
if (display.r == 0 && display.g == 0 && display.b == 0) {
display.blinkPeriod = 0;
display.blinkOffTime = 0;
} else if (display.blinkPeriod == 0) {
display.blinkPeriod = 1;
display.blinkOffTime = 0;
}
blockEntity.notifyUpdate();
}

private byte constrainByte(String name, int min, int max, Object rawValue) throws LuaException {
if (!(rawValue instanceof Number))
throw LuaValues.badField(name, "number", LuaValues.getType(rawValue));
int value = ((Number) rawValue).intValue();
if (value < min || value > max)
throw new LuaException("field " + name + " must be in range " + min + "-" + max);
return (byte) value;
}

private NixieTubeBlockEntity.ComputerSignal signal() {
if (blockEntity.computerSignal == null)
blockEntity.computerSignal = new NixieTubeBlockEntity.ComputerSignal();
return blockEntity.computerSignal;
}

@NotNull
@Override
public String getType() {
return "Create_NixieTube";
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.simibubi.create.compat.computercraft.implementation.peripherals;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.ArrayList;
import java.util.List;

import com.simibubi.create.compat.computercraft.events.ComputerEvent;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -17,29 +20,42 @@
public abstract class SyncedPeripheral<T extends SmartBlockEntity> implements IPeripheral {

protected final T blockEntity;
private final AtomicInteger computers = new AtomicInteger();
private final List<@NotNull IComputerAccess> computers = new ArrayList<>();

public SyncedPeripheral(T blockEntity) {
this.blockEntity = blockEntity;
}

@Override
public void attach(@NotNull IComputerAccess computer) {
computers.incrementAndGet();
updateBlockEntity();
synchronized (computers) {
computers.add(computer);
if (computers.size() == 1)
onFirstAttach();
updateBlockEntity();
}
}

protected void onFirstAttach() {}

@Override
public void detach(@NotNull IComputerAccess computer) {
computers.decrementAndGet();
updateBlockEntity();
synchronized (computers) {
computers.remove(computer);
updateBlockEntity();
if (computers.isEmpty())
onLastDetach();
}
}

protected void onLastDetach() {}

private void updateBlockEntity() {
boolean hasAttachedComputer = computers.get() > 0;
boolean hasAttachedComputer = !computers.isEmpty();

blockEntity.getBehaviour(ComputerBehaviour.TYPE).setHasAttachedComputer(hasAttachedComputer);
AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new AttachedComputerPacket(blockEntity.getBlockPos(), hasAttachedComputer));
AllPackets.getChannel().send(PacketDistributor.ALL.noArg(),
new AttachedComputerPacket(blockEntity.getBlockPos(), hasAttachedComputer));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class NixieTubeDisplayTarget extends SingleLineDisplayTarget {
@Override
protected void acceptLine(MutableComponent text, DisplayLinkContext context) {
String tagElement = Component.Serializer.toJson(text);
NixieTubeBlock.walkNixies(context.level(), context.getTargetPos(), (currentPos, rowPosition) -> {
NixieTubeBlock.walkNixies(context.level(), context.getTargetPos(), false, (currentPos, rowPosition) -> {
BlockEntity blockEntity = context.level()
.getBlockEntity(currentPos);
if (blockEntity instanceof NixieTubeBlockEntity nixie)
Expand All @@ -33,7 +33,8 @@ protected void acceptLine(MutableComponent text, DisplayLinkContext context) {
@Override
protected int getWidth(DisplayLinkContext context) {
MutableInt count = new MutableInt(0);
NixieTubeBlock.walkNixies(context.level(), context.getTargetPos(), (currentPos, rowPosition) -> count.add(2));
NixieTubeBlock.walkNixies(context.level(), context.getTargetPos(), false,
(currentPos, rowPosition) -> count.add(2));
return count.intValue();
}

Expand All @@ -42,7 +43,7 @@ protected int getWidth(DisplayLinkContext context) {
public AABB getMultiblockBounds(LevelAccessor level, BlockPos pos) {
MutableObject<BlockPos> start = new MutableObject<>(null);
MutableObject<BlockPos> end = new MutableObject<>(null);
NixieTubeBlock.walkNixies(level, pos, (currentPos, rowPosition) -> {
NixieTubeBlock.walkNixies(level, pos, true, (currentPos, rowPosition) -> {
end.setValue(currentPos);
if (start.getValue() == null)
start.setValue(currentPos);
Expand Down
Loading