Allow placing routing restrictions on tunnel/bridge entrance/exit signals

No reserve through support
This commit is contained in:
Jonathan G Rennison
2021-11-13 22:28:14 +00:00
parent 1ee59c8333
commit 74bfe4e6d2
18 changed files with 393 additions and 73 deletions

View File

@@ -4001,11 +4001,12 @@ static bool HasLongReservePbsSignalOnTrackdir(Train* v, TileIndex tile, Trackdir
return false;
}
static TileIndex CheckLongReservePbsTunnelBridgeOnTrackdir(Train* v, TileIndex tile, Trackdir trackdir)
static TileIndex CheckLongReservePbsTunnelBridgeOnTrackdir(Train* v, TileIndex tile, Trackdir trackdir, bool restricted_only = false)
{
if (_settings_game.vehicle.train_braking_model == TBM_REALISTIC && IsTunnelBridgeSignalSimulationEntranceTile(tile) && TrackdirEntersTunnelBridge(tile, trackdir)) {
TileIndex end = GetOtherTunnelBridgeEnd(tile);
if (restricted_only && !IsTunnelBridgeRestrictedSignal(end)) return INVALID_TILE;
int raw_free_tiles;
if (v->lookahead != nullptr && v->lookahead->reservation_end_tile == tile && v->lookahead->reservation_end_trackdir == trackdir) { // TODO fix loop case
if (HasBit(v->lookahead->flags, TRLF_TB_EXIT_FREE)) {
@@ -4033,7 +4034,7 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td
const bool long_enough = IsReservationLookAheadLongEnough(v, lookahead_state);
// We reserved up to a unoccupied signalled tunnel/bridge, reserve past it as well. recursion
TileIndex exit_tile = long_enough ? INVALID_TILE : CheckLongReservePbsTunnelBridgeOnTrackdir(v, tile, td);
TileIndex exit_tile = CheckLongReservePbsTunnelBridgeOnTrackdir(v, tile, td, long_enough);
if (exit_tile != INVALID_TILE) {
CFollowTrackRail ft(v);
Trackdir exit_td = GetTunnelBridgeExitTrackdir(exit_tile);
@@ -4042,6 +4043,23 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td
if ((ft.m_new_td_bits & TrackBitsToTrackdirBits(reserved_bits)) == TRACKDIR_BIT_NONE) {
/* next tile is not reserved */
bool long_reserve = !long_enough;
if (IsTunnelBridgeRestrictedSignal(exit_tile)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(exit_tile, TrackdirToTrack(exit_td));
if (prog && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_ACQUIRE_ON_RES | TRPAUF_LONG_RESERVE)) {
TraceRestrictProgramResult out;
if (long_reserve) out.flags |= TRPRF_LONG_RESERVE;
TraceRestrictProgramInput input(exit_tile, exit_td, nullptr, nullptr);
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_ACQUIRE_ON_RES;
prog->Execute(v, input, out);
if (out.flags & TRPRF_WAIT_AT_PBS) {
return;
}
long_reserve = (out.flags & TRPRF_LONG_RESERVE);
}
}
if (!long_reserve) return;
SignalState exit_state = GetTunnelBridgeExitSignalState(exit_tile);
/* reserve exit to make contiguous reservation */
@@ -4051,10 +4069,6 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td
SetTunnelReservation(exit_tile, true);
}
SetTunnelBridgeExitSignalState(exit_tile, SIGNAL_STATE_GREEN);
if (_extra_aspects > 0) {
SetTunnelBridgeExitSignalAspect(exit_tile, 0);
UpdateAspectDeferred(exit_tile, GetTunnelBridgeExitTrackdir(exit_tile));
}
ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), CTTF_NO_LOOKAHEAD_VALIDATE | (force_res ? CTTF_FORCE_RES : CTTF_NONE), nullptr, lookahead_state);
@@ -4067,6 +4081,10 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td
}
SetTunnelBridgeExitSignalState(exit_tile, exit_state);
} else {
if (_extra_aspects > 0) {
SetTunnelBridgeExitSignalAspect(exit_tile, 0);
UpdateAspectDeferred(exit_tile, GetTunnelBridgeExitTrackdir(exit_tile));
}
MarkTileDirtyByTile(exit_tile, VMDF_NOT_MAP_MODE);
}
}
@@ -4995,6 +5013,23 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
}
}
auto try_exit_reservation = [&]() -> bool {
if (IsTunnelBridgeRestrictedSignal(tile)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(td));
if (prog && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_ACQUIRE_ON_RES)) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(tile, td, nullptr, nullptr);
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_ACQUIRE_ON_RES;
prog->Execute(t, input, out);
if (out.flags & TRPRF_WAIT_AT_PBS) {
return false;
}
}
}
return TryPathReserve(t);
};
if (_settings_game.vehicle.train_braking_model == TBM_REALISTIC) {
if (unlikely(t->lookahead == nullptr)) {
FillTrainReservationLookAhead(t);
@@ -5004,10 +5039,6 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
if (t->lookahead->reservation_end_tile == t->tile && t->lookahead->reservation_end_position - t->lookahead->current_position <= (int)TILE_SIZE && !HasBit(t->lookahead->flags, TRLF_TB_EXIT_FREE)) return false;
SignalState exit_state = GetTunnelBridgeExitSignalState(tile);
SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_GREEN);
if (_extra_aspects > 0) {
SetTunnelBridgeExitSignalAspect(tile, 0);
UpdateAspectDeferred(tile, GetTunnelBridgeExitTrackdir(tile));
}
/* Get tile margin before changing vehicle direction */
const int tile_margin = GetTileMarginInFrontOfTrain(t);
@@ -5018,7 +5049,7 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
t->tile = tile;
t->track = TRACK_BIT_WORMHOLE;
t->direction = TrackdirToDirection(td);
bool ok = TryPathReserve(t);
bool ok = try_exit_reservation();
if (!ok && (t->lookahead->reservation_end_position >= t->lookahead->current_position && t->lookahead->reservation_end_position > t->lookahead->current_position + tile_margin)) {
/* Reservation was made previously and was valid then.
* To avoid unexpected braking due to stopping short of the lookahead end,
@@ -5026,6 +5057,10 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
ok = true;
}
if (ok) {
if (_extra_aspects > 0) {
SetTunnelBridgeExitSignalAspect(tile, 0);
UpdateAspectDeferred(tile, GetTunnelBridgeExitTrackdir(tile));
}
mark_dirty = true;
if (t->lookahead->reservation_end_tile == veh_orig_tile && t->lookahead->reservation_end_position - t->lookahead->current_position <= (int)TILE_SIZE) {
/* Less than a tile of lookahead, advance tile */
@@ -5057,7 +5092,7 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
t->tile = tile;
t->track = TRACK_BIT_WORMHOLE;
t->direction = TrackdirToDirection(td);
bool ok = TryPathReserve(t);
bool ok = try_exit_reservation();
t->tile = veh_orig_tile;
t->track = veh_orig_track;
t->direction = veh_orig_direction;
@@ -5170,6 +5205,21 @@ void DecrementPendingSpeedRestrictions(Train *v)
}
}
void HandleTraceRestrictSpeedRestrictionAction(const TraceRestrictProgramResult &out, Train *v, Trackdir signal_td)
{
if (out.flags & TRPRF_SPEED_RESTRICTION_SET) {
SetBit(v->flags, VRF_PENDING_SPEED_RESTRICTION);
auto range = pending_speed_restriction_change_map.equal_range(v->index);
for (auto it = range.first; it != range.second; ++it) {
if ((uint16) (out.speed_restriction + 0xFFFF) < (uint16) (it->second.new_speed + 0xFFFF)) it->second.new_speed = out.speed_restriction;
}
uint16 flags = 0;
if (IsDiagonalTrack(TrackdirToTrack(signal_td))) SetBit(flags, PSRCF_DIAGONAL);
pending_speed_restriction_change_map.insert({ v->index, { (uint16) (v->gcache.cached_total_length + (HasBit(flags, PSRCF_DIAGONAL) ? 8 : 4)), out.speed_restriction, v->speed_restriction, flags } });
if ((uint16) (out.speed_restriction + 0xFFFF) < (uint16) (v->speed_restriction + 0xFFFF)) v->speed_restriction = out.speed_restriction;
}
}
/**
* Move a vehicle chain one movement stop forwards.
* @param v First vehicle to move.
@@ -5366,17 +5416,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
v->reverse_distance = v->gcache.cached_total_length + (IsDiagonalTrack(TrackdirToTrack(dir)) ? 16 : 8);
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
}
if (out.flags & TRPRF_SPEED_RESTRICTION_SET) {
SetBit(v->flags, VRF_PENDING_SPEED_RESTRICTION);
auto range = pending_speed_restriction_change_map.equal_range(v->index);
for (auto it = range.first; it != range.second; ++it) {
if ((uint16) (out.speed_restriction + 0xFFFF) < (uint16) (it->second.new_speed + 0xFFFF)) it->second.new_speed = out.speed_restriction;
}
uint16 flags = 0;
if (IsDiagonalTrack(TrackdirToTrack(dir))) SetBit(flags, PSRCF_DIAGONAL);
pending_speed_restriction_change_map.insert({ v->index, { (uint16) (v->gcache.cached_total_length + (HasBit(flags, PSRCF_DIAGONAL) ? 8 : 4)), out.speed_restriction, v->speed_restriction, flags } });
if ((uint16) (out.speed_restriction + 0xFFFF) < (uint16) (v->speed_restriction + 0xFFFF)) v->speed_restriction = out.speed_restriction;
}
HandleTraceRestrictSpeedRestrictionAction(out, v, dir);
}
}
}
@@ -5519,6 +5559,31 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
/* Entered wormhole set counters. */
v->wait_counter = (TILE_SIZE * simulated_wormhole_signals) - TILE_SIZE;
v->tunnel_bridge_signal_num = 0;
if (v->IsFrontEngine() && IsTunnelBridgeSignalSimulationEntrance(old_tile) && IsTunnelBridgeRestrictedSignal(old_tile)) {
const Trackdir trackdir = GetTunnelBridgeEntranceTrackdir(old_tile);
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, TrackdirToTrack(trackdir));
if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr);
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER;
prog->Execute(v, input, out);
HandleTraceRestrictSpeedRestrictionAction(out, v, trackdir);
}
}
if (v->Next() == nullptr && IsTunnelBridgeSignalSimulationEntrance(old_tile) && IsTunnelBridgeRestrictedSignal(old_tile)) {
const Trackdir trackdir = GetTunnelBridgeEntranceTrackdir(old_tile);
const Track track = TrackdirToTrack(trackdir);
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, track);
if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr);
input.permitted_slot_operations = TRPISP_RELEASE_BACK;
prog->Execute(first, input, out);
}
}
}
uint distance = v->wait_counter;
@@ -5534,6 +5599,17 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
return false;
}
leaving = true;
if (IsTunnelBridgeRestrictedSignal(gp.new_tile) && IsTunnelBridgeSignalSimulationExit(gp.new_tile)) {
const Trackdir trackdir = GetTunnelBridgeExitTrackdir(gp.new_tile);
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.new_tile, TrackdirToTrack(trackdir));
if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(gp.new_tile, trackdir, nullptr, nullptr);
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER;
prog->Execute(v, input, out);
HandleTraceRestrictSpeedRestrictionAction(out, v, trackdir);
}
}
} else {
if (IsTooCloseBehindTrain(v, gp.new_tile, v->wait_counter, distance == 0)) {
if (distance == 0) v->wait_counter = 0;
@@ -5765,6 +5841,22 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
}
}
}
if (IsTileType(gp.old_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(gp.old_tile) && IsTunnelBridgeRestrictedSignal(gp.old_tile)) {
const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTunnelBridgeTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir));
const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks);
const Track track = TrackdirToTrack(rev_trackdir);
if (TrackdirEntersTunnelBridge(gp.old_tile, rev_trackdir)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track);
if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(gp.old_tile, ReverseTrackdir(rev_trackdir), nullptr, nullptr);
input.permitted_slot_operations = TRPISP_RELEASE_BACK;
prog->Execute(first, input, out);
}
}
}
}
}