mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-01-15 08:47:36 +01:00
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
This commit is contained in:
parent
a9a37b313c
commit
6dd3231b6d
9 changed files with 67 additions and 48 deletions
|
@ -176,9 +176,9 @@ public class GlobalRailwayManager {
|
||||||
for (TrackGraph graph : trackNetworks.values())
|
for (TrackGraph graph : trackNetworks.values())
|
||||||
graph.tickPoints(false);
|
graph.tickPoints(false);
|
||||||
|
|
||||||
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_K))
|
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_K))
|
||||||
// trackNetworks.values()
|
trackNetworks.values()
|
||||||
// .forEach(TrackGraph::debugViewReserved);
|
.forEach(TrackGraph::debugViewReserved);
|
||||||
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown())
|
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown())
|
||||||
// trackNetworks.values()
|
// trackNetworks.values()
|
||||||
// .forEach(TrackGraph::debugViewNodes);
|
// .forEach(TrackGraph::debugViewNodes);
|
||||||
|
|
|
@ -44,8 +44,9 @@ public class TrackEdge {
|
||||||
}
|
}
|
||||||
|
|
||||||
public double incrementT(TrackNode node1, TrackNode node2, double currentT, double distance) {
|
public double incrementT(TrackNode node1, TrackNode node2, double currentT, double distance) {
|
||||||
|
boolean tooFar = Math.abs(distance) > 5;
|
||||||
distance = distance / getLength(node1, node2);
|
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) {
|
public Vec3 getPosition(TrackNode node1, TrackNode node2, double t) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.simibubi.create.content.logistics.trains.entity;
|
package com.simibubi.create.content.logistics.trains.entity;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -39,6 +40,7 @@ import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.NbtUtils;
|
import net.minecraft.nbt.NbtUtils;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
@ -53,7 +55,7 @@ public class Navigation {
|
||||||
|
|
||||||
private TravellingPoint signalScout;
|
private TravellingPoint signalScout;
|
||||||
public Pair<UUID, Boolean> waitingForSignal;
|
public Pair<UUID, Boolean> waitingForSignal;
|
||||||
private Set<UUID> waitingForChainedGroups;
|
private Map<UUID, SignalBoundary> waitingForChainedGroups;
|
||||||
public double distanceToSignal;
|
public double distanceToSignal;
|
||||||
public int ticksWaitingForSignal;
|
public int ticksWaitingForSignal;
|
||||||
|
|
||||||
|
@ -61,7 +63,7 @@ public class Navigation {
|
||||||
this.train = train;
|
this.train = train;
|
||||||
currentPath = new ArrayList<>();
|
currentPath = new ArrayList<>();
|
||||||
signalScout = new TravellingPoint();
|
signalScout = new TravellingPoint();
|
||||||
waitingForChainedGroups = new HashSet<>();
|
waitingForChainedGroups = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick(Level level) {
|
public void tick(Level level) {
|
||||||
|
@ -101,11 +103,11 @@ public class Navigation {
|
||||||
// Signals
|
// Signals
|
||||||
if (train.graph != null) {
|
if (train.graph != null) {
|
||||||
if (waitingForSignal != null && currentSignalResolved()) {
|
if (waitingForSignal != null && currentSignalResolved()) {
|
||||||
SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, waitingForSignal.getFirst());
|
UUID signalId = waitingForSignal.getFirst();
|
||||||
if (signal.types.get(waitingForSignal.getSecond()) == SignalType.CROSS_SIGNAL)
|
SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, signalId);
|
||||||
train.reservedSignalBlocks.addAll(waitingForChainedGroups);
|
if (signal != null && signal.types.get(waitingForSignal.getSecond()) == SignalType.CROSS_SIGNAL)
|
||||||
waitingForSignal = null;
|
|
||||||
waitingForChainedGroups.clear();
|
waitingForChainedGroups.clear();
|
||||||
|
waitingForSignal = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
TravellingPoint leadingPoint = !destinationBehindTrain ? train.carriages.get(0)
|
TravellingPoint leadingPoint = !destinationBehindTrain ? train.carriages.get(0)
|
||||||
|
@ -126,16 +128,15 @@ public class Navigation {
|
||||||
signalScout.edge = leadingPoint.edge;
|
signalScout.edge = leadingPoint.edge;
|
||||||
signalScout.position = leadingPoint.position;
|
signalScout.position = leadingPoint.position;
|
||||||
|
|
||||||
double brakingDistanceNoFlicker =
|
double brakingDistanceNoFlicker = brakingDistance + 3 - (brakingDistance % 3);
|
||||||
Math.max(preDepartureLookAhead, brakingDistance + 3 - (brakingDistance % 3));
|
double scanDistance = Mth.clamp(brakingDistanceNoFlicker, preDepartureLookAhead, distanceToDestination);
|
||||||
double scanDistance = Math.min(distanceToDestination, brakingDistanceNoFlicker);
|
|
||||||
|
|
||||||
MutableDouble crossSignalDistanceTracker = new MutableDouble(-1);
|
MutableDouble crossSignalDistanceTracker = new MutableDouble(-1);
|
||||||
MutableObject<Pair<UUID, Boolean>> trackingCrossSignal = new MutableObject<>(null);
|
MutableObject<Pair<UUID, Boolean>> trackingCrossSignal = new MutableObject<>(null);
|
||||||
waitingForChainedGroups.clear();
|
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) -> {
|
(distance, couple) -> {
|
||||||
// > scanDistance and not following down a cross signal
|
// > scanDistance and not following down a cross signal
|
||||||
boolean crossSignalTracked = trackingCrossSignal.getValue() != null;
|
boolean crossSignalTracked = trackingCrossSignal.getValue() != null;
|
||||||
|
@ -158,15 +159,11 @@ public class Navigation {
|
||||||
boolean crossSignal = signal.types.get(primary) == SignalType.CROSS_SIGNAL;
|
boolean crossSignal = signal.types.get(primary) == SignalType.CROSS_SIGNAL;
|
||||||
boolean occupied = signalEdgeGroup.isOccupiedUnless(train);
|
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 (!crossSignalTracked) {
|
||||||
if (crossSignal) { // Now entering cross signal path
|
if (crossSignal) { // Now entering cross signal path
|
||||||
trackingCrossSignal.setValue(Pair.of(boundary.id, primary));
|
trackingCrossSignal.setValue(Pair.of(boundary.id, primary));
|
||||||
crossSignalDistanceTracker.setValue(distance);
|
crossSignalDistanceTracker.setValue(distance);
|
||||||
waitingForChainedGroups.add(entering);
|
waitingForChainedGroups.put(entering, signal);
|
||||||
}
|
}
|
||||||
if (occupied) { // Section is occupied
|
if (occupied) { // Section is occupied
|
||||||
waitingForSignal = Pair.of(boundary.id, primary);
|
waitingForSignal = Pair.of(boundary.id, primary);
|
||||||
|
@ -174,8 +171,14 @@ public class Navigation {
|
||||||
if (!crossSignal)
|
if (!crossSignal)
|
||||||
return true; // Standard entry signal, do not collect any further segments
|
return true; // Standard entry signal, do not collect any further segments
|
||||||
}
|
}
|
||||||
} else {
|
if (!occupied && !crossSignal && distance < distanceToSignal + .25
|
||||||
waitingForChainedGroups.add(entering); // Add group to chain
|
&& 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
|
if (occupied) { // Section is occupied, but wait at the cross signal that started the chain
|
||||||
waitingForSignal = trackingCrossSignal.getValue();
|
waitingForSignal = trackingCrossSignal.getValue();
|
||||||
distanceToSignal = crossSignalDistanceTracker.doubleValue();
|
distanceToSignal = crossSignalDistanceTracker.doubleValue();
|
||||||
|
@ -186,8 +189,7 @@ public class Navigation {
|
||||||
if (distance < distanceToSignal + .25) {
|
if (distance < distanceToSignal + .25) {
|
||||||
// Collect and reset the signal chain because none were blocked
|
// Collect and reset the signal chain because none were blocked
|
||||||
trackingCrossSignal.setValue(null);
|
trackingCrossSignal.setValue(null);
|
||||||
train.reservedSignalBlocks.addAll(waitingForChainedGroups);
|
reserveChain();
|
||||||
waitingForChainedGroups.clear();
|
|
||||||
return false;
|
return false;
|
||||||
} else
|
} else
|
||||||
return true; // End of a blocked signal chain
|
return true; // End of a blocked signal chain
|
||||||
|
@ -202,20 +204,13 @@ public class Navigation {
|
||||||
curveDistanceTracker.setValue(distance);
|
curveDistanceTracker.setValue(distance);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (trackingCrossSignal.getValue() != null) {
|
if (trackingCrossSignal.getValue() != null && waitingForSignal == null)
|
||||||
if (waitingForSignal == null) {
|
reserveChain();
|
||||||
train.reservedSignalBlocks.addAll(waitingForChainedGroups);
|
|
||||||
waitingForChainedGroups.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
distanceToNextCurve = curveDistanceTracker.floatValue();
|
distanceToNextCurve = curveDistanceTracker.floatValue();
|
||||||
|
|
||||||
} else {
|
} else
|
||||||
ticksWaitingForSignal++;
|
ticksWaitingForSignal++;
|
||||||
// if chain signal try finding new path/destination every x ticks
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double targetDistance = waitingForSignal != null ? distanceToSignal : distanceToDestination;
|
double targetDistance = waitingForSignal != null ? distanceToSignal : distanceToDestination;
|
||||||
|
@ -265,6 +260,16 @@ public class Navigation {
|
||||||
train.approachTargetSpeed(1);
|
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() {
|
private boolean currentSignalResolved() {
|
||||||
if (distanceToDestination < .5f)
|
if (distanceToDestination < .5f)
|
||||||
return true;
|
return true;
|
||||||
|
@ -274,10 +279,12 @@ public class Navigation {
|
||||||
|
|
||||||
// Cross Signal
|
// Cross Signal
|
||||||
if (signal.types.get(waitingForSignal.getSecond()) == SignalType.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);
|
SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId);
|
||||||
if (signalEdgeGroup == null)
|
if (signalEdgeGroup == null) { // Migration, re-initialize chain
|
||||||
continue;
|
waitingForSignal.setFirst(null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (signalEdgeGroup.isOccupiedUnless(train))
|
if (signalEdgeGroup.isOccupiedUnless(train))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -629,7 +636,7 @@ public class Navigation {
|
||||||
TrackEdge newEdge = target.getValue();
|
TrackEdge newEdge = target.getValue();
|
||||||
double newDistance = newEdge.getLength(node2, newNode) + distance;
|
double newDistance = newEdge.getLength(node2, newNode) + distance;
|
||||||
int newPenalty = penalty;
|
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));
|
frontier.add(new FrontierEntry(newDistance, newPenalty, node2, newNode, newEdge));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,16 +123,17 @@ public class Train {
|
||||||
status.tick(level);
|
status.tick(level);
|
||||||
if (graph == null && !migratingPoints.isEmpty())
|
if (graph == null && !migratingPoints.isEmpty())
|
||||||
reattachToTracks(level);
|
reattachToTracks(level);
|
||||||
|
if (graph == null) {
|
||||||
addToSignalGroups(occupiedSignalBlocks.keySet());
|
addToSignalGroups(occupiedSignalBlocks.keySet());
|
||||||
|
|
||||||
if (graph == null)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (updateSignalBlocks) {
|
if (updateSignalBlocks) {
|
||||||
updateSignalBlocks = false;
|
updateSignalBlocks = false;
|
||||||
collectInitiallyOccupiedSignalBlocks();
|
collectInitiallyOccupiedSignalBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addToSignalGroups(occupiedSignalBlocks.keySet());
|
||||||
addToSignalGroups(reservedSignalBlocks);
|
addToSignalGroups(reservedSignalBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,6 +187,15 @@ public class TravellingPoint {
|
||||||
double currentT = position / edgeLength;
|
double currentT = position / edgeLength;
|
||||||
double incrementT = edge.incrementT(node1, node2, currentT, distance);
|
double incrementT = edge.incrementT(node1, node2, currentT, distance);
|
||||||
position = incrementT * edgeLength;
|
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<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
||||||
|
|
||||||
boolean forward = distance > 0;
|
boolean forward = distance > 0;
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class SignalBoundary extends TrackEdgePoint {
|
||||||
groups = Couple.create(null, null);
|
groups = Couple.create(null, null);
|
||||||
sidesToUpdate = Couple.create(true, true);
|
sidesToUpdate = Couple.create(true, true);
|
||||||
types = Couple.create(() -> SignalType.ENTRY_SIGNAL);
|
types = Couple.create(() -> SignalType.ENTRY_SIGNAL);
|
||||||
cachedStates = Couple.create(() -> SignalState.GREEN);
|
cachedStates = Couple.create(() -> SignalState.INVALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGroup(TrackNode side, UUID groupId) {
|
public void setGroup(TrackNode side, UUID groupId) {
|
||||||
|
|
|
@ -115,15 +115,16 @@ public class SignalPropagator {
|
||||||
if (startEdge == null)
|
if (startEdge == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!forCollection)
|
if (!forCollection) {
|
||||||
|
notifyTrains(graph, startEdge, oppositeEdge);
|
||||||
Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge, oppositeEdge);
|
Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge, oppositeEdge);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for signal on the same edge
|
// Check for signal on the same edge
|
||||||
SignalBoundary immediateBoundary = startEdge.getEdgeData()
|
SignalBoundary immediateBoundary = startEdge.getEdgeData()
|
||||||
.next(EdgePointType.SIGNAL, node1, node2, startEdge, signal.getLocationOn(node1, node2, startEdge));
|
.next(EdgePointType.SIGNAL, node1, node2, startEdge, signal.getLocationOn(node1, node2, startEdge));
|
||||||
if (immediateBoundary != null) {
|
if (immediateBoundary != null) {
|
||||||
if (boundaryCallback.test(Pair.of(node1, immediateBoundary)))
|
boundaryCallback.test(Pair.of(node1, immediateBoundary));
|
||||||
notifyTrains(graph, startEdge, oppositeEdge);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class SignalRenderer extends SafeTileEntityRenderer<SignalTileEntity> {
|
||||||
if (signalState.isRedLight(renderTime))
|
if (signalState.isRedLight(renderTime))
|
||||||
CachedBufferer.partial(AllBlockPartials.SIGNAL_ON, blockState)
|
CachedBufferer.partial(AllBlockPartials.SIGNAL_ON, blockState)
|
||||||
.renderInto(ms, buffer.getBuffer(RenderType.solid()));
|
.renderInto(ms, buffer.getBuffer(RenderType.solid()));
|
||||||
else if (signalState.isGreenLight(renderTime))
|
else
|
||||||
CachedBufferer.partial(AllBlockPartials.SIGNAL_OFF, blockState)
|
CachedBufferer.partial(AllBlockPartials.SIGNAL_OFF, blockState)
|
||||||
.renderInto(ms, buffer.getBuffer(RenderType.solid()));
|
.renderInto(ms, buffer.getBuffer(RenderType.solid()));
|
||||||
|
|
||||||
|
|
|
@ -247,7 +247,7 @@ public class TrackPlacement {
|
||||||
int hDistance = info.end1Extent;
|
int hDistance = info.end1Extent;
|
||||||
if (axis1.y == 0 || !Mth.equal(absAscend + 1, dist / axis1.length())) {
|
if (axis1.y == 0 || !Mth.equal(absAscend + 1, dist / axis1.length())) {
|
||||||
info.end1Extent = 0;
|
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)
|
if (hDistance < minHDistance)
|
||||||
return info.withMessage("too_steep");
|
return info.withMessage("too_steep");
|
||||||
if (hDistance > minHDistance) {
|
if (hDistance > minHDistance) {
|
||||||
|
|
Loading…
Reference in a new issue