Add tracerestrict feature reverse behind signal

This commit is contained in:
Jonathan G Rennison
2018-12-05 20:01:09 +00:00
parent a315d39067
commit cd41683b9b
12 changed files with 162 additions and 6 deletions

View File

@@ -208,17 +208,25 @@ public:
}
/** add multiple nodes - direct children of the given node */
inline void AddMultipleNodes(Node *parent, const TrackFollower &tf)
template <class TNodeFunc>
inline void AddMultipleNodes(Node *parent, const TrackFollower &tf, TNodeFunc node_func)
{
bool is_choice = (KillFirstBit(tf.m_new_td_bits) != TRACKDIR_BIT_NONE);
for (TrackdirBits rtds = tf.m_new_td_bits; rtds != TRACKDIR_BIT_NONE; rtds = KillFirstBit(rtds)) {
Trackdir td = (Trackdir)FindFirstBit2x64(rtds);
Node &n = Yapf().CreateNewNode();
n.Set(parent, tf.m_new_tile, td, is_choice);
node_func(n);
Yapf().AddNewNode(n, tf);
}
}
/** add multiple nodes - direct children of the given node */
inline void AddMultipleNodes(Node *parent, const TrackFollower &tf)
{
AddMultipleNodes(parent, tf, [&](Node &n) {});
}
/**
* In some cases an intermediate node branch should be pruned.
* The most prominent case is when a red EOL signal is encountered, but

View File

@@ -273,6 +273,9 @@ private:
*is_res_through = false;
flags_to_check |= TRPAUF_RESERVE_THROUGH;
}
if (GetSignalType(tile, TrackdirToTrack(trackdir)) == SIGTYPE_PBS && !HasSignalOnTrackdir(tile, trackdir)) {
flags_to_check |= TRPAUF_REVERSE;
}
if (prog && prog->actions_used_flags & flags_to_check) {
prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir, &TraceRestrictPreviousSignalCallback, &n), out);
if (out.flags & TRPRF_RESERVE_THROUGH && is_res_through != NULL) {
@@ -282,6 +285,10 @@ private:
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
return true;
}
if (out.flags & TRPRF_REVERSE && flags_to_check & TRPAUF_REVERSE && !n.flags_u.flags_s.m_reverse_pending) {
n.flags_u.flags_s.m_reverse_pending = true;
n.m_segment->m_end_segment_reason |= ESRB_REVERSE;
}
cost += out.penalty;
}
return false;
@@ -478,6 +485,17 @@ public:
assert(!is_cached_segment);
/* Skip the first transition cost calculation. */
goto no_entry_cost;
} else if (n.flags_u.flags_s.m_teleport) {
int x1 = 2 * TileX(prev.tile);
int y1 = 2 * TileY(prev.tile);
int x2 = 2 * TileX(cur.tile);
int y2 = 2 * TileY(cur.tile);
int dx = abs(x1 - x2);
int dy = abs(y1 - y2);
int dmin = min(dx, dy);
int dxy = abs(dx - dy);
segment_entry_cost += dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
goto no_entry_cost;
}
for (;;) {
@@ -723,8 +741,10 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th
/* Do we have an excuse why not to continue pathfinding in this direction? */
if (!target_seen && (end_segment_reason & ESRB_ABORT_PF_MASK) != ESRB_NONE) {
/* Reason to not continue. Stop this PF branch. */
return false;
if (likely(!n.flags_u.flags_s.m_reverse_pending || (end_segment_reason & ESRB_ABORT_PF_MASK_PENDING_REVERSE) != ESRB_NONE)) {
/* Reason to not continue. Stop this PF branch. */
return false;
}
}
/* Special costs for the case we have reached our target. */

View File

@@ -137,6 +137,8 @@ struct CYapfRailNodeT
bool m_targed_seen : 1;
bool m_choice_seen : 1;
bool m_last_signal_was_red : 1;
bool m_reverse_pending : 1;
bool m_teleport : 1;
} flags_s;
} flags_u;
SignalType m_last_red_signal_type;
@@ -174,6 +176,7 @@ struct CYapfRailNodeT
m_last_signal_type = parent->m_last_signal_type;
}
flags_u.flags_s.m_choice_seen |= is_choice;
flags_u.flags_s.m_teleport = false;
}
inline TileIndex GetLastTile() const

View File

@@ -293,6 +293,21 @@ public:
inline void PfFollowNode(Node &old_node)
{
TrackFollower F(Yapf().GetVehicle());
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;
while (rev_node && !(rev_node->m_segment->m_end_segment_reason & ESRB_REVERSE)) {
rev_node = rev_node->m_parent;
}
if (rev_node) {
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;
n.flags_u.flags_s.m_teleport = true;
});
}
return;
}
}
if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
Yapf().AddMultipleNodes(&old_node, F);
}
@@ -471,6 +486,21 @@ public:
inline void PfFollowNode(Node &old_node)
{
TrackFollower F(Yapf().GetVehicle());
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;
while (rev_node && !(rev_node->m_segment->m_end_segment_reason & ESRB_REVERSE)) {
rev_node = rev_node->m_parent;
}
if (rev_node) {
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;
n.flags_u.flags_s.m_teleport = true;
});
}
return;
}
}
if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
Yapf().AddMultipleNodes(&old_node, F);
}

View File

@@ -31,6 +31,7 @@ enum EndSegmentReason {
ESR_FIRST_TWO_WAY_RED, ///< first signal was 2-way and it was red
ESR_LOOK_AHEAD_END, ///< we have just passed the last look-ahead signal
ESR_TARGET_REACHED, ///< we have just reached the destination
ESR_REVERSE, ///< we should reverse after this point
/* Special values */
ESR_NONE = 0xFF, ///< no reason to end the segment here
@@ -53,6 +54,7 @@ enum EndSegmentReasonBits {
ESRB_FIRST_TWO_WAY_RED = 1 << ESR_FIRST_TWO_WAY_RED,
ESRB_LOOK_AHEAD_END = 1 << ESR_LOOK_AHEAD_END,
ESRB_TARGET_REACHED = 1 << ESR_TARGET_REACHED,
ESRB_REVERSE = 1 << ESR_REVERSE,
/* Additional (composite) values. */
@@ -60,10 +62,13 @@ 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_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,
/* 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,
/* Reasons to abort pathfinding in this direction, when reversing is pending. */
ESRB_ABORT_PF_MASK_PENDING_REVERSE = ESRB_ABORT_PF_MASK & ~ESRB_DEAD_END,
};
DECLARE_ENUM_AS_BIT_SET(EndSegmentReasonBits)