diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index 581fa15159..a4a2096540 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -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 { diff --git a/src/pathfinder/yapf/yapf_node_rail.hpp b/src/pathfinder/yapf/yapf_node_rail.hpp index d92386ab3e..e337c17e55 100644 --- a/src/pathfinder/yapf/yapf_node_rail.hpp +++ b/src/pathfinder/yapf/yapf_node_rail.hpp @@ -215,6 +215,35 @@ struct CYapfRailNodeT return (obj.*func)(cur, cur_td); } + template + 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); diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp index 662413849a..e4a469e6c5 100644 --- a/src/pathfinder/yapf/yapf_rail.cpp +++ b/src/pathfinder/yapf/yapf_rail.cpp @@ -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())) { diff --git a/src/pathfinder/yapf/yapf_type.hpp b/src/pathfinder/yapf/yapf_type.hpp index 51bb0e1da6..35d9b0e267 100644 --- a/src/pathfinder/yapf/yapf_type.hpp +++ b/src/pathfinder/yapf/yapf_type.hpp @@ -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"