Tracerestrict: Handle slot acquire and wait at PBS on intermediary reservation signals
Wait at PBS is applied as if on the starting signal
This commit is contained in:
		@@ -194,15 +194,15 @@ struct CYapfRailNodeT
 | 
			
		||||
		m_segment->m_last_td = td;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <class Tbase, class Tfunc, class Tpf>
 | 
			
		||||
	bool IterateTiles(const Train *v, Tpf &yapf, Tbase &obj, bool (Tfunc::*func)(TileIndex, Trackdir)) const
 | 
			
		||||
	template <class Tbase, class Tpf, class Tfunc>
 | 
			
		||||
	bool IterateTiles(const Train *v, Tpf &yapf, Tfunc func) const
 | 
			
		||||
	{
 | 
			
		||||
		typename Tbase::TrackFollower ft(v, yapf.GetCompatibleRailTypes());
 | 
			
		||||
		TileIndex cur = base::GetTile();
 | 
			
		||||
		Trackdir  cur_td = base::GetTrackdir();
 | 
			
		||||
 | 
			
		||||
		while (cur != GetLastTile() || cur_td != GetLastTrackdir()) {
 | 
			
		||||
			if (!((obj.*func)(cur, cur_td))) return false;
 | 
			
		||||
			if (!(func(cur, cur_td))) return false;
 | 
			
		||||
 | 
			
		||||
			if (!ft.Follow(cur, cur_td)) break;
 | 
			
		||||
			cur = ft.m_new_tile;
 | 
			
		||||
@@ -210,7 +210,15 @@ struct CYapfRailNodeT
 | 
			
		||||
			cur_td = FindFirstTrackdir(ft.m_new_td_bits);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return (obj.*func)(cur, cur_td);
 | 
			
		||||
		return func(cur, cur_td);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <class Tbase, class Tpf, class Tfunc>
 | 
			
		||||
	bool IterateTiles(const Train *v, Tpf &yapf, Tbase &obj, bool (Tfunc::*func)(TileIndex, Trackdir)) const
 | 
			
		||||
	{
 | 
			
		||||
		return this->template IterateTiles<Tbase>(v, yapf, [&](TileIndex tile, Trackdir td) -> bool {
 | 
			
		||||
			return (obj.*func)(tile, td);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <class Tbase, class Tpf>
 | 
			
		||||
 
 | 
			
		||||
@@ -186,11 +186,38 @@ public:
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Don't bother if the target is reserved. */
 | 
			
		||||
		PBSWaitingPositionRestrictedSignalInfo restricted_signal_info;
 | 
			
		||||
		if (!IsWaitingPositionFree(Yapf().GetVehicle(), m_res_dest, m_res_dest_td, false, &restricted_signal_info)) return false;
 | 
			
		||||
		PBSWaitingPositionRestrictedSignalState restricted_signal_state;
 | 
			
		||||
		restricted_signal_state.defer_test_if_slot_conditional = true;
 | 
			
		||||
		if (!IsWaitingPositionFree(Yapf().GetVehicle(), m_res_dest, m_res_dest_td, false, &restricted_signal_state)) return false;
 | 
			
		||||
 | 
			
		||||
		static TraceRestrictSlotTemporaryState temporary_slot_state;
 | 
			
		||||
		assert(temporary_slot_state.IsEmpty());
 | 
			
		||||
 | 
			
		||||
		struct IntermediaryTraceRestrictSignalInfo {
 | 
			
		||||
			const TraceRestrictProgram *prog;
 | 
			
		||||
			TileIndex tile;
 | 
			
		||||
			Trackdir  trackdir;
 | 
			
		||||
		};
 | 
			
		||||
		/* Nodes are iterated in reverse order (from the target), but tiles within the node are iterated in forward order (towards the target).
 | 
			
		||||
		 * intermediary_restricted_signals is in reverse order, (the first signal to evaluate at the end).
 | 
			
		||||
		 */
 | 
			
		||||
		static std::vector<IntermediaryTraceRestrictSignalInfo> intermediary_restricted_signals;
 | 
			
		||||
		intermediary_restricted_signals.clear();
 | 
			
		||||
 | 
			
		||||
		for (Node *node = m_res_node; node->m_parent != nullptr; node = node->m_parent) {
 | 
			
		||||
			node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::ReserveSingleTrack);
 | 
			
		||||
			const size_t intermediary_restricted_signals_current_size = intermediary_restricted_signals.size();
 | 
			
		||||
			node->template IterateTiles<CYapfReserveTrack>(Yapf().GetVehicle(), Yapf(), [&](TileIndex tile, Trackdir td) -> bool {
 | 
			
		||||
				/* Cheapest tests first */
 | 
			
		||||
				if (IsTileType(tile, MP_RAILWAY) && HasSignals(tile) && IsRestrictedSignal(tile) && HasSignalOnTrack(tile, TrackdirToTrack(td))) {
 | 
			
		||||
					const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(td));
 | 
			
		||||
					if (prog != nullptr && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE)) {
 | 
			
		||||
						/* Insert at intermediary_restricted_signals_current_size, such that if there are multiple signals for this node, they end up in reverse order */
 | 
			
		||||
						intermediary_restricted_signals.insert(intermediary_restricted_signals.begin() + intermediary_restricted_signals_current_size, { prog, tile, td });
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return this->ReserveSingleTrack(tile, td);
 | 
			
		||||
			});
 | 
			
		||||
			if (m_res_fail_tile != INVALID_TILE) {
 | 
			
		||||
				/* Reservation failed, undo. */
 | 
			
		||||
				Node *fail_node = m_res_node;
 | 
			
		||||
@@ -201,17 +228,52 @@ public:
 | 
			
		||||
					fail_node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::UnreserveSingleTrack);
 | 
			
		||||
				} while (fail_node != node && (fail_node = fail_node->m_parent) != nullptr);
 | 
			
		||||
 | 
			
		||||
				temporary_slot_state.RevertTemporaryChanges(Yapf().GetVehicle()->index);
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (restricted_signal_info.tile != INVALID_TILE) {
 | 
			
		||||
			const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(restricted_signal_info.tile, TrackdirToTrack(restricted_signal_info.trackdir));
 | 
			
		||||
			if (prog && prog->actions_used_flags & TRPAUF_PBS_RES_END_SLOT) {
 | 
			
		||||
		auto undo_reservation = [&]() {
 | 
			
		||||
			for (Node *node = m_res_node; node->m_parent != nullptr; node = node->m_parent) {
 | 
			
		||||
				node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::UnreserveSingleTrack);
 | 
			
		||||
			}
 | 
			
		||||
			temporary_slot_state.RevertTemporaryChanges(Yapf().GetVehicle()->index);
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* Iterate in reverse order */
 | 
			
		||||
		for (auto iter = intermediary_restricted_signals.rbegin(); iter != intermediary_restricted_signals.rend(); ++iter) {
 | 
			
		||||
			extern TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *, TraceRestrictPBSEntrySignalAuxField mode);
 | 
			
		||||
 | 
			
		||||
			TraceRestrictProgramInput input(iter->tile, iter->trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, nullptr);
 | 
			
		||||
			input.permitted_slot_operations = TRPISP_ACQUIRE_TEMP_STATE;
 | 
			
		||||
			input.slot_temporary_state = &temporary_slot_state;
 | 
			
		||||
			TraceRestrictProgramResult out;
 | 
			
		||||
			iter->prog->Execute(Yapf().GetVehicle(), input, out);
 | 
			
		||||
			if (out.flags & TRPRF_WAIT_AT_PBS) {
 | 
			
		||||
				/* Wait at PBS is set, take this as waiting at the start signal */
 | 
			
		||||
				undo_reservation();
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (restricted_signal_state.deferred_test) {
 | 
			
		||||
			/* The IsWaitingPositionFree restricted signal test was deferred due to possible slot changes during reservation, test it now */
 | 
			
		||||
			if (!IsWaitingPositionFreeTraceRestrictExecute(restricted_signal_state.prog, Yapf().GetVehicle(), restricted_signal_state.tile, restricted_signal_state.trackdir)) {
 | 
			
		||||
				/* Target is reserved, undo reservation */
 | 
			
		||||
				undo_reservation();
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		temporary_slot_state.ApplyTemporaryChanges(Yapf().GetVehicle()->index);
 | 
			
		||||
 | 
			
		||||
		if (restricted_signal_state.prog != nullptr) {
 | 
			
		||||
			const TraceRestrictProgram *prog = restricted_signal_state.prog;
 | 
			
		||||
			if (prog != nullptr && prog->actions_used_flags & TRPAUF_PBS_RES_END_SLOT) {
 | 
			
		||||
				extern TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *, TraceRestrictPBSEntrySignalAuxField mode);
 | 
			
		||||
 | 
			
		||||
				TraceRestrictProgramResult out;
 | 
			
		||||
				TraceRestrictProgramInput input(restricted_signal_info.tile, restricted_signal_info.trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, nullptr);
 | 
			
		||||
				TraceRestrictProgramInput input(restricted_signal_state.tile, restricted_signal_state.trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, nullptr);
 | 
			
		||||
				input.permitted_slot_operations = TRPISP_PBS_RES_END_ACQUIRE | TRPISP_PBS_RES_END_RELEASE;
 | 
			
		||||
				prog->Execute(Yapf().GetVehicle(), input, out);
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user