diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 2e3b2099f..5500a5ab0 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -495,7 +495,7 @@ e815bfd854c2653f10828bb11950f7fb991d7efc assets/create/blockstates/stressometer. a2454400b1cf9889f70aebdc89c52a1be25f543c assets/create/blockstates/tiled_glass_pane.json 96c45abe7a5d9273feaf5f747d14cee8e04b58da assets/create/blockstates/track.json 98b936d72da49ee02eacd0b3244fe133e5575bb1 assets/create/blockstates/track_observer.json -408ae1009ee8bb2f2b83753d5909c53744f7865f assets/create/blockstates/track_signal.json +2bc61c806a9a903c139a79d4d296c119d9f590b2 assets/create/blockstates/track_signal.json 60609cfbcc9be6f7e41fb493ef3147beb9750b60 assets/create/blockstates/track_station.json b000a6cde143f8a12fc8996d1ac8b5164f75253b assets/create/blockstates/train_door.json 836c443ab8778f0ff2b16bdf5f3339a0871c273e assets/create/blockstates/train_trapdoor.json diff --git a/src/generated/resources/assets/create/blockstates/track_signal.json b/src/generated/resources/assets/create/blockstates/track_signal.json index 22f491f71..66cd77eb7 100644 --- a/src/generated/resources/assets/create/blockstates/track_signal.json +++ b/src/generated/resources/assets/create/blockstates/track_signal.json @@ -1,9 +1,15 @@ { "variants": { - "type=entry_signal": { + "powered=false,type=entry_signal": { "model": "create:block/track_signal/block_entry_signal" }, - "type=cross_signal": { + "powered=true,type=entry_signal": { + "model": "create:block/track_signal/block_entry_signal" + }, + "powered=false,type=cross_signal": { + "model": "create:block/track_signal/block_cross_signal" + }, + "powered=true,type=cross_signal": { "model": "create:block/track_signal/block_cross_signal" } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java index 530213259..efa728704 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java @@ -160,7 +160,7 @@ public class NixieTubeRenderer extends SafeTileEntityRenderer waitingForSignal; - private Map waitingForChainedGroups; + private Map> waitingForChainedGroups; public double distanceToSignal; public int ticksWaitingForSignal; @@ -158,13 +158,14 @@ public class Navigation { boolean primary = entering.equals(signal.groups.getFirst()); boolean crossSignal = signal.types.get(primary) == SignalType.CROSS_SIGNAL; - boolean occupied = signalEdgeGroup.isOccupiedUnless(train); + boolean occupied = + signal.isForcedRed(nodes.getSecond()) || signalEdgeGroup.isOccupiedUnless(train); if (!crossSignalTracked) { if (crossSignal) { // Now entering cross signal path trackingCrossSignal.setValue(Pair.of(boundary.id, primary)); crossSignalDistanceTracker.setValue(distance); - waitingForChainedGroups.put(entering, signal); + waitingForChainedGroups.put(entering, Pair.of(signal, primary)); } if (occupied) { // Section is occupied waitingForSignal = Pair.of(boundary.id, primary); @@ -179,7 +180,7 @@ public class Navigation { } if (crossSignalTracked) { - waitingForChainedGroups.put(entering, signal); // Add group to chain + waitingForChainedGroups.put(entering, Pair.of(signal, primary)); // Add group to chain if (occupied) { // Section is occupied, but wait at the cross signal that started the chain waitingForSignal = trackingCrossSignal.getValue(); distanceToSignal = crossSignalDistanceTracker.doubleValue(); @@ -272,7 +273,7 @@ public class Navigation { waitingForChainedGroups.forEach((groupId, boundary) -> { SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId); if (signalEdgeGroup != null) - signalEdgeGroup.reserved = boundary; + signalEdgeGroup.reserved = boundary.getFirst(); }); waitingForChainedGroups.clear(); } @@ -286,12 +287,18 @@ public class Navigation { // Cross Signal if (signal.types.get(waitingForSignal.getSecond()) == SignalType.CROSS_SIGNAL) { - for (UUID groupId : waitingForChainedGroups.keySet()) { - SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId); + for (Entry> entry : waitingForChainedGroups.entrySet()) { + Pair boundary = entry.getValue(); + SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(entry.getKey()); if (signalEdgeGroup == null) { // Migration, re-initialize chain waitingForSignal.setFirst(null); return true; } + if (boundary.getFirst() + .isForcedRed(boundary.getSecond())) { + train.reservedSignalBlocks.clear(); + return false; + } if (signalEdgeGroup.isOccupiedUnless(train)) return false; } @@ -607,6 +614,10 @@ public class Navigation { if (!point.canNavigateVia(node2)) continue Search; if (point instanceof SignalBoundary signal) { + if (signal.isForcedRed(node2)) { + penalty += Train.Penalties.REDSTONE_RED_SIGNAL; + continue; + } UUID group = signal.getGroup(node2); if (group == null) continue; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java index 185f309b9..41f860d99 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java @@ -989,7 +989,7 @@ public class Train { public static class Penalties { static final int STATION = 200, STATION_WITH_TRAIN = 300; static final int MANUAL_TRAIN = 200, IDLE_TRAIN = 700, ARRIVING_TRAIN = 50, WAITING_TRAIN = 50, ANY_TRAIN = 25, - RED_SIGNAL = 25; + RED_SIGNAL = 25, REDSTONE_RED_SIGNAL = 400; } public int getNavigationPenalty() { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java index 70b06dfe3..e232d7032 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java @@ -2,6 +2,8 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint.signal import java.util.Random; +import javax.annotation.Nullable; + import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.block.ITE; @@ -13,18 +15,22 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.StringRepresentable; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; public class SignalBlock extends Block implements ITE, IWrenchable { public static final EnumProperty TYPE = EnumProperty.create("type", SignalType.class); + public static final BooleanProperty POWERED = BlockStateProperties.POWERED; public enum SignalType implements StringRepresentable { ENTRY_SIGNAL, CROSS_SIGNAL; @@ -37,7 +43,8 @@ public class SignalBlock extends Block implements ITE, IWrench public SignalBlock(Properties p_53182_) { super(p_53182_); - registerDefaultState(defaultBlockState().setValue(TYPE, SignalType.ENTRY_SIGNAL)); + registerDefaultState(defaultBlockState().setValue(TYPE, SignalType.ENTRY_SIGNAL) + .setValue(POWERED, false)); } @Override @@ -47,7 +54,41 @@ public class SignalBlock extends Block implements ITE, IWrench @Override protected void createBlockStateDefinition(Builder pBuilder) { - super.createBlockStateDefinition(pBuilder.add(TYPE)); + super.createBlockStateDefinition(pBuilder.add(TYPE, POWERED)); + } + + @Override + public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) { + return false; + } + + @Nullable + @Override + public BlockState getStateForPlacement(BlockPlaceContext pContext) { + return this.defaultBlockState() + .setValue(POWERED, Boolean.valueOf(pContext.getLevel() + .hasNeighborSignal(pContext.getClickedPos()))); + } + + @Override + public void neighborChanged(BlockState pState, Level pLevel, BlockPos pPos, Block pBlock, BlockPos pFromPos, + boolean pIsMoving) { + if (pLevel.isClientSide) + return; + boolean powered = pState.getValue(POWERED); + if (powered == pLevel.hasNeighborSignal(pPos)) + return; + if (powered) { + pLevel.scheduleTick(pPos, this, 4); + } else { + pLevel.setBlock(pPos, pState.cycle(POWERED), 2); + } + } + + @Override + public void tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, Random pRand) { + if (pState.getValue(POWERED) && !pLevel.hasNeighborSignal(pPos)) + pLevel.setBlock(pPos, pState.cycle(POWERED), 2); } @Override @@ -76,23 +117,13 @@ public class SignalBlock extends Block implements ITE, IWrench } @Override - public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) { - return side != null; - } - - @Override - public boolean isSignalSource(BlockState state) { + public boolean hasAnalogOutputSignal(BlockState pState) { return true; } @Override - public void tick(BlockState blockState, ServerLevel world, BlockPos pos, Random random) { - getTileEntityOptional(world, pos).ifPresent(SignalTileEntity::updatePowerAfterDelay); - } - - @Override - public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) { - return getTileEntityOptional(blockAccess, pos).filter(SignalTileEntity::isPowered) + public int getAnalogOutputSignal(BlockState pState, Level blockAccess, BlockPos pPos) { + return getTileEntityOptional(blockAccess, pPos).filter(SignalTileEntity::isPowered) .map($ -> 15) .orElse(0); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java index 5de7ffaff..6d57f86e2 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java @@ -1,9 +1,8 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; -import java.util.HashSet; +import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import java.util.UUID; import com.google.common.base.Objects; @@ -29,7 +28,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; public class SignalBoundary extends TrackEdgePoint { - public Couple> blockEntities; + public Couple> blockEntities; public Couple types; public Couple groups; public Couple sidesToUpdate; @@ -38,7 +37,7 @@ public class SignalBoundary extends TrackEdgePoint { private Couple> chainedSignals; public SignalBoundary() { - blockEntities = Couple.create(HashSet::new); + blockEntities = Couple.create(HashMap::new); chainedSignals = Couple.create(null, null); groups = Couple.create(null, null); sidesToUpdate = Couple.create(true, true); @@ -83,7 +82,8 @@ public class SignalBoundary extends TrackEdgePoint { @Override public void invalidate(LevelAccessor level) { - blockEntities.forEach(s -> s.forEach(pos -> invalidateAt(level, pos))); + blockEntities.forEach(s -> s.keySet() + .forEach(p -> invalidateAt(level, p))); groups.forEach(uuid -> { if (Create.RAILWAYS.signalEdgeGroups.remove(uuid) != null) Create.RAILWAYS.sync.edgeGroupRemoved(uuid); @@ -97,18 +97,24 @@ public class SignalBoundary extends TrackEdgePoint { @Override public void tileAdded(BlockEntity tile, boolean front) { - Set tilesOnSide = blockEntities.get(front); + Map tilesOnSide = blockEntities.get(front); if (tilesOnSide.isEmpty()) tile.getBlockState() .getOptionalValue(SignalBlock.TYPE) .ifPresent(type -> types.set(front, type)); - tilesOnSide.add(tile.getBlockPos()); + tilesOnSide.put(tile.getBlockPos(), tile instanceof SignalTileEntity ste && ste.getReportedPower()); + } + + public void updateTilePower(SignalTileEntity tile) { + for (boolean front : Iterate.trueAndFalse) + blockEntities.get(front) + .computeIfPresent(tile.getBlockPos(), (p, c) -> tile.getReportedPower()); } @Override public void tileRemoved(BlockPos tilePos, boolean front) { blockEntities.forEach(s -> s.remove(tilePos)); - if (blockEntities.both(Set::isEmpty)) + if (blockEntities.both(Map::isEmpty)) removeFromAllGraphs(); } @@ -134,8 +140,8 @@ public class SignalBoundary extends TrackEdgePoint { public OverlayState getOverlayFor(BlockPos tile) { for (boolean first : Iterate.trueAndFalse) { - Set set = blockEntities.get(first); - for (BlockPos blockPos : set) { + Map set = blockEntities.get(first); + for (BlockPos blockPos : set.keySet()) { if (blockPos.equals(tile)) return blockEntities.get(!first) .isEmpty() ? OverlayState.RENDER : OverlayState.DUAL; @@ -147,13 +153,13 @@ public class SignalBoundary extends TrackEdgePoint { public SignalType getTypeFor(BlockPos tile) { return types.get(blockEntities.getFirst() - .contains(tile)); + .containsKey(tile)); } public SignalState getStateFor(BlockPos tile) { for (boolean first : Iterate.trueAndFalse) { - Set set = blockEntities.get(first); - if (set.contains(tile)) + Map set = blockEntities.get(first); + if (set.containsKey(tile)) return cachedStates.get(first); } return SignalState.INVALID; @@ -177,10 +183,14 @@ public class SignalBoundary extends TrackEdgePoint { private void tickState(TrackGraph graph) { for (boolean current : Iterate.trueAndFalse) { - Set set = blockEntities.get(current); + Map set = blockEntities.get(current); if (set.isEmpty()) continue; + boolean forcedRed = set.values() + .stream() + .anyMatch(Boolean::booleanValue); + UUID group = groups.get(current); if (Objects.equal(group, groups.get(!current))) { cachedStates.set(current, SignalState.INVALID); @@ -194,11 +204,22 @@ public class SignalBoundary extends TrackEdgePoint { continue; } - boolean occupiedUnlessBySelf = signalEdgeGroup.isOccupiedUnless(this); + boolean occupiedUnlessBySelf = forcedRed || signalEdgeGroup.isOccupiedUnless(this); cachedStates.set(current, occupiedUnlessBySelf ? SignalState.RED : resolveSignalChain(graph, current)); } } + public boolean isForcedRed(TrackNode side) { + return isForcedRed(isPrimary(side)); + } + + public boolean isForcedRed(boolean primary) { + return blockEntities.get(primary) + .values() + .stream() + .anyMatch(Boolean::booleanValue); + } + private SignalState resolveSignalChain(TrackGraph graph, boolean side) { if (types.get(side) != SignalType.CROSS_SIGNAL) return SignalState.GREEN; @@ -244,14 +265,14 @@ public class SignalBoundary extends TrackEdgePoint { if (migration) return; - blockEntities = Couple.create(HashSet::new); + blockEntities = Couple.create(HashMap::new); groups = Couple.create(null, null); for (int i = 1; i <= 2; i++) if (nbt.contains("Tiles" + i)) { boolean first = i == 1; NBTHelper.iterateCompoundList(nbt.getList("Tiles" + i, Tag.TAG_COMPOUND), c -> blockEntities.get(first) - .add(NbtUtils.readBlockPos(c))); + .put(NbtUtils.readBlockPos(c), c.getBoolean("Power"))); } for (int i = 1; i <= 2; i++) @@ -280,7 +301,12 @@ public class SignalBoundary extends TrackEdgePoint { for (int i = 1; i <= 2; i++) if (!blockEntities.get(i == 1) .isEmpty()) - nbt.put("Tiles" + i, NBTHelper.writeCompoundList(blockEntities.get(i == 1), NbtUtils::writeBlockPos)); + nbt.put("Tiles" + i, NBTHelper.writeCompoundList(blockEntities.get(i == 1) + .entrySet(), e -> { + CompoundTag c = NbtUtils.writeBlockPos(e.getKey()); + c.putBoolean("Power", e.getValue()); + return c; + })); for (int i = 1; i <= 2; i++) if (groups.get(i == 1) != null) nbt.putUUID("Group" + i, groups.get(i == 1)); @@ -306,7 +332,7 @@ public class SignalBoundary extends TrackEdgePoint { public void cycleSignalType(BlockPos pos) { types.set(blockEntities.getFirst() - .contains(pos), SignalType.values()[(getTypeFor(pos).ordinal() + 1) % SignalType.values().length]); + .containsKey(pos), SignalType.values()[(getTypeFor(pos).ordinal() + 1) % SignalType.values().length]); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java index f73576cc7..68bccc274 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java @@ -15,11 +15,9 @@ import com.simibubi.create.foundation.utility.NBTHelper; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; -import net.minecraft.world.ticks.TickPriority; public class SignalTileEntity extends SmartTileEntity implements ITransformableTE { @@ -48,11 +46,13 @@ public class SignalTileEntity extends SmartTileEntity implements ITransformableT private SignalState state; private OverlayState overlay; private int switchToRedAfterTrainEntered; + private boolean lastReportedPower; public SignalTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); this.state = SignalState.INVALID; this.overlay = OverlayState.SKIP; + this.lastReportedPower = false; } @Override @@ -60,6 +60,7 @@ public class SignalTileEntity extends SmartTileEntity implements ITransformableT super.write(tag, clientPacket); NBTHelper.writeEnum(tag, "State", state); NBTHelper.writeEnum(tag, "Overlay", overlay); + tag.putBoolean("Power", lastReportedPower); } @Override @@ -67,6 +68,7 @@ public class SignalTileEntity extends SmartTileEntity implements ITransformableT super.read(tag, clientPacket); state = NBTHelper.readEnum(tag, "State", SignalState.class); overlay = NBTHelper.readEnum(tag, "Overlay", OverlayState.class); + lastReportedPower = tag.getBoolean("Power"); invalidateRenderBoundingBox(); } @@ -79,17 +81,6 @@ public class SignalTileEntity extends SmartTileEntity implements ITransformableT return state == SignalState.RED; } - protected void scheduleBlockTick() { - Block block = getBlockState().getBlock(); - if (!level.getBlockTicks() - .willTickThisTick(worldPosition, block)) - level.scheduleTick(worldPosition, block, 2, TickPriority.NORMAL); - } - - public void updatePowerAfterDelay() { - level.blockUpdated(worldPosition, getBlockState().getBlock()); - } - @Override public void addBehaviours(List behaviours) { edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.SIGNAL); @@ -109,11 +100,21 @@ public class SignalTileEntity extends SmartTileEntity implements ITransformableT return; } - getBlockState().getOptionalValue(SignalBlock.TYPE) + BlockState blockState = getBlockState(); + + blockState.getOptionalValue(SignalBlock.POWERED).ifPresent(powered -> { + if (lastReportedPower == powered) + return; + lastReportedPower = powered; + boundary.updateTilePower(this); + notifyUpdate(); + }); + + blockState.getOptionalValue(SignalBlock.TYPE) .ifPresent(stateType -> { SignalType targetType = boundary.getTypeFor(worldPosition); if (stateType != targetType) { - level.setBlock(worldPosition, getBlockState().setValue(SignalBlock.TYPE, targetType), 3); + level.setBlock(worldPosition, blockState.setValue(SignalBlock.TYPE, targetType), 3); refreshBlockState(); } }); @@ -122,6 +123,10 @@ public class SignalTileEntity extends SmartTileEntity implements ITransformableT setOverlay(boundary.getOverlayFor(worldPosition)); } + public boolean getReportedPower() { + return lastReportedPower; + } + public SignalState getState() { return state; } @@ -147,7 +152,6 @@ public class SignalTileEntity extends SmartTileEntity implements ITransformableT this.state = state; switchToRedAfterTrainEntered = state == SignalState.GREEN || state == SignalState.YELLOW ? 15 : 0; notifyUpdate(); - scheduleBlockTick(); } @Override