diff --git a/src/lang/english.txt b/src/lang/english.txt index 53bebd56c3..084c08398a 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2473,10 +2473,16 @@ STR_TRACE_RESTRICT_SLOT_ACQUIRE_WAIT :Acquire or wait STR_TRACE_RESTRICT_SLOT_TRY_ACQUIRE :Try to acquire STR_TRACE_RESTRICT_SLOT_RELEASE_FRONT :Release (front) STR_TRACE_RESTRICT_SLOT_RELEASE_BACK :Release (back) +STR_TRACE_RESTRICT_SLOT_PBS_RES_END_ACQUIRE_WAIT :PBS end: Acquire or wait +STR_TRACE_RESTRICT_SLOT_PBS_RES_END_TRY_ACQUIRE :PBS end: Try to acquire +STR_TRACE_RESTRICT_SLOT_PBS_RES_END_RELEASE :PBS end: Release STR_TRACE_RESTRICT_SLOT_ACQUIRE_WAIT_ITEM :Acquire slot: {STRING1}{BLACK}{STRING}, or wait at PBS signal STR_TRACE_RESTRICT_SLOT_TRY_ACQUIRE_ITEM :Try to acquire slot: {STRING1}{BLACK}{STRING}, or continue anyway STR_TRACE_RESTRICT_SLOT_RELEASE_FRONT_ITEM :Release slot: {STRING1}{BLACK}{STRING} (front of train) STR_TRACE_RESTRICT_SLOT_RELEASE_BACK_ITEM :Release slot: {STRING1}{BLACK}{STRING} (back of train) +STR_TRACE_RESTRICT_SLOT_PBS_RES_END_ACQUIRE_WAIT_ITEM :PBS reservation ending here: Acquire slot: {STRING1}{BLACK}{STRING}, or wait at start +STR_TRACE_RESTRICT_SLOT_PBS_RES_END_TRY_ACQUIRE_ITEM :PBS reservation ending here: Acquire slot: {STRING1}{BLACK}{STRING}, or continue anyway +STR_TRACE_RESTRICT_SLOT_PBS_RES_END_RELEASE_ITEM :PBS reservation ending here: Release slot: {STRING1}{BLACK}{STRING} STR_TRACE_RESTRICT_SLOT_NAME :{TRSLOT} STR_TRACE_RESTRICT_SLOT_LIST_HEADER :{BLACK}Slot{CONSUME_ARG}{P "" s}: {LTBLUE} STR_TRACE_RESTRICT_SLOT_LIST_SEPARATOR :{BLACK}, {LTBLUE} diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp index e3ae2c8a96..0d2d75cadd 100644 --- a/src/pathfinder/yapf/yapf_rail.cpp +++ b/src/pathfinder/yapf/yapf_rail.cpp @@ -18,6 +18,7 @@ #include "yapf_destrail.hpp" #include "../../viewport_func.h" #include "../../newgrf_station.h" +#include "../../tracerestrict.h" #include "../../safeguards.h" @@ -159,7 +160,8 @@ public: } /* Don't bother if the target is reserved. */ - if (!IsWaitingPositionFree(Yapf().GetVehicle(), m_res_dest, m_res_dest_td)) return false; + PBSWaitingPositionRestrictedSignalInfo restricted_signal_info; + if (!IsWaitingPositionFree(Yapf().GetVehicle(), m_res_dest, m_res_dest_td, false, &restricted_signal_info)) return false; for (Node *node = m_res_node; node->m_parent != NULL; node = node->m_parent) { node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack::ReserveSingleTrack); @@ -177,6 +179,18 @@ public: } } + 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) { + extern TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *); + + TraceRestrictProgramResult out; + TraceRestrictProgramInput input(restricted_signal_info.tile, restricted_signal_info.trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, NULL); + input.permitted_slot_operations = TRPISP_PBS_RES_END_ACQUIRE | TRPISP_PBS_RES_END_RELEASE; + prog->Execute(Yapf().GetVehicle(), input, out); + } + } + if (target != NULL) target->okay = true; if (Yapf().CanUseGlobalCache(*m_res_node)) { diff --git a/src/pbs.cpp b/src/pbs.cpp index dc9e404145..737756e459 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -515,7 +515,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo * @param forbid_90deg Don't allow trains to make 90 degree turns * @return True if the position is free */ -bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg) +bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg, PBSWaitingPositionRestrictedSignalInfo *restricted_signal_info) { Track track = TrackdirToTrack(trackdir); TrackBits reserved = GetReservedTrackbits(tile); @@ -526,12 +526,18 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo /* Not reserved and depot or not a pbs signal -> free. */ if (IsRailDepotTile(tile)) return true; - auto pbs_res_end_wait_test = [v](TileIndex t, Trackdir td) -> bool { + auto pbs_res_end_wait_test = [v, restricted_signal_info](TileIndex t, Trackdir td) -> bool { if (IsRestrictedSignal(t)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(t, TrackdirToTrack(td)); + if (restricted_signal_info && prog) { + restricted_signal_info->tile = t; + restricted_signal_info->trackdir = td; + } if (prog && prog->actions_used_flags & TRPAUF_PBS_RES_END_WAIT) { + TraceRestrictProgramInput input(t, td, &VehiclePosTraceRestrictPreviousSignalCallback, NULL); + input.permitted_slot_operations = TRPISP_PBS_RES_END_ACQ_DRY; TraceRestrictProgramResult out; - prog->Execute(v, TraceRestrictProgramInput(t, td, &VehiclePosTraceRestrictPreviousSignalCallback, NULL), out); + prog->Execute(v, input, out); if (out.flags & TRPRF_PBS_RES_END_WAIT) { return false; } diff --git a/src/pbs.h b/src/pbs.h index 223aeccacf..38f386e7bb 100644 --- a/src/pbs.h +++ b/src/pbs.h @@ -46,9 +46,14 @@ struct PBSTileInfo { PBSTileInfo(TileIndex _t, Trackdir _td, bool _okay) : tile(_t), trackdir(_td), okay(_okay) {} }; +struct PBSWaitingPositionRestrictedSignalInfo { + TileIndex tile = INVALID_TILE; + Trackdir trackdir = INVALID_TRACKDIR; +}; + PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res = NULL); bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg = false); -bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg = false); +bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg = false, PBSWaitingPositionRestrictedSignalInfo *restricted_signal_info = nullptr); Train *GetTrainForReservation(TileIndex tile, Track track); diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index e5f34f5b36..9056939e61 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -519,6 +519,22 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp if (input.permitted_slot_operations & TRPISP_RELEASE_FRONT) slot->Vacate(v->index); break; + case TRSCOF_PBS_RES_END_ACQ_WAIT: + if (input.permitted_slot_operations & TRPISP_PBS_RES_END_ACQUIRE) { + if (!slot->Occupy(v->index)) out.flags |= TRPRF_PBS_RES_END_WAIT; + } else if (input.permitted_slot_operations & TRPISP_PBS_RES_END_ACQ_DRY) { + if (!slot->OccupyDryRun(v->index)) out.flags |= TRPRF_PBS_RES_END_WAIT; + } + break; + + case TRSCOF_PBS_RES_END_ACQ_TRY: + if (input.permitted_slot_operations & TRPISP_PBS_RES_END_ACQUIRE) slot->Occupy(v->index); + break; + + case TRSCOF_PBS_RES_END_RELEASE: + if (input.permitted_slot_operations & TRPISP_PBS_RES_END_RELEASE) slot->Vacate(v->index); + break; + default: NOT_REACHED(); break; @@ -673,6 +689,15 @@ CommandCost TraceRestrictProgram::Validate(const std::vector actions_used_flags |= TRPAUF_SLOT_RELEASE_FRONT; break; + case TRSCOF_PBS_RES_END_ACQ_WAIT: + actions_used_flags |= TRPAUF_PBS_RES_END_SLOT | TRPAUF_PBS_RES_END_WAIT; + break; + + case TRSCOF_PBS_RES_END_ACQ_TRY: + case TRSCOF_PBS_RES_END_RELEASE: + actions_used_flags |= TRPAUF_PBS_RES_END_SLOT; + break; + default: NOT_REACHED(); break; @@ -1467,6 +1492,18 @@ bool TraceRestrictSlot::Occupy(VehicleID id, bool force) return true; } +/** + * Dry-run adding vehicle ID to occupants if possible and not already an occupant + * @param id Vehicle ID + * @return whether vehicle IDwould be an occupant + */ +bool TraceRestrictSlot::OccupyDryRun(VehicleID id) +{ + if (this->IsOccupant(id)) return true; + if (this->occupants.size() >= this->max_occupancy) return false; + return true; +} + /** * Remove vehicle ID from occupants * @param id Vehicle ID diff --git a/src/tracerestrict.h b/src/tracerestrict.h index 3e7974f2e3..17fff7e509 100644 --- a/src/tracerestrict.h +++ b/src/tracerestrict.h @@ -240,6 +240,9 @@ enum TraceRestrictSlotCondOpField { TRSCOF_ACQUIRE_TRY = 1, ///< try to acquire a slot, or carry on otherwise TRSCOF_RELEASE_BACK = 2, ///< release a slot (back of train) TRSCOF_RELEASE_FRONT = 3, ///< release a slot (front of train) + TRSCOF_PBS_RES_END_ACQ_WAIT = 4, ///< PBS reservations ending at this signal: acquire a slot, or wait + TRSCOF_PBS_RES_END_ACQ_TRY = 5, ///< PBS reservations ending at this signal: acquire a slot, or carry on otherwise + TRSCOF_PBS_RES_END_RELEASE = 6, ///< PBS reservations ending at this signal: release a slot /* space up to 8 */ }; @@ -287,6 +290,7 @@ enum TraceRestrictProgramActionsUsedFlags { TRPAUF_SLOT_RELEASE_BACK = 1 << 5, ///< Slot release (back) action is present TRPAUF_SLOT_RELEASE_FRONT = 1 << 6, ///< Slot release (front) action is present TRPAUF_PBS_RES_END_WAIT = 1 << 7, ///< PBS reservations ending at this signal wait action is present + TRPAUF_PBS_RES_END_SLOT = 1 << 8, ///< PBS reservations ending at this signal slot action is present }; DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramActionsUsedFlags) @@ -297,6 +301,9 @@ enum TraceRestrictProgramInputSlotPermissions { TRPISP_ACQUIRE = 1 << 0, ///< Slot acquire is permitted TRPISP_RELEASE_BACK = 1 << 1, ///< Slot release (back) is permitted TRPISP_RELEASE_FRONT = 1 << 2, ///< Slot release (front) is permitted + TRPISP_PBS_RES_END_ACQUIRE = 1 << 3, ///< Slot acquire (PBS reservations ending at this signal) is permitted + TRPISP_PBS_RES_END_ACQ_DRY = 1 << 4, ///< Dry-run slot acquire (PBS reservations ending at this signal) is permitted + TRPISP_PBS_RES_END_RELEASE = 1 << 5, ///< Slot release (PBS reservations ending at this signal) is permitted }; DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramInputSlotPermissions) @@ -781,6 +788,7 @@ struct TraceRestrictSlot : TraceRestrictSlotPool::PoolItem<&_tracerestrictslot_p } bool Occupy(VehicleID id, bool force = false); + bool OccupyDryRun(VehicleID ids); void Vacate(VehicleID id); void Clear(); diff --git a/src/tracerestrict_gui.cpp b/src/tracerestrict_gui.cpp index cdbfeb43e5..4aa7bbbc67 100644 --- a/src/tracerestrict_gui.cpp +++ b/src/tracerestrict_gui.cpp @@ -506,6 +506,9 @@ static const StringID _slot_op_cond_ops_str[] = { STR_TRACE_RESTRICT_SLOT_TRY_ACQUIRE, STR_TRACE_RESTRICT_SLOT_RELEASE_FRONT, STR_TRACE_RESTRICT_SLOT_RELEASE_BACK, + STR_TRACE_RESTRICT_SLOT_PBS_RES_END_ACQUIRE_WAIT, + STR_TRACE_RESTRICT_SLOT_PBS_RES_END_TRY_ACQUIRE, + STR_TRACE_RESTRICT_SLOT_PBS_RES_END_RELEASE, INVALID_STRING_ID, }; static const uint _slot_op_cond_ops_val[] = { @@ -513,6 +516,9 @@ static const uint _slot_op_cond_ops_val[] = { TRSCOF_ACQUIRE_TRY, TRSCOF_RELEASE_FRONT, TRSCOF_RELEASE_BACK, + TRSCOF_PBS_RES_END_ACQ_WAIT, + TRSCOF_PBS_RES_END_ACQ_TRY, + TRSCOF_PBS_RES_END_RELEASE, }; /** cargo conditional operators dropdown list set */ static const TraceRestrictDropDownListSet _slot_op_cond_ops = { @@ -1079,6 +1085,18 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric instruction_string = STR_TRACE_RESTRICT_SLOT_RELEASE_FRONT_ITEM; break; + case TRSCOF_PBS_RES_END_ACQ_WAIT: + instruction_string = STR_TRACE_RESTRICT_SLOT_PBS_RES_END_ACQUIRE_WAIT_ITEM; + break; + + case TRSCOF_PBS_RES_END_ACQ_TRY: + instruction_string = STR_TRACE_RESTRICT_SLOT_PBS_RES_END_TRY_ACQUIRE_ITEM; + break; + + case TRSCOF_PBS_RES_END_RELEASE: + instruction_string = STR_TRACE_RESTRICT_SLOT_PBS_RES_END_RELEASE_ITEM; + break; + default: NOT_REACHED(); break; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 648c9fff4e..84face3c2b 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2405,9 +2405,19 @@ static PBSTileInfo ExtendTrainReservation(const Train *v, const PBSTileInfo &ori cur_td = FindFirstTrackdir(ft.m_new_td_bits); if (IsSafeWaitingPosition(v, tile, cur_td, true, _settings_game.pf.forbid_90_deg)) { - bool wp_free = IsWaitingPositionFree(v, tile, cur_td, _settings_game.pf.forbid_90_deg); + PBSWaitingPositionRestrictedSignalInfo restricted_signal_info; + bool wp_free = IsWaitingPositionFree(v, tile, cur_td, _settings_game.pf.forbid_90_deg, &restricted_signal_info); if (!(wp_free && TryReserveRailTrack(tile, TrackdirToTrack(cur_td)))) break; /* Safe position is all good, path valid and okay. */ + 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) { + TraceRestrictProgramResult out; + TraceRestrictProgramInput input(restricted_signal_info.tile, restricted_signal_info.trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, NULL); + input.permitted_slot_operations = TRPISP_PBS_RES_END_ACQUIRE | TRPISP_PBS_RES_END_RELEASE; + prog->Execute(v, input, out); + } + } return PBSTileInfo(tile, cur_td, true); }