mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r26549) -Change: better estimation for link capacities during full load
This commit is contained in:
parent
b5566ae6ec
commit
11d98f043e
|
@ -1721,7 +1721,7 @@ static void LoadUnloadVehicle(Vehicle *front)
|
||||||
* along them. Otherwise the vehicle could wait for cargo
|
* along them. Otherwise the vehicle could wait for cargo
|
||||||
* indefinitely if it hasn't visited the other links yet, or if the
|
* indefinitely if it hasn't visited the other links yet, or if the
|
||||||
* links die while it's loading. */
|
* links die while it's loading. */
|
||||||
if (!finished_loading) LinkRefresher::Run(front);
|
if (!finished_loading) LinkRefresher::Run(front, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
SB(front->vehicle_flags, VF_LOADING_FINISHED, 1, finished_loading);
|
SB(front->vehicle_flags, VF_LOADING_FINISHED, 1, finished_loading);
|
||||||
|
|
|
@ -197,47 +197,41 @@ NodeID LinkGraph::AddNode(const Station *st)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill an edge with values from a link. If usage < capacity set the usage,
|
* Fill an edge with values from a link. Set the restricted or unrestricted
|
||||||
* otherwise set the restricted or unrestricted update timestamp.
|
* update timestamp according to the given update mode.
|
||||||
* @param to Destination node of the link.
|
* @param to Destination node of the link.
|
||||||
* @param capacity Capacity of the link.
|
* @param capacity Capacity of the link.
|
||||||
* @param usage Usage to be added or REFRESH_UNRESTRICTED or REFRESH_RESTRICTED.
|
* @param usage Usage to be added.
|
||||||
|
* @param mode Update mode to be used.
|
||||||
*/
|
*/
|
||||||
void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage)
|
void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode)
|
||||||
{
|
{
|
||||||
assert(this->index != to);
|
assert(this->index != to);
|
||||||
BaseEdge &edge = this->edges[to];
|
BaseEdge &edge = this->edges[to];
|
||||||
BaseEdge &first = this->edges[this->index];
|
BaseEdge &first = this->edges[this->index];
|
||||||
edge.capacity = capacity;
|
edge.capacity = capacity;
|
||||||
|
edge.usage = usage;
|
||||||
edge.next_edge = first.next_edge;
|
edge.next_edge = first.next_edge;
|
||||||
first.next_edge = to;
|
first.next_edge = to;
|
||||||
switch (usage) {
|
if (mode & EUM_UNRESTRICTED) edge.last_unrestricted_update = _date;
|
||||||
case REFRESH_UNRESTRICTED:
|
if (mode & EUM_RESTRICTED) edge.last_restricted_update = _date;
|
||||||
edge.last_unrestricted_update = _date;
|
|
||||||
break;
|
|
||||||
case REFRESH_RESTRICTED:
|
|
||||||
edge.last_restricted_update = _date;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
edge.usage = usage;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an edge if none exists yet or updates an existing edge.
|
* Creates an edge if none exists yet or updates an existing edge.
|
||||||
* @param to Target node.
|
* @param to Target node.
|
||||||
* @param capacity Capacity of the link.
|
* @param capacity Capacity of the link.
|
||||||
* @param usage Usage to be added or REFRESH_UNRESTRICTED or REFRESH_RESTRICTED.
|
* @param usage Usage to be added.
|
||||||
|
* @param mode Update mode to be used.
|
||||||
*/
|
*/
|
||||||
void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage)
|
void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode)
|
||||||
{
|
{
|
||||||
assert(capacity > 0);
|
assert(capacity > 0);
|
||||||
assert(usage <= capacity || usage == REFRESH_RESTRICTED || usage == REFRESH_UNRESTRICTED);
|
assert(usage <= capacity);
|
||||||
if (this->edges[to].capacity == 0) {
|
if (this->edges[to].capacity == 0) {
|
||||||
this->AddEdge(to, capacity, usage);
|
this->AddEdge(to, capacity, usage, mode);
|
||||||
} else {
|
} else {
|
||||||
(*this)[to].Update(capacity, usage);
|
(*this)[to].Update(capacity, usage, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,34 +264,30 @@ void LinkGraph::Node::RemoveEdge(NodeID to)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new edge or update an existing one. If usage is REFRESH_UNRESTRICTED
|
* Update an edge. If mode contains UM_REFRESH refresh the edge to have at
|
||||||
* or REFRESH_RESTRICTED refresh the edge to have at least the given capacity
|
* least the given capacity and usage, otherwise add the capacity and usage.
|
||||||
* and also update the respective update timestamp, otherwise add the capacity.
|
* In any case set the respective update timestamp(s), according to the given
|
||||||
|
* mode.
|
||||||
* @param from Start node of the edge.
|
* @param from Start node of the edge.
|
||||||
* @param to End node of the edge.
|
* @param to End node of the edge.
|
||||||
* @param capacity Capacity to be added/updated.
|
* @param capacity Capacity to be added/updated.
|
||||||
* @param usage Usage to be added or REFRESH_UNRESTRICTED or REFRESH_RESTRICTED.
|
* @param usage Usage to be added.
|
||||||
|
* @param mode Update mode to be applied.
|
||||||
*/
|
*/
|
||||||
void LinkGraph::Edge::Update(uint capacity, uint usage)
|
void LinkGraph::Edge::Update(uint capacity, uint usage, EdgeUpdateMode mode)
|
||||||
{
|
{
|
||||||
assert(this->edge.capacity > 0);
|
assert(this->edge.capacity > 0);
|
||||||
if (usage > capacity) {
|
assert(capacity >= usage);
|
||||||
this->edge.capacity = max(this->edge.capacity, capacity);
|
|
||||||
switch (usage) {
|
if (mode & EUM_INCREASE) {
|
||||||
case REFRESH_UNRESTRICTED:
|
|
||||||
this->edge.last_unrestricted_update = _date;
|
|
||||||
break;
|
|
||||||
case REFRESH_RESTRICTED:
|
|
||||||
this->edge.last_restricted_update = _date;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
NOT_REACHED();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this->edge.capacity += capacity;
|
this->edge.capacity += capacity;
|
||||||
this->edge.usage += usage;
|
this->edge.usage += usage;
|
||||||
|
} else if (mode & EUM_REFRESH) {
|
||||||
|
this->edge.capacity = max(this->edge.capacity, capacity);
|
||||||
|
this->edge.usage = max(this->edge.usage, usage);
|
||||||
}
|
}
|
||||||
|
if (mode & EUM_UNRESTRICTED) this->edge.last_unrestricted_update = _date;
|
||||||
|
if (mode & EUM_RESTRICTED) this->edge.last_restricted_update = _date;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -40,22 +40,6 @@ extern LinkGraphPool _link_graph_pool;
|
||||||
class LinkGraph : public LinkGraphPool::PoolItem<&_link_graph_pool> {
|
class LinkGraph : public LinkGraphPool::PoolItem<&_link_graph_pool> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
|
||||||
* Special modes for updating links. 'Restricted' means that vehicles with
|
|
||||||
* 'no loading' orders are serving the link. If a link is only served by
|
|
||||||
* such vehicles it's 'fully restricted'. This means the link can be used
|
|
||||||
* by cargo arriving in such vehicles, but not by cargo generated or
|
|
||||||
* transferring at the source station of the link. In order to find out
|
|
||||||
* about this condition we keep two update timestamps in each link, one for
|
|
||||||
* the restricted and one for the unrestricted part of it. If either one
|
|
||||||
* times out while the other is still valid the link becomes fully
|
|
||||||
* restricted or fully unrestricted, respectively.
|
|
||||||
*/
|
|
||||||
enum UpdateMode {
|
|
||||||
REFRESH_RESTRICTED = UINT_MAX - 1, ///< Refresh restricted link.
|
|
||||||
REFRESH_UNRESTRICTED = UINT_MAX ///< Refresh unrestricted link.
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node of the link graph. contains all relevant information from the associated
|
* Node of the link graph. contains all relevant information from the associated
|
||||||
* station. It's copied so that the link graph job can work on its own data set
|
* station. It's copied so that the link graph job can work on its own data set
|
||||||
|
@ -313,7 +297,7 @@ public:
|
||||||
* @param edge Edge to be wrapped.
|
* @param edge Edge to be wrapped.
|
||||||
*/
|
*/
|
||||||
Edge(BaseEdge &edge) : EdgeWrapper<BaseEdge>(edge) {}
|
Edge(BaseEdge &edge) : EdgeWrapper<BaseEdge>(edge) {}
|
||||||
void Update(uint capacity, uint usage);
|
void Update(uint capacity, uint usage, EdgeUpdateMode mode);
|
||||||
void Restrict() { this->edge.last_unrestricted_update = INVALID_DATE; }
|
void Restrict() { this->edge.last_unrestricted_update = INVALID_DATE; }
|
||||||
void Release() { this->edge.last_restricted_update = INVALID_DATE; }
|
void Release() { this->edge.last_restricted_update = INVALID_DATE; }
|
||||||
};
|
};
|
||||||
|
@ -437,8 +421,8 @@ public:
|
||||||
this->node.demand = demand;
|
this->node.demand = demand;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddEdge(NodeID to, uint capacity, uint usage = 0);
|
void AddEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode);
|
||||||
void UpdateEdge(NodeID to, uint capacity, uint usage = 0);
|
void UpdateEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode);
|
||||||
void RemoveEdge(NodeID to);
|
void RemoveEdge(NodeID to);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,4 +39,26 @@ enum DistributionType {
|
||||||
template <> struct EnumPropsT<DistributionType> : MakeEnumPropsT<DistributionType, byte, DT_BEGIN, DT_END, DT_NUM> {};
|
template <> struct EnumPropsT<DistributionType> : MakeEnumPropsT<DistributionType, byte, DT_BEGIN, DT_END, DT_NUM> {};
|
||||||
typedef TinyEnumT<DistributionType> DistributionTypeByte; // typedefing-enumification of DistributionType
|
typedef TinyEnumT<DistributionType> DistributionTypeByte; // typedefing-enumification of DistributionType
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special modes for updating links. 'Restricted' means that vehicles with
|
||||||
|
* 'no loading' orders are serving the link. If a link is only served by
|
||||||
|
* such vehicles it's 'fully restricted'. This means the link can be used
|
||||||
|
* by cargo arriving in such vehicles, but not by cargo generated or
|
||||||
|
* transferring at the source station of the link. In order to find out
|
||||||
|
* about this condition we keep two update timestamps in each link, one for
|
||||||
|
* the restricted and one for the unrestricted part of it. If either one
|
||||||
|
* times out while the other is still valid the link becomes fully
|
||||||
|
* restricted or fully unrestricted, respectively.
|
||||||
|
* Refreshing a link makes just sure a minimum capacity is kept. Increasing
|
||||||
|
* actually adds the given capacity.
|
||||||
|
*/
|
||||||
|
enum EdgeUpdateMode {
|
||||||
|
EUM_INCREASE = 1, ///< Increase capacity.
|
||||||
|
EUM_REFRESH = 1 << 1, ///< Refresh capacity.
|
||||||
|
EUM_RESTRICTED = 1 << 2, ///< Use restricted link.
|
||||||
|
EUM_UNRESTRICTED = 1 << 3, ///< Use unrestricted link.
|
||||||
|
};
|
||||||
|
|
||||||
|
DECLARE_ENUM_AS_BIT_SET(EdgeUpdateMode)
|
||||||
|
|
||||||
#endif /* LINKGRAPH_TYPE_H */
|
#endif /* LINKGRAPH_TYPE_H */
|
||||||
|
|
|
@ -23,8 +23,9 @@
|
||||||
* Refresh all links the given vehicle will visit.
|
* Refresh all links the given vehicle will visit.
|
||||||
* @param v Vehicle to refresh links for.
|
* @param v Vehicle to refresh links for.
|
||||||
* @param allow_merge If the refresher is allowed to merge or extend link graphs.
|
* @param allow_merge If the refresher is allowed to merge or extend link graphs.
|
||||||
|
* @param is_full_loading If the vehicle is full loading.
|
||||||
*/
|
*/
|
||||||
/* static */ void LinkRefresher::Run(Vehicle *v, bool allow_merge)
|
/* static */ void LinkRefresher::Run(Vehicle *v, bool allow_merge, bool is_full_loading)
|
||||||
{
|
{
|
||||||
/* If there are no orders we can't predict anything.*/
|
/* If there are no orders we can't predict anything.*/
|
||||||
if (v->orders.list == NULL) return;
|
if (v->orders.list == NULL) return;
|
||||||
|
@ -34,7 +35,7 @@
|
||||||
if (first == NULL) return;
|
if (first == NULL) return;
|
||||||
|
|
||||||
HopSet seen_hops;
|
HopSet seen_hops;
|
||||||
LinkRefresher refresher(v, &seen_hops, allow_merge);
|
LinkRefresher refresher(v, &seen_hops, allow_merge, is_full_loading);
|
||||||
|
|
||||||
refresher.RefreshLinks(first, first, v->last_loading_station != INVALID_STATION ? 1 << HAS_CARGO : 0);
|
refresher.RefreshLinks(first, first, v->last_loading_station != INVALID_STATION ? 1 << HAS_CARGO : 0);
|
||||||
}
|
}
|
||||||
|
@ -65,9 +66,11 @@ bool LinkRefresher::Hop::operator<(const Hop &other) const
|
||||||
* @param seen_hops Set of hops already seen. This is shared between this
|
* @param seen_hops Set of hops already seen. This is shared between this
|
||||||
* refresher and all its children.
|
* refresher and all its children.
|
||||||
* @param allow_merge If the refresher is allowed to merge or extend link graphs.
|
* @param allow_merge If the refresher is allowed to merge or extend link graphs.
|
||||||
|
* @param is_full_loading If the vehicle is full loading.
|
||||||
*/
|
*/
|
||||||
LinkRefresher::LinkRefresher(Vehicle *vehicle, HopSet *seen_hops, bool allow_merge) :
|
LinkRefresher::LinkRefresher(Vehicle *vehicle, HopSet *seen_hops, bool allow_merge, bool is_full_loading) :
|
||||||
vehicle(vehicle), seen_hops(seen_hops), cargo(CT_INVALID), allow_merge(allow_merge)
|
vehicle(vehicle), seen_hops(seen_hops), cargo(CT_INVALID), allow_merge(allow_merge),
|
||||||
|
is_full_loading(is_full_loading)
|
||||||
{
|
{
|
||||||
/* Assemble list of capacities and set last loading stations to 0. */
|
/* Assemble list of capacities and set last loading stations to 0. */
|
||||||
for (Vehicle *v = this->vehicle; v != NULL; v = v->Next()) {
|
for (Vehicle *v = this->vehicle; v != NULL; v = v->Next()) {
|
||||||
|
@ -205,10 +208,32 @@ void LinkRefresher::RefreshStats(const Order *cur, const Order *next)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A link is at least partly restricted if a
|
/* A link is at least partly restricted if a vehicle can't load at its source. */
|
||||||
* vehicle can't load at its source. */
|
EdgeUpdateMode restricted_mode = (cur->GetLoadType() & OLFB_NO_LOAD) == 0 ?
|
||||||
IncreaseStats(st, c, next_station, i->second,
|
EUM_UNRESTRICTED : EUM_RESTRICTED;
|
||||||
(cur->GetLoadType() & OLFB_NO_LOAD) == 0 ? LinkGraph::REFRESH_UNRESTRICTED : LinkGraph::REFRESH_RESTRICTED);
|
|
||||||
|
/* If the vehicle is currently full loading, increase the capacities at the station
|
||||||
|
* where it is loading by an estimate of what it would have transported if it wasn't
|
||||||
|
* loading. Don't do that if the vehicle has been waiting for longer than the entire
|
||||||
|
* order list is supposed to take, though. If that is the case the total duration is
|
||||||
|
* probably far off and we'd greatly overestimate the capacity by increasing.*/
|
||||||
|
if (this->is_full_loading && this->vehicle->orders.list != NULL &&
|
||||||
|
st->index == vehicle->last_station_visited &&
|
||||||
|
this->vehicle->orders.list->GetTotalDuration() >
|
||||||
|
(Ticks)this->vehicle->current_order_time) {
|
||||||
|
uint effective_capacity = i->second * this->vehicle->load_unload_ticks;
|
||||||
|
if (effective_capacity > (uint)this->vehicle->orders.list->GetTotalDuration()) {
|
||||||
|
IncreaseStats(st, c, next_station, effective_capacity /
|
||||||
|
this->vehicle->orders.list->GetTotalDuration(), 0,
|
||||||
|
EUM_INCREASE | restricted_mode);
|
||||||
|
} else if (RandomRange(this->vehicle->orders.list->GetTotalDuration()) < effective_capacity) {
|
||||||
|
IncreaseStats(st, c, next_station, 1, 0, EUM_INCREASE | restricted_mode);
|
||||||
|
} else {
|
||||||
|
IncreaseStats(st, c, next_station, i->second, 0, EUM_REFRESH | restricted_mode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
IncreaseStats(st, c, next_station, i->second, 0, EUM_REFRESH | restricted_mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
class LinkRefresher {
|
class LinkRefresher {
|
||||||
public:
|
public:
|
||||||
static void Run(Vehicle *v, bool allow_merge = true);
|
static void Run(Vehicle *v, bool allow_merge = true, bool is_full_loading = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
@ -88,8 +88,9 @@ protected:
|
||||||
HopSet *seen_hops; ///< Hops already seen. If the same hop is seen twice we stop the algorithm. This is shared between all Refreshers of the same run.
|
HopSet *seen_hops; ///< Hops already seen. If the same hop is seen twice we stop the algorithm. This is shared between all Refreshers of the same run.
|
||||||
CargoID cargo; ///< Cargo given in last refit order.
|
CargoID cargo; ///< Cargo given in last refit order.
|
||||||
bool allow_merge; ///< If the refresher is allowed to merge or extend link graphs.
|
bool allow_merge; ///< If the refresher is allowed to merge or extend link graphs.
|
||||||
|
bool is_full_loading; ///< If the vehicle is full loading.
|
||||||
|
|
||||||
LinkRefresher(Vehicle *v, HopSet *seen_hops, bool allow_merge);
|
LinkRefresher(Vehicle *v, HopSet *seen_hops, bool allow_merge, bool is_full_loading);
|
||||||
|
|
||||||
void HandleRefit(const Order *next);
|
void HandleRefit(const Order *next);
|
||||||
void ResetRefit();
|
void ResetRefit();
|
||||||
|
|
|
@ -3505,9 +3505,10 @@ void DeleteStaleLinks(Station *from)
|
||||||
* @param cargo Cargo to increase stat for.
|
* @param cargo Cargo to increase stat for.
|
||||||
* @param next_station_id Station the consist will be travelling to next.
|
* @param next_station_id Station the consist will be travelling to next.
|
||||||
* @param capacity Capacity to add to link stat.
|
* @param capacity Capacity to add to link stat.
|
||||||
* @param usage Usage to add to link stat. If UINT_MAX refresh the link instead of increasing.
|
* @param usage Usage to add to link stat.
|
||||||
|
* @param mode Update mode to be applied.
|
||||||
*/
|
*/
|
||||||
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage)
|
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode)
|
||||||
{
|
{
|
||||||
GoodsEntry &ge1 = st->goods[cargo];
|
GoodsEntry &ge1 = st->goods[cargo];
|
||||||
Station *st2 = Station::Get(next_station_id);
|
Station *st2 = Station::Get(next_station_id);
|
||||||
|
@ -3549,7 +3550,7 @@ void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lg != NULL) {
|
if (lg != NULL) {
|
||||||
(*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage);
|
(*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3570,7 +3571,7 @@ void IncreaseStats(Station *st, const Vehicle *front, StationID next_station_id)
|
||||||
* As usage is not such an important figure anyway we just
|
* As usage is not such an important figure anyway we just
|
||||||
* ignore the additional cargo then.*/
|
* ignore the additional cargo then.*/
|
||||||
IncreaseStats(st, v->cargo_type, next_station_id, v->refit_cap,
|
IncreaseStats(st, v->cargo_type, next_station_id, v->refit_cap,
|
||||||
min(v->refit_cap, v->cargo.StoredCount()));
|
min(v->refit_cap, v->cargo.StoredCount()), EUM_INCREASE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "vehicle_type.h"
|
#include "vehicle_type.h"
|
||||||
#include "economy_func.h"
|
#include "economy_func.h"
|
||||||
#include "rail.h"
|
#include "rail.h"
|
||||||
|
#include "linkgraph/linkgraph_type.h"
|
||||||
|
|
||||||
void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius);
|
void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius);
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ void UpdateAirportsNoise();
|
||||||
bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset);
|
bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset);
|
||||||
|
|
||||||
void IncreaseStats(Station *st, const Vehicle *v, StationID next_station_id);
|
void IncreaseStats(Station *st, const Vehicle *v, StationID next_station_id);
|
||||||
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage);
|
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode);
|
||||||
void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2);
|
void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue