mirror of https://github.com/OpenTTD/OpenTTD.git
Codechange: Store accepted and produced cargo in vector instead of array.
Most industries do not use the full 16 slots, so this can save a little memory and iteration time.
This commit is contained in:
parent
00e0021e3a
commit
3de8853e29
|
@ -90,14 +90,14 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
|||
TimerGameEconomy::Date last_accepted; ///< Last day cargo was accepted by this industry
|
||||
};
|
||||
|
||||
using ProducedCargoArray = std::array<ProducedCargo, INDUSTRY_NUM_OUTPUTS>;
|
||||
using AcceptedCargoArray = std::array<AcceptedCargo, INDUSTRY_NUM_INPUTS>;
|
||||
using ProducedCargoes = std::vector<ProducedCargo>;
|
||||
using AcceptedCargoes = std::vector<AcceptedCargo>;
|
||||
|
||||
TileArea location; ///< Location of the industry
|
||||
Town *town; ///< Nearest town
|
||||
Station *neutral_station; ///< Associated neutral station
|
||||
ProducedCargoArray produced; ///< INDUSTRY_NUM_OUTPUTS production cargo slots
|
||||
AcceptedCargoArray accepted; ///< INDUSTRY_NUM_INPUTS input cargo slots
|
||||
ProducedCargoes produced; ///< produced cargo slots
|
||||
AcceptedCargoes accepted; ///< accepted cargo slots
|
||||
uint8_t prod_level; ///< general production level
|
||||
uint16_t counter; ///< used for animation and/or production (if available cargo)
|
||||
|
||||
|
@ -166,7 +166,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
|||
* @param cargo CargoID to find.
|
||||
* @return Iterator pointing to produced cargo slot if it exists, or the end iterator.
|
||||
*/
|
||||
inline ProducedCargoArray::iterator GetCargoProduced(CargoID cargo)
|
||||
inline ProducedCargoes::iterator GetCargoProduced(CargoID cargo)
|
||||
{
|
||||
if (!IsValidCargoID(cargo)) return std::end(this->produced);
|
||||
return std::find_if(std::begin(this->produced), std::end(this->produced), [&cargo](const auto &p) { return p.cargo == cargo; });
|
||||
|
@ -177,7 +177,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
|||
* @param cargo CargoID to find.
|
||||
* @return Iterator pointing to produced cargo slot if it exists, or the end iterator.
|
||||
*/
|
||||
inline ProducedCargoArray::const_iterator GetCargoProduced(CargoID cargo) const
|
||||
inline ProducedCargoes::const_iterator GetCargoProduced(CargoID cargo) const
|
||||
{
|
||||
if (!IsValidCargoID(cargo)) return std::end(this->produced);
|
||||
return std::find_if(std::begin(this->produced), std::end(this->produced), [&cargo](const auto &p) { return p.cargo == cargo; });
|
||||
|
@ -188,7 +188,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
|||
* @param cargo CargoID to find.
|
||||
* @return Iterator pointing to accepted cargo slot if it exists, or the end iterator.
|
||||
*/
|
||||
inline AcceptedCargoArray::iterator GetCargoAccepted(CargoID cargo)
|
||||
inline AcceptedCargoes::iterator GetCargoAccepted(CargoID cargo)
|
||||
{
|
||||
if (!IsValidCargoID(cargo)) return std::end(this->accepted);
|
||||
return std::find_if(std::begin(this->accepted), std::end(this->accepted), [&cargo](const auto &a) { return a.cargo == cargo; });
|
||||
|
@ -332,4 +332,6 @@ enum IndustryDirectoryInvalidateWindowData {
|
|||
IDIWD_FORCE_RESORT,
|
||||
};
|
||||
|
||||
void TrimIndustryAcceptedProduced(Industry *ind);
|
||||
|
||||
#endif /* INDUSTRY_H */
|
||||
|
|
|
@ -1788,15 +1788,19 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
|||
i->type = type;
|
||||
Industry::IncIndustryTypeCount(type);
|
||||
|
||||
for (auto it = std::begin(i->produced); it != std::end(i->produced); ++it) {
|
||||
size_t index = it - std::begin(i->produced);
|
||||
it->cargo = indspec->produced_cargo[index];
|
||||
it->rate = indspec->production_rate[index];
|
||||
for (size_t index = 0; index < lengthof(indspec->produced_cargo); ++index) {
|
||||
if (!IsValidCargoID(indspec->produced_cargo[index])) break;
|
||||
|
||||
Industry::ProducedCargo &p = i->produced.emplace_back();
|
||||
p.cargo = indspec->produced_cargo[index];
|
||||
p.rate = indspec->production_rate[index];
|
||||
}
|
||||
|
||||
for (auto it = std::begin(i->accepted); it != std::end(i->accepted); ++it) {
|
||||
size_t index = it - std::begin(i->accepted);
|
||||
it->cargo = indspec->accepts_cargo[index];
|
||||
for (size_t index = 0; index < lengthof(indspec->accepts_cargo); ++index) {
|
||||
if (!IsValidCargoID(indspec->accepts_cargo[index])) break;
|
||||
|
||||
Industry::AcceptedCargo &a = i->accepted.emplace_back();
|
||||
a.cargo = indspec->accepts_cargo[index];
|
||||
}
|
||||
|
||||
/* Randomize inital production if non-original economy is used and there are no production related callbacks. */
|
||||
|
@ -1870,7 +1874,7 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
|||
|
||||
if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
|
||||
/* Clear all input cargo types */
|
||||
for (auto &a : i->accepted) a.cargo = INVALID_CARGO;
|
||||
i->accepted.clear();
|
||||
/* Query actual types */
|
||||
uint maxcargoes = (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) ? static_cast<uint>(i->accepted.size()) : 3;
|
||||
for (uint j = 0; j < maxcargoes; j++) {
|
||||
|
@ -1884,7 +1888,12 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
|||
/* Industries without "unlimited" cargo types support depend on the specific order/slots of cargo types.
|
||||
* They need to be able to blank out specific slots without aborting the callback sequence,
|
||||
* and solve this by returning undefined cargo indexes. Skip these. */
|
||||
if (!IsValidCargoID(cargo) && !(indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED)) continue;
|
||||
if (!IsValidCargoID(cargo) && !(indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED)) {
|
||||
/* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
|
||||
Industry::AcceptedCargo &a = i->accepted.emplace_back();
|
||||
a.cargo = INVALID_CARGO;
|
||||
continue;
|
||||
}
|
||||
/* Verify valid cargo */
|
||||
if (std::find(indspec->accepts_cargo, endof(indspec->accepts_cargo), cargo) == endof(indspec->accepts_cargo)) {
|
||||
/* Cargo not in spec, error in NewGRF */
|
||||
|
@ -1896,13 +1905,14 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
|||
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
|
||||
break;
|
||||
}
|
||||
i->accepted[j].cargo = cargo;
|
||||
Industry::AcceptedCargo &a = i->accepted.emplace_back();
|
||||
a.cargo = cargo;
|
||||
}
|
||||
}
|
||||
|
||||
if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
|
||||
/* Clear all output cargo types */
|
||||
for (auto &p : i->produced) p.cargo = INVALID_CARGO;
|
||||
i->produced.clear();
|
||||
/* Query actual types */
|
||||
uint maxcargoes = (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) ? static_cast<uint>(i->produced.size()) : 2;
|
||||
for (uint j = 0; j < maxcargoes; j++) {
|
||||
|
@ -1914,7 +1924,12 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
|||
}
|
||||
CargoID cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
|
||||
/* Allow older GRFs to skip slots. */
|
||||
if (!IsValidCargoID(cargo) && !(indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED)) continue;
|
||||
if (!IsValidCargoID(cargo) && !(indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED)) {
|
||||
/* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
|
||||
Industry::ProducedCargo &p = i->produced.emplace_back();
|
||||
p.cargo = INVALID_CARGO;
|
||||
continue;
|
||||
}
|
||||
/* Verify valid cargo */
|
||||
if (std::find(indspec->produced_cargo, endof(indspec->produced_cargo), cargo) == endof(indspec->produced_cargo)) {
|
||||
/* Cargo not in spec, error in NewGRF */
|
||||
|
@ -1926,7 +1941,8 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
|||
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
|
||||
break;
|
||||
}
|
||||
i->produced[j].cargo = cargo;
|
||||
Industry::ProducedCargo &p = i->produced.emplace_back();
|
||||
p.cargo = cargo;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3212,3 +3228,18 @@ bool IndustryCompare::operator() (const IndustryListEntry &lhs, const IndustryLi
|
|||
/* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unused industry accepted/produced slots -- entries after the last slot with valid cargo.
|
||||
* @param ind Industry to trim slots.
|
||||
*/
|
||||
void TrimIndustryAcceptedProduced(Industry *ind)
|
||||
{
|
||||
auto ita = std::find_if(std::rbegin(ind->accepted), std::rend(ind->accepted), [](const auto &a) { return IsValidCargoID(a.cargo); });
|
||||
ind->accepted.erase(ita.base(), std::end(ind->accepted));
|
||||
ind->accepted.shrink_to_fit();
|
||||
|
||||
auto itp = std::find_if(std::rbegin(ind->produced), std::rend(ind->produced), [](const auto &p) { return IsValidCargoID(p.cargo); });
|
||||
ind->produced.erase(itp.base(), std::end(ind->produced));
|
||||
ind->produced.shrink_to_fit();
|
||||
}
|
||||
|
|
|
@ -3044,16 +3044,6 @@ bool AfterLoadGame()
|
|||
if (IsSavegameVersionBefore(SLV_EXTEND_INDUSTRY_CARGO_SLOTS)) {
|
||||
/* Make sure added industry cargo slots are cleared */
|
||||
for (Industry *i : Industry::Iterate()) {
|
||||
for (auto it = std::begin(i->produced) + 2; it != std::end(i->produced); ++it) {
|
||||
it->cargo = INVALID_CARGO;
|
||||
it->waiting = 0;
|
||||
it->rate = 0;
|
||||
it->history = {};
|
||||
}
|
||||
for (auto it = std::begin(i->accepted) + 3; it != std::end(i->accepted); ++it) {
|
||||
it->cargo = INVALID_CARGO;
|
||||
it->waiting = 0;
|
||||
}
|
||||
/* Make sure last_cargo_accepted_at is copied to elements for every valid input cargo.
|
||||
* The loading routine should put the original singular value into the first array element. */
|
||||
for (auto &a : i->accepted) {
|
||||
|
|
|
@ -39,11 +39,12 @@ public:
|
|||
|
||||
void Load(Industry *i) const override
|
||||
{
|
||||
size_t len = SlGetStructListLength(i->accepted.size());
|
||||
size_t len = SlGetStructListLength(INDUSTRY_NUM_INPUTS);
|
||||
|
||||
for (auto &a : i->accepted) {
|
||||
if (--len > i->accepted.size()) break; // unsigned so wraps after hitting zero.
|
||||
SlObject(&a, this->GetDescription());
|
||||
i->accepted.reserve(len);
|
||||
for (size_t index = 0; index < len; ++index) {
|
||||
auto &a = i->accepted.emplace_back();
|
||||
SlObject(&a, this->GetLoadDescription());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,11 +116,12 @@ public:
|
|||
|
||||
void Load(Industry *i) const override
|
||||
{
|
||||
size_t len = SlGetStructListLength(i->produced.size());
|
||||
size_t len = SlGetStructListLength(INDUSTRY_NUM_OUTPUTS);
|
||||
|
||||
for (auto &p : i->produced) {
|
||||
if (--len > i->produced.size()) break; // unsigned so wraps after hitting zero.
|
||||
SlObject(&p, this->GetDescription());
|
||||
i->produced.reserve(len);
|
||||
for (size_t index = 0; index < len; ++index) {
|
||||
auto &p = i->produced.emplace_back();
|
||||
SlObject(&p, this->GetLoadDescription());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,17 +216,19 @@ struct INDYChunkHandler : ChunkHandler {
|
|||
}
|
||||
}
|
||||
|
||||
void LoadMoveAcceptsProduced(Industry *i) const
|
||||
void LoadMoveAcceptsProduced(Industry *i, uint inputs, uint outputs) const
|
||||
{
|
||||
for (uint j = 0; j != INDUSTRY_NUM_INPUTS; ++j) {
|
||||
auto &a = i->accepted[j];
|
||||
i->accepted.reserve(inputs);
|
||||
for (uint j = 0; j != inputs; ++j) {
|
||||
auto &a = i->accepted.emplace_back();
|
||||
a.cargo = SlIndustryAccepted::old_cargo[j];
|
||||
a.waiting = SlIndustryAccepted::old_waiting[j];
|
||||
a.last_accepted = SlIndustryAccepted::old_last_accepted[j];
|
||||
}
|
||||
|
||||
for (uint j = 0; j != INDUSTRY_NUM_OUTPUTS; ++j) {
|
||||
auto &p = i->produced[j];
|
||||
i->produced.reserve(outputs);
|
||||
for (uint j = 0; j != outputs; ++j) {
|
||||
auto &p = i->produced.emplace_back();
|
||||
p.cargo = SlIndustryProduced::old_cargo[j];
|
||||
p.waiting = SlIndustryProduced::old_waiting[j];
|
||||
p.rate = SlIndustryProduced::old_rate[j];
|
||||
|
@ -256,8 +260,13 @@ struct INDYChunkHandler : ChunkHandler {
|
|||
i->psa = new PersistentStorage(0, 0, 0);
|
||||
std::copy(std::begin(_old_ind_persistent_storage.storage), std::end(_old_ind_persistent_storage.storage), std::begin(i->psa->storage));
|
||||
}
|
||||
if (IsSavegameVersionBefore(SLV_INDUSTRY_CARGO_REORGANISE)) LoadMoveAcceptsProduced(i);
|
||||
if (IsSavegameVersionBefore(SLV_EXTEND_INDUSTRY_CARGO_SLOTS)) {
|
||||
LoadMoveAcceptsProduced(i, 3, 2);
|
||||
} else if (IsSavegameVersionBefore(SLV_INDUSTRY_CARGO_REORGANISE)) {
|
||||
LoadMoveAcceptsProduced(i, INDUSTRY_NUM_INPUTS, INDUSTRY_NUM_OUTPUTS);
|
||||
}
|
||||
Industry::IncIndustryTypeCount(i->type);
|
||||
TrimIndustryAcceptedProduced(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -804,6 +804,10 @@ static bool LoadOldStation(LoadgameState *ls, int num)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Old save games always have 3 input and 2 output slots per industry. */
|
||||
static std::array<Industry::AcceptedCargo, 3> _old_accepted{};
|
||||
static std::array<Industry::ProducedCargo, 2> _old_produced{};
|
||||
|
||||
static const OldChunks industry_chunk[] = {
|
||||
OCL_SVAR( OC_TILE, Industry, location.tile ),
|
||||
OCL_VAR ( OC_UINT32, 1, &_old_town_index ),
|
||||
|
@ -811,29 +815,29 @@ static const OldChunks industry_chunk[] = {
|
|||
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Industry, location.h ),
|
||||
OCL_NULL( 2 ), ///< used to be industry's produced_cargo
|
||||
|
||||
OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced[0].waiting ),
|
||||
OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced[1].waiting ),
|
||||
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced[0].waiting ),
|
||||
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced[1].waiting ),
|
||||
OCL_VAR( OC_TTD | OC_UINT16, 1, &_old_produced[0].waiting ),
|
||||
OCL_VAR( OC_TTD | OC_UINT16, 1, &_old_produced[1].waiting ),
|
||||
OCL_VAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, 1, &_old_produced[0].waiting ),
|
||||
OCL_VAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, 1, &_old_produced[1].waiting ),
|
||||
|
||||
OCL_SVAR( OC_UINT8, Industry, produced[0].rate ),
|
||||
OCL_SVAR( OC_UINT8, Industry, produced[1].rate ),
|
||||
OCL_VAR( OC_UINT8, 1, &_old_produced[0].rate ),
|
||||
OCL_VAR( OC_UINT8, 1, &_old_produced[1].rate ),
|
||||
|
||||
OCL_NULL( 3 ), ///< used to be industry's accepts_cargo
|
||||
|
||||
OCL_SVAR( OC_UINT8, Industry, prod_level ),
|
||||
|
||||
OCL_SVAR( OC_UINT16, Industry, produced[0].history[THIS_MONTH].production ),
|
||||
OCL_SVAR( OC_UINT16, Industry, produced[1].history[THIS_MONTH].production ),
|
||||
OCL_SVAR( OC_UINT16, Industry, produced[0].history[THIS_MONTH].transported ),
|
||||
OCL_SVAR( OC_UINT16, Industry, produced[1].history[THIS_MONTH].transported ),
|
||||
OCL_VAR( OC_UINT16, 1, &_old_produced[0].history[THIS_MONTH].production ),
|
||||
OCL_VAR( OC_UINT16, 1, &_old_produced[1].history[THIS_MONTH].production ),
|
||||
OCL_VAR( OC_UINT16, 1, &_old_produced[0].history[THIS_MONTH].transported ),
|
||||
OCL_VAR( OC_UINT16, 1, &_old_produced[1].history[THIS_MONTH].transported ),
|
||||
|
||||
OCL_NULL( 2 ), ///< last_month_pct_transported, now computed on the fly
|
||||
|
||||
OCL_SVAR( OC_UINT16, Industry, produced[0].history[LAST_MONTH].production ),
|
||||
OCL_SVAR( OC_UINT16, Industry, produced[1].history[LAST_MONTH].production ),
|
||||
OCL_SVAR( OC_UINT16, Industry, produced[0].history[LAST_MONTH].transported ),
|
||||
OCL_SVAR( OC_UINT16, Industry, produced[1].history[LAST_MONTH].transported ),
|
||||
OCL_VAR( OC_UINT16, 1, &_old_produced[0].history[LAST_MONTH].production ),
|
||||
OCL_VAR( OC_UINT16, 1, &_old_produced[1].history[LAST_MONTH].production ),
|
||||
OCL_VAR( OC_UINT16, 1, &_old_produced[0].history[LAST_MONTH].transported ),
|
||||
OCL_VAR( OC_UINT16, 1, &_old_produced[1].history[LAST_MONTH].transported ),
|
||||
|
||||
OCL_SVAR( OC_UINT8, Industry, type ),
|
||||
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, counter ),
|
||||
|
@ -854,6 +858,10 @@ static bool LoadOldIndustry(LoadgameState *ls, int num)
|
|||
if (!LoadChunk(ls, i, industry_chunk)) return false;
|
||||
|
||||
if (i->location.tile != 0) {
|
||||
/* Copy data from old fixed arrays to industry. */
|
||||
std::copy(std::begin(_old_accepted), std::end(_old_accepted), std::back_inserter(i->accepted));
|
||||
std::copy(std::begin(_old_produced), std::end(_old_produced), std::back_inserter(i->produced));
|
||||
|
||||
i->town = RemapTown(i->location.tile);
|
||||
|
||||
if (_savegame_type == SGT_TTO) {
|
||||
|
@ -867,6 +875,7 @@ static bool LoadOldIndustry(LoadgameState *ls, int num)
|
|||
}
|
||||
|
||||
Industry::IncIndustryTypeCount(i->type);
|
||||
TrimIndustryAcceptedProduced(i);
|
||||
} else {
|
||||
delete i;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue