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:
@@ -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)) {
|
if (!tf_local.Follow(cur.tile, cur.td)) {
|
||||||
assert(tf_local.m_err != TrackFollower::EC_NONE);
|
assert(tf_local.m_err != TrackFollower::EC_NONE);
|
||||||
/* Can't move to the next tile (EOL?). */
|
/* 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) {
|
if (tf_local.m_err == TrackFollower::EC_RAIL_ROAD_TYPE) {
|
||||||
end_segment_reason |= ESRB_RAIL_TYPE;
|
end_segment_reason |= ESRB_RAIL_TYPE;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -215,6 +215,35 @@ struct CYapfRailNodeT
|
|||||||
return (obj.*func)(cur, cur_td);
|
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
|
void Dump(DumpTarget &dmp) const
|
||||||
{
|
{
|
||||||
base::Dump(dmp);
|
base::Dump(dmp);
|
||||||
|
@@ -289,13 +289,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline void PfFollowNode(Node &old_node)
|
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)) {
|
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;
|
Node *rev_node = &old_node;
|
||||||
|
uint length = 0;
|
||||||
while (rev_node && !(rev_node->m_segment->m_end_segment_reason & ESRB_REVERSE)) {
|
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;
|
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()))) {
|
if (F.Follow(rev_node->GetLastTile(), ReverseTrackdir(rev_node->GetLastTrackdir()))) {
|
||||||
Yapf().AddMultipleNodes(&old_node, F, [&](Node &n) {
|
Yapf().AddMultipleNodes(&old_node, F, [&](Node &n) {
|
||||||
n.flags_u.flags_s.m_reverse_pending = false;
|
n.flags_u.flags_s.m_reverse_pending = false;
|
||||||
@@ -303,6 +306,8 @@ public:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
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())) {
|
if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
|
||||||
@@ -482,13 +487,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline void PfFollowNode(Node &old_node)
|
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)) {
|
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;
|
Node *rev_node = &old_node;
|
||||||
|
uint length = 0;
|
||||||
while (rev_node && !(rev_node->m_segment->m_end_segment_reason & ESRB_REVERSE)) {
|
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;
|
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()))) {
|
if (F.Follow(rev_node->GetLastTile(), ReverseTrackdir(rev_node->GetLastTrackdir()))) {
|
||||||
Yapf().AddMultipleNodes(&old_node, F, [&](Node &n) {
|
Yapf().AddMultipleNodes(&old_node, F, [&](Node &n) {
|
||||||
n.flags_u.flags_s.m_reverse_pending = false;
|
n.flags_u.flags_s.m_reverse_pending = false;
|
||||||
@@ -496,6 +504,8 @@ public:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
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())) {
|
if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
enum EndSegmentReason {
|
enum EndSegmentReason {
|
||||||
/* The following reasons can be saved into cached segment */
|
/* The following reasons can be saved into cached segment */
|
||||||
ESR_DEAD_END = 0, ///< track ends here
|
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_RAIL_TYPE, ///< the next tile has a different rail type than our tiles
|
||||||
ESR_INFINITE_LOOP, ///< infinite loop detected
|
ESR_INFINITE_LOOP, ///< infinite loop detected
|
||||||
ESR_SEGMENT_TOO_LONG, ///< the segment is too long (possible infinite loop)
|
ESR_SEGMENT_TOO_LONG, ///< the segment is too long (possible infinite loop)
|
||||||
@@ -42,6 +43,7 @@ enum EndSegmentReasonBits {
|
|||||||
ESRB_NONE = 0,
|
ESRB_NONE = 0,
|
||||||
|
|
||||||
ESRB_DEAD_END = 1 << ESR_DEAD_END,
|
ESRB_DEAD_END = 1 << ESR_DEAD_END,
|
||||||
|
ESRB_DEAD_END_EOL = 1 << ESR_DEAD_END_EOL,
|
||||||
ESRB_RAIL_TYPE = 1 << ESR_RAIL_TYPE,
|
ESRB_RAIL_TYPE = 1 << ESR_RAIL_TYPE,
|
||||||
ESRB_INFINITE_LOOP = 1 << ESR_INFINITE_LOOP,
|
ESRB_INFINITE_LOOP = 1 << ESR_INFINITE_LOOP,
|
||||||
ESRB_SEGMENT_TOO_LONG = 1 << ESR_SEGMENT_TOO_LONG,
|
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,
|
ESRB_POSSIBLE_TARGET = ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
|
||||||
|
|
||||||
/* What reasons can be stored back into cached segment. */
|
/* 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. */
|
/* 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,
|
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)
|
inline std::string ValueStr(EndSegmentReasonBits bits)
|
||||||
{
|
{
|
||||||
static const char * const end_segment_reason_names[] = {
|
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",
|
"DEPOT", "WAYPOINT", "STATION", "SAFE_TILE",
|
||||||
"PATH_TOO_LONG", "FIRST_TWO_WAY_RED", "LOOK_AHEAD_END", "TARGET_REACHED",
|
"PATH_TOO_LONG", "FIRST_TWO_WAY_RED", "LOOK_AHEAD_END", "TARGET_REACHED",
|
||||||
"REVERSE"
|
"REVERSE"
|
||||||
|
Reference in New Issue
Block a user