From 36bee83864ecffe526d7693dab8bb04fb3f6a4e2 Mon Sep 17 00:00:00 2001 From: dP Date: Sat, 19 Feb 2022 21:08:23 +0300 Subject: [PATCH] Change: Deliver cargo to the closest industry first (#9536) --- src/cargomonitor.cpp | 6 +++--- src/economy.cpp | 3 ++- src/industry_cmd.cpp | 14 +++++++------- src/station.cpp | 41 +++++++++++++++++++++++++++++++++-------- src/station_base.h | 16 ++++++++++++---- src/subsidy.cpp | 6 +++--- 6 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/cargomonitor.cpp b/src/cargomonitor.cpp index 2941a29556..7614cba6ec 100644 --- a/src/cargomonitor.cpp +++ b/src/cargomonitor.cpp @@ -149,9 +149,9 @@ void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, Sour if (iter != _cargo_deliveries.end()) iter->second += amount; /* Industry delivery. */ - for (Industry *ind : st->industries_near) { - if (ind->index != dest) continue; - CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, ind->index); + for (const auto &i : st->industries_near) { + if (i.industry->index != dest) continue; + CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, i.industry->index); CargoMonitorMap::iterator iter = _cargo_deliveries.find(num); if (iter != _cargo_deliveries.end()) iter->second += amount; } diff --git a/src/economy.cpp b/src/economy.cpp index e915653efd..bc3692e3a4 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1040,9 +1040,10 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n uint accepted = 0; - for (Industry *ind : st->industries_near) { + for (const auto &i : st->industries_near) { if (num_pieces == 0) break; + Industry *ind = i.industry; if (ind->index == source) continue; uint cargo_index; diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index e6a01c097d..90e917cd35 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -199,7 +199,7 @@ Industry::~Industry() CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index); for (Station *st : this->stations_near) { - st->industries_near.erase(this); + st->RemoveIndustryToDeliver(this); } } @@ -1701,15 +1701,14 @@ static void PopulateStationsNearby(Industry *ind) /* Industry has a neutral station. Use it and ignore any other nearby stations. */ ind->stations_near.insert(ind->neutral_station); ind->neutral_station->industries_near.clear(); - ind->neutral_station->industries_near.insert(ind); + ind->neutral_station->industries_near.insert(IndustryListEntry{0, ind}); return; } ForAllStationsAroundTiles(ind->location, [ind](Station *st, TileIndex tile) { if (!IsTileType(tile, MP_INDUSTRY) || GetIndustryIndex(tile) != ind->index) return false; - ind->stations_near.insert(st); - st->AddIndustryToDeliver(ind); - return true; + st->AddIndustryToDeliver(ind, tile); + return false; }); } @@ -3069,7 +3068,8 @@ extern const TileTypeProcs _tile_type_industry_procs = { TerraformTile_Industry, // terraform_tile_proc }; -bool IndustryCompare::operator() (const Industry *lhs, const Industry *rhs) const +bool IndustryCompare::operator() (const IndustryListEntry &lhs, const IndustryListEntry &rhs) const { - return lhs->index < rhs->index; + /* Compare by distance first and use index as a tiebreaker. */ + return std::tie(lhs.distance, lhs.industry->index) < std::tie(rhs.distance, rhs.industry->index); } diff --git a/src/station.cpp b/src/station.cpp index 877f53d4e0..fc258fcc92 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -357,12 +357,25 @@ Rect Station::GetCatchmentRect() const /** * Add nearby industry to station's industries_near list if it accepts cargo. - * @param ind Industry + * For industries that are already on the list update distance if it's closer. + * @param ind Industry + * @param tile Tile of the industry to measure distance to. */ -void Station::AddIndustryToDeliver(Industry *ind) +void Station::AddIndustryToDeliver(Industry *ind, TileIndex tile) { - /* Don't check further if this industry is already in the list */ - if (this->industries_near.find(ind) != this->industries_near.end()) return; + /* Using DistanceMax to get about the same order as with previously used CircularTileSearch. */ + uint distance = DistanceMax(this->xy, tile); + + /* Don't check further if this industry is already in the list but update the distance if it's closer */ + auto pos = std::find_if(this->industries_near.begin(), this->industries_near.end(), [&](const IndustryListEntry &e) { return e.industry->index == ind->index; }); + if (pos != this->industries_near.end()) { + if (pos->distance > distance) { + auto node = this->industries_near.extract(pos); + node.value().distance = distance; + this->industries_near.insert(std::move(node)); + } + return; + } /* Include only industries that can accept cargo */ uint cargo_index; @@ -371,9 +384,21 @@ void Station::AddIndustryToDeliver(Industry *ind) } if (cargo_index >= lengthof(ind->accepts_cargo)) return; - this->industries_near.insert(ind); + this->industries_near.insert(IndustryListEntry{distance, ind}); } +/** + * Remove nearby industry from station's industries_near list. + * @param ind Industry + */ +void Station::RemoveIndustryToDeliver(Industry *ind) { + auto pos = std::find_if(this->industries_near.begin(), this->industries_near.end(), [&](const IndustryListEntry &e) { return e.industry->index == ind->index; }); + if (pos != this->industries_near.end()) { + this->industries_near.erase(pos); + } +} + + /** * Remove this station from the nearby stations lists of all towns and industries. */ @@ -423,11 +448,11 @@ void Station::RecomputeCatchment() } /* The industry's stations_near may have been computed before its neutral station was built so clear and re-add here. */ for (Station *st : this->industry->stations_near) { - st->industries_near.erase(this->industry); + st->RemoveIndustryToDeliver(this->industry); } this->industry->stations_near.clear(); this->industry->stations_near.insert(this); - this->industries_near.insert(this->industry); + this->industries_near.insert(IndustryListEntry{0, this->industry}); return; } @@ -462,7 +487,7 @@ void Station::RecomputeCatchment() i->stations_near.insert(this); /* Add if we can deliver to this industry as well */ - this->AddIndustryToDeliver(i); + this->AddIndustryToDeliver(i, tile); } } } diff --git a/src/station_base.h b/src/station_base.h index eff191860c..ebb29026a9 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -437,11 +437,18 @@ private: } }; -struct IndustryCompare { - bool operator() (const Industry *lhs, const Industry *rhs) const; +struct IndustryListEntry { + uint distance; + Industry *industry; + + bool operator== (const IndustryListEntry &other) const { return this->distance == other.distance && this->industry == other.industry; }; }; -typedef std::set IndustryList; +struct IndustryCompare { + bool operator() (const IndustryListEntry &lhs, const IndustryListEntry &rhs) const; +}; + +typedef std::set IndustryList; /** Station data structure */ struct Station FINAL : SpecializedStation { @@ -500,7 +507,8 @@ public: uint GetCatchmentRadius() const; Rect GetCatchmentRect() const; bool CatchmentCoversTown(TownID t) const; - void AddIndustryToDeliver(Industry *ind); + void AddIndustryToDeliver(Industry *ind, TileIndex tile); + void RemoveIndustryToDeliver(Industry *ind); void RemoveFromAllNearbyLists(); inline bool TileIsInCatchment(TileIndex tile) const diff --git a/src/subsidy.cpp b/src/subsidy.cpp index 0c32dbcf12..6b56feead2 100644 --- a/src/subsidy.cpp +++ b/src/subsidy.cpp @@ -600,9 +600,9 @@ bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, if (s->cargo_type == cargo_type && s->src_type == src_type && s->src == src && (!s->IsAwarded() || s->awarded == company)) { switch (s->dst_type) { case ST_INDUSTRY: - for (Industry *ind : st->industries_near) { - if (s->dst == ind->index) { - assert(ind->part_of_subsidy & POS_DST); + for (const auto &i : st->industries_near) { + if (s->dst == i.industry->index) { + assert(i.industry->part_of_subsidy & POS_DST); subsidised = true; if (!s->IsAwarded()) s->AwardTo(company); }