Recently
this pull request was merged into the code, addressing some of the issues I mentioned in the above post. However, with that implementation I have found that ahead signals are sometimes not displayed in TrackMonitor, so probably TCS scripts will fail too. I also think that minCheckDistanceM should still be used in some situations (for example, when starting the simulation or in unsignalled areas).
Here there is a diff file with the code we use in our OR modified version in order to improve multiplayer experience, just in case anyone is interested:
diff --git a/Source/Orts.Simulation/Simulation/Physics/Train.cs b/Source/Orts.Simulation/Simulation/Physics/Train.cs
index 9eebe56d0..fba715f04 100644
--- a/Source/Orts.Simulation/Simulation/Physics/Train.cs
+++ b/Source/Orts.Simulation/Simulation/Physics/Train.cs
@@ -9010,8 +9010,8 @@ public void UpdateExplorerMode(int signalObjectIndex)
List<int> tempSections = new List<int>();
tempSections = signalRef.ScanRoute(this, requiredPosition.TCSectionIndex, requiredPosition.TCOffset,
- requiredPosition.TCDirection, forward, -1, true, false,
- false, false, true, false, false, false, false, IsFreight);
+ requiredPosition.TCDirection, forward, minCheckDistanceM, true, false,
+ true, false, true, false, false, false, false, IsFreight);
if (tempSections.Count > 0)
{
@@ -9045,6 +9045,7 @@ public void UpdateExplorerMode(int signalObjectIndex)
thisSection = signalRef.TrackCircuitList[requiredPosition.TCSectionIndex];
offsetM = direction == 0 ? requiredPosition.TCOffset : thisSection.Length - requiredPosition.TCOffset;
bool endWithSignal = false; // ends with signal at STOP
+ bool hasEndSignal = false; // ends with cleared signal
int sectionWithSignalIndex = 0;
for (int iindex = 0; iindex < newRoute.Count && !endWithSignal; iindex++)
@@ -9063,17 +9064,19 @@ public void UpdateExplorerMode(int signalObjectIndex)
{
var endSignal = thisSection.EndSignals[reqDirection];
var thisAspect = thisSection.EndSignals[reqDirection].this_sig_lr(MstsSignalFunction.NORMAL);
+ hasEndSignal = true;
if (thisAspect == MstsSignalAspect.STOP && endSignal.hasPermission != SignalObject.Permission.Granted)
{
endWithSignal = true;
sectionWithSignalIndex = iindex;
}
- else if (!endSignal.enabled) // signal cleared by default only - request for proper clearing
+ else if (endSignal.enabledTrain == null) // signal cleared by default only - request for proper clearing
{
- endSignal.requestClearSignalExplorer(newRoute, thisRouted, true, 0); // do NOT propagate
+ var extendedRoute = endSignal.requestClearSignalExplorer(newRoute, thisRouted, true, 0); // do NOT propagate
+ if (iindex + 1 == newRoute.Count)
+ newRoute = extendedRoute;
}
-
}
}
@@ -9090,6 +9093,64 @@ public void UpdateExplorerMode(int signalObjectIndex)
}
}
+ // if route does not end with signal and is too short, extend
+
+ if (!endWithSignal && totalLengthM < minCheckDistanceM)
+ {
+
+ float extendedDistanceM = minCheckDistanceM - totalLengthM;
+ TCRouteElement lastElement = newRoute[newRoute.Count - 1];
+
+ int lastSectionIndex = lastElement.TCSectionIndex;
+ TrackCircuitSection lastSection = signalRef.TrackCircuitList[lastSectionIndex];
+
+ int nextSectionIndex = lastSection.Pins[lastElement.OutPin[0], lastElement.OutPin[1]].Link;
+ int nextSectionDirection = lastSection.Pins[lastElement.OutPin[0], lastElement.OutPin[1]].Direction;
+
+ // check if last item is non-aligned switch
+
+ MisalignedSwitch[direction, 0] = -1;
+ MisalignedSwitch[direction, 1] = -1;
+
+ TrackCircuitSection nextSection = nextSectionIndex >= 0 ? signalRef.TrackCircuitList[nextSectionIndex] : null;
+ if (nextSection != null && nextSection.CircuitType == TrackCircuitSection.TrackCircuitType.Junction)
+ {
+ if (nextSection.Pins[0, 0].Link != lastSectionIndex &&
+ nextSection.Pins[0, 1].Link != lastSectionIndex &&
+ nextSection.Pins[1, nextSection.JunctionLastRoute].Link != lastSectionIndex)
+ {
+ MisalignedSwitch[direction, 0] = nextSection.Index;
+ MisalignedSwitch[direction, 1] = lastSectionIndex;
+ }
+ }
+
+ List<int> tempSections = new List<int>();
+
+ if (nextSectionIndex >= 0 && MisalignedSwitch[direction, 0] < 0)
+ {
+ bool reqAutoAlign = hasEndSignal; // auto-align switches if route is extended from signal
+
+ tempSections = signalRef.ScanRoute(this, nextSectionIndex, 0,
+ nextSectionDirection, forward, extendedDistanceM, true, reqAutoAlign,
+ true, false, true, false, false, false, false, IsFreight);
+ }
+
+ if (tempSections.Count > 0)
+ {
+ // add new sections
+
+ int prevSection = lastElement.TCSectionIndex;
+
+ foreach (int sectionIndex in tempSections)
+ {
+ thisElement = new Train.TCRouteElement(signalRef.TrackCircuitList[Math.Abs(sectionIndex)],
+ sectionIndex > 0 ? 0 : 1, signalRef, prevSection);
+ newRoute.Add(thisElement);
+ prevSection = Math.Abs(sectionIndex);
+ }
+ }
+ }
+
// check for any uncleared signals in route - if first found, request clear signal
bool unclearedSignal = false;
@@ -9255,12 +9316,67 @@ public void UpdateExplorerMode(int signalObjectIndex)
if (endAuthority == END_AUTHORITY.SIGNAL)
{
- TrackCircuitSection lastSection = signalRef.TrackCircuitList[newRoute[newRoute.Count - 1].TCSectionIndex];
- int lastDirection = newRoute[newRoute.Count - 1].Direction;
- if (lastSection.EndSignals[lastDirection] != null && lastSection.EndSignals[lastDirection].thisRef == nextUnclearSignalIndex)
+ //TrackCircuitSection lastSection = signalRef.TrackCircuitList[newRoute[newRoute.Count - 1].TCSectionIndex];
+ //int lastDirection = newRoute[newRoute.Count - 1].Direction;
+
+ if (unclearedSignal && signalIndex < newRoute.Count)
{
+ //TrackCircuitSection lastSection = signalRef.TrackCircuitList[newRoute[signalIndex].TCSectionIndex];
SignalObject reqSignal = signalRef.SignalObjects[nextUnclearSignalIndex];
- newRoute = reqSignal.requestClearSignalExplorer(newRoute, forward ? routedForward : routedBackward, false, 0);
+ bool firstSignalPassed = false;
+ int numCleared = 0;
+ totalLengthM = 0;
+ offsetM = direction == 0 ? requiredPosition.TCOffset : thisSection.Length - requiredPosition.TCOffset;
+ for (int iindex = 0; iindex < newRoute.Count && (firstSignalPassed || totalLengthM < minCheckDistanceM); iindex++)
+ {
+ thisSection = signalRef.TrackCircuitList[newRoute[iindex].TCSectionIndex];
+ int actDirection = newRoute[iindex].Direction;
+
+ if (!thisSection.IsAvailable(this))
+ break;
+
+ totalLengthM += thisSection.Length - offsetM;
+ offsetM = 0;
+
+ if (thisSection.EndSignals[actDirection] != null)
+ {
+ var thisSignal = thisSection.EndSignals[actDirection];
+ if (!firstSignalPassed)
+ {
+ firstSignalPassed = true;
+ if (thisSignal == reqSignal)
+ {
+ for (int i = newRoute.Count - 1; i >= iindex + 1; i--)
+ {
+ thisSection = signalRef.TrackCircuitList[newRoute[i].TCSectionIndex];
+ thisSection.RemoveTrain(this, true);
+ newRoute.RemoveAt(i);
+ }
+ newRoute = thisSignal.requestClearSignalExplorer(newRoute, thisRouted, false, 0);
+ break;
+ }
+ int num = thisSignal.SignalNumClearAhead_MSTS;
+ if (num <= -2)
+ num = thisSignal.SignalNumClearAheadActive;
+ numCleared = Math.Max(num - thisSignal.SignalNumNormalHeads, 0);
+ }
+ else
+ {
+ if (thisSignal == reqSignal && numCleared > 0)
+ {
+ for (int i = newRoute.Count - 1; i >= iindex + 1; i--)
+ {
+ thisSection = signalRef.TrackCircuitList[newRoute[i].TCSectionIndex];
+ thisSection.RemoveTrain(this, true);
+ newRoute.RemoveAt(i);
+ }
+ newRoute = thisSignal.requestClearSignalExplorer(newRoute, thisRouted, true, numCleared);
+ break;
+ }
+ numCleared = Math.Max(numCleared - thisSignal.SignalNumNormalHeads, 0);
+ }
+ }
+ }
}
}
}