Move StationCargoList and FlowStatMap out of GoodsEntry struct

Move them into a new GoodsEntryData struct referenced
using a std::unique_ptr from GoodsEntry.
The unique_ptr may be nullptr if the cargo list and flow stat map
are both empty (this is the case for unused cargoes).

This reduces GoodsEntry from 128 to 24 bytes,
and Station from 8680 to 2024 bytes,
(on Linux x86_64).
pull/590/head
Jonathan G Rennison 10 months ago
parent cd2ab6430b
commit 19835b51ee

@ -1476,7 +1476,7 @@ static void MaybeCrashAirplane(Aircraft *v)
/* Crash the airplane. Remove all goods stored at the station. */
for (CargoID i = 0; i < NUM_CARGO; i++) {
st->goods[i].rating = 1;
st->goods[i].cargo.Truncate();
if (st->goods[i].data != nullptr) st->goods[i].data->cargo.Truncate();
}
CrashAirplane(v);

@ -638,6 +638,8 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
CargoPacketList transfer_deliver;
std::vector<CargoPacket *> keep;
const FlowStatMap &flows = ge->CreateData().flows;
bool force_keep = (order_flags & OUFB_NO_UNLOAD) != 0;
bool force_unload = (order_flags & OUFB_UNLOAD) != 0;
bool force_transfer = (order_flags & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0;
@ -656,8 +658,8 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
action = MTA_TRANSFER;
/* We cannot send the cargo to any of the possible next hops and
* also not to the current station. */
FlowStatMap::const_iterator flow_it(ge->flows.find(cp->source));
if (flow_it == ge->flows.end()) {
FlowStatMap::const_iterator flow_it(flows.find(cp->source));
if (flow_it == flows.end()) {
cargo_next = INVALID_STATION;
} else {
FlowStat new_shares = *flow_it;
@ -675,12 +677,12 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
} else {
/* Rewrite an invalid source station to some random other one to
* avoid keeping the cargo in the vehicle forever. */
if (cp->source == INVALID_STATION && !ge->flows.empty()) {
cp->source = ge->flows.FirstStationID();
if (cp->source == INVALID_STATION && !flows.empty()) {
cp->source = flows.FirstStationID();
}
bool restricted = false;
FlowStatMap::const_iterator flow_it(ge->flows.find(cp->source));
if (flow_it == ge->flows.end()) {
FlowStatMap::const_iterator flow_it(flows.find(cp->source));
if (flow_it == flows.end()) {
cargo_next = INVALID_STATION;
} else {
cargo_next = flow_it->GetViaWithRestricted(restricted);

@ -605,6 +605,11 @@ public:
this->reserved_count += count;
}
void LoadSetReservedCount(uint count)
{
this->reserved_count = count;
}
/**
* Are the two CargoPackets mergeable in the context of
* a list of CargoPackets for a Station?

@ -1668,7 +1668,7 @@ struct ReturnCargoAction
*/
bool operator()(Vehicle *v)
{
v->cargo.Return(UINT_MAX, &this->st->goods[v->cargo_type].cargo, this->next_hop);
v->cargo.Return(UINT_MAX, &this->st->goods[v->cargo_type].CreateData().cargo, this->next_hop);
return true;
}
};
@ -1704,7 +1704,7 @@ struct FinalizeRefitAction
bool operator()(Vehicle *v)
{
if (this->do_reserve || (cargo_type_loading == nullptr || (cargo_type_loading->current_order.GetCargoLoadTypeRaw(v->cargo_type) & OLFB_FULL_LOAD))) {
this->st->goods[v->cargo_type].cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(),
this->st->goods[v->cargo_type].CreateData().cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(),
&v->cargo, st->xy, this->next_station.Get(v->cargo_type));
}
this->consist_capleft[v->cargo_type] += v->cargo_cap - v->cargo.RemainingCount();
@ -1740,7 +1740,7 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station
new_cid = v_start->cargo_type;
for (CargoID cid : SetCargoBitIterator(refit_mask)) {
if (check_order && v->First()->current_order.GetCargoLoadType(cid) == OLFB_NO_LOAD) continue;
if (st->goods[cid].cargo.HasCargoFor(next_station.Get(cid))) {
if (st->goods[cid].data != nullptr && st->goods[cid].data->cargo.HasCargoFor(next_station.Get(cid))) {
/* Try to find out if auto-refitting would succeed. In case the refit is allowed,
* the returned refit capacity will be greater than zero. */
DoCommand(v_start->tile, v_start->index, cid | 1U << 24 | 0xFF << 8 | 1U << 16, DC_QUERY_COST, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts.
@ -1752,7 +1752,7 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station
* of 0 for all cargoes. */
if (_returned_refit_capacity > 0 && (consist_capleft[cid] < consist_capleft[new_cid] ||
(consist_capleft[cid] == consist_capleft[new_cid] &&
st->goods[cid].cargo.AvailableCount() > st->goods[new_cid].cargo.AvailableCount()))) {
st->goods[cid].data->cargo.AvailableCount() > st->goods[new_cid].CargoAvailableCount()))) {
new_cid = cid;
}
}
@ -1809,7 +1809,7 @@ struct ReserveCargoAction {
if (!(flags & OLFB_FULL_LOAD) && !through_load) return true;
}
if (v->cargo_cap > v->cargo.RemainingCount() && MayLoadUnderExclusiveRights(st, v)) {
st->goods[v->cargo_type].cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(),
st->goods[v->cargo_type].CreateData().cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(),
&v->cargo, st->xy, next_station.Get(v->cargo_type));
}
@ -2022,6 +2022,7 @@ static void LoadUnloadVehicle(Vehicle *front)
artic_part++;
GoodsEntry *ge = &st->goods[v->cargo_type];
GoodsEntryData &ged = ge->CreateData();
if (HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) && payment == nullptr) {
/* Once the payment has been made, never attempt to unload again */
@ -2046,7 +2047,7 @@ static void LoadUnloadVehicle(Vehicle *front)
uint new_remaining = v->cargo.RemainingCount() + v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER);
if (v->cargo_cap < new_remaining) {
/* Return some of the reserved cargo to not overload the vehicle. */
v->cargo.Return(new_remaining - v->cargo_cap, &ge->cargo, INVALID_STATION);
v->cargo.Return(new_remaining - v->cargo_cap, &ged.cargo, INVALID_STATION);
}
/* Keep instead of delivering. This may lead to no cargo being unloaded, so ...*/
@ -2073,7 +2074,7 @@ static void LoadUnloadVehicle(Vehicle *front)
}
}
amount_unloaded = v->cargo.Unload(amount_unloaded, &ge->cargo, payment);
amount_unloaded = v->cargo.Unload(amount_unloaded, &ged.cargo, payment);
remaining = v->cargo.UnloadCount() > 0;
if (amount_unloaded > 0) {
dirty_vehicle = true;
@ -2143,11 +2144,11 @@ static void LoadUnloadVehicle(Vehicle *front)
/* If there's goods waiting at the station, and the vehicle
* has capacity for it, load it on the vehicle. */
if ((v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0 || ge->cargo.AvailableCount() > 0) && MayLoadUnderExclusiveRights(st, v)) {
if ((v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0 || ged.cargo.AvailableCount() > 0) && MayLoadUnderExclusiveRights(st, v)) {
if (v->cargo.StoredCount() == 0) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
if (_settings_game.order.gradual_loading) cap_left = std::min(cap_left, GetLoadAmount(v));
uint loaded = ge->cargo.Load(cap_left, &v->cargo, st->xy, next_station.Get(v->cargo_type));
uint loaded = ged.cargo.Load(cap_left, &v->cargo, st->xy, next_station.Get(v->cargo_type));
if (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) {
/* Remember if there are reservations left so that we don't stop
* loading before they're loaded. */
@ -2175,7 +2176,7 @@ static void LoadUnloadVehicle(Vehicle *front)
st->time_since_load = 0;
ge->last_vehicle_type = v->type;
if (ge->cargo.TotalCount() == 0) {
if (ged.cargo.TotalCount() == 0) {
TriggerStationRandomisation(st, st->xy, SRT_CARGO_TAKEN, v->cargo_type);
TriggerStationAnimation(st, st->xy, SAT_CARGO_TAKEN, v->cargo_type);
AirportAnimationTrigger(st, AAT_STATION_CARGO_TAKEN, v->cargo_type);

@ -172,7 +172,7 @@ void LinkGraphOverlay::RebuildCache(bool incremental)
item->to_pt = to_pt;
}
this->AddStats(c, lg.Monthly(edge.Capacity()), lg.Monthly(edge.Usage()),
ge.flows.GetFlowVia(to->index),
ge.data != nullptr ? ge.data->flows.GetFlowVia(to->index) : 0,
edge.TravelTime(),
from->owner == OWNER_NONE || to->owner == OWNER_NONE,
item->prop);

@ -121,6 +121,7 @@ void LinkGraphJob::FinaliseJob()
LinkGraph *lg = LinkGraph::Get(ge.link_graph);
FlowStatMap &flows = from.Flows();
FlowStatMap &geflows = ge.CreateData().flows;
for (Edge &edge : from.GetEdges()) {
if (edge.Flow() == 0) continue;
@ -135,7 +136,7 @@ void LinkGraphJob::FinaliseJob()
/* Delete old flows for source stations which have been deleted
* from the new flows. This avoids flow cycles between old and
* new flows. */
while (!erased.IsEmpty()) ge.flows.erase(erased.Pop());
while (!erased.IsEmpty()) geflows.erase(erased.Pop());
} else if (lg_edge.LastUnrestrictedUpdate() == INVALID_DATE) {
/* Edge is fully restricted. */
flows.RestrictFlows(to);
@ -146,7 +147,7 @@ void LinkGraphJob::FinaliseJob()
* really delete them as we could then end up with unroutable cargo
* somewhere. Do delete them and also reroute relevant cargo if
* automatic distribution has been turned off for that cargo. */
for (FlowStatMap::iterator it(ge.flows.begin()); it != ge.flows.end();) {
for (FlowStatMap::iterator it(geflows.begin()); it != geflows.end();) {
FlowStatMap::iterator new_it = flows.find(it->GetOrigin());
if (new_it == flows.end()) {
if (_settings_game.linkgraph.GetDistributionType(this->Cargo()) != DT_MANUAL) {
@ -154,7 +155,7 @@ void LinkGraphJob::FinaliseJob()
NodeID origin = it->GetOrigin();
FlowStat shares(INVALID_STATION, INVALID_STATION, 1);
it->SwapShares(shares);
it = ge.flows.erase(it);
it = geflows.erase(it);
for (FlowStat::const_iterator shares_it(shares.begin());
shares_it != shares.end(); ++shares_it) {
RerouteCargoFromSource(st, this->Cargo(), origin, shares_it->second, st->index);
@ -165,7 +166,7 @@ void LinkGraphJob::FinaliseJob()
} else {
FlowStat shares(INVALID_STATION, INVALID_STATION, 1);
it->SwapShares(shares);
it = ge.flows.erase(it);
it = geflows.erase(it);
for (FlowStat::const_iterator shares_it(shares.begin());
shares_it != shares.end(); ++shares_it) {
RerouteCargo(st, this->Cargo(), shares_it->second, st->index);
@ -178,9 +179,9 @@ void LinkGraphJob::FinaliseJob()
}
}
for (FlowStatMap::iterator it(flows.begin()); it != flows.end(); ++it) {
ge.flows.insert(std::move(*it));
geflows.insert(std::move(*it));
}
ge.flows.SortStorage();
geflows.SortStorage();
InvalidateWindowData(WC_STATION_VIEW, st->index, this->Cargo());
}
}

@ -271,7 +271,7 @@ RoadStopResolverObject::RoadStopResolverObject(const RoadStopSpec *roadstopspec,
/* Pick the first cargo that we have waiting */
for (const CargoSpec *cs : CargoSpec::Iterate()) {
if (roadstopspec->grf_prop.spritegroup[cs->Index()] != nullptr &&
station->goods[cs->Index()].cargo.TotalCount() > 0) {
station->goods[cs->Index()].CargoTotalCount() > 0) {
ctype = cs->Index();
break;
}
@ -474,7 +474,7 @@ void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTri
if (trigger == RSRT_CARGO_TAKEN) {
/* Create a bitmask of completely empty cargo types to be matched */
for (CargoID i = 0; i < NUM_CARGO; i++) {
if (st->goods[i].cargo.TotalCount() == 0) {
if (st->goods[i].CargoTotalCount() == 0) {
SetBit(empty_mask, i);
}
}
@ -699,7 +699,7 @@ void DumpRoadStopSpriteGroup(const BaseStation *st, const RoadStopSpec *spec, Du
/* Pick the first cargo that we have waiting */
for (const CargoSpec *cs : CargoSpec::Iterate()) {
if (spec->grf_prop.spritegroup[cs->Index()] != nullptr &&
station->goods[cs->Index()].cargo.TotalCount() > 0) {
station->goods[cs->Index()].CargoTotalCount() > 0) {
ctype = cs->Index();
break;
}

@ -447,10 +447,10 @@ uint32 Station::GetNewGRFVariable(const ResolverObject &object, uint16 variable,
const GoodsEntry *ge = &this->goods[c];
switch (variable) {
case 0x60: return std::min<uint32>(ge->cargo.TotalCount(), 4095);
case 0x60: return std::min<uint32>(ge->CargoTotalCount(), 4095);
case 0x61: return ge->HasVehicleEverTriedLoading() && ge->IsSupplyAllowed() ? ge->time_since_pickup : 0;
case 0x62: return ge->HasRating() ? ge->rating : 0xFFFFFFFF;
case 0x63: return ge->cargo.DaysInTransit();
case 0x63: return ge->data != nullptr ? ge->data->cargo.DaysInTransit() : 0;
case 0x64: return ge->HasVehicleEverTriedLoading() && ge->IsSupplyAllowed() ? ge->last_speed | (ge->last_age << 8) : 0xFF00;
case 0x65: return GB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1) << 3;
case 0x69: {
@ -466,12 +466,12 @@ uint32 Station::GetNewGRFVariable(const ResolverObject &object, uint16 variable,
if (variable >= 0x8C && variable <= 0xEC) {
const GoodsEntry *g = &this->goods[GB(variable - 0x8C, 3, 4)];
switch (GB(variable - 0x8C, 0, 3)) {
case 0: return g->cargo.TotalCount();
case 1: return GB(std::min(g->cargo.TotalCount(), 4095u), 0, 4) | (GB(g->status, GoodsEntry::GES_ACCEPTANCE, 1) << 7);
case 0: return g->CargoTotalCount();
case 1: return GB(std::min(g->CargoTotalCount(), 4095u), 0, 4) | (GB(g->status, GoodsEntry::GES_ACCEPTANCE, 1) << 7);
case 2: return g->time_since_pickup;
case 3: return g->rating;
case 4: return g->cargo.Source();
case 5: return g->cargo.DaysInTransit();
case 4: return g->data != nullptr ? g->data->cargo.Source() : INVALID_STATION;
case 5: return g->data != nullptr ? g->data->cargo.DaysInTransit() : 0;
case 6: return g->last_speed;
case 7: return g->last_age;
}
@ -533,12 +533,12 @@ uint32 Waypoint::GetNewGRFVariable(const ResolverObject &object, uint16 variable
case CT_DEFAULT:
for (CargoID cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
cargo += st->goods[cargo_type].cargo.TotalCount();
cargo += st->goods[cargo_type].CargoTotalCount();
}
break;
default:
cargo = st->goods[this->station_scope.cargo_type].cargo.TotalCount();
cargo = st->goods[this->station_scope.cargo_type].CargoTotalCount();
break;
}
@ -598,7 +598,7 @@ StationResolverObject::StationResolverObject(const StationSpec *statspec, BaseSt
/* Pick the first cargo that we have waiting */
for (const CargoSpec *cs : CargoSpec::Iterate()) {
if (this->station_scope.statspec->grf_prop.spritegroup[cs->Index()] != nullptr &&
st->goods[cs->Index()].cargo.TotalCount() > 0) {
st->goods[cs->Index()].CargoTotalCount() > 0) {
ctype = cs->Index();
break;
}
@ -1006,7 +1006,7 @@ void TriggerStationRandomisation(Station *st, TileIndex trigger_tile, StationRan
if (trigger == SRT_CARGO_TAKEN) {
/* Create a bitmask of completely empty cargo types to be matched */
for (CargoID i = 0; i < NUM_CARGO; i++) {
if (st->goods[i].cargo.TotalCount() == 0) {
if (st->goods[i].CargoTotalCount() == 0) {
SetBit(empty_mask, i);
}
}

@ -1916,14 +1916,16 @@ void CheckCaches(bool force_check, std::function<void(const char *)> log, CheckC
for (Station *st : Station::Iterate()) {
for (CargoID c = 0; c < NUM_CARGO; c++) {
uint old_count = st->goods[c].cargo.TotalCount();
uint64 old_cargo_days_in_transit = st->goods[c].cargo.CargoDaysInTransit();
if (st->goods[c].data == nullptr) continue;
st->goods[c].cargo.InvalidateCache();
uint old_count = st->goods[c].data->cargo.TotalCount();
uint64 old_cargo_days_in_transit = st->goods[c].data->cargo.CargoDaysInTransit();
st->goods[c].data->cargo.InvalidateCache();
uint changed = 0;
if (st->goods[c].cargo.TotalCount() != old_count) SetBit(changed, 0);
if (st->goods[c].cargo.CargoDaysInTransit() != old_cargo_days_in_transit) SetBit(changed, 1);
if (st->goods[c].data->cargo.TotalCount() != old_count) SetBit(changed, 0);
if (st->goods[c].data->cargo.CargoDaysInTransit() != old_cargo_days_in_transit) SetBit(changed, 1);
if (changed != 0) {
CCLOG("station cargo cache mismatch: station %i, company %i, cargo %u: %c%c",
st->index, (int)st->owner, c,

@ -3097,16 +3097,16 @@ VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v, Pro
case OCV_UNCONDITIONALLY: skip_order = true; break;
case OCV_CARGO_WAITING: {
StationID next_station = GetNextRealStation(v, order);
if (Station::IsValidID(next_station)) skip_order = OrderConditionCompare(occ, (Station::Get(next_station)->goods[value].cargo.AvailableCount() > 0), value);
if (Station::IsValidID(next_station)) skip_order = OrderConditionCompare(occ, (Station::Get(next_station)->goods[value].CargoAvailableCount() > 0), value);
break;
}
case OCV_CARGO_WAITING_AMOUNT: {
StationID next_station = GetNextRealStation(v, order);
if (Station::IsValidID(next_station)) {
if (GB(order->GetXData(), 16, 16) == 0) {
skip_order = OrderConditionCompare(occ, Station::Get(next_station)->goods[value].cargo.AvailableCount(), GB(order->GetXData(), 0, 16));
skip_order = OrderConditionCompare(occ, Station::Get(next_station)->goods[value].CargoAvailableCount(), GB(order->GetXData(), 0, 16));
} else {
skip_order = OrderConditionCompare(occ, Station::Get(next_station)->goods[value].cargo.AvailableViaCount(GB(order->GetXData(), 16, 16) - 2), GB(order->GetXData(), 0, 16));
skip_order = OrderConditionCompare(occ, Station::Get(next_station)->goods[value].CargoAvailableViaCount(GB(order->GetXData(), 16, 16) - 2), GB(order->GetXData(), 0, 16));
}
}
break;

@ -2051,7 +2051,7 @@ bool AfterLoadGame()
for (Station *st : Station::Iterate()) {
for (CargoID c = 0; c < NUM_CARGO; c++) {
st->goods[c].last_speed = 0;
if (st->goods[c].cargo.AvailableCount() != 0) SetBit(st->goods[c].status, GoodsEntry::GES_RATING);
if (st->goods[c].CargoAvailableCount() != 0) SetBit(st->goods[c].status, GoodsEntry::GES_RATING);
}
}
}

@ -40,6 +40,7 @@ static Money _cargo_feeder_share;
CargoPacketList _packets;
uint32 _old_num_dests;
uint _cargo_reserved_count;
struct FlowSaveLoad {
FlowSaveLoad() : source(0), via(0), share(0), restricted(false) {}
@ -61,7 +62,7 @@ static byte _old_last_vehicle_type;
*/
static void SwapPackets(GoodsEntry *ge)
{
StationCargoPacketMap &ge_packets = const_cast<StationCargoPacketMap &>(*ge->cargo.Packets());
StationCargoPacketMap &ge_packets = const_cast<StationCargoPacketMap &>(*ge->data->cargo.Packets());
if (_packets.empty()) {
std::map<StationID, CargoPacketList>::iterator it(ge_packets.find(INVALID_STATION));
@ -153,14 +154,15 @@ public:
StationCargoPair pair;
for (uint j = 0; j < num_dests; ++j) {
SlObject(&pair, this->GetLoadDescription());
const_cast<StationCargoPacketMap &>(*(ge->cargo.Packets()))[pair.first].swap(pair.second);
const_cast<StationCargoPacketMap &>(*(ge->data->cargo.Packets()))[pair.first].swap(pair.second);
assert(pair.second.empty());
}
}
void FixPointers(GoodsEntry *ge) const override
{
for (StationCargoPacketMap::ConstMapIterator it = ge->cargo.Packets()->begin(); it != ge->cargo.Packets()->end(); ++it) {
if (ge->data == nullptr) return;
for (StationCargoPacketMap::ConstMapIterator it = ge->data->cargo.Packets()->begin(); it != ge->data->cargo.Packets()->end(); ++it) {
SlObject(const_cast<StationCargoPair *>(&(*it)), this->GetDescription());
}
}
@ -192,7 +194,7 @@ public:
for (uint32 j = 0; j < num_flows; ++j) {
SlObject(&flow, this->GetLoadDescription());
if (fs == nullptr || prev_source != flow.source) {
fs = &(*(ge->flows.insert(ge->flows.end(), FlowStat(flow.source, flow.via, flow.share, flow.restricted))));
fs = &(*(ge->data->flows.insert(ge->data->flows.end(), FlowStat(flow.source, flow.via, flow.share, flow.restricted))));
} else {
fs->AppendShare(flow.via, flow.share, flow.restricted);
}
@ -229,7 +231,7 @@ public:
SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, SLV_150, SL_MAX_VERSION),
SLEG_CONDREFRING("packets", _packets, REF_CARGO_PACKET, SLV_68, SLV_183),
SLEG_CONDVAR("old_num_dests", _old_num_dests, SLE_UINT32, SLV_183, SLV_SAVELOAD_LIST_LENGTH),
SLE_CONDVAR(GoodsEntry, cargo.reserved_count, SLE_UINT, SLV_181, SL_MAX_VERSION),
SLEG_CONDVAR("cargo.reserved_count", _cargo_reserved_count, SLE_UINT, SLV_181, SL_MAX_VERSION),
SLE_CONDVAR(GoodsEntry, link_graph, SLE_UINT16, SLV_183, SL_MAX_VERSION),
SLE_CONDVAR(GoodsEntry, node, SLE_UINT16, SLV_183, SL_MAX_VERSION),
SLEG_CONDVAR("old_num_flows", _old_num_flows, SLE_UINT32, SLV_183, SLV_SAVELOAD_LIST_LENGTH),
@ -258,19 +260,15 @@ public:
void Save(BaseStation *bst) const override
{
Station *st = Station::From(bst);
SlSetStructListLength(NUM_CARGO);
for (CargoID i = 0; i < NUM_CARGO; i++) {
SlObject(&st->goods[i], this->GetDescription());
}
NOT_REACHED();
}
void Load(BaseStation *bst) const override
{
Station *st = Station::From(bst);
std::unique_ptr<GoodsEntryData> spare_ged;
/* Before savegame version 161, persistent storages were not stored in a pool. */
if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_145) && st->facilities & FACIL_AIRPORT) {
/* Store the old persistent storage. The GRFID will be added later. */
@ -282,7 +280,15 @@ public:
size_t num_cargo = this->GetNumCargo();
for (size_t i = 0; i < num_cargo; i++) {
GoodsEntry *ge = &st->goods[i];
if (ge->data == nullptr) {
if (spare_ged != nullptr) {
ge->data = std::move(spare_ged);
} else {
ge->data.reset(new GoodsEntryData());
}
}
SlObject(ge, this->GetLoadDescription());
if (!IsSavegameVersionBefore(SLV_181)) ge->data->cargo.LoadSetReservedCount(_cargo_reserved_count);
if (IsSavegameVersionBefore(SLV_183)) {
SwapPackets(ge);
}
@ -300,10 +306,13 @@ public:
/* Don't construct the packet with station here, because that'll fail with old savegames */
CargoPacket *cp = new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, source, _cargo_source_xy, _cargo_source_xy, _cargo_feeder_share);
ge->cargo.Append(cp, INVALID_STATION);
ge->data->cargo.Append(cp, INVALID_STATION);
SB(ge->status, GoodsEntry::GES_RATING, 1, 1);
}
}
if (ge->data->MayBeRemoved()) {
spare_ged = std::move(ge->data);
}
}
}

@ -58,7 +58,10 @@ template<bool Tfrom, bool Tvia>
return -1;
}
const StationCargoList &cargo_list = ::Station::Get(station_id)->goods[cargo_id].cargo;
const GoodsEntry &ge = ::Station::Get(station_id)->goods[cargo_id];
if (ge.data == nullptr) return 0;
const StationCargoList &cargo_list = ge.data->cargo;
if (!Tfrom && !Tvia) return cargo_list.TotalCount();
uint16 cargo_count = 0;
@ -106,7 +109,10 @@ template<bool Tfrom, bool Tvia>
return -1;
}
const FlowStatMap &flows = ::Station::Get(station_id)->goods[cargo_id].flows;
const GoodsEntry &ge = ::Station::Get(station_id)->goods[cargo_id];
if (ge.data == nullptr) return 0;
const FlowStatMap &flows = ge.data->flows;
if (Tfrom) {
return Tvia ? flows.GetFlowFromVia(from_station_id, via_station_id) :
flows.GetFlowFrom(from_station_id);

@ -171,8 +171,11 @@ void ScriptStationList_CargoWaiting::Add(StationID station_id, CargoID cargo, St
CargoCollector collector(this, station_id, cargo, other_station);
if (collector.GE() == nullptr) return;
StationCargoList::ConstIterator iter = collector.GE()->cargo.Packets()->begin();
StationCargoList::ConstIterator end = collector.GE()->cargo.Packets()->end();
const GoodsEntry *ge = collector.GE();
if (ge->data == nullptr) return;
StationCargoList::ConstIterator iter = ge->data->cargo.Packets()->begin();
StationCargoList::ConstIterator end = ge->data->cargo.Packets()->end();
for (; iter != end; ++iter) {
collector.Update<Tselector>((*iter)->SourceStation(), iter.GetKey(), (*iter)->Count());
}
@ -185,8 +188,11 @@ void ScriptStationList_CargoPlanned::Add(StationID station_id, CargoID cargo, St
CargoCollector collector(this, station_id, cargo, other_station);
if (collector.GE() == nullptr) return;
FlowStatMap::const_iterator iter = collector.GE()->flows.begin();
FlowStatMap::const_iterator end = collector.GE()->flows.end();
const GoodsEntry *ge = collector.GE();
if (ge->data == nullptr) return;
FlowStatMap::const_iterator iter = ge->data->flows.begin();
FlowStatMap::const_iterator end = ge->data->flows.end();
for (; iter != end; ++iter) {
uint prev = 0;
for (FlowStat::const_iterator flow_iter = iter->begin();
@ -209,8 +215,11 @@ ScriptStationList_CargoWaitingViaByFrom::ScriptStationList_CargoWaitingViaByFrom
CargoCollector collector(this, station_id, cargo, via);
if (collector.GE() == nullptr) return;
const GoodsEntry *ge = collector.GE();
if (ge->data == nullptr) return;
std::pair<StationCargoList::ConstIterator, StationCargoList::ConstIterator> range =
collector.GE()->cargo.Packets()->equal_range(via);
ge->data->cargo.Packets()->equal_range(via);
for (StationCargoList::ConstIterator iter = range.first; iter != range.second; ++iter) {
collector.Update<CS_VIA_BY_FROM>((*iter)->SourceStation(), iter.GetKey(), (*iter)->Count());
}
@ -255,8 +264,11 @@ ScriptStationList_CargoPlannedFromByVia::ScriptStationList_CargoPlannedFromByVia
CargoCollector collector(this, station_id, cargo, from);
if (collector.GE() == nullptr) return;
FlowStatMap::const_iterator iter = collector.GE()->flows.find(from);
if (iter == collector.GE()->flows.end()) return;
const GoodsEntry *ge = collector.GE();
if (ge->data == nullptr) return;
FlowStatMap::const_iterator iter = ge->data->flows.find(from);
if (iter == ge->data->flows.end()) return;
uint prev = 0;
for (FlowStat::const_iterator flow_iter = iter->begin();
flow_iter != iter->end(); ++flow_iter) {

@ -49,7 +49,8 @@ extern btree::btree_map<uint64, Money> _cargo_packet_deferred_payments;
for (CargoID c = 0; c < NUM_CARGO; c++) {
GoodsEntry *ge = &st->goods[c];
const StationCargoPacketMap *packets = ge->cargo.Packets();
if (ge->data == nullptr) continue;
const StationCargoPacketMap *packets = ge->data->cargo.Packets();
for (StationCargoList::ConstIterator it(packets->begin()); it != packets->end(); it++) {
CargoPacket *cp = *it;
cp->source_xy = Station::IsValidID(cp->source) ? Station::Get(cp->source)->xy : st->xy;
@ -73,7 +74,9 @@ extern btree::btree_map<uint64, Money> _cargo_packet_deferred_payments;
for (Vehicle *v : Vehicle::Iterate()) v->cargo.InvalidateCache();
for (Station *st : Station::Iterate()) {
for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
for (CargoID c = 0; c < NUM_CARGO; c++) {
if (st->goods[c].data != nullptr) st->goods[c].data->cargo.InvalidateCache();
}
}
}
@ -95,7 +98,7 @@ extern btree::btree_map<uint64, Money> _cargo_packet_deferred_payments;
Station *st = Station::Get(v->First()->last_station_visited);
assert_msg(st != nullptr, "%s", scope_dumper().VehicleInfo(v));
for (CargoPacket *cp : iter.second) {
st->goods[v->cargo_type].cargo.AfterLoadIncreaseReservationCount(cp->count);
st->goods[v->cargo_type].CreateData().cargo.AfterLoadIncreaseReservationCount(cp->count);
v->cargo.Append(cp, VehicleCargoList::MTA_LOAD);
}
}

@ -706,7 +706,7 @@ static bool LoadOldGood(LoadgameState *ls, int num)
SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
SB(ge->status, GoodsEntry::GES_RATING, 1, _cargo_source != 0xFF);
if (GB(_waiting_acceptance, 0, 12) != 0 && CargoPacket::CanAllocateItem()) {
ge->cargo.Append(new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, 0, 0),
ge->CreateData().cargo.Append(new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, 0, 0),
INVALID_STATION);
}

@ -237,6 +237,7 @@ static uint16 _cargo_source;
static uint32 _cargo_source_xy;
static uint8 _cargo_days;
static Money _cargo_feeder_share;
static uint _cargo_reserved_count;
static const SaveLoad _station_speclist_desc[] = {
SLE_CONDVAR(StationSpecList, grfid, SLE_UINT32, SLV_27, SL_MAX_VERSION),
@ -295,7 +296,7 @@ SaveLoadTable GetGoodsDesc()
SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, SLV_150, SL_MAX_VERSION),
SLEG_CONDPTRRING_X( _packets, REF_CARGO_PACKET, SLV_68, SLV_183, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, 0, 0)),
SLEG_CONDVAR_X( _num_dests, SLE_UINT32, SLV_183, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_OR, XSLFI_CHILLPP)),
SLE_CONDVAR(GoodsEntry, cargo.reserved_count, SLE_UINT, SLV_181, SL_MAX_VERSION),
SLEG_CONDVAR( _cargo_reserved_count,SLE_UINT, SLV_181, SL_MAX_VERSION),
SLE_CONDVAR(GoodsEntry, link_graph, SLE_UINT16, SLV_183, SL_MAX_VERSION),
SLE_CONDVAR(GoodsEntry, node, SLE_UINT16, SLV_183, SL_MAX_VERSION),
SLEG_CONDVAR( _num_flows, SLE_UINT32, SLV_183, SL_MAX_VERSION),
@ -321,7 +322,9 @@ static const SaveLoad _cargo_list_desc[] = {
*/
static void SwapPackets(GoodsEntry *ge)
{
StationCargoPacketMap &ge_packets = const_cast<StationCargoPacketMap &>(*ge->cargo.Packets());
if (_packets.empty() && ge->data == nullptr) return;
StationCargoPacketMap &ge_packets = const_cast<StationCargoPacketMap &>(*ge->CreateData().cargo.Packets());
if (_packets.empty()) {
std::map<StationID, CargoPacketList>::iterator it(ge_packets.find(INVALID_STATION));
@ -342,6 +345,7 @@ static void Load_STNS()
_cargo_days = 0;
_cargo_feeder_share = 0;
_num_specs = 0;
_cargo_reserved_count = 0;
uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
int index;
@ -355,6 +359,7 @@ static void Load_STNS()
for (CargoID i = 0; i < num_cargo; i++) {
GoodsEntry *ge = &st->goods[i];
SlObject(ge, GetGoodsDesc());
if (_cargo_reserved_count) ge->CreateData().cargo.LoadSetReservedCount(_cargo_reserved_count);
SwapPackets(ge);
if (IsSavegameVersionBefore(SLV_68)) {
SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
@ -370,7 +375,7 @@ static void Load_STNS()
/* Don't construct the packet with station here, because that'll fail with old savegames */
CargoPacket *cp = new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, source, _cargo_source_xy, _cargo_source_xy, _cargo_feeder_share);
ge->cargo.Append(cp, INVALID_STATION);
ge->CreateData().cargo.Append(cp, INVALID_STATION);
SB(ge->status, GoodsEntry::GES_RATING, 1, 1);
}
}
@ -544,10 +549,19 @@ static void RealSave_STNN(BaseStation *bst)
if (!waypoint) {
Station *st = Station::From(bst);
for (CargoID i = 0; i < NUM_CARGO; i++) {
_num_dests = (uint32)st->goods[i].cargo.Packets()->MapSize();
_num_flows = (uint32)st->goods[i].flows.size();
const GoodsEntryData *ged = st->goods[i].data.get();
if (ged != nullptr) {
_cargo_reserved_count = ged->cargo.ReservedCount();
_num_dests = (uint32)ged->cargo.Packets()->MapSize();
_num_flows = (uint32)ged->flows.size();
} else {
_cargo_reserved_count = 0;
_num_dests = 0;
_num_flows = 0;
}
SlObjectSaveFiltered(&st->goods[i], _filtered_goods_desc);
for (FlowStatMap::const_iterator outer_it(st->goods[i].flows.begin()); outer_it != st->goods[i].flows.end(); ++outer_it) {
if (ged == nullptr) continue;
for (FlowStatMap::const_iterator outer_it(ged->flows.begin()); outer_it != ged->flows.end(); ++outer_it) {
uint32 sum_shares = 0;
FlowSaveLoad flow;
flow.source = outer_it->GetOrigin();
@ -571,7 +585,7 @@ static void RealSave_STNN(BaseStation *bst)
}
SlWriteUint16(outer_it->GetRawFlags());
}
for (StationCargoPacketMap::ConstMapIterator it(st->goods[i].cargo.Packets()->begin()); it != st->goods[i].cargo.Packets()->end(); ++it) {
for (StationCargoPacketMap::ConstMapIterator it(ged->cargo.Packets()->begin()); it != ged->cargo.Packets()->end(); ++it) {
SlObjectSaveFiltered(const_cast<StationCargoPacketMap::value_type *>(&(*it)), _cargo_list_desc); // _cargo_list_desc has no conditionals
}
}
@ -620,6 +634,9 @@ static void Load_STNN()
_num_specs = 0;
_num_roadstop_specs = 0;
_num_roadstop_custom_tiles = 0;
_cargo_reserved_count = 0;
std::unique_ptr<GoodsEntryData> spare_ged;
const uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
ReadBuffer *buffer = ReadBuffer::GetCurrent();
@ -643,10 +660,19 @@ static void Load_STNN()
}
for (CargoID i = 0; i < num_cargo; i++) {
SlObjectLoadFiltered(&st->goods[i], _filtered_goods_desc);
GoodsEntry &ge = st->goods[i];
if (ge.data == nullptr) {
if (spare_ged != nullptr) {
ge.data = std::move(spare_ged);
} else {
ge.data.reset(new GoodsEntryData());
}
}
SlObjectLoadFiltered(&ge, _filtered_goods_desc);
ge.data->cargo.LoadSetReservedCount(_cargo_reserved_count);
StationID prev_source = INVALID_STATION;
if (SlXvIsFeaturePresent(XSLFI_FLOW_STAT_FLAGS)) {
st->goods[i].flows.reserve(_num_flows);
ge.data->flows.reserve(_num_flows);
for (uint32 j = 0; j < _num_flows; ++j) {
FlowSaveLoad flow;
buffer->CheckBytes(2 + 4);
@ -657,7 +683,7 @@ static void Load_STNN()
flow.via = buffer->RawReadUint16();
flow.share = buffer->RawReadUint32();
flow.restricted = (buffer->RawReadByte() != 0);
FlowStat *fs = &(*(st->goods[i].flows.insert(st->goods[i].flows.end(), FlowStat(flow.source, flow.via, flow.share, flow.restricted))));
FlowStat *fs = &(*(ge.data->flows.insert(ge.data->flows.end(), FlowStat(flow.source, flow.via, flow.share, flow.restricted))));
for (uint32 k = 1; k < flow_count; ++k) {
buffer->CheckBytes(2 + 4 + 1);
flow.via = buffer->RawReadUint16();
@ -679,7 +705,7 @@ static void Load_STNN()
if (!IsSavegameVersionBefore(SLV_187)) flow.restricted = (buffer->ReadByte() != 0);
if (fs == nullptr || prev_source != flow.source) {
fs = &(*(st->goods[i].flows.insert(st->goods[i].flows.end(), FlowStat(flow.source, flow.via, flow.share, flow.restricted))));
fs = &(*(ge.data->flows.insert(ge.data->flows.end(), FlowStat(flow.source, flow.via, flow.share, flow.restricted))));
} else {
fs->AppendShare(flow.via, flow.share, flow.restricted);
}
@ -687,7 +713,7 @@ static void Load_STNN()
}
}
if (IsSavegameVersionBefore(SLV_183) && SlXvIsFeatureMissing(XSLFI_CHILLPP)) {
SwapPackets(&st->goods[i]);
SwapPackets(&ge);
} else {
if (SlXvIsFeaturePresent(XSLFI_CHILLPP)) {
SlSkipBytes(8);
@ -701,11 +727,14 @@ static void Load_STNN()
StationCargoPair pair;
for (uint j = 0; j < _num_dests; ++j) {
SlObjectLoadFiltered(&pair, _cargo_list_desc); // _cargo_list_desc has no conditionals
const_cast<StationCargoPacketMap &>(*(st->goods[i].cargo.Packets()))[pair.first].swap(pair.second);
const_cast<StationCargoPacketMap &>(*(ge.data->cargo.Packets()))[pair.first].swap(pair.second);
assert(pair.second.empty());
}
}
if (SlXvIsFeatureMissing(XSLFI_ST_LAST_VEH_TYPE)) st->goods[i].last_vehicle_type = _old_last_vehicle_type;
if (SlXvIsFeatureMissing(XSLFI_ST_LAST_VEH_TYPE)) ge.last_vehicle_type = _old_last_vehicle_type;
if (ge.data->MayBeRemoved()) {
spare_ged = std::move(ge.data);
}
}
st->station_cargo_history.resize(CountBits(st->station_cargo_history_cargoes));
@ -780,8 +809,10 @@ static void Ptrs_STNN()
SwapPackets(ge);
} else {
//SlObject(ge, GetGoodsDesc());
for (StationCargoPacketMap::ConstMapIterator it = ge->cargo.Packets()->begin(); it != ge->cargo.Packets()->end(); ++it) {
SlObjectPtrOrNullFiltered(const_cast<StationCargoPair *>(&(*it)), _cargo_list_desc); // _cargo_list_desc has no conditionals
if (ge->data != nullptr) {
for (StationCargoPacketMap::ConstMapIterator it = ge->data->cargo.Packets()->begin(); it != ge->data->cargo.Packets()->end(); ++it) {
SlObjectPtrOrNullFiltered(const_cast<StationCargoPair *>(&(*it)), _cargo_list_desc); // _cargo_list_desc has no conditionals
}
}
}
}

@ -42,6 +42,8 @@ std::array<ExtraStationNameInfo, MAX_EXTRA_STATION_NAMES> _extra_station_names;
uint _extra_station_names_used;
uint8 _extra_station_names_probability;
const StationCargoList _empty_cargo_list{};
const FlowStatMap _empty_flows{};
StationKdtree _station_kdtree(Kdtree_StationXYFunc);
@ -93,7 +95,7 @@ Station::~Station()
{
if (CleaningPool()) {
for (CargoID c = 0; c < NUM_CARGO; c++) {
this->goods[c].cargo.OnCleanPool();
if (this->goods[c].data != nullptr) this->goods[c].data->cargo.OnCleanPool();
}
return;
}
@ -113,9 +115,10 @@ Station::~Station()
for (NodeID node = 0; node < lg->Size(); ++node) {
Station *st = Station::Get((*lg)[node].Station());
st->goods[c].flows.erase(this->index);
GoodsEntryData *ged = st->goods[c].data.get();
if (ged != nullptr) ged->flows.erase(this->index);
if (lg->GetConstEdge(node, this->goods[c].node).LastUpdate() != INVALID_DATE) {
st->goods[c].flows.DeleteFlows(this->index);
if (ged != nullptr) ged->flows.DeleteFlows(this->index);
RerouteCargo(st, c, this->index, st->index);
}
}
@ -161,7 +164,7 @@ Station::~Station()
DeleteStationNews(this->index);
for (CargoID c = 0; c < NUM_CARGO; c++) {
this->goods[c].cargo.Truncate();
if (this->goods[c].data != nullptr) this->goods[c].data->cargo.Truncate();
}
CargoPacket::InvalidateAllFrom(this->index);

@ -501,6 +501,16 @@ public:
void SortStorage();
};
struct GoodsEntryData {
StationCargoList cargo; ///< The cargo packets of cargo waiting in this station
FlowStatMap flows; ///< Planned flows through this station.
bool MayBeRemoved() const
{
return this->cargo.Packets()->MapSize() == 0 && this->cargo.ReservedCount() == 0 && this->flows.empty();
}
};
/**
* Stores station stats for a single cargo.
*/
@ -597,11 +607,12 @@ struct GoodsEntry {
byte last_age;
byte amount_fract; ///< Fractional part of the amount in the cargo list
StationCargoList cargo; ///< The cargo packets of cargo waiting in this station
std::unique_ptr<GoodsEntryData> data;
LinkGraphID link_graph; ///< Link graph this station belongs to.
NodeID node; ///< ID of node in link graph referring to this goods entry.
FlowStatMap flows; ///< Planned flows through this station.
uint max_waiting_cargo; ///< Max cargo from this station waiting at any station.
bool IsSupplyAllowed() const
@ -632,8 +643,10 @@ struct GoodsEntry {
*/
inline StationID GetVia(StationID source) const
{
FlowStatMap::const_iterator flow_it(this->flows.find(source));
return flow_it != this->flows.end() ? flow_it->GetVia() : INVALID_STATION;
if (this->data == nullptr) return INVALID_STATION;
FlowStatMap::const_iterator flow_it(this->data->flows.find(source));
return flow_it != this->data->flows.end() ? flow_it->GetVia() : INVALID_STATION;
}
/**
@ -646,8 +659,54 @@ struct GoodsEntry {
*/
inline StationID GetVia(StationID source, StationID excluded, StationID excluded2 = INVALID_STATION) const
{
FlowStatMap::const_iterator flow_it(this->flows.find(source));
return flow_it != this->flows.end() ? flow_it->GetVia(excluded, excluded2) : INVALID_STATION;
if (this->data == nullptr) return INVALID_STATION;
FlowStatMap::const_iterator flow_it(this->data->flows.find(source));
return flow_it != this->data->flows.end() ? flow_it->GetVia(excluded, excluded2) : INVALID_STATION;
}
GoodsEntryData &CreateData()
{
if (this->data == nullptr) this->data.reset(new GoodsEntryData());
return *this->data;
}
const GoodsEntryData &CreateData() const
{
if (this->data == nullptr) const_cast<GoodsEntry *>(this)->data.reset(new GoodsEntryData());
return *this->data;
}
inline uint CargoAvailableCount() const
{
return this->data != nullptr ? this->data->cargo.AvailableCount() : 0;
}
inline uint CargoReservedCount() const
{
return this->data != nullptr ? this->data->cargo.ReservedCount() : 0;
}
inline uint CargoTotalCount() const
{
return this->data != nullptr ? this->data->cargo.TotalCount() : 0;
}
inline uint CargoAvailableViaCount(StationID next) const
{
return this->data != nullptr ? this->data->cargo.AvailableViaCount(next) : 0;
}
const StationCargoList &ConstCargoList() const
{
extern const StationCargoList _empty_cargo_list;
return this->data != nullptr ? this->data->cargo : _empty_cargo_list;
}
const FlowStatMap &ConstFlows() const
{
extern const FlowStatMap _empty_flows;
return this->data != nullptr ? this->data->flows : _empty_flows;
}
};

@ -469,7 +469,7 @@ void Station::UpdateCargoHistory()
uint storage_offset = 0;
bool update_window = false;
for (const CargoSpec *cs : CargoSpec::Iterate()) {
uint amount = this->goods[cs->Index()].cargo.TotalCount();
uint amount = this->goods[cs->Index()].CargoTotalCount();
if (!HasBit(this->station_cargo_history_cargoes, cs->Index())) {
if (amount == 0) {
/* No cargo present, and no history stored for this cargo, no work to do */
@ -4115,8 +4115,10 @@ static void TruncateCargo(const CargoSpec *cs, GoodsEntry *ge, uint amount = UIN
/* If truncating also punish the source stations' ratings to
* decrease the flow of incoming cargo. */
if (ge->data == nullptr) return;
StationCargoAmountMap waiting_per_source;
ge->cargo.Truncate(amount, &waiting_per_source);
ge->data->cargo.Truncate(amount, &waiting_per_source);
for (StationCargoAmountMap::iterator i(waiting_per_source.begin()); i != waiting_per_source.end(); ++i) {
Station *source_station = Station::GetIfValid(i->first);
if (source_station == nullptr) continue;
@ -4290,12 +4292,12 @@ static void UpdateStationRating(Station *st)
{
int rating = GetTargetRating(st, cs, ge);
uint waiting = ge->cargo.AvailableCount();
uint waiting = ge->CargoAvailableCount();
/* num_dests is at least 1 if there is any cargo as
* INVALID_STATION is also a destination.
*/
const uint num_dests = (uint)ge->cargo.Packets()->MapSize();
const uint num_dests = ge->data != nullptr ? (uint)ge->data->cargo.Packets()->MapSize() : 0;
/* Average amount of cargo per next hop, but prefer solitary stations
* with only one or two next hops. They are allowed to have more
@ -4352,12 +4354,12 @@ static void UpdateStationRating(Station *st)
/* We can't truncate cargo that's already reserved for loading.
* Thus StoredCount() here. */
if (waiting_changed && waiting < ge->cargo.AvailableCount()) {
if (waiting_changed && waiting < ge->CargoAvailableCount()) {
/* Feed back the exact own waiting cargo at this station for the
* next rating calculation. */
ge->max_waiting_cargo = 0;
TruncateCargo(cs, ge, ge->cargo.AvailableCount() - waiting);
TruncateCargo(cs, ge, ge->CargoAvailableCount() - waiting);
} else {
/* If the average number per next hop is low, be more forgiving. */
ge->max_waiting_cargo = waiting_avg;
@ -4388,7 +4390,7 @@ void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2)
GoodsEntry &ge = st->goods[c];
/* Reroute cargo in station. */
ge.cargo.Reroute(UINT_MAX, &ge.cargo, avoid, avoid2, &ge);
if (ge.data != nullptr) ge.data->cargo.Reroute(UINT_MAX, &ge.data->cargo, avoid, avoid2, &ge);
/* Reroute cargo staged to be transferred. */
for (Vehicle *v : st->loading_vehicles) {
@ -4413,7 +4415,7 @@ void RerouteCargoFromSource(Station *st, CargoID c, StationID source, StationID
GoodsEntry &ge = st->goods[c];
/* Reroute cargo in station. */
ge.cargo.RerouteFromSource(UINT_MAX, &ge.cargo, source, avoid, avoid2, &ge);
if (ge.data != nullptr) ge.data->cargo.RerouteFromSource(UINT_MAX, &ge.data->cargo, source, avoid, avoid2, &ge);
/* Reroute cargo staged to be transferred. */
for (Vehicle *v : st->loading_vehicles) {
@ -4520,12 +4522,12 @@ void DeleteStaleLinks(Station *from)
if (!updated) {
/* If it's still considered dead remove it. */
result = LinkGraph::EdgeIterationResult::EraseEdge;
ge.flows.DeleteFlows(to->index);
if (ge.data != nullptr) ge.data->flows.DeleteFlows(to->index);
RerouteCargo(from, c, to->index, from->index);
}
} else if (edge.LastUnrestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastUnrestrictedUpdate()) > timeout) {
edge.Restrict();
ge.flows.RestrictFlows(to->index);
if (ge.data != nullptr) ge.data->flows.RestrictFlows(to->index);
RerouteCargo(from, c, to->index, from->index);
} else if (edge.LastRestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastRestrictedUpdate()) > timeout) {
edge.Release();
@ -4697,7 +4699,7 @@ static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceT
if (amount == 0) return 0;
StationID next = ge.GetVia(st->index);
ge.cargo.Append(new CargoPacket(st->index, st->xy, amount, source_type, source_id), next);
ge.CreateData().cargo.Append(new CargoPacket(st->index, st->xy, amount, source_type, source_id), next);
LinkGraph *lg = nullptr;
if (ge.link_graph == INVALID_LINK_GRAPH) {
if (LinkGraph::CanAllocateItem()) {
@ -5686,7 +5688,8 @@ void DumpStationFlowStats(char *b, const char *last)
for (const Station *st : Station::Iterate()) {
for (CargoID i = 0; i < NUM_CARGO; i++) {
const GoodsEntry &ge = st->goods[i];
for (FlowStatMap::const_iterator it(ge.flows.begin()); it != ge.flows.end(); ++it) {
if (ge.data == nullptr) continue;
for (FlowStatMap::const_iterator it(ge.data->flows.begin()); it != ge.data->flows.end(); ++it) {
count_map[(uint32)it->size()]++;
invalid_map[it->GetRawFlags() & 0x1F]++;
}

@ -334,7 +334,7 @@ protected:
int diff = 0;
for (CargoID j : SetCargoBitIterator(cargo_filter)) {
diff += a->goods[j].cargo.TotalCount() - b->goods[j].cargo.TotalCount();
diff += a->goods[j].CargoTotalCount() - b->goods[j].CargoTotalCount();
}
return diff < 0;
@ -346,7 +346,7 @@ protected:
int diff = 0;
for (CargoID j : SetCargoBitIterator(cargo_filter)) {
diff += a->goods[j].cargo.AvailableCount() - b->goods[j].cargo.AvailableCount();
diff += a->goods[j].CargoAvailableCount() - b->goods[j].CargoAvailableCount();
}
return diff < 0;
@ -573,7 +573,7 @@ public:
/* show cargo waiting and station ratings */
for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
CargoID cid = cs->Index();
if (st->goods[cid].cargo.TotalCount() > 0) {
if (st->goods[cid].CargoTotalCount() > 0) {
/* For RTL we work in exactly the opposite direction. So
* decrement the space needed first, then draw to the left
* instead of drawing to the left and then incrementing
@ -582,7 +582,7 @@ public:
x -= rating_width + rating_spacing;
if (x < tr.left) break;
}
StationsWndShowStationRating(x, x + rating_width, tr.top, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating);
StationsWndShowStationRating(x, x + rating_width, tr.top, cid, st->goods[cid].CargoTotalCount(), st->goods[cid].rating);
if (!rtl) {
x += rating_width + rating_spacing;
if (x > tr.right) break;
@ -1649,7 +1649,9 @@ struct StationViewWindow : public Window {
CargoDataEntry *cargo_entry = cached_destinations.InsertOrRetrieve(i);
cargo_entry->Clear();
const FlowStatMap &flows = st->goods[i].flows;
if (st->goods[i].data == nullptr) return;
const FlowStatMap &flows = st->goods[i].data->flows;
for (const auto &it : flows) {
StationID from = it.GetOrigin();
CargoDataEntry *source_entry = cargo_entry->InsertOrRetrieve(from);
@ -1680,13 +1682,17 @@ struct StationViewWindow : public Window {
{
if (depth <= 128 && Station::IsValidID(next) && Station::IsValidID(source)) {
CargoDataEntry tmp;
const FlowStatMap &flowmap = Station::Get(next)->goods[cargo].flows;
FlowStatMap::const_iterator map_it = flowmap.find(source);
if (map_it != flowmap.end()) {
uint32 prev_count = 0;
for (FlowStat::const_iterator i = map_it->begin(); i != map_it->end(); ++i) {
tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count);
prev_count = i->first;
const GoodsEntry &ge = Station::Get(next)->goods[cargo];
if (ge.data != nullptr) {
const FlowStatMap &flowmap = ge.data->flows;
FlowStatMap::const_iterator map_it = flowmap.find(source);
if (map_it != flowmap.end()) {
uint32 prev_count = 0;
for (FlowStat::const_iterator i = map_it->begin(); i != map_it->end(); ++i) {
tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count);
prev_count = i->first;
}
}
}
@ -1807,9 +1813,9 @@ struct StationViewWindow : public Window {
}
if (this->current_mode == MODE_WAITING) {
this->BuildCargoList(i, st->goods[i].cargo, cargo);
this->BuildCargoList(i, st->goods[i].ConstCargoList(), cargo);
} else {
this->BuildFlowList(i, st->goods[i].flows, cargo);
this->BuildFlowList(i, st->goods[i].ConstFlows(), cargo);
}
}
}
@ -1971,8 +1977,8 @@ struct StationViewWindow : public Window {
sym = "+";
} else {
/* Only draw '+' if there is something to be shown. */
const StationCargoList &list = Station::Get(this->window_number)->goods[cargo].cargo;
if (grouping == GR_CARGO && (list.ReservedCount() > 0 || cd->HasTransfers())) {
const GoodsEntry &ge = Station::Get(this->window_number)->goods[cargo];
if (grouping == GR_CARGO && (ge.CargoReservedCount() > 0 || cd->HasTransfers())) {
sym = "+";
}
}

@ -1909,15 +1909,16 @@ class NIHStationStruct : public NIHelper {
for (const CargoSpec *cs : CargoSpec::Iterate()) {
const GoodsEntry *ge = &st->goods[cs->Index()];
const StationCargoPacketMap *pkts = ge->cargo.Packets();
if (pkts->empty() && ge->status == 0) {
if (ge->data == nullptr && ge->status == 0) {
/* Nothing of note to show */
continue;
}
const StationCargoPacketMap *pkts = ge->data != nullptr ? ge->data->cargo.Packets() : nullptr;
seprintf(buffer, lastof(buffer), " Goods entry: %u: %s", cs->Index(), GetStringPtr(cs->name));
output.print(buffer);
seprintf(buffer, lastof(buffer), " Status: %c%c%c%c%c%c%c",
char *b = buffer + seprintf(buffer, lastof(buffer), " Status: %c%c%c%c%c%c%c",
HasBit(ge->status, GoodsEntry::GES_ACCEPTANCE) ? 'a' : '-',
HasBit(ge->status, GoodsEntry::GES_RATING) ? 'r' : '-',
HasBit(ge->status, GoodsEntry::GES_EVER_ACCEPTED) ? 'e' : '-',
@ -1925,15 +1926,17 @@ class NIHStationStruct : public NIHelper {
HasBit(ge->status, GoodsEntry::GES_CURRENT_MONTH) ? 'c' : '-',
HasBit(ge->status, GoodsEntry::GES_ACCEPTED_BIGTICK) ? 'b' : '-',
HasBit(ge->status, GoodsEntry::GES_NO_CARGO_SUPPLY) ? 'n' : '-');
if (ge->data != nullptr && ge->data->MayBeRemoved()) b += seprintf(b, lastof(buffer), ", (removable)");
if (ge->data == nullptr) b += seprintf(b, lastof(buffer), ", (no data)");
output.print(buffer);
if (ge->amount_fract > 0) {
seprintf(buffer, lastof(buffer), " Amount fract: %u", ge->amount_fract);
output.print(buffer);
}
if (!pkts->empty()) {
seprintf(buffer, lastof(buffer), " Cargo packets: %u, available: %u, reserved: %u",
(uint)pkts->size(), ge->cargo.AvailableCount(), ge->cargo.ReservedCount());
if (pkts != nullptr && pkts->MapSize() > 0) {
seprintf(buffer, lastof(buffer), " Cargo packets: %u, cargo packet keys: %u, available: %u, reserved: %u",
(uint)pkts->size(), (uint)pkts->MapSize(), ge->CargoAvailableCount(), ge->CargoReservedCount());
output.print(buffer);
}
if (ge->link_graph != INVALID_LINK_GRAPH) {
@ -1944,12 +1947,12 @@ class NIHStationStruct : public NIHelper {
seprintf(buffer, lastof(buffer), " Max waiting cargo: %u", ge->max_waiting_cargo);
output.print(buffer);
}
if (ge->flows.size() > 0) {
if (ge->data != nullptr && ge->data->flows.size() > 0) {
size_t total_shares = 0;
for (const FlowStat &fs : ge->flows) {
for (const FlowStat &fs : ge->data->flows) {
total_shares += fs.size();
}
seprintf(buffer, lastof(buffer), " Flows: %u, total shares: %u", (uint)ge->flows.size(), (uint)total_shares);
seprintf(buffer, lastof(buffer), " Flows: %u, total shares: %u", (uint)ge->data->flows.size(), (uint)total_shares);
output.print(buffer);
}
}

@ -3318,7 +3318,7 @@ void Vehicle::CancelReservation(StationID next, Station *st)
VehicleCargoList &cargo = v->cargo;
if (cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) {
DEBUG(misc, 1, "cancelling cargo reservation");
cargo.Return(UINT_MAX, &st->goods[v->cargo_type].cargo, next);
cargo.Return(UINT_MAX, &st->goods[v->cargo_type].CreateData().cargo, next);
cargo.SetTransferLoadPlace(st->xy);
}
cargo.KeepAll();

@ -307,7 +307,7 @@ void ShowStationViewportTooltip(Window *w, const TileIndex tile)
SetDParam(0, cs->name);
SetDParam(1, ToPercent8(goods_entry->rating));
SetDParam(2, cs->Index());
SetDParam(3, goods_entry->cargo.TotalCount());
SetDParam(3, goods_entry->CargoTotalCount());
msg += GetString(STR_STATION_VIEW_CARGO_LINE_TOOLTIP);
}
}

Loading…
Cancel
Save