diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 9bf64d0473..8c81dcc01f 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -1660,6 +1660,7 @@ struct StationCargoGraphWindow final : BaseGraphWindow { Scrollbar *vscroll; ///< Cargo list scrollbar. uint legend_width {}; ///< Width of legend 'blob'. CargoTypes legend_excluded_cargo; + CargoTypes present_cargoes; StationCargoGraphWindow(WindowDesc *desc, WindowNumber window) : BaseGraphWindow(desc, WID_SCG_GRAPH, STR_JUST_COMMA) @@ -1674,10 +1675,9 @@ struct StationCargoGraphWindow final : BaseGraphWindow { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_SCG_MATRIX_SCROLLBAR); - this->vscroll->SetCount(_sorted_standard_cargo_specs_size); /* Initialise the data set */ - this->OnHundredthTick(); + this->FillGraphData(); this->FinishInitNested(window); } @@ -1687,17 +1687,6 @@ struct StationCargoGraphWindow final : BaseGraphWindow { /* Width of the legend blob. */ this->legend_width = (FONT_HEIGHT_SMALL - ScaleFontTrad(1)) * 8 / 5; this->legend_excluded_cargo = 0; - - const Station* station = Station::GetIfValid(this->station_id); - - if (station == nullptr) return; - - const CargoSpec *cs; - FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { - if (station->goods[cs->Index()].cargo.AvailableCount() == 0) { - SetBit(legend_excluded_cargo, cs->Index()); - } - } } void SetStringParameters(int widget) const override @@ -1714,6 +1703,7 @@ struct StationCargoGraphWindow final : BaseGraphWindow { uint8 i = 0; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + if (!HasBit(this->present_cargoes, cs->Index())) continue; if (HasBit(legend_excluded_cargo, cs->Index())) SetBit(this->excluded_data, i); i++; } @@ -1761,6 +1751,7 @@ struct StationCargoGraphWindow final : BaseGraphWindow { const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + if (!HasBit(this->present_cargoes, cs->Index())) continue; if (pos-- > 0) continue; if (--max < 0) break; @@ -1786,17 +1777,18 @@ struct StationCargoGraphWindow final : BaseGraphWindow { switch (widget) { case WID_SCG_ENABLE_CARGOES: /* Remove all cargoes from the excluded lists. */ - legend_excluded_cargo = 0; + this->legend_excluded_cargo = 0; this->excluded_data = 0; this->SetDirty(); break; case WID_SCG_DISABLE_CARGOES: { /* Add all cargoes to the excluded lists. */ + this->legend_excluded_cargo = ~static_cast(0); int i = 0; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { - SetBit(legend_excluded_cargo, cs->Index()); + if (!HasBit(this->present_cargoes, cs->Index())) continue; SetBit(this->excluded_data, i); i++; } @@ -1810,6 +1802,7 @@ struct StationCargoGraphWindow final : BaseGraphWindow { const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + if (!HasBit(this->present_cargoes, cs->Index())) continue; if (row-- > 0) continue; ToggleBit(legend_excluded_cargo, cs->Index()); @@ -1840,25 +1833,32 @@ struct StationCargoGraphWindow final : BaseGraphWindow { void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; - this->OnHundredthTick(); + this->FillGraphData(); } - void OnHundredthTick() override + void FillGraphData() { - this->UpdateExcludedData(); - const Station* station = Station::GetIfValid(this->station_id); - if (station == nullptr) return; + this->present_cargoes = station->station_cargo_history_cargoes; + this->vscroll->SetCount(CountBits(this->present_cargoes)); + + this->UpdateExcludedData(); + uint8 i = 0; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + if (!HasBit(this->present_cargoes, cs->Index())) continue; this->colours[i] = cs->legend_colour; + const auto &history = station->station_cargo_history[CountBits(this->present_cargoes & (cs->CargoTypesBit() - 1))]; + + uint offset = station->station_cargo_history_offset; for (uint j = 0; j < MAX_STATION_CARGO_HISTORY_DAYS; j++) { - - this->cost[i][j] = station->station_cargo_history[cs->Index() * MAX_STATION_CARGO_HISTORY_DAYS + j] * STATION_CARGO_HISTORY_FACTOR; + this->cost[i][j] = history[offset]; + offset++; + if (offset == MAX_STATION_CARGO_HISTORY_DAYS) offset = 0; } i++; } diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 8d81d508ac..4a6a63787b 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -459,7 +459,6 @@ static const SaveLoad _station_desc[] = { SLE_CONDVAR(Station, always_accepted, SLE_FILE_U32 | SLE_VAR_U64, SLV_127, SLV_EXTEND_CARGOTYPES), SLE_CONDVAR(Station, always_accepted, SLE_UINT64, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION), SLE_CONDNULL_X(32 * 24, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_22)), - SLE_CONDARR(Station, station_cargo_history, SLE_UINT8, NUM_CARGO * MAX_STATION_CARGO_HISTORY_DAYS, SL_JOKER_1_22, SL_MAX_VERSION), SLE_END() }; diff --git a/src/station.cpp b/src/station.cpp index 69e4e91051..effc2c898d 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -78,7 +78,8 @@ Station::Station(TileIndex tile) : indtype(IT_INVALID), time_since_load(255), time_since_unload(255), - station_cargo_history{} + station_cargo_history_cargoes(0), + station_cargo_history_offset(0) { /* this->random_bits is set in Station::AddFacility() */ } diff --git a/src/station_base.h b/src/station_base.h index ad4e9d0625..c11f1fa24c 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -23,6 +23,7 @@ #include "core/endian_type.hpp" #include #include +#include #include #include #include @@ -808,7 +809,9 @@ public: IndustryList industries_near; ///< Cached list of industries near the station that can accept cargo, @see DeliverGoodsToIndustry() Industry *industry; ///< NOSAVE: Associated industry for neutral stations. (Rebuilt on load from Industry->st) - uint8 station_cargo_history[NUM_CARGO * MAX_STATION_CARGO_HISTORY_DAYS]; ///< Station history of waiting cargo. + CargoTypes station_cargo_history_cargoes; ///< Bitmask of cargoes in station_cargo_history + uint8 station_cargo_history_offset; ///< Start offset in station_cargo_history cargo ring buffer + std::vector> station_cargo_history; ///< Station history of waiting cargo. Station(TileIndex tile = INVALID_TILE); ~Station(); diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 4b3a9ad762..7c45135f35 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -409,16 +409,26 @@ void Station::GetTileArea(TileArea *ta, StationType type) const */ void Station::UpdateCargoHistory() { - const CargoSpec* cs; - FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { - auto amount = this->goods[cs->Index()].cargo.AvailableCount(); - - std::rotate(std::begin(this->station_cargo_history) + cs->Index() * MAX_STATION_CARGO_HISTORY_DAYS, - std::begin(this->station_cargo_history) + cs->Index() * MAX_STATION_CARGO_HISTORY_DAYS + 1, - std::begin(this->station_cargo_history) + (cs->Index() + 1) * MAX_STATION_CARGO_HISTORY_DAYS); - - this->station_cargo_history[(cs->Index() + 1) * MAX_STATION_CARGO_HISTORY_DAYS - 1] = std::clamp(amount / STATION_CARGO_HISTORY_FACTOR, (uint)0, (uint)UINT8_MAX); + uint storage_offset = 0; + bool update_window = false; + for (const CargoSpec *cs : CargoSpec::Iterate()) { + uint amount = this->goods[cs->Index()].cargo.TotalCount(); + 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 */ + continue; + } else { + if (this->station_cargo_history_cargoes == 0) update_window = true; + SetBit(this->station_cargo_history_cargoes, cs->Index()); + this->station_cargo_history.emplace(this->station_cargo_history.begin() + storage_offset); + } + } + this->station_cargo_history[storage_offset][this->station_cargo_history_offset] = static_cast(std::clamp(amount, (uint)0, (uint)UINT16_MAX)); + storage_offset++; } + this->station_cargo_history_offset++; + if (this->station_cargo_history_offset == MAX_STATION_CARGO_HISTORY_DAYS) this->station_cargo_history_offset = 0; + if (update_window) InvalidateWindowData(WC_STATION_VIEW, this->index, -1); } /** @@ -3788,7 +3798,7 @@ bool GetNewGrfRating(const Station *st, const CargoSpec *cs, const GoodsEntry *g { *new_grf_rating = 0; bool is_using_newgrf_rating = false; - + /* Perform custom station rating. If it succeeds the speed, days in transit and * waiting cargo ratings must not be executed. */ @@ -3822,7 +3832,7 @@ int GetSpeedRating(const GoodsEntry *ge) int GetWaitTimeRating(const CargoSpec *cs, const GoodsEntry *ge) { int rating = 0; - + uint wait_time = ge->time_since_pickup; if (_settings_game.station.cargo_class_rating_wait_time) { @@ -3895,7 +3905,7 @@ int GetTargetRating(const Station *st, const CargoSpec *cs, const GoodsEntry *ge } else if (HasBit(cs->callback_mask, CBM_CARGO_STATION_RATING_CALC)) { int new_grf_rating; - + if (GetNewGrfRating(st, cs, ge, &new_grf_rating)) { skip = true; rating += new_grf_rating; @@ -4265,6 +4275,7 @@ void StationDailyLoop() for (Station *st : Station::Iterate()) { st->UpdateCargoHistory(); } + InvalidateWindowClassesData(WC_STATION_CARGO); } } diff --git a/src/station_gui.cpp b/src/station_gui.cpp index b5456d3a27..8477a7ad74 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -1366,6 +1366,12 @@ struct StationViewWindow : public Window { SetViewportCatchmentStation(Station::Get(this->window_number), false); } + void OnInit() override + { + const Station *st = Station::Get(this->window_number); + SetWidgetDisabledState(WID_SV_HISTORY, st->station_cargo_history_cargoes == 0); + } + /** * Show a certain cargo entry characterized by source/next/dest station, cargo ID and amount of cargo at the * right place in the cargo view. I.e. update as many rows as are expanded following that characterization. diff --git a/src/station_type.h b/src/station_type.h index 2194f59b23..a8e657efc1 100644 --- a/src/station_type.h +++ b/src/station_type.h @@ -28,7 +28,6 @@ static const StationID NEW_STATION = 0xFFFE; static const StationID INVALID_STATION = 0xFFFF; static const uint MAX_STATION_CARGO_HISTORY_DAYS = 24; -static const uint STATION_CARGO_HISTORY_FACTOR = 25; typedef SmallStack StationIDStack;