1
0
Fork 0

Fix #14396: Industry production graph showed zero instead of N/A.

Record the number of valid history records per industry so that the graph avoids showing values which are not present as zero.
pull/14321/head
Peter Nelson 2025-07-06 15:33:22 +01:00 committed by Peter Nelson
parent 9b55ad5b8d
commit 290144c5c9
7 changed files with 49 additions and 4 deletions

View File

@ -222,6 +222,7 @@ protected:
const Tprojection &proj; ///< Projection to apply.
inline void Fill(uint i, const auto &data) const { this->dataset.values[i] = std::invoke(this->proj, data); }
inline void MakeInvalid(uint i) const { this->dataset.values[i] = INVALID_DATAPOINT; }
};
/**
@ -1685,7 +1686,7 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
transported.dash = 2;
auto transported_filler = Filler{transported, &Industry::ProducedHistory::transported};
FillFromHistory<GRAPH_NUM_MONTHS>(p.history, produced_filler, transported_filler);
FillFromHistory<GRAPH_NUM_MONTHS>(p.history, i->valid_history, produced_filler, transported_filler);
}
this->SetDirty();

View File

@ -89,6 +89,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
TileArea location{INVALID_TILE, 0, 0}; ///< Location of the industry
Town *town = nullptr; ///< Nearest town
Station *neutral_station = nullptr; ///< Associated neutral station
ValidHistoryMask valid_history = 0; ///< Mask of valid history records.
ProducedCargoes produced{}; ///< produced cargo slots
AcceptedCargoes accepted{}; ///< accepted cargo slots
uint8_t prod_level = 0; ///< general production level

View File

@ -1837,6 +1837,8 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
for (auto &p : i->produced) {
p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false);
}
UpdateValidHistory(i->valid_history);
}
if (indspec->callback_mask.Test(IndustryCallbackMask::DecideColour)) {
@ -2494,6 +2496,8 @@ void GenerateIndustries()
*/
static void UpdateIndustryStatistics(Industry *i)
{
UpdateValidHistory(i->valid_history);
for (auto &p : i->produced) {
if (IsValidCargoType(p.cargo)) {
if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year;

View File

@ -10,8 +10,18 @@
#ifndef HISTORY_FUNC_HPP
#define HISTORY_FUNC_HPP
#include "../core/bitmath_func.hpp"
#include "history_type.hpp"
/**
* Update mask of valid history records.
* @param[in,out] valid_history Valid history records.
*/
inline void UpdateValidHistory(ValidHistoryMask &valid_history)
{
SB(valid_history, LAST_MONTH, HISTORY_RECORDS - LAST_MONTH, GB(valid_history, LAST_MONTH, HISTORY_RECORDS - LAST_MONTH) << 1ULL | 1ULL);
}
/**
* Rotate history.
* @tparam T type of history data element.
@ -27,14 +37,19 @@ void RotateHistory(HistoryData<T> &history)
/**
* Fill some data with historical data.
* @param history Historical data to fill from.
* @param valid_history Mask of valid history records.
* @param fillers Fillers to fill with history data.
*/
template <uint N, typename T, typename... Tfillers>
void FillFromHistory(const HistoryData<T> &history, Tfillers... fillers)
void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, Tfillers... fillers)
{
for (uint i = 0; i != N; ++i) {
if (HasBit(valid_history, N - i)) {
auto &data = history[N - i];
(fillers.Fill(i, data), ...);
} else {
(fillers.MakeInvalid(i), ...);
}
}
}

View File

@ -22,4 +22,7 @@ static constexpr uint8_t LAST_MONTH = 1;
template <typename T>
using HistoryData = std::array<T, HISTORY_RECORDS>;
/** Mask of valid history records. */
using ValidHistoryMask = uint64_t;
#endif /* HISTORY_TYPE_HPP */

View File

@ -162,6 +162,8 @@ static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION),
SLE_CONDSSTR(Industry, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_INDUSTRY_TEXT, SL_MAX_VERSION),
SLE_CONDVAR(Industry, valid_history, SLE_UINT64, SLV_INDUSTRY_NUM_VALID_HISTORY, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("accepted", SlIndustryAccepted, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("produced", SlIndustryProduced, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
};
@ -228,6 +230,24 @@ struct INDYChunkHandler : ChunkHandler {
} else if (IsSavegameVersionBefore(SLV_INDUSTRY_CARGO_REORGANISE)) {
LoadMoveAcceptsProduced(i, INDUSTRY_NUM_INPUTS, INDUSTRY_NUM_OUTPUTS);
}
if (IsSavegameVersionBefore(SLV_INDUSTRY_NUM_VALID_HISTORY)) {
/* The last month has always been recorded. */
size_t oldest_valid = LAST_MONTH;
if (!IsSavegameVersionBefore(SLV_PRODUCTION_HISTORY)) {
/* History was extended but we did not keep track of valid history, so assume it from the oldest non-zero value. */
for (const auto &p : i->produced) {
if (!IsValidCargoType(p.cargo)) continue;
for (size_t n = LAST_MONTH; n < std::size(p.history); ++n) {
if (p.history[n].production == 0 && p.history[n].transported == 0) continue;
oldest_valid = std::max(oldest_valid, n);
}
}
}
/* Set mask bits up to and including the oldest valid record. */
i->valid_history = (std::numeric_limits<uint64_t>::max() >> (std::numeric_limits<uint64_t>::digits - (oldest_valid + 1 - LAST_MONTH))) << LAST_MONTH;
}
Industry::industries[i->type].insert(i->index);
}
}

View File

@ -404,6 +404,7 @@ enum SaveLoadVersion : uint16_t {
SLV_ORDERS_OWNED_BY_ORDERLIST, ///< 354 PR#13948 Orders stored in OrderList, pool removed.
SLV_FACE_STYLES, ///< 355 PR#14319 Addition of face styles, replacing gender and ethnicity.
SLV_INDUSTRY_NUM_VALID_HISTORY, ///< 356 PR#14416 Store number of valid history records for industries.
SL_MAX_VERSION, ///< Highest possible saveload version
};