Departures: Use more general order destination detection abstraction

This commit is contained in:
Jonathan G Rennison 2024-09-05 17:37:53 +01:00
parent fb37caf785
commit 9d277a5a4c
6 changed files with 57 additions and 24 deletions

View File

@ -86,29 +86,31 @@ struct OrderDateQueueItem {
};
template <typename LOAD_FILTER>
bool IsArrivalDepartureTest(const DepartureCallingSettings &settings, const Order *order, StationID station, LOAD_FILTER load_filter)
bool IsArrivalDepartureTest(const DepartureCallingSettings &settings, const Order *order, LOAD_FILTER load_filter)
{
if (order->GetType() == OT_GOTO_STATION && (StationID)order->GetDestination() == station) {
if (order->GetType() == OT_GOTO_STATION) {
if (!settings.departure_no_load_test && !load_filter(order)) return false;
return settings.allow_via || ((order->GetWaitTime() != 0 || order->IsWaitTimetabled()) && !(order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION));
} else if (order->GetType() == OT_GOTO_WAYPOINT && (StationID)order->GetDestination() == station) {
} else if (order->GetType() == OT_GOTO_WAYPOINT) {
if (settings.allow_via) return true;
return (order->GetWaitTime() != 0 || order->IsWaitTimetabled());
} else {
return false;
return true;
}
}
bool DepartureCallingSettings::IsDeparture(const Order *order, StationID station)
bool DepartureCallingSettings::IsDeparture(const Order *order, const DepartureOrderDestinationDetector &source)
{
return IsArrivalDepartureTest(*this, order, station, [](const Order *order) {
if (!source.OrderMatches(order)) return false;
return IsArrivalDepartureTest(*this, order, [](const Order *order) {
return order->GetLoadType() != OLFB_NO_LOAD;
});
}
bool DepartureCallingSettings::IsArrival(const Order *order, StationID station)
bool DepartureCallingSettings::IsArrival(const Order *order, const DepartureOrderDestinationDetector &source)
{
return IsArrivalDepartureTest(*this, order, station, [](const Order *order) {
if (!source.OrderMatches(order)) return false;
return IsArrivalDepartureTest(*this, order, [](const Order *order) {
return order->GetUnloadType() != OUFB_NO_UNLOAD;
});
}
@ -283,13 +285,13 @@ static void ScheduledDispatchDepartureLocalFix(DepartureList &departure_list)
/**
* Compute an up-to-date list of departures for a station.
* @param station the station to compute the departures of
* @param source the station/etc to compute the departures of
* @param vehicles set of all the vehicles stopping at this station, of all vehicles types that we are interested in
* @param type the type of departures to get (departures or arrivals)
* @param calling_settings departure calling settings
* @return a list of departures, which is empty if an error occurred
*/
DepartureList MakeDepartureList(StationID station, const std::vector<const Vehicle *> &vehicles, DepartureType type, DepartureCallingSettings calling_settings)
DepartureList MakeDepartureList(DepartureOrderDestinationDetector source, const std::vector<const Vehicle *> &vehicles, DepartureType type, DepartureCallingSettings calling_settings)
{
/* This function is the meat of the departure boards functionality. */
/* As an overview, it works by repeatedly considering the best possible next departure to show. */
@ -435,8 +437,8 @@ DepartureList MakeDepartureList(StationID station, const std::vector<const Vehic
/* If the vehicle will be stopping at and loading from this station, and its wait time is not zero, then it is a departure. */
/* If the vehicle will be stopping at and unloading at this station, and its wait time is not zero, then it is an arrival. */
if ((type == D_DEPARTURE && calling_settings.IsDeparture(order, station)) ||
(type == D_ARRIVAL && calling_settings.IsArrival(order, station))) {
if ((type == D_DEPARTURE && calling_settings.IsDeparture(order, source)) ||
(type == D_ARRIVAL && calling_settings.IsArrival(order, source))) {
/* If the departure was scheduled to have already begun and has been cancelled, do not show it. */
if (start_ticks < 0 && status == D_CANCELLED) {
break;
@ -601,15 +603,14 @@ DepartureList MakeDepartureList(StationID station, const std::vector<const Vehic
/* If we reach the original station again, then use it as the terminus. */
if (order->GetType() == OT_GOTO_STATION &&
(StationID)order->GetDestination() == station &&
source.OrderMatches(order) &&
(order->GetUnloadType() != OUFB_NO_UNLOAD ||
calling_settings.show_all_stops) &&
(((order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0) || ((lod.order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0))) {
/* If we're not calling anywhere, then skip this departure. */
found_terminus = (d->calling_at.size() > 0);
break;
} else if (order->GetType() == OT_GOTO_WAYPOINT &&
(StationID)order->GetDestination() == station) {
} else if (order->GetType() == OT_GOTO_WAYPOINT && source.OrderMatches(order)) {
/* If we're not calling anywhere, then skip this departure. */
found_terminus = (d->calling_at.size() > 0);
break;
@ -808,7 +809,7 @@ DepartureList MakeDepartureList(StationID station, const std::vector<const Vehic
if ((o->GetType() == OT_GOTO_STATION ||
o->GetType() == OT_IMPLICIT) &&
(o->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0) {
if (o->GetDestination() == station) {
if (source.StationMatches(o->GetDestination())) {
/* Remove all possible origins */
possible_origins.clear();
} else {
@ -825,7 +826,7 @@ DepartureList MakeDepartureList(StationID station, const std::vector<const Vehic
calling_settings.show_all_stops) &&
(o->GetType() == OT_GOTO_STATION ||
o->GetType() == OT_IMPLICIT) &&
o->GetDestination() != station &&
!source.StationMatches(o->GetDestination()) &&
(o->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0) {
possible_origins.push_back({ o->GetDestination(), i });
}
@ -938,8 +939,8 @@ DepartureList MakeDepartureList(StationID station, const std::vector<const Vehic
}
/* If the order loads from this station (or unloads if we're computing arrivals) and has a wait time set, then it is suitable for being a departure. */
if ((type == D_DEPARTURE && calling_settings.IsDeparture(order, station)) ||
(type == D_ARRIVAL && calling_settings.IsArrival(order, station))) {
if ((type == D_DEPARTURE && calling_settings.IsDeparture(order, source)) ||
(type == D_ARRIVAL && calling_settings.IsArrival(order, source))) {
lod.order = order;
found_next_order = true;
break;

View File

@ -17,7 +17,7 @@
#include <vector>
DepartureList MakeDepartureList(StationID station, const std::vector<const Vehicle *> &vehicles, DepartureType type, DepartureCallingSettings calling_settings);
DepartureList MakeDepartureList(DepartureOrderDestinationDetector source, const std::vector<const Vehicle *> &vehicles, DepartureType type, DepartureCallingSettings calling_settings);
Ticks GetDeparturesMaxTicksAhead();

View File

@ -482,6 +482,15 @@ public:
bool show_pax = this->cargo_mode != DCF_FREIGHT_ONLY;
bool show_freight = this->cargo_mode != DCF_PAX_ONLY;
DepartureOrderDestinationDetector source;
if (this->is_waypoint) {
SetBit(source.order_type_mask, OT_GOTO_WAYPOINT);
source.destination = this->station;
} else {
SetBit(source.order_type_mask, OT_GOTO_STATION);
source.destination = this->station;
}
DepartureCallingSettings settings;
settings.allow_via = this->is_waypoint || this->show_via;
settings.departure_no_load_test = this->is_waypoint || _settings_client.gui.departure_show_all_stops;
@ -490,12 +499,12 @@ public:
settings.show_freight = show_freight;
if (this->mode != DM_ARRIVALS) {
this->departures = MakeDepartureList(this->station, this->vehicles, D_DEPARTURE, settings);
this->departures = MakeDepartureList(source, this->vehicles, D_DEPARTURE, settings);
} else {
this->departures.clear();
}
if (this->mode == DM_ARRIVALS || this->mode == DM_SEPARATE) {
this->arrivals = MakeDepartureList(this->station, this->vehicles, D_ARRIVAL, settings);
this->arrivals = MakeDepartureList(source, this->vehicles, D_ARRIVAL, settings);
} else {
this->arrivals.clear();
}

View File

@ -15,6 +15,7 @@
#include "station_base.h"
#include "order_base.h"
#include "vehicle_base.h"
#include "core/bitmath_func.hpp"
#include <vector>
/** Whether or not a vehicle has arrived for a departure. */
@ -113,6 +114,21 @@ struct Departure {
}
};
struct DepartureOrderDestinationDetector {
OrderTypeMask order_type_mask = 0;
DestinationID destination;
bool OrderMatches(const Order *order) const
{
return HasBit(this->order_type_mask, order->GetType()) && order->GetDestination() == this->destination;
}
bool StationMatches(StationID station) const
{
return HasBit(this->order_type_mask, OT_GOTO_STATION) && station == this->destination;
}
};
struct DepartureCallingSettings {
bool allow_via = false;
bool departure_no_load_test = false;
@ -120,8 +136,8 @@ struct DepartureCallingSettings {
bool show_pax = false;
bool show_freight = false;
bool IsDeparture(const Order *order, StationID station);
bool IsArrival(const Order *order, StationID station);
bool IsDeparture(const Order *order, const DepartureOrderDestinationDetector &source);
bool IsArrival(const Order *order, const DepartureOrderDestinationDetector &source);
};
typedef std::vector<std::unique_ptr<Departure>> DepartureList;

View File

@ -45,6 +45,8 @@
#include "3rdparty/robin_hood/robin_hood.h"
#include <limits>
#include "safeguards.h"
/* DestinationID must be at least as large as every these below, because it can
@ -53,6 +55,9 @@
static_assert(sizeof(DestinationID) >= sizeof(DepotID));
static_assert(sizeof(DestinationID) >= sizeof(StationID));
/* OrderTypeMask must be large enough for all order types */
static_assert(std::numeric_limits<OrderTypeMask>::digits >= OT_END);
OrderPool _order_pool("Order");
INSTANTIATE_POOL_METHODS(Order)
OrderListPool _orderlist_pool("OrderList");

View File

@ -55,6 +55,8 @@ enum OrderType : uint8_t {
OT_END
};
using OrderTypeMask = uint16_t;
enum OrderSlotSubType : uint8_t {
OSST_RELEASE = 0,
OSST_TRY_ACQUIRE = 1,