From 6dd3231b6dcb7a46c0df258c0a0c2d6d41de3764 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Thu, 17 Mar 2022 23:14:53 +0100 Subject: [PATCH] Traffic Frights - Fixed Trains ignoring their signal when nearby graph nodes are changed - Fixed Trains not being notified of new signal blocks if they share an edge with the added/removed signal - Fixed Navigation reserving chained signal blocks before verifying that it can be fully traversed - Fixed Track placement requiring much shallower slopes for diagonal tracks - Fixed long range navigation choosing detours near the beginning - Temporarily patched and highlighted a problem with track traversal and long distances --- .../trains/GlobalRailwayManager.java | 6 +- .../content/logistics/trains/TrackEdge.java | 3 +- .../logistics/trains/entity/Navigation.java | 75 ++++++++++--------- .../logistics/trains/entity/Train.java | 9 ++- .../trains/entity/TravellingPoint.java | 9 +++ .../edgePoint/signal/SignalBoundary.java | 2 +- .../edgePoint/signal/SignalPropagator.java | 7 +- .../edgePoint/signal/SignalRenderer.java | 2 +- .../trains/track/TrackPlacement.java | 2 +- 9 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java b/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java index c0cecc5ec..3b1b27359 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java @@ -176,9 +176,9 @@ public class GlobalRailwayManager { for (TrackGraph graph : trackNetworks.values()) graph.tickPoints(false); -// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_K)) -// trackNetworks.values() -// .forEach(TrackGraph::debugViewReserved); + if (AllKeys.isKeyDown(GLFW.GLFW_KEY_K)) + trackNetworks.values() + .forEach(TrackGraph::debugViewReserved); // if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown()) // trackNetworks.values() // .forEach(TrackGraph::debugViewNodes); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java index 3abe283f6..311bcc214 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java @@ -44,8 +44,9 @@ public class TrackEdge { } public double incrementT(TrackNode node1, TrackNode node2, double currentT, double distance) { + boolean tooFar = Math.abs(distance) > 5; distance = distance / getLength(node1, node2); - return isTurn() ? turn.incrementT(currentT, distance) : currentT + distance; + return !tooFar && isTurn() ? turn.incrementT(currentT, distance) : currentT + distance; } public Vec3 getPosition(TrackNode node1, TrackNode node2, double t) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java index 180ce6a04..4593f30d1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.logistics.trains.entity; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; @@ -39,6 +40,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; +import net.minecraft.util.Mth; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -53,7 +55,7 @@ public class Navigation { private TravellingPoint signalScout; public Pair waitingForSignal; - private Set waitingForChainedGroups; + private Map waitingForChainedGroups; public double distanceToSignal; public int ticksWaitingForSignal; @@ -61,7 +63,7 @@ public class Navigation { this.train = train; currentPath = new ArrayList<>(); signalScout = new TravellingPoint(); - waitingForChainedGroups = new HashSet<>(); + waitingForChainedGroups = new HashMap<>(); } public void tick(Level level) { @@ -101,11 +103,11 @@ public class Navigation { // Signals if (train.graph != null) { if (waitingForSignal != null && currentSignalResolved()) { - SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, waitingForSignal.getFirst()); - if (signal.types.get(waitingForSignal.getSecond()) == SignalType.CROSS_SIGNAL) - train.reservedSignalBlocks.addAll(waitingForChainedGroups); + UUID signalId = waitingForSignal.getFirst(); + SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, signalId); + if (signal != null && signal.types.get(waitingForSignal.getSecond()) == SignalType.CROSS_SIGNAL) + waitingForChainedGroups.clear(); waitingForSignal = null; - waitingForChainedGroups.clear(); } TravellingPoint leadingPoint = !destinationBehindTrain ? train.carriages.get(0) @@ -126,16 +128,15 @@ public class Navigation { signalScout.edge = leadingPoint.edge; signalScout.position = leadingPoint.position; - double brakingDistanceNoFlicker = - Math.max(preDepartureLookAhead, brakingDistance + 3 - (brakingDistance % 3)); - double scanDistance = Math.min(distanceToDestination, brakingDistanceNoFlicker); + double brakingDistanceNoFlicker = brakingDistance + 3 - (brakingDistance % 3); + double scanDistance = Mth.clamp(brakingDistanceNoFlicker, preDepartureLookAhead, distanceToDestination); MutableDouble crossSignalDistanceTracker = new MutableDouble(-1); MutableObject> trackingCrossSignal = new MutableObject<>(null); waitingForChainedGroups.clear(); -// train.reservedSignalBlocks.clear(); - signalScout.travel(train.graph, distanceToDestination * speedMod, controlSignalScout(), + // Adding 50 to the distance due to unresolved inaccuracies in TravellingPoint::travel + signalScout.travel(train.graph, (distanceToDestination + 50) * speedMod, controlSignalScout(), (distance, couple) -> { // > scanDistance and not following down a cross signal boolean crossSignalTracked = trackingCrossSignal.getValue() != null; @@ -158,15 +159,11 @@ public class Navigation { boolean crossSignal = signal.types.get(primary) == SignalType.CROSS_SIGNAL; boolean occupied = signalEdgeGroup.isOccupiedUnless(train); - if (!occupied && distance < distanceToSignal + .25) - signalEdgeGroup.reserved = signal; // Reserve group for traversal, unless waiting at an - // earlier cross signal - if (!crossSignalTracked) { if (crossSignal) { // Now entering cross signal path trackingCrossSignal.setValue(Pair.of(boundary.id, primary)); crossSignalDistanceTracker.setValue(distance); - waitingForChainedGroups.add(entering); + waitingForChainedGroups.put(entering, signal); } if (occupied) { // Section is occupied waitingForSignal = Pair.of(boundary.id, primary); @@ -174,8 +171,14 @@ public class Navigation { if (!crossSignal) return true; // Standard entry signal, do not collect any further segments } - } else { - waitingForChainedGroups.add(entering); // Add group to chain + if (!occupied && !crossSignal && distance < distanceToSignal + .25 + && distance < brakingDistanceNoFlicker) + signalEdgeGroup.reserved = signal; // Reserve group for traversal + return false; + } + + if (crossSignalTracked) { + waitingForChainedGroups.put(entering, signal); // 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(); @@ -186,8 +189,7 @@ public class Navigation { if (distance < distanceToSignal + .25) { // Collect and reset the signal chain because none were blocked trackingCrossSignal.setValue(null); - train.reservedSignalBlocks.addAll(waitingForChainedGroups); - waitingForChainedGroups.clear(); + reserveChain(); return false; } else return true; // End of a blocked signal chain @@ -202,20 +204,13 @@ public class Navigation { curveDistanceTracker.setValue(distance); }); - if (trackingCrossSignal.getValue() != null) { - if (waitingForSignal == null) { - train.reservedSignalBlocks.addAll(waitingForChainedGroups); - waitingForChainedGroups.clear(); - } - } + if (trackingCrossSignal.getValue() != null && waitingForSignal == null) + reserveChain(); distanceToNextCurve = curveDistanceTracker.floatValue(); - } else { + } else ticksWaitingForSignal++; - // if chain signal try finding new path/destination every x ticks - } - } double targetDistance = waitingForSignal != null ? distanceToSignal : distanceToDestination; @@ -265,6 +260,16 @@ public class Navigation { train.approachTargetSpeed(1); } + private void reserveChain() { + train.reservedSignalBlocks.addAll(waitingForChainedGroups.keySet()); + waitingForChainedGroups.forEach((groupId, boundary) -> { + SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId); + if (signalEdgeGroup != null) + signalEdgeGroup.reserved = boundary; + }); + waitingForChainedGroups.clear(); + } + private boolean currentSignalResolved() { if (distanceToDestination < .5f) return true; @@ -274,10 +279,12 @@ public class Navigation { // Cross Signal if (signal.types.get(waitingForSignal.getSecond()) == SignalType.CROSS_SIGNAL) { - for (UUID groupId : waitingForChainedGroups) { + for (UUID groupId : waitingForChainedGroups.keySet()) { SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId); - if (signalEdgeGroup == null) - continue; + if (signalEdgeGroup == null) { // Migration, re-initialize chain + waitingForSignal.setFirst(null); + return true; + } if (signalEdgeGroup.isOccupiedUnless(train)) return false; } @@ -629,7 +636,7 @@ public class Navigation { TrackEdge newEdge = target.getValue(); double newDistance = newEdge.getLength(node2, newNode) + distance; int newPenalty = penalty; - reachedVia.put(newEdge, Pair.of(validTargets.size() > 1, Couple.create(node1, node2))); + reachedVia.putIfAbsent(newEdge, Pair.of(validTargets.size() > 1, Couple.create(node1, node2))); frontier.add(new FrontierEntry(newDistance, newPenalty, node2, newNode, newEdge)); } } 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 d101d6c2f..82cdb43f0 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 @@ -123,16 +123,17 @@ public class Train { status.tick(level); if (graph == null && !migratingPoints.isEmpty()) reattachToTracks(level); - - addToSignalGroups(occupiedSignalBlocks.keySet()); - - if (graph == null) + if (graph == null) { + addToSignalGroups(occupiedSignalBlocks.keySet()); return; + } + if (updateSignalBlocks) { updateSignalBlocks = false; collectInitiallyOccupiedSignalBlocks(); } + addToSignalGroups(occupiedSignalBlocks.keySet()); addToSignalGroups(reservedSignalBlocks); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java index 833bf1614..f47778ca0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java @@ -187,6 +187,15 @@ public class TravellingPoint { double currentT = position / edgeLength; double incrementT = edge.incrementT(node1, node2, currentT, distance); position = incrementT * edgeLength; + + // FIXME: using incrementT like this becomes inaccurate at medium-long distances + // travelling points would travel only 50m instead of 100m due to the low + // incrementT at their starting position (e.g. bezier turn) + // In an ideal scenario the amount added to position would iterate the traversed + // edges for context first + + // A workaround was added in TrackEdge::incrementT + List> validTargets = new ArrayList<>(); boolean forward = distance > 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 ea0bbc308..d5f28b2b7 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 @@ -42,7 +42,7 @@ public class SignalBoundary extends TrackEdgePoint { groups = Couple.create(null, null); sidesToUpdate = Couple.create(true, true); types = Couple.create(() -> SignalType.ENTRY_SIGNAL); - cachedStates = Couple.create(() -> SignalState.GREEN); + cachedStates = Couple.create(() -> SignalState.INVALID); } public void setGroup(TrackNode side, UUID groupId) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java index 09b0fe31b..e6cc4448b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java @@ -115,15 +115,16 @@ public class SignalPropagator { if (startEdge == null) return; - if (!forCollection) + if (!forCollection) { + notifyTrains(graph, startEdge, oppositeEdge); Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge, oppositeEdge); + } // Check for signal on the same edge SignalBoundary immediateBoundary = startEdge.getEdgeData() .next(EdgePointType.SIGNAL, node1, node2, startEdge, signal.getLocationOn(node1, node2, startEdge)); if (immediateBoundary != null) { - if (boundaryCallback.test(Pair.of(node1, immediateBoundary))) - notifyTrains(graph, startEdge, oppositeEdge); + boundaryCallback.test(Pair.of(node1, immediateBoundary)); return; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalRenderer.java index 1f81e8da5..066dd7b08 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalRenderer.java @@ -34,7 +34,7 @@ public class SignalRenderer extends SafeTileEntityRenderer { if (signalState.isRedLight(renderTime)) CachedBufferer.partial(AllBlockPartials.SIGNAL_ON, blockState) .renderInto(ms, buffer.getBuffer(RenderType.solid())); - else if (signalState.isGreenLight(renderTime)) + else CachedBufferer.partial(AllBlockPartials.SIGNAL_OFF, blockState) .renderInto(ms, buffer.getBuffer(RenderType.solid())); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java index 6b9f9969b..f7182e0f1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java @@ -247,7 +247,7 @@ public class TrackPlacement { int hDistance = info.end1Extent; if (axis1.y == 0 || !Mth.equal(absAscend + 1, dist / axis1.length())) { info.end1Extent = 0; - double minHDistance = Math.max(absAscend < 4 ? absAscend * 4 : absAscend * 3, 6); + double minHDistance = Math.max(absAscend < 4 ? absAscend * 4 : absAscend * 3, 6) / axis1.length(); if (hDistance < minHDistance) return info.withMessage("too_steep"); if (hDistance > minHDistance) {