diff --git a/src/lang/english.txt b/src/lang/english.txt index dd5fb3cffe..e8d25d8ae7 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2309,6 +2309,9 @@ STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Setting this to STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Saturation of short paths before using high-capacity paths: {STRING2} STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Frequently there are multiple paths between two given stations. Cargodist will saturate the shortest path first, then use the second shortest path until that is saturated and so on. Saturation is determined by an estimation of capacity and planned usage. Once it has saturated all paths, if there is still demand left, it will overload all paths, prefering the ones with high capacity. Most of the time the algorithm will not estimate the capacity accurately, though. This setting allows you to specify up to which percentage a shorter path must be saturated in the first pass before choosing the next longer one. Set it to less than 100% to avoid overcrowded stations in case of overestimated capacity. +STR_CONFIG_SETTING_AIRCRAFT_PATH_COST :Scale distance of paths which use aircraft: {STRING2} +STR_CONFIG_SETTING_AIRCRAFT_PATH_COST_HELPTEXT :This scales the cost (distance metric) of paths which use aircraft, such that they appear longer/less direct than they actually are. The reduces the tendency for direct routes using aircraft to become heavily overloaded. + STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Speed units: {STRING2} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Whenever a speed is shown in the user interface, show it in the selected units ###length 4 diff --git a/src/linkgraph/linkgraph.cpp b/src/linkgraph/linkgraph.cpp index 93af907fc0..6685f5b7ae 100644 --- a/src/linkgraph/linkgraph.cpp +++ b/src/linkgraph/linkgraph.cpp @@ -41,6 +41,7 @@ inline void LinkGraph::BaseEdge::Init() this->usage = 0; this->last_unrestricted_update = INVALID_DATE; this->last_restricted_update = INVALID_DATE; + this->last_aircraft_update = INVALID_DATE; this->next_edge = INVALID_NODE; } @@ -59,6 +60,7 @@ void LinkGraph::ShiftDates(int interval) BaseEdge &edge = this->edges[node1][node2]; if (edge.last_unrestricted_update != INVALID_DATE) edge.last_unrestricted_update += interval; if (edge.last_restricted_update != INVALID_DATE) edge.last_restricted_update += interval; + if (edge.last_aircraft_update != INVALID_DATE) edge.last_aircraft_update += interval; } } } @@ -199,6 +201,7 @@ void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMo first.next_edge = to; if (mode & EUM_UNRESTRICTED) edge.last_unrestricted_update = _date; if (mode & EUM_RESTRICTED) edge.last_restricted_update = _date; + if (mode & EUM_AIRCRAFT) edge.last_aircraft_update = _date; } /** @@ -230,6 +233,7 @@ void LinkGraph::Node::RemoveEdge(NodeID to) edge.capacity = 0; edge.last_unrestricted_update = INVALID_DATE; edge.last_restricted_update = INVALID_DATE; + edge.last_aircraft_update = INVALID_DATE; edge.usage = 0; NodeID prev = this->index; @@ -270,6 +274,7 @@ void LinkGraph::Edge::Update(uint capacity, uint usage, EdgeUpdateMode mode) } if (mode & EUM_UNRESTRICTED) this->edge.last_unrestricted_update = _date; if (mode & EUM_RESTRICTED) this->edge.last_restricted_update = _date; + if (mode & EUM_AIRCRAFT) this->edge.last_aircraft_update = _date; } /** diff --git a/src/linkgraph/linkgraph.h b/src/linkgraph/linkgraph.h index 5ee1edc7d2..bb9db08ada 100644 --- a/src/linkgraph/linkgraph.h +++ b/src/linkgraph/linkgraph.h @@ -72,6 +72,7 @@ public: uint usage; ///< Usage of the link. Date last_unrestricted_update; ///< When the unrestricted part of the link was last updated. Date last_restricted_update; ///< When the restricted part of the link was last updated. + Date last_aircraft_update; ///< When aircraft capacity of the link was last updated. NodeID next_edge; ///< Destination of next valid edge starting at the same source node. void Init(); }; @@ -117,6 +118,12 @@ public: */ Date LastRestrictedUpdate() const { return this->edge.last_restricted_update; } + /** + * Get the date of the last update to the edge's aircraft capacity. + * @return Last update. + */ + Date LastAircraftUpdate() const { return this->edge.last_aircraft_update; } + /** * Get the date of the last update to any part of the edge's capacity. * @return Last update. @@ -307,6 +314,7 @@ public: void Update(uint capacity, uint usage, EdgeUpdateMode mode); void Restrict() { this->edge.last_unrestricted_update = INVALID_DATE; } void Release() { this->edge.last_restricted_update = INVALID_DATE; } + void ClearAircraft() { this->edge.last_aircraft_update = INVALID_DATE; } }; /** diff --git a/src/linkgraph/linkgraph_type.h b/src/linkgraph/linkgraph_type.h index 544db136fb..fc128df01f 100644 --- a/src/linkgraph/linkgraph_type.h +++ b/src/linkgraph/linkgraph_type.h @@ -48,6 +48,7 @@ enum EdgeUpdateMode { EUM_REFRESH = 1 << 1, ///< Refresh capacity. EUM_RESTRICTED = 1 << 2, ///< Use restricted link. EUM_UNRESTRICTED = 1 << 3, ///< Use unrestricted link. + EUM_AIRCRAFT = 1 << 4, ///< Capacity is an aircraft link. }; DECLARE_ENUM_AS_BIT_SET(EdgeUpdateMode) diff --git a/src/linkgraph/mcf.cpp b/src/linkgraph/mcf.cpp index f490c962a8..8b6123362c 100644 --- a/src/linkgraph/mcf.cpp +++ b/src/linkgraph/mcf.cpp @@ -284,6 +284,8 @@ void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths) this->job.path_allocator.SetParameters(sizeof(Tannotation), (8192 - 32) / sizeof(Tannotation)); + const uint16 aircraft_link_scale = this->job.Settings().aircraft_link_scale; + for (NodeID node = 0; node < size; ++node) { Tannotation *anno = new (this->job.path_allocator.Allocate()) Tannotation(node, node == source_node); anno->UpdateAnnotation(); @@ -310,6 +312,10 @@ void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths) } /* punish in-between stops a little */ uint distance = DistanceMaxPlusManhattan(this->job[from].XY(), this->job[to].XY()) + 1; + if (edge.LastAircraftUpdate() != INVALID_DATE && aircraft_link_scale != 100) { + distance *= aircraft_link_scale; + distance /= 100; + } Tannotation *dest = static_cast(paths[to]); if (dest->IsBetter(source, capacity, capacity - edge.Flow(), distance)) { if (dest->GetAnnosSetFlag()) annos.erase(AnnoSetItem(dest)); diff --git a/src/linkgraph/refresh.cpp b/src/linkgraph/refresh.cpp index fc43277c17..f79070736d 100644 --- a/src/linkgraph/refresh.cpp +++ b/src/linkgraph/refresh.cpp @@ -55,7 +55,10 @@ HopSet seen_hops; LinkRefresher refresher(v, &seen_hops, allow_merge, is_full_loading, iter_cargo_mask); - refresher.RefreshLinks(first, first, (iter_cargo_mask & have_cargo_mask) ? 1 << HAS_CARGO : 0); + uint8 flags = 0; + if (iter_cargo_mask & have_cargo_mask) flags |= 1 << HAS_CARGO; + if (v->type == VEH_AIRCRAFT) flags |= 1 << AIRCRAFT; + refresher.RefreshLinks(first, first, flags); } cargo_mask &= ~iter_cargo_mask; @@ -234,7 +237,7 @@ const Order *LinkRefresher::PredictNextOrder(const Order *cur, const Order *next * @param cur Last stop where the consist could interact with cargo. * @param next Next order to be processed. */ -void LinkRefresher::RefreshStats(const Order *cur, const Order *next) +void LinkRefresher::RefreshStats(const Order *cur, const Order *next, uint8 flags) { StationID next_station = next->GetDestination(); Station *st = Station::GetIfValid(cur->GetDestination()); @@ -257,6 +260,8 @@ void LinkRefresher::RefreshStats(const Order *cur, const Order *next) EdgeUpdateMode restricted_mode = (cur->GetCargoLoadType(c) & OLFB_NO_LOAD) == 0 ? EUM_UNRESTRICTED : EUM_RESTRICTED; + if (HasBit(flags, AIRCRAFT)) restricted_mode |= EUM_AIRCRAFT; + /* 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 @@ -347,7 +352,7 @@ void LinkRefresher::RefreshLinks(const Order *cur, const Order *next, uint8 flag if (cur->IsType(OT_GOTO_STATION) || cur->IsType(OT_IMPLICIT)) { if (cur->CanLeaveWithCargo(HasBit(flags, HAS_CARGO), FindFirstBit(this->cargo_mask))) { SetBit(flags, HAS_CARGO); - this->RefreshStats(cur, next); + this->RefreshStats(cur, next, flags); } else { ClrBit(flags, HAS_CARGO); } diff --git a/src/linkgraph/refresh.h b/src/linkgraph/refresh.h index d0fc786259..65f3c56664 100644 --- a/src/linkgraph/refresh.h +++ b/src/linkgraph/refresh.h @@ -34,6 +34,7 @@ protected: WAS_REFIT, ///< Consist was refit since the last stop where it could interact with cargo. RESET_REFIT, ///< Consist had a chance to load since the last refit and the refit capacities can be reset. IN_AUTOREFIT, ///< Currently doing an autorefit loop. Ignore the first autorefit order. + AIRCRAFT, ///< Vehicle is an aircraft. }; /** @@ -93,7 +94,7 @@ protected: bool HandleRefit(CargoID refit_cargo); void ResetRefit(); - void RefreshStats(const Order *cur, const Order *next); + void RefreshStats(const Order *cur, const Order *next, uint8 flags); const Order *PredictNextOrder(const Order *cur, const Order *next, uint8 flags, uint num_hops = 0); void RefreshLinks(const Order *cur, const Order *next, uint8 flags, uint num_hops = 0); diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 3495cec3a8..9c32c4b7a5 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -160,6 +160,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr }, { XSLFI_BANKRUPTCY_EXTRA, XSCF_NULL, 1, 1, "bankruptcy_extra", nullptr, nullptr, nullptr }, { XSLFI_OBJECT_GROUND_TYPES, XSCF_NULL, 1, 1, "object_ground_types", nullptr, nullptr, nullptr }, + { XSLFI_LINKGRAPH_AIRCRAFT, XSCF_NULL, 1, 1, "linkgraph_aircraft", nullptr, nullptr, nullptr }, { XSLFI_SCRIPT_INT64, XSCF_NULL, 1, 1, "script_int64", nullptr, nullptr, nullptr }, { XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 35708d9291..b36cf9052f 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -114,6 +114,7 @@ enum SlXvFeatureIndex { XSLFI_EXTRA_SIGNAL_TYPES, ///< Extra signal types XSLFI_BANKRUPTCY_EXTRA, ///< Extra company bankruptcy fields XSLFI_OBJECT_GROUND_TYPES, ///< Object ground types + XSLFI_LINKGRAPH_AIRCRAFT, ///< Link graph last aircraft update field and aircraft link scaling setting XSLFI_SCRIPT_INT64, ///< See: SLV_SCRIPT_INT64 diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index 58b7b92e05..eb0ad68cef 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -128,6 +128,7 @@ static const SaveLoad _edge_desc[] = { SLE_VAR(Edge, usage, SLE_UINT32), SLE_VAR(Edge, last_unrestricted_update, SLE_INT32), SLE_CONDVAR(Edge, last_restricted_update, SLE_INT32, SLV_187, SL_MAX_VERSION), + SLE_CONDVAR_X(Edge, last_aircraft_update, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_AIRCRAFT)), SLE_VAR(Edge, next_edge, SLE_UINT16), }; diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index c9148915f1..2cb06653b6 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -2204,6 +2204,7 @@ static SettingsContainer &GetSettingsTree() cdist->Add(new SettingEntry("linkgraph.demand_size")); cdist->Add(new SettingEntry("linkgraph.short_path_saturation")); cdist->Add(new SettingEntry("linkgraph.recalc_not_scaled_by_daylength")); + cdist->Add(new SettingEntry("linkgraph.aircraft_link_scale")); } SettingsPage *treedist = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_TREES)); { diff --git a/src/settings_type.h b/src/settings_type.h index b07fc7b2ed..043da3a257 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -691,6 +691,7 @@ struct LinkGraphSettings { uint8 demand_size; ///< influence of supply ("station size") on the demand function uint8 demand_distance; ///< influence of distance between stations on the demand function uint8 short_path_saturation; ///< percentage up to which short paths are saturated before saturating most capacious paths + uint16 aircraft_link_scale; ///< scale effective distance of aircraft links inline DistributionType GetDistributionType(CargoID cargo) const { if (this->distribution_per_cargo[cargo] != DT_PER_CARGO_DEFAULT) return this->distribution_per_cargo[cargo]; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 0e851e142c..98b2541bd5 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -4124,6 +4124,9 @@ void DeleteStaleLinks(Station *from) ++it; // Do that before removing the edge. Anything else may crash. assert(_date >= edge.LastUpdate()); uint timeout = std::max((LinkGraph::MIN_TIMEOUT_DISTANCE + (DistanceManhattan(from->xy, to->xy) >> 3)) / _settings_game.economy.day_length_factor, 1); + if (edge.LastAircraftUpdate() != INVALID_DATE && (uint)(_date - edge.LastAircraftUpdate()) > timeout) { + edge.ClearAircraft(); + } if ((uint)(_date - edge.LastUpdate()) > timeout) { bool updated = false; diff --git a/src/table/settings/settings.ini b/src/table/settings/settings.ini index e0196a88ed..724d759507 100644 --- a/src/table/settings/settings.ini +++ b/src/table/settings/settings.ini @@ -1226,6 +1226,18 @@ str = STR_CONFIG_SETTING_SHORT_PATH_SATURATION strval = STR_CONFIG_SETTING_PERCENTAGE strhelp = STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT +[SDT_VAR] +var = linkgraph.aircraft_link_scale +type = SLE_UINT16 +def = 100 +min = 100 +max = 1000 +interval = 50 +str = STR_CONFIG_SETTING_AIRCRAFT_PATH_COST +strval = STR_CONFIG_SETTING_PERCENTAGE +strhelp = STR_CONFIG_SETTING_AIRCRAFT_PATH_COST_HELPTEXT +extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_AIRCRAFT, 1, 1) + [SDT_VAR] var = economy.old_town_cargo_factor type = SLE_INT8 diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 25b1503c92..7f820d93ab 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -3148,8 +3148,10 @@ static void VehicleIncreaseStats(const Vehicle *front) * among the wagons in that case. * As usage is not such an important figure anyway we just * ignore the additional cargo then.*/ + EdgeUpdateMode restricted_mode = EUM_INCREASE; + if (v->type == VEH_AIRCRAFT) restricted_mode |= EUM_AIRCRAFT; IncreaseStats(Station::Get(last_loading_station), v->cargo_type, front->last_station_visited, v->refit_cap, - std::min(v->refit_cap, v->cargo.StoredCount()), EUM_INCREASE); + std::min(v->refit_cap, v->cargo.StoredCount()), restricted_mode); } } }