mirror of https://github.com/OpenTTD/OpenTTD
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
parent
9b55ad5b8d
commit
290144c5c9
|
@ -222,6 +222,7 @@ protected:
|
||||||
const Tprojection &proj; ///< Projection to apply.
|
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 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;
|
transported.dash = 2;
|
||||||
auto transported_filler = Filler{transported, &Industry::ProducedHistory::transported};
|
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();
|
this->SetDirty();
|
||||||
|
|
|
@ -89,6 +89,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
||||||
TileArea location{INVALID_TILE, 0, 0}; ///< Location of the industry
|
TileArea location{INVALID_TILE, 0, 0}; ///< Location of the industry
|
||||||
Town *town = nullptr; ///< Nearest town
|
Town *town = nullptr; ///< Nearest town
|
||||||
Station *neutral_station = nullptr; ///< Associated neutral station
|
Station *neutral_station = nullptr; ///< Associated neutral station
|
||||||
|
ValidHistoryMask valid_history = 0; ///< Mask of valid history records.
|
||||||
ProducedCargoes produced{}; ///< produced cargo slots
|
ProducedCargoes produced{}; ///< produced cargo slots
|
||||||
AcceptedCargoes accepted{}; ///< accepted cargo slots
|
AcceptedCargoes accepted{}; ///< accepted cargo slots
|
||||||
uint8_t prod_level = 0; ///< general production level
|
uint8_t prod_level = 0; ///< general production level
|
||||||
|
|
|
@ -1837,6 +1837,8 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
||||||
for (auto &p : i->produced) {
|
for (auto &p : i->produced) {
|
||||||
p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false);
|
p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateValidHistory(i->valid_history);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indspec->callback_mask.Test(IndustryCallbackMask::DecideColour)) {
|
if (indspec->callback_mask.Test(IndustryCallbackMask::DecideColour)) {
|
||||||
|
@ -2494,6 +2496,8 @@ void GenerateIndustries()
|
||||||
*/
|
*/
|
||||||
static void UpdateIndustryStatistics(Industry *i)
|
static void UpdateIndustryStatistics(Industry *i)
|
||||||
{
|
{
|
||||||
|
UpdateValidHistory(i->valid_history);
|
||||||
|
|
||||||
for (auto &p : i->produced) {
|
for (auto &p : i->produced) {
|
||||||
if (IsValidCargoType(p.cargo)) {
|
if (IsValidCargoType(p.cargo)) {
|
||||||
if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year;
|
if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year;
|
||||||
|
|
|
@ -10,8 +10,18 @@
|
||||||
#ifndef HISTORY_FUNC_HPP
|
#ifndef HISTORY_FUNC_HPP
|
||||||
#define HISTORY_FUNC_HPP
|
#define HISTORY_FUNC_HPP
|
||||||
|
|
||||||
|
#include "../core/bitmath_func.hpp"
|
||||||
#include "history_type.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.
|
* Rotate history.
|
||||||
* @tparam T type of history data element.
|
* @tparam T type of history data element.
|
||||||
|
@ -27,14 +37,19 @@ void RotateHistory(HistoryData<T> &history)
|
||||||
/**
|
/**
|
||||||
* Fill some data with historical data.
|
* Fill some data with historical data.
|
||||||
* @param history Historical data to fill from.
|
* @param history Historical data to fill from.
|
||||||
|
* @param valid_history Mask of valid history records.
|
||||||
* @param fillers Fillers to fill with history data.
|
* @param fillers Fillers to fill with history data.
|
||||||
*/
|
*/
|
||||||
template <uint N, typename T, typename... Tfillers>
|
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) {
|
for (uint i = 0; i != N; ++i) {
|
||||||
|
if (HasBit(valid_history, N - i)) {
|
||||||
auto &data = history[N - i];
|
auto &data = history[N - i];
|
||||||
(fillers.Fill(i, data), ...);
|
(fillers.Fill(i, data), ...);
|
||||||
|
} else {
|
||||||
|
(fillers.MakeInvalid(i), ...);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,4 +22,7 @@ static constexpr uint8_t LAST_MONTH = 1;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using HistoryData = std::array<T, HISTORY_RECORDS>;
|
using HistoryData = std::array<T, HISTORY_RECORDS>;
|
||||||
|
|
||||||
|
/** Mask of valid history records. */
|
||||||
|
using ValidHistoryMask = uint64_t;
|
||||||
|
|
||||||
#endif /* HISTORY_TYPE_HPP */
|
#endif /* HISTORY_TYPE_HPP */
|
||||||
|
|
|
@ -162,6 +162,8 @@ static const SaveLoad _industry_desc[] = {
|
||||||
SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION),
|
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_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("accepted", SlIndustryAccepted, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
|
||||||
SLEG_CONDSTRUCTLIST("produced", SlIndustryProduced, 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)) {
|
} else if (IsSavegameVersionBefore(SLV_INDUSTRY_CARGO_REORGANISE)) {
|
||||||
LoadMoveAcceptsProduced(i, INDUSTRY_NUM_INPUTS, INDUSTRY_NUM_OUTPUTS);
|
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);
|
Industry::industries[i->type].insert(i->index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -404,6 +404,7 @@ enum SaveLoadVersion : uint16_t {
|
||||||
SLV_ORDERS_OWNED_BY_ORDERLIST, ///< 354 PR#13948 Orders stored in OrderList, pool removed.
|
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_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
|
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue