Improve handling of conditional order waiting loops

Do not leave station/depot/waypoint at all if conditional order
loop would result in re-starting waiting/loading

Only actually leave and update timetable at end of loop

Rate-limit loop checks regardless of timetabled wait time
This commit is contained in:
Jonathan G Rennison
2022-01-19 00:09:55 +00:00
parent 904ff6757d
commit beb6d01fe8
5 changed files with 146 additions and 11 deletions

View File

@@ -3334,6 +3334,8 @@ void Vehicle::LeaveStation()
delete this->cargo_payment;
assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
ClrBit(this->vehicle_flags, VF_COND_ORDER_WAIT);
TileIndex station_tile = INVALID_TILE;
if (this->type == VEH_TRAIN) {
@@ -3497,6 +3499,20 @@ void Vehicle::ResetRefitCaps()
for (Vehicle *v = this; v != nullptr; v = v->Next()) v->refit_cap = v->cargo_cap;
}
static bool ShouldVehicleContinueWaiting(Vehicle *v)
{
if (v->GetNumOrders() < 1) return false;
/* Rate-limit re-checking of conditional order loop */
if (HasBit(v->vehicle_flags, VF_COND_ORDER_WAIT) && v->tick_counter % 32 != 0) return true;
/* If conditional orders lead back to this order, just keep waiting without leaving the order */
bool loop = AdvanceOrderIndexDeferred(v, v->cur_implicit_order_index) == v->cur_implicit_order_index;
FlushAdvanceOrderIndexDeferred(v, loop);
if (loop) SetBit(v->vehicle_flags, VF_COND_ORDER_WAIT);
return loop;
}
/**
* Handle the loading of the vehicle; when not it skips through dummy
* orders and does nothing in all other cases.
@@ -3517,7 +3533,7 @@ void Vehicle::HandleLoading(bool mode)
if (!mode && this->type != VEH_TRAIN) PayStationSharingFee(this, Station::Get(this->last_station_visited));
/* Not the first call for this tick, or still loading */
if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || (this->current_order_time < wait_time && this->current_order.GetLeaveType() != OLT_LEAVE_EARLY)) {
if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || (this->current_order_time < wait_time && this->current_order.GetLeaveType() != OLT_LEAVE_EARLY) || ShouldVehicleContinueWaiting(this)) {
if (!mode && this->type == VEH_TRAIN && HasBit(Train::From(this)->flags, VRF_ADVANCE_IN_PLATFORM)) this->AdvanceLoadingInStation();
return;
}
@@ -3559,8 +3575,12 @@ void Vehicle::HandleWaiting(bool stop_waiting, bool process_orders)
if (!stop_waiting && this->current_order_time < wait_time && this->current_order.GetLeaveType() != OLT_LEAVE_EARLY) {
return;
}
if (!stop_waiting && process_orders && ShouldVehicleContinueWaiting(this)) {
return;
}
/* When wait_time is expired, we move on. */
ClrBit(this->vehicle_flags, VF_COND_ORDER_WAIT);
UpdateVehicleTimetable(this, false);
this->IncrementImplicitOrderIndex();
this->current_order.MakeDummy();
@@ -3668,6 +3688,7 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command, Tile
if (flags & DC_EXEC) {
if (this->current_order.IsAnyLoadingType()) this->LeaveStation();
if (this->current_order.IsType(OT_WAITING)) this->HandleWaiting(true);
if (this->type == VEH_TRAIN) {
for (Train *v = Train::From(this); v != nullptr; v = v->Next()) {
@@ -4123,6 +4144,7 @@ void DumpVehicleFlagsGeneric(const Vehicle *v, T dump, U dump_header)
dump('s', "VF_TIMETABLE_SEPARATION", HasBit(v->vehicle_flags, VF_TIMETABLE_SEPARATION));
dump('a', "VF_AUTOMATE_TIMETABLE", HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE));
dump('Q', "VF_HAVE_SLOT", HasBit(v->vehicle_flags, VF_HAVE_SLOT));
dump('W', "VF_COND_ORDER_WAIT", HasBit(v->vehicle_flags, VF_COND_ORDER_WAIT));
dump_header("vcf:", "cached_veh_flags:");
dump('l', "VCF_LAST_VISUAL_EFFECT", HasBit(v->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT));
dump('z', "VCF_GV_ZERO_SLOPE_RESIST", HasBit(v->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST));