Reverse behind signal pathfinding now takes into account train length

This is to avoid pathfinding into a reversing track section which
is too short
This commit is contained in:
Jonathan G Rennison
2021-09-11 14:53:08 +01:00
parent 29df09e917
commit 7018babeac
4 changed files with 48 additions and 6 deletions

View File

@@ -685,6 +685,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th
if (!tf_local.Follow(cur.tile, cur.td)) {
assert(tf_local.m_err != TrackFollower::EC_NONE);
/* Can't move to the next tile (EOL?). */
if (!(end_segment_reason & (ESRB_RAIL_TYPE | ESRB_DEAD_END))) end_segment_reason |= ESRB_DEAD_END_EOL;
if (tf_local.m_err == TrackFollower::EC_RAIL_ROAD_TYPE) {
end_segment_reason |= ESRB_RAIL_TYPE;
} else {

View File

@@ -215,6 +215,35 @@ struct CYapfRailNodeT
return (obj.*func)(cur, cur_td);
}
template <class Tbase, class Tpf>
uint GetNodeLength(const Train *v, Tpf &yapf, Tbase &obj) const
{
typename Tbase::TrackFollower ft(v, yapf.GetCompatibleRailTypes());
TileIndex cur = base::GetTile();
Trackdir cur_td = base::GetTrackdir();
uint length = 0;
while (cur != GetLastTile() || cur_td != GetLastTrackdir()) {
length += IsDiagonalTrackdir(cur_td) ? TILE_SIZE : (TILE_SIZE / 2);
if (!ft.Follow(cur, cur_td)) break;
length += TILE_SIZE * ft.m_tiles_skipped;
cur = ft.m_new_tile;
assert(KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE);
cur_td = FindFirstTrackdir(ft.m_new_td_bits);
}
EndSegmentReasonBits esrb = this->m_segment->m_end_segment_reason;
if (!(esrb & ESRB_DEAD_END) || (esrb & ESRB_DEAD_END_EOL)) {
length += IsDiagonalTrackdir(cur_td) ? TILE_SIZE : (TILE_SIZE / 2);
if (IsTileType(cur, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationEntrance(cur) && TrackdirEntersTunnelBridge(cur, cur_td)) {
length += TILE_SIZE * GetTunnelBridgeLength(cur, GetOtherTunnelBridgeEnd(cur));
}
}
return length;
}
void Dump(DumpTarget &dmp) const
{
base::Dump(dmp);

View File

@@ -289,13 +289,16 @@ public:
*/
inline void PfFollowNode(Node &old_node)
{
TrackFollower F(Yapf().GetVehicle());
const Train *v = Yapf().GetVehicle();
TrackFollower F(v);
if (old_node.flags_u.flags_s.m_reverse_pending && old_node.m_segment->m_end_segment_reason & (ESRB_SAFE_TILE | ESRB_DEPOT | ESRB_DEAD_END)) {
Node *rev_node = &old_node;
uint length = 0;
while (rev_node && !(rev_node->m_segment->m_end_segment_reason & ESRB_REVERSE)) {
length += rev_node->GetNodeLength(v, Yapf(), *this);
rev_node = rev_node->m_parent;
}
if (rev_node) {
if (rev_node && length >= v->gcache.cached_total_length) {
if (F.Follow(rev_node->GetLastTile(), ReverseTrackdir(rev_node->GetLastTrackdir()))) {
Yapf().AddMultipleNodes(&old_node, F, [&](Node &n) {
n.flags_u.flags_s.m_reverse_pending = false;
@@ -303,6 +306,8 @@ public:
});
}
return;
} else if (old_node.m_segment->m_end_segment_reason & (ESRB_DEPOT | ESRB_DEAD_END)) {
return;
}
}
if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
@@ -482,13 +487,16 @@ public:
*/
inline void PfFollowNode(Node &old_node)
{
TrackFollower F(Yapf().GetVehicle());
const Train *v = Yapf().GetVehicle();
TrackFollower F(v);
if (old_node.flags_u.flags_s.m_reverse_pending && old_node.m_segment->m_end_segment_reason & (ESRB_SAFE_TILE | ESRB_DEPOT | ESRB_DEAD_END)) {
Node *rev_node = &old_node;
uint length = 0;
while (rev_node && !(rev_node->m_segment->m_end_segment_reason & ESRB_REVERSE)) {
length += rev_node->GetNodeLength(v, Yapf(), *this);
rev_node = rev_node->m_parent;
}
if (rev_node) {
if (rev_node && length >= v->gcache.cached_total_length) {
if (F.Follow(rev_node->GetLastTile(), ReverseTrackdir(rev_node->GetLastTrackdir()))) {
Yapf().AddMultipleNodes(&old_node, F, [&](Node &n) {
n.flags_u.flags_s.m_reverse_pending = false;
@@ -496,6 +504,8 @@ public:
});
}
return;
} else if (old_node.m_segment->m_end_segment_reason & (ESRB_DEPOT | ESRB_DEAD_END)) {
return;
}
}
if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {

View File

@@ -17,6 +17,7 @@
enum EndSegmentReason {
/* The following reasons can be saved into cached segment */
ESR_DEAD_END = 0, ///< track ends here
ESR_DEAD_END_EOL, ///< track ends here bit refers to the next tile, the last tile of the segment itself is usable
ESR_RAIL_TYPE, ///< the next tile has a different rail type than our tiles
ESR_INFINITE_LOOP, ///< infinite loop detected
ESR_SEGMENT_TOO_LONG, ///< the segment is too long (possible infinite loop)
@@ -42,6 +43,7 @@ enum EndSegmentReasonBits {
ESRB_NONE = 0,
ESRB_DEAD_END = 1 << ESR_DEAD_END,
ESRB_DEAD_END_EOL = 1 << ESR_DEAD_END_EOL,
ESRB_RAIL_TYPE = 1 << ESR_RAIL_TYPE,
ESRB_INFINITE_LOOP = 1 << ESR_INFINITE_LOOP,
ESRB_SEGMENT_TOO_LONG = 1 << ESR_SEGMENT_TOO_LONG,
@@ -63,7 +65,7 @@ enum EndSegmentReasonBits {
ESRB_POSSIBLE_TARGET = ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
/* What reasons can be stored back into cached segment. */
ESRB_CACHED_MASK = ESRB_DEAD_END | ESRB_RAIL_TYPE | ESRB_INFINITE_LOOP | ESRB_SEGMENT_TOO_LONG | ESRB_CHOICE_FOLLOWS | ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE | ESRB_REVERSE,
ESRB_CACHED_MASK = ESRB_DEAD_END | ESRB_DEAD_END_EOL | ESRB_RAIL_TYPE | ESRB_INFINITE_LOOP | ESRB_SEGMENT_TOO_LONG | ESRB_CHOICE_FOLLOWS | ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE | ESRB_REVERSE,
/* Reasons to abort pathfinding in this direction. */
ESRB_ABORT_PF_MASK = ESRB_DEAD_END | ESRB_PATH_TOO_LONG | ESRB_INFINITE_LOOP | ESRB_FIRST_TWO_WAY_RED,
@@ -77,7 +79,7 @@ DECLARE_ENUM_AS_BIT_SET(EndSegmentReasonBits)
inline std::string ValueStr(EndSegmentReasonBits bits)
{
static const char * const end_segment_reason_names[] = {
"DEAD_END", "RAIL_TYPE", "INFINITE_LOOP", "SEGMENT_TOO_LONG", "CHOICE_FOLLOWS",
"DEAD_END", "DEAD_END_EOL", "RAIL_TYPE", "INFINITE_LOOP", "SEGMENT_TOO_LONG", "CHOICE_FOLLOWS",
"DEPOT", "WAYPOINT", "STATION", "SAFE_TILE",
"PATH_TOO_LONG", "FIRST_TWO_WAY_RED", "LOOK_AHEAD_END", "TARGET_REACHED",
"REVERSE"