mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-02-07 10:54:59 +01:00
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
This commit is contained in:
parent
522dbc7f37
commit
96a325c03b
13 changed files with 621 additions and 76 deletions
|
@ -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"),
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.compat.computercraft.implementation;
|
|||
|
||||
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;
|
||||
|
@ -12,6 +13,7 @@ import com.simibubi.create.content.kinetics.gauge.StressGaugeBlockEntity;
|
|||
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;
|
||||
|
||||
|
@ -40,6 +42,8 @@ public class ComputerBehaviour extends AbstractComputerBehaviour {
|
|||
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)
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
@ -17,7 +20,7 @@ import net.minecraftforge.network.PacketDistributor;
|
|||
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;
|
||||
|
@ -25,21 +28,34 @@ public abstract class SyncedPeripheral<T extends SmartBlockEntity> implements IP
|
|||
|
||||
@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
|
||||
|
|
|
@ -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)
|
||||
|
@ -33,7 +33,8 @@ public class NixieTubeDisplayTarget extends SingleLineDisplayTarget {
|
|||
@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();
|
||||
}
|
||||
|
||||
|
@ -42,7 +43,7 @@ public class NixieTubeDisplayTarget extends SingleLineDisplayTarget {
|
|||
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);
|
||||
|
|
|
@ -6,9 +6,14 @@ import java.util.List;
|
|||
import java.util.Random;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
import com.simibubi.create.AllBlockEntityTypes;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.compat.Mods;
|
||||
import com.simibubi.create.content.equipment.clipboard.ClipboardEntry;
|
||||
import com.simibubi.create.content.equipment.wrench.IWrenchable;
|
||||
import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement;
|
||||
|
@ -71,6 +76,11 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock
|
|||
|
||||
if (nixie == null)
|
||||
return InteractionResult.PASS;
|
||||
|
||||
// Refuse interaction if nixie tube is in a computer-controlled row
|
||||
if (isInComputerControlledRow(world, pos))
|
||||
return InteractionResult.PASS;
|
||||
|
||||
if (heldItem.isEmpty()) {
|
||||
if (nixie.reactsToRedstone())
|
||||
return InteractionResult.PASS;
|
||||
|
@ -101,7 +111,8 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock
|
|||
return InteractionResult.SUCCESS;
|
||||
|
||||
String tagUsed = tagElement;
|
||||
walkNixies(world, pos, (currentPos, rowPosition) -> {
|
||||
// Skip computer check in this walk since it was already performed at the start.
|
||||
walkNixies(world, pos, true, (currentPos, rowPosition) -> {
|
||||
if (display)
|
||||
withBlockEntityDo(world, currentPos, be -> be.displayCustomText(tagUsed, rowPosition));
|
||||
if (dye != null)
|
||||
|
@ -111,40 +122,98 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock
|
|||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
public static void walkNixies(LevelAccessor world, BlockPos start, BiConsumer<BlockPos, Integer> callback) {
|
||||
BlockState state = world.getBlockState(start);
|
||||
if (!(state.getBlock() instanceof NixieTubeBlock))
|
||||
return;
|
||||
|
||||
BlockPos currentPos = start;
|
||||
Direction left = state.getValue(FACING)
|
||||
.getOpposite();
|
||||
|
||||
public static Direction getLeftNixieDirection(@NotNull BlockState state) {
|
||||
Direction left = state.getValue(FACING).getOpposite();
|
||||
if (state.getValue(FACE) == DoubleAttachFace.WALL)
|
||||
left = Direction.UP;
|
||||
if (state.getValue(FACE) == DoubleAttachFace.WALL_REVERSED)
|
||||
left = Direction.DOWN;
|
||||
return left;
|
||||
}
|
||||
|
||||
public static Direction getRightNixieDirection(@NotNull BlockState state) {
|
||||
return getLeftNixieDirection(state).getOpposite();
|
||||
}
|
||||
|
||||
public static boolean isInComputerControlledRow(@NotNull LevelAccessor world, @NotNull BlockPos pos) {
|
||||
return Mods.COMPUTERCRAFT.isLoaded() && !walkNixies(world, pos, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk down a nixie tube row and execute a callback on each tube in said row.
|
||||
* @param world The world the tubes are in.
|
||||
* @param start Start position for the walk.
|
||||
* @param allowComputerControlled Allow or disallow running callbacks if the row is computer-controlled.
|
||||
* @param callback Callback to run for each tube.
|
||||
* @return True if the row was walked, false if the walk was aborted because it is computer-controlled.
|
||||
*/
|
||||
public static boolean walkNixies(@NotNull LevelAccessor world, @NotNull BlockPos start,
|
||||
boolean allowComputerControlled,
|
||||
@Nullable BiConsumer<BlockPos, Integer> callback) {
|
||||
BlockState state = world.getBlockState(start);
|
||||
if (!(state.getBlock() instanceof NixieTubeBlock))
|
||||
return false;
|
||||
|
||||
// If ComputerCraft is not installed, ignore allowComputerControlled since
|
||||
// nixies can't be computer-controlled
|
||||
if (!Mods.COMPUTERCRAFT.isLoaded())
|
||||
allowComputerControlled = true;
|
||||
|
||||
BlockPos currentPos = start;
|
||||
Direction left = getLeftNixieDirection(state);
|
||||
Direction right = left.getOpposite();
|
||||
|
||||
while (true) {
|
||||
BlockPos nextPos = currentPos.relative(left);
|
||||
if (!areNixieBlocksEqual(world.getBlockState(nextPos), state))
|
||||
break;
|
||||
// If computer-controlled nixie walking is disallowed, presence of any (same-color)
|
||||
// controlled nixies aborts the entire nixie walk.
|
||||
if (!allowComputerControlled && world.getBlockEntity(nextPos) instanceof NixieTubeBlockEntity ntbe &&
|
||||
ntbe.computerBehaviour.hasAttachedComputer()) {
|
||||
return false;
|
||||
}
|
||||
currentPos = nextPos;
|
||||
}
|
||||
|
||||
// As explained above, a controlled nixie in the row aborts the walk if they are disallowed,
|
||||
// and that includes those down the chain too.
|
||||
if (!allowComputerControlled) {
|
||||
// Check the start block itself
|
||||
if (world.getBlockEntity(start) instanceof NixieTubeBlockEntity ntbe &&
|
||||
ntbe.computerBehaviour.hasAttachedComputer()) {
|
||||
return false;
|
||||
}
|
||||
BlockPos leftmostPos = currentPos;
|
||||
// No need to iterate over the nixies to the left again
|
||||
currentPos = start;
|
||||
while (true) {
|
||||
BlockPos nextPos = currentPos.relative(right);
|
||||
if (!areNixieBlocksEqual(world.getBlockState(nextPos), state))
|
||||
break;
|
||||
if (world.getBlockEntity(nextPos) instanceof NixieTubeBlockEntity ntbe &&
|
||||
ntbe.computerBehaviour.hasAttachedComputer()) {
|
||||
return false;
|
||||
}
|
||||
currentPos = nextPos;
|
||||
}
|
||||
currentPos = leftmostPos;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
while (true) {
|
||||
final int rowPosition = index;
|
||||
callback.accept(currentPos, rowPosition);
|
||||
if (callback != null)
|
||||
callback.accept(currentPos, rowPosition);
|
||||
BlockPos nextPos = currentPos.relative(right);
|
||||
if (!areNixieBlocksEqual(world.getBlockState(nextPos), state))
|
||||
break;
|
||||
currentPos = nextPos;
|
||||
index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -153,10 +222,41 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BlockState p_196243_1_, Level p_196243_2_, BlockPos p_196243_3_, BlockState p_196243_4_,
|
||||
boolean p_196243_5_) {
|
||||
if (!(p_196243_4_.getBlock() instanceof NixieTubeBlock))
|
||||
p_196243_2_.removeBlockEntity(p_196243_3_);
|
||||
public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||
if (newState.getBlock() instanceof NixieTubeBlock)
|
||||
return;
|
||||
world.removeBlockEntity(pos);
|
||||
if (Mods.COMPUTERCRAFT.isLoaded()) {
|
||||
// A computer-controlled nixie tube row may have been broken in the middle.
|
||||
Direction left = getLeftNixieDirection(state);
|
||||
BlockPos leftPos = pos.relative(left);
|
||||
if (areNixieBlocksEqual(world.getBlockState(leftPos), state)) {
|
||||
boolean leftRowComputerControlled = isInComputerControlledRow(world, leftPos);
|
||||
walkNixies(world, leftPos, true, leftRowComputerControlled ?
|
||||
(currentPos, rowPosition) -> {
|
||||
if (world.getBlockEntity(currentPos) instanceof NixieTubeBlockEntity ntbe)
|
||||
ntbe.displayCustomText("{\"text\":\"\"}", rowPosition);
|
||||
} :
|
||||
(currentPos, rowPosition) -> {
|
||||
if (world.getBlockEntity(currentPos) instanceof NixieTubeBlockEntity ntbe)
|
||||
NixieTubeBlock.updateDisplayedRedstoneValue(ntbe, true);
|
||||
});
|
||||
}
|
||||
Direction right = left.getOpposite();
|
||||
BlockPos rightPos = pos.relative(right);
|
||||
if (areNixieBlocksEqual(world.getBlockState(rightPos), state)) {
|
||||
boolean rightRowComputerControlled = isInComputerControlledRow(world, rightPos);
|
||||
walkNixies(world, rightPos, true, rightRowComputerControlled ?
|
||||
(currentPos, rowPosition) -> {
|
||||
if (world.getBlockEntity(currentPos) instanceof NixieTubeBlockEntity ntbe)
|
||||
ntbe.displayCustomText("{\"text\":\"\"}", rowPosition);
|
||||
} :
|
||||
(currentPos, rowPosition) -> {
|
||||
if (world.getBlockEntity(currentPos) instanceof NixieTubeBlockEntity ntbe)
|
||||
NixieTubeBlock.updateDisplayedRedstoneValue(ntbe, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -237,18 +337,30 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock
|
|||
|
||||
@Override
|
||||
public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
|
||||
if (state.getBlock() == oldState.getBlock() || isMoving)
|
||||
if (state.getBlock() == oldState.getBlock() || isMoving || oldState.getBlock() instanceof NixieTubeBlock)
|
||||
return;
|
||||
if (Mods.COMPUTERCRAFT.isLoaded() && isInComputerControlledRow(worldIn, pos)) {
|
||||
// The nixie tube has been placed in a computer-controlled row.
|
||||
walkNixies(worldIn, pos, true, (currentPos, rowPosition) -> {
|
||||
if (worldIn.getBlockEntity(currentPos) instanceof NixieTubeBlockEntity ntbe)
|
||||
ntbe.displayCustomText("{\"text\":\"\"}", rowPosition);
|
||||
});
|
||||
return;
|
||||
}
|
||||
updateDisplayedRedstoneValue(state, worldIn, pos);
|
||||
}
|
||||
|
||||
public static void updateDisplayedRedstoneValue(NixieTubeBlockEntity be, boolean force) {
|
||||
if (be.getLevel() == null || be.getLevel().isClientSide)
|
||||
return;
|
||||
if (be.reactsToRedstone() || force)
|
||||
be.updateRedstoneStrength(getPower(be.getLevel(), be.getBlockPos()));
|
||||
}
|
||||
|
||||
private void updateDisplayedRedstoneValue(BlockState state, Level worldIn, BlockPos pos) {
|
||||
if (worldIn.isClientSide)
|
||||
return;
|
||||
withBlockEntityDo(worldIn, pos, be -> {
|
||||
if (be.reactsToRedstone())
|
||||
be.updateRedstoneStrength(getPower(worldIn, pos));
|
||||
});
|
||||
withBlockEntityDo(worldIn, pos, be -> NixieTubeBlock.updateDisplayedRedstoneValue(be, false));
|
||||
}
|
||||
|
||||
static boolean isValidBlock(BlockGetter world, BlockPos pos, boolean above) {
|
||||
|
@ -257,7 +369,7 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock
|
|||
.isEmpty();
|
||||
}
|
||||
|
||||
private int getPower(Level worldIn, BlockPos pos) {
|
||||
private static int getPower(Level worldIn, BlockPos pos) {
|
||||
int power = 0;
|
||||
for (Direction direction : Iterate.directions)
|
||||
power = Math.max(worldIn.getSignal(pos.relative(direction), direction), power);
|
||||
|
|
|
@ -4,6 +4,14 @@ import java.lang.ref.WeakReference;
|
|||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour;
|
||||
import com.simibubi.create.compat.computercraft.ComputerCraftProxy;
|
||||
import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock;
|
||||
import com.simibubi.create.content.trains.signal.SignalBlockEntity;
|
||||
import com.simibubi.create.content.trains.signal.SignalBlockEntity.SignalState;
|
||||
|
@ -13,6 +21,8 @@ import com.simibubi.create.foundation.utility.Components;
|
|||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.DynamicComponent;
|
||||
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -23,15 +33,62 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
|
||||
public class NixieTubeBlockEntity extends SmartBlockEntity {
|
||||
|
||||
public static final class ComputerSignal {
|
||||
public static final class TubeDisplay {
|
||||
public static final int ENCODED_SIZE = 7;
|
||||
|
||||
public byte r = 63, g = 63, b = 63;
|
||||
public byte blinkPeriod = 0, blinkOffTime = 0;
|
||||
public byte glowWidth = 1, glowHeight = 1;
|
||||
|
||||
public void decode(byte[] data, int offset) {
|
||||
r = data[offset];
|
||||
g = data[offset + 1];
|
||||
b = data[offset + 2];
|
||||
blinkPeriod = data[offset + 3];
|
||||
blinkOffTime = data[offset + 4];
|
||||
glowWidth = data[offset + 5];
|
||||
glowHeight = data[offset + 6];
|
||||
}
|
||||
|
||||
public void encode(byte[] data, int offset) {
|
||||
data[offset] = r;
|
||||
data[offset + 1] = g;
|
||||
data[offset + 2] = b;
|
||||
data[offset + 3] = blinkPeriod;
|
||||
data[offset + 4] = blinkOffTime;
|
||||
data[offset + 5] = glowWidth;
|
||||
data[offset + 6] = glowHeight;
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull TubeDisplay first = new TubeDisplay();
|
||||
public @NotNull TubeDisplay second = new TubeDisplay();
|
||||
|
||||
public void decode(byte[] encoded) {
|
||||
first.decode(encoded, 0);
|
||||
second.decode(encoded, TubeDisplay.ENCODED_SIZE);
|
||||
}
|
||||
|
||||
public byte[] encode() {
|
||||
byte[] encoded = new byte[TubeDisplay.ENCODED_SIZE * 2];
|
||||
first.encode(encoded, 0);
|
||||
second.encode(encoded, TubeDisplay.ENCODED_SIZE);
|
||||
return encoded;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Couple<String> EMPTY = Couple.create("", "");
|
||||
|
||||
private int redstoneStrength;
|
||||
private Optional<DynamicComponent> customText;
|
||||
private int nixieIndex;
|
||||
private Couple<String> displayedStrings;
|
||||
public AbstractComputerBehaviour computerBehaviour;
|
||||
|
||||
private WeakReference<SignalBlockEntity> cachedSignalTE;
|
||||
public SignalState signalState;
|
||||
public @Nullable SignalState signalState;
|
||||
public @Nullable ComputerSignal computerSignal;
|
||||
|
||||
public NixieTubeBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
|
@ -47,6 +104,13 @@ public class NixieTubeBlockEntity extends SmartBlockEntity {
|
|||
return;
|
||||
|
||||
signalState = null;
|
||||
if (computerBehaviour.hasAttachedComputer()) {
|
||||
if (level.isClientSide && cachedSignalTE.get() != null) {
|
||||
cachedSignalTE = new WeakReference<>(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SignalBlockEntity signalBlockEntity = cachedSignalTE.get();
|
||||
|
||||
if (signalBlockEntity == null || signalBlockEntity.isRemoved()) {
|
||||
|
@ -71,7 +135,7 @@ public class NixieTubeBlockEntity extends SmartBlockEntity {
|
|||
//
|
||||
|
||||
public boolean reactsToRedstone() {
|
||||
return customText.isEmpty();
|
||||
return !computerBehaviour.hasAttachedComputer() && customText.isEmpty();
|
||||
}
|
||||
|
||||
public Couple<String> getDisplayedStrings() {
|
||||
|
@ -108,7 +172,7 @@ public class NixieTubeBlockEntity extends SmartBlockEntity {
|
|||
}
|
||||
|
||||
public void updateDisplayedStrings() {
|
||||
if (signalState != null)
|
||||
if (signalState != null || computerSignal != null)
|
||||
return;
|
||||
customText.map(DynamicComponent::resolve)
|
||||
.ifPresentOrElse(
|
||||
|
@ -144,12 +208,25 @@ public class NixieTubeBlockEntity extends SmartBlockEntity {
|
|||
customText = Optional.empty();
|
||||
nixieIndex = 0;
|
||||
}
|
||||
} else {
|
||||
customText = Optional.empty();
|
||||
nixieIndex = 0;
|
||||
}
|
||||
|
||||
if (customText.isEmpty())
|
||||
redstoneStrength = nbt.getInt("RedstoneStrength");
|
||||
if (clientPacket)
|
||||
if (clientPacket) {
|
||||
if (nbt.contains("ComputerSignal")) {
|
||||
byte[] encodedComputerSignal = nbt.getByteArray("ComputerSignal");
|
||||
if (computerSignal == null)
|
||||
computerSignal = new ComputerSignal();
|
||||
computerSignal.decode(encodedComputerSignal);
|
||||
} else {
|
||||
computerSignal = null;
|
||||
}
|
||||
|
||||
updateDisplayedStrings();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -162,6 +239,8 @@ public class NixieTubeBlockEntity extends SmartBlockEntity {
|
|||
.write(nbt);
|
||||
} else
|
||||
nbt.putInt("RedstoneStrength", redstoneStrength);
|
||||
if (clientPacket && computerSignal != null)
|
||||
nbt.putByteArray("ComputerSignal", computerSignal.encode());
|
||||
}
|
||||
|
||||
private String charOrEmpty(String string, int index) {
|
||||
|
@ -169,6 +248,21 @@ public class NixieTubeBlockEntity extends SmartBlockEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {}
|
||||
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
|
||||
behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @NotNull LazyOptional<T> getCapability(@NotNull Capability<T> cap, Direction side) {
|
||||
if (computerBehaviour.isPeripheralCap(cap))
|
||||
return computerBehaviour.getPeripheralCapability();
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
computerBehaviour.removePeripheral();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
|
||||
public class NixieTubeRenderer extends SafeBlockEntityRenderer<NixieTubeBlockEntity> {
|
||||
|
||||
private static final int GLOW_VIEW_DISTANCE = 96;
|
||||
private static Random r = new Random();
|
||||
|
||||
public NixieTubeRenderer(BlockEntityRendererProvider.Context context) {}
|
||||
|
@ -52,7 +53,7 @@ public class NixieTubeRenderer extends SafeBlockEntityRenderer<NixieTubeBlockEnt
|
|||
.rotateZ(xRot)
|
||||
.unCentre();
|
||||
|
||||
if (be.signalState != null) {
|
||||
if (be.signalState != null || be.computerSignal != null) {
|
||||
renderAsSignal(be, partialTicks, ms, buffer, light, overlay);
|
||||
ms.popPose();
|
||||
return;
|
||||
|
@ -144,55 +145,111 @@ public class NixieTubeRenderer extends SafeBlockEntityRenderer<NixieTubeBlockEnt
|
|||
ms.pushPose();
|
||||
ms.translate(1 / 2f, 7.5f / 16f, 1 / 2f);
|
||||
float renderTime = AnimationTickHolder.getRenderTime(be.getLevel());
|
||||
Vec3 lampVec = Vec3.atCenterOf(be.getBlockPos());
|
||||
Vec3 diff = lampVec.subtract(observerVec);
|
||||
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
Vec3 lampVec = Vec3.atCenterOf(be.getBlockPos());
|
||||
Vec3 diff = lampVec.subtract(observerVec);
|
||||
if (be.signalState != null) {
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
if (first && !be.signalState.isRedLight(renderTime))
|
||||
continue;
|
||||
if (!first && !be.signalState.isGreenLight(renderTime) && !be.signalState.isYellowLight(renderTime))
|
||||
continue;
|
||||
|
||||
if (first && !be.signalState.isRedLight(renderTime))
|
||||
continue;
|
||||
if (!first && !be.signalState.isGreenLight(renderTime) && !be.signalState.isYellowLight(renderTime))
|
||||
continue;
|
||||
boolean flip = first == invertTubes;
|
||||
boolean yellow = be.signalState.isYellowLight(renderTime);
|
||||
|
||||
boolean flip = first == invertTubes;
|
||||
boolean yellow = be.signalState.isYellowLight(renderTime);
|
||||
ms.pushPose();
|
||||
ms.translate(flip ? 4 / 16f : -4 / 16f, 0, 0);
|
||||
|
||||
ms.pushPose();
|
||||
ms.translate(flip ? 4 / 16f : -4 / 16f, 0, 0);
|
||||
if (diff.lengthSqr() < GLOW_VIEW_DISTANCE * GLOW_VIEW_DISTANCE) {
|
||||
boolean vert = first ^ facing.getAxis()
|
||||
.isHorizontal();
|
||||
float longSide = yellow ? 1 : 4;
|
||||
float longSideGlow = yellow ? 2 : 5.125f;
|
||||
|
||||
if (diff.lengthSqr() < 96 * 96) {
|
||||
boolean vert = first ^ facing.getAxis()
|
||||
.isHorizontal();
|
||||
float longSide = yellow ? 1 : 4;
|
||||
float longSideGlow = yellow ? 2 : 5.125f;
|
||||
CachedBufferer.partial(AllPartialModels.SIGNAL_WHITE_CUBE, blockState)
|
||||
.light(0xf000f0)
|
||||
.disableDiffuse()
|
||||
.scale(vert ? longSide : 1, vert ? 1 : longSide, 1)
|
||||
.renderInto(ms, buffer.getBuffer(RenderType.translucent()));
|
||||
|
||||
CachedBufferer.partial(AllPartialModels.SIGNAL_WHITE_CUBE, blockState)
|
||||
.light(0xf000f0)
|
||||
.disableDiffuse()
|
||||
.scale(vert ? longSide : 1, vert ? 1 : longSide, 1)
|
||||
.renderInto(ms, buffer.getBuffer(RenderType.translucent()));
|
||||
CachedBufferer
|
||||
.partial(
|
||||
first ? AllPartialModels.SIGNAL_RED_GLOW
|
||||
: yellow ? AllPartialModels.SIGNAL_YELLOW_GLOW : AllPartialModels.SIGNAL_WHITE_GLOW,
|
||||
blockState)
|
||||
.light(0xf000f0)
|
||||
.disableDiffuse()
|
||||
.scale(vert ? longSideGlow : 2, vert ? 2 : longSideGlow, 2)
|
||||
.renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive()));
|
||||
}
|
||||
|
||||
CachedBufferer
|
||||
.partial(
|
||||
first ? AllPartialModels.SIGNAL_RED_GLOW
|
||||
: yellow ? AllPartialModels.SIGNAL_YELLOW_GLOW : AllPartialModels.SIGNAL_WHITE_GLOW,
|
||||
blockState)
|
||||
.light(0xf000f0)
|
||||
.disableDiffuse()
|
||||
.scale(vert ? longSideGlow : 2, vert ? 2 : longSideGlow, 2)
|
||||
.renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive()));
|
||||
.partial(first ? AllPartialModels.SIGNAL_RED
|
||||
: yellow ? AllPartialModels.SIGNAL_YELLOW : AllPartialModels.SIGNAL_WHITE, blockState)
|
||||
.light(0xF000F0)
|
||||
.disableDiffuse()
|
||||
.scale(1 + 1 / 16f)
|
||||
.renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive()));
|
||||
|
||||
ms.popPose();
|
||||
}
|
||||
} else if (be.computerSignal != null) {
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
NixieTubeBlockEntity.ComputerSignal.TubeDisplay tubeDisplay = first ?
|
||||
be.computerSignal.first : be.computerSignal.second;
|
||||
if (tubeDisplay.blinkPeriod == 0 || tubeDisplay.blinkPeriod > 1 && renderTime % tubeDisplay.blinkPeriod < tubeDisplay.blinkOffTime)
|
||||
continue;
|
||||
|
||||
CachedBufferer
|
||||
.partial(first ? AllPartialModels.SIGNAL_RED
|
||||
: yellow ? AllPartialModels.SIGNAL_YELLOW : AllPartialModels.SIGNAL_WHITE, blockState)
|
||||
.light(0xF000F0)
|
||||
.disableDiffuse()
|
||||
.scale(1 + 1 / 16f)
|
||||
.renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive()));
|
||||
boolean flip = first == invertTubes;
|
||||
|
||||
ms.popPose();
|
||||
ms.pushPose();
|
||||
ms.translate(flip ? 4 / 16f : -4 / 16f, 0, 0);
|
||||
|
||||
if (diff.lengthSqr() < GLOW_VIEW_DISTANCE * GLOW_VIEW_DISTANCE) {
|
||||
boolean horiz = facing.getAxis().isHorizontal();
|
||||
float width = horiz ? tubeDisplay.glowWidth : tubeDisplay.glowHeight;
|
||||
float height = horiz ? tubeDisplay.glowHeight : tubeDisplay.glowWidth;
|
||||
|
||||
CachedBufferer.partial(AllPartialModels.SIGNAL_COMPUTER_WHITE_CUBE, blockState)
|
||||
.light(0xf000f0)
|
||||
.disableDiffuse()
|
||||
.scale(width, height, 1)
|
||||
.renderInto(ms, buffer.getBuffer(RenderType.translucent()));
|
||||
|
||||
CachedBufferer
|
||||
.partial(AllPartialModels.SIGNAL_COMPUTER_WHITE_GLOW, blockState)
|
||||
.light(0xf000f0)
|
||||
.color(
|
||||
Math.min(((tubeDisplay.r & 0xFF) * 6 + 256) >> 3, 255),
|
||||
Math.min(((tubeDisplay.g & 0xFF) * 6 + 256) >> 3, 255),
|
||||
Math.min(((tubeDisplay.b & 0xFF) * 6 + 256) >> 3, 255),
|
||||
255)
|
||||
.disableDiffuse()
|
||||
.scale(width + 1.125f, height + 1.125f, 2)
|
||||
.renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive()));
|
||||
}
|
||||
|
||||
CachedBufferer
|
||||
.partial(AllPartialModels.SIGNAL_COMPUTER_WHITE_BASE, blockState)
|
||||
.light(0xF000F0)
|
||||
.color(12, 12, 12, 255)
|
||||
.disableDiffuse()
|
||||
.scale(1 + 1.25f / 16f)
|
||||
.renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive()));
|
||||
|
||||
CachedBufferer
|
||||
.partial(AllPartialModels.SIGNAL_COMPUTER_WHITE, blockState)
|
||||
.light(0xF000F0)
|
||||
.color(tubeDisplay.r, tubeDisplay.g, tubeDisplay.b, 255)
|
||||
.disableDiffuse()
|
||||
.scale(1 + 1 / 16f)
|
||||
.renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive()));
|
||||
|
||||
ms.popPose();
|
||||
}
|
||||
}
|
||||
|
||||
ms.popPose();
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"textures": {
|
||||
"0": "create:block/signal_glow_3",
|
||||
"particle": "create:block/signal_glow_3"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [-0.5, -0.5, -0.5],
|
||||
"to": [0.5, 0.5, 0.5],
|
||||
"faces": {
|
||||
"north": {"uv": [1, 1, 2, 2], "texture": "#0"},
|
||||
"east": {"uv": [1, 1, 2, 2], "texture": "#0"},
|
||||
"south": {"uv": [1, 1, 2, 2], "texture": "#0"},
|
||||
"west": {"uv": [1, 1, 2, 2], "texture": "#0"},
|
||||
"up": {"uv": [1, 1, 2, 2], "texture": "#0"},
|
||||
"down": {"uv": [1, 1, 2, 2], "texture": "#0"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"textures": {
|
||||
"0": "create:block/signal_glow_3",
|
||||
"particle": "create:block/signal_glow_3"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [-0.5, -0.5, -0.5],
|
||||
"to": [0.5, 0.5, 0.5],
|
||||
"faces": {
|
||||
"north": {"uv": [1, 0, 2, 1], "texture": "#0"},
|
||||
"east": {"uv": [1, 0, 2, 1], "texture": "#0"},
|
||||
"south": {"uv": [1, 0, 2, 1], "texture": "#0"},
|
||||
"west": {"uv": [1, 0, 2, 1], "texture": "#0"},
|
||||
"up": {"uv": [1, 0, 2, 1], "texture": "#0"},
|
||||
"down": {"uv": [1, 0, 2, 1], "texture": "#0"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"parent": "block/block",
|
||||
"ambientocclusion": false,
|
||||
"textures": {
|
||||
"1": "create:block/signal_glow_3",
|
||||
"particle": "create:block/signal_glow_3"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "tube3",
|
||||
"from": [-3, -4.5, -3],
|
||||
"to": [3, 4.5, 3],
|
||||
"rotation": {"angle": 0, "axis": "z", "origin": [8, 8, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [10, 7, 16, 16], "texture": "#1"},
|
||||
"east": {"uv": [10, 7, 16, 16], "texture": "#1"},
|
||||
"south": {"uv": [10, 7, 16, 16], "texture": "#1"},
|
||||
"west": {"uv": [10, 7, 16, 16], "texture": "#1"},
|
||||
"up": {"uv": [10, 0, 16, 6], "rotation": 90, "texture": "#1"},
|
||||
"down": {"uv": [10, 0, 16, 6], "rotation": 90, "texture": "#1"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"parent": "block/block",
|
||||
"ambientocclusion": false,
|
||||
"textures": {
|
||||
"1": "create:block/signal_glow_3",
|
||||
"particle": "create:block/signal_glow_3"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "tube3",
|
||||
"from": [-3, -4.5, -3],
|
||||
"to": [3, 4.5, 3],
|
||||
"rotation": {"angle": 0, "axis": "z", "origin": [8, 8, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [3, 7, 9, 16], "texture": "#1"},
|
||||
"east": {"uv": [3, 7, 9, 16], "texture": "#1"},
|
||||
"south": {"uv": [3, 7, 9, 16], "texture": "#1"},
|
||||
"west": {"uv": [3, 7, 9, 16], "texture": "#1"},
|
||||
"up": {"uv": [3, 0, 9, 6], "rotation": 90, "texture": "#1"},
|
||||
"down": {"uv": [3, 0, 9, 6], "rotation": 90, "texture": "#1"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 242 B |
Loading…
Reference in a new issue