diff --git a/src/command.cpp b/src/command.cpp index b5865ad4ae..ffac3dd45c 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -421,7 +421,7 @@ uint32_t CommandCost::textref_stack[16]; */ void CommandCost::UseTextRefStack(const GRFFile *grffile, uint num_registers) { - extern TemporaryStorageArray _temp_store; + extern TemporaryStorageArray _temp_store; assert(num_registers < lengthof(textref_stack)); this->textref_stack_grffile = grffile; diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index a126193fbc..522390f344 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -195,7 +195,7 @@ public: * @param grfid Parameter for the PSA. Only required for items with parameters. * @return Span of the storage array or an empty span when not present. */ - virtual const std::span GetPSA([[maybe_unused]] uint index, [[maybe_unused]] uint32_t grfid) const + virtual std::span GetPSA([[maybe_unused]] uint index, [[maybe_unused]] uint32_t grfid) const { return {}; } @@ -477,9 +477,11 @@ struct NewGRFInspectWindow : Window { } else { this->DrawString(r, i++, "Persistent storage:"); } - assert(psa.size() % 4 == 0); - for (size_t j = 0; j < psa.size(); j += 4) { - this->DrawString(r, i++, fmt::format(" {}: {} {} {} {}", j, psa[j], psa[j + 1], psa[j + 2], psa[j + 3])); + for (uint index = 0; const int32_t &value : psa) { + if (value != 0) { + this->DrawString(r, i++, fmt::format(" {:02x}: {:08x} ({})", index, value, value)); + } + ++index; } } diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 98e31571b7..e1e3badc37 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -24,6 +24,7 @@ #include "newgrf_railtype.h" #include "newgrf_roadtype.h" #include "ship.h" +#include "newgrf_debug.h" #include "safeguards.h" @@ -315,6 +316,23 @@ static uint8_t MapAircraftMovementAction(const Aircraft *v) return this->v == nullptr ? 0 : this->v->waiting_triggers; } +/* virtual */ void VehicleScopeResolver::StorePSA(uint pos, int32_t value) +{ + if (this->v == nullptr) return; + + /* const_cast because we're in too deep to change Vehicle to be non-const. */ + Vehicle *v = const_cast(this->v); + if (v->psa == nullptr) { + /* There is no need to create a storage if the value is zero. */ + if (value == 0) return; + + uint32_t grfid = (this->ro.grffile != nullptr) ? this->ro.grffile->grfid : 0; + assert(PersistentStorage::CanAllocateItem()); + v->psa = new PersistentStorage(grfid, GetGrfSpecFeature(this->v->type), INVALID_TILE); + } + v->psa->StoreValue(pos, value); +} + /* virtual */ ScopeResolver *VehicleResolverObject::GetScope(VarSpriteGroupScope scope, uint8_t relative) { @@ -693,6 +711,8 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec default: return 0x00; } + case 0x7C: return (v->psa != nullptr) ? v->psa->GetValue(parameter) : 0; + case 0xFE: case 0xFF: { uint16_t modflags = 0; diff --git a/src/newgrf_engine.h b/src/newgrf_engine.h index c08e4b19f7..f31a0b5326 100644 --- a/src/newgrf_engine.h +++ b/src/newgrf_engine.h @@ -41,6 +41,7 @@ struct VehicleScopeResolver : public ScopeResolver { uint32_t GetRandomBits() const override; uint32_t GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const override; uint32_t GetTriggers() const override; + void StorePSA(uint pos, int32_t value) override; }; /** Resolver for a vehicle (chain) */ diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index 1b8596659e..ae5bbb34fe 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -18,7 +18,7 @@ SpriteGroupPool _spritegroup_pool("SpriteGroup"); INSTANTIATE_POOL_METHODS(SpriteGroup) -TemporaryStorageArray _temp_store; +TemporaryStorageArray _temp_store; /** diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 32eba6af32..1b9f2a79f8 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -28,7 +28,7 @@ */ inline uint32_t GetRegister(uint i) { - extern TemporaryStorageArray _temp_store; + extern TemporaryStorageArray _temp_store; return _temp_store.GetValue(i); } diff --git a/src/newgrf_storage.cpp b/src/newgrf_storage.cpp index ae90bfd555..54d3faecc3 100644 --- a/src/newgrf_storage.cpp +++ b/src/newgrf_storage.cpp @@ -39,11 +39,47 @@ BasePersistentStorageArray::~BasePersistentStorageArray() * arrays, which saves quite a few clears, etc. after callbacks. * @param storage the array that has changed */ -void AddChangedPersistentStorage(BasePersistentStorageArray *storage) +static void AddChangedPersistentStorage(BasePersistentStorageArray *storage) { _changed_storage_arrays->insert(storage); } +/** + * Stores some value at a given position. + * If there is no backup of the data that backup is made and then + * we write the data. + * @param pos the position to write at + * @param value the value to write + */ +void PersistentStorageArray::StoreValue(uint pos, int32_t value) +{ + /* Out of the scope of the array */ + if (pos >= PersistentStorageArray::SIZE) return; + + if (pos >= std::size(this->storage)) { + if (value == 0) return; + + this->storage.resize(pos + 1); + } else { + /* The value hasn't changed, so we pretend nothing happened. + * Saves a few cycles and such and it's pretty easy to check. */ + if (value == this->storage[pos]) return; + } + + /* We do not have made a backup; lets do so */ + if (AreChangesPersistent()) { + assert(!this->prev_storage); + } else if (!this->prev_storage) { + this->prev_storage = std::make_unique(this->storage); + + /* We only need to register ourselves when we made the backup + * as that is the only time something will have changed */ + AddChangedPersistentStorage(this); + } + + this->storage[pos] = value; +} + /** * Clear temporary changes made since the last call to SwitchMode, and * set whether subsequent changes shall be persistent or temporary. diff --git a/src/newgrf_storage.h b/src/newgrf_storage.h index 3db901b984..33894d09b3 100644 --- a/src/newgrf_storage.h +++ b/src/newgrf_storage.h @@ -60,60 +60,30 @@ private: /** * Class for persistent storage of data. * On #ClearChanges that data is either reverted or saved. - * @tparam TYPE the type of variable to store. - * @tparam SIZE the size of the array. */ -template struct PersistentStorageArray : BasePersistentStorageArray { - using StorageType = std::array; + using StorageType = std::vector; + static constexpr size_t SIZE = 256; StorageType storage{}; ///< Memory for the storage array std::unique_ptr prev_storage{}; ///< Temporary memory to store previous state so it can be reverted, e.g. for command tests. - /** - * Stores some value at a given position. - * If there is no backup of the data that backup is made and then - * we write the data. - * @param pos the position to write at - * @param value the value to write - */ - void StoreValue(uint pos, int32_t value) - { - /* Out of the scope of the array */ - if (pos >= SIZE) return; - - /* The value hasn't changed, so we pretend nothing happened. - * Saves a few cycles and such and it's pretty easy to check. */ - if (this->storage[pos] == value) return; - - /* We do not have made a backup; lets do so */ - if (AreChangesPersistent()) { - assert(!this->prev_storage); - } else if (!this->prev_storage) { - this->prev_storage = std::make_unique(this->storage); - - /* We only need to register ourselves when we made the backup - * as that is the only time something will have changed */ - AddChangedPersistentStorage(this); - } - - this->storage[pos] = value; - } + void StoreValue(uint pos, int32_t value); /** * Gets the value from a given position. * @param pos the position to get the data from * @return the data from that position */ - TYPE GetValue(uint pos) const + inline int32_t GetValue(uint pos) const { /* Out of the scope of the array */ - if (pos >= SIZE) return 0; + if (pos >= std::size(this->storage)) return 0; return this->storage[pos]; } - void ClearChanges() override + inline void ClearChanges() override { if (this->prev_storage) { this->storage = *this->prev_storage; @@ -126,12 +96,11 @@ struct PersistentStorageArray : BasePersistentStorageArray { /** * Class for temporary storage of data. * On #ClearChanges that data is always zero-ed. - * @tparam TYPE the type of variable to store. - * @tparam SIZE the size of the array. */ -template struct TemporaryStorageArray { - using StorageType = std::array; + static constexpr size_t SIZE = 0x110; + + using StorageType = std::array; using StorageInitType = std::array; StorageType storage{}; ///< Memory for the storage array @@ -143,7 +112,7 @@ struct TemporaryStorageArray { * @param pos the position to write at * @param value the value to write */ - void StoreValue(uint pos, int32_t value) + inline void StoreValue(uint pos, int32_t value) { /* Out of the scope of the array */ if (pos >= SIZE) return; @@ -157,7 +126,7 @@ struct TemporaryStorageArray { * @param pos the position to get the data from * @return the data from that position */ - TYPE GetValue(uint pos) const + inline int32_t GetValue(uint pos) const { /* Out of the scope of the array */ if (pos >= SIZE) return 0; @@ -170,7 +139,7 @@ struct TemporaryStorageArray { return this->storage[pos]; } - void ClearChanges() + inline void ClearChanges() { /* Increment init_key to invalidate all storage */ this->init_key++; @@ -182,10 +151,6 @@ struct TemporaryStorageArray { } }; -void AddChangedPersistentStorage(BasePersistentStorageArray *storage); - -typedef PersistentStorageArray OldPersistentStorage; - typedef uint32_t PersistentStorageID; struct PersistentStorage; @@ -196,7 +161,7 @@ extern PersistentStoragePool _persistent_storage_pool; /** * Class for pooled persistent storage of data. */ -struct PersistentStorage : PersistentStorageArray, PersistentStoragePool::PoolItem<&_persistent_storage_pool> { +struct PersistentStorage : PersistentStorageArray, PersistentStoragePool::PoolItem<&_persistent_storage_pool> { /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ PersistentStorage(const uint32_t new_grfid, uint8_t feature, TileIndex tile) { @@ -206,6 +171,7 @@ struct PersistentStorage : PersistentStorageArray, PersistentStora } }; -static_assert(std::tuple_size_v <= std::tuple_size_v); +/* storage_sl.cpp */ +PersistentStorage *ConvertOldPersistentStorage(std::span old_storage); #endif /* NEWGRF_STORAGE_H */ diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index ceed99b30a..07dab9f5b0 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -797,7 +797,7 @@ void RestoreTextRefStackBackup(struct TextRefStack *backup) */ void StartTextRefStackUsage(const GRFFile *grffile, uint8_t numEntries, const uint32_t *values) { - extern TemporaryStorageArray _temp_store; + extern TemporaryStorageArray _temp_store; _newgrf_textrefstack.ResetStack(grffile); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index cfceb63a23..980dc67923 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -48,6 +48,7 @@ #include "../subsidy_base.h" #include "../subsidy_func.h" #include "../newgrf.h" +#include "../newgrf_debug.h" #include "../newgrf_station.h" #include "../engine_func.h" #include "../rail_gui.h" @@ -290,6 +291,11 @@ static void InitializeWindowsAndCaches() it->tile = t->xy; } } + for (Vehicle *v : Vehicle::Iterate()) { + if (v->psa != nullptr) { + v->psa->feature = GetGrfSpecFeature(v->type); + } + } for (RoadVehicle *rv : RoadVehicle::Iterate()) { if (rv->IsFrontEngine()) { rv->CargoChanged(); @@ -2798,16 +2804,7 @@ bool AfterLoadGame() for (Industry *ind : Industry::Iterate()) { assert(ind->psa != nullptr); - /* Check if the old storage was empty. */ - bool is_empty = true; - for (uint i = 0; i < sizeof(ind->psa->storage); i++) { - if (ind->psa->GetValue(i) != 0) { - is_empty = false; - break; - } - } - - if (!is_empty) { + if (!ind->psa->storage.empty()) { ind->psa->grfid = _industry_mngr.GetGRFID(ind->type); } else { delete ind->psa; @@ -2821,21 +2818,11 @@ bool AfterLoadGame() if (!(st->facilities & FACIL_AIRPORT)) continue; assert(st->airport.psa != nullptr); - /* Check if the old storage was empty. */ - bool is_empty = true; - for (uint i = 0; i < sizeof(st->airport.psa->storage); i++) { - if (st->airport.psa->GetValue(i) != 0) { - is_empty = false; - break; - } - } - - if (!is_empty) { + if (!st->airport.psa->storage.empty()) { st->airport.psa->grfid = _airport_mngr.GetGRFID(st->airport.type); } else { delete st->airport.psa; st->airport.psa = nullptr; - } } } diff --git a/src/saveload/industry_sl.cpp b/src/saveload/industry_sl.cpp index 85ba3c4d6a..dd8b385a88 100644 --- a/src/saveload/industry_sl.cpp +++ b/src/saveload/industry_sl.cpp @@ -17,7 +17,8 @@ #include "../safeguards.h" -static OldPersistentStorage _old_ind_persistent_storage; +/** Old persistent storage for industries was a fixed array of 16 elements. */ +static std::array _old_ind_persistent_storage; class SlIndustryAccepted : public VectorSaveLoadHandler { public: @@ -156,7 +157,7 @@ static const SaveLoad _industry_desc[] = { SLE_CONDVAR(Industry, exclusive_supplier, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION), SLE_CONDVAR(Industry, exclusive_consumer, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION), - SLEG_CONDARR("storage", _old_ind_persistent_storage.storage, SLE_UINT32, 16, SLV_76, SLV_161), + SLEG_CONDARR("storage", _old_ind_persistent_storage, SLE_FILE_U32 | SLE_VAR_I32, 16, SLV_76, SLV_161), SLE_CONDREF(Industry, psa, REF_STORAGE, SLV_161, SL_MAX_VERSION), SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION), @@ -207,6 +208,7 @@ struct INDYChunkHandler : ChunkHandler { { const std::vector slt = SlCompatTableHeader(_industry_desc, _industry_sl_compat); + _old_ind_persistent_storage.fill(0); int index; SlIndustryAccepted::ResetOldStructure(); @@ -219,9 +221,7 @@ struct INDYChunkHandler : ChunkHandler { /* Before savegame version 161, persistent storages were not stored in a pool. */ if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_76)) { /* Store the old persistent storage. The GRFID will be added later. */ - assert(PersistentStorage::CanAllocateItem()); - i->psa = new PersistentStorage(0, 0, TileIndex{}); - std::copy(std::begin(_old_ind_persistent_storage.storage), std::end(_old_ind_persistent_storage.storage), std::begin(i->psa->storage)); + i->psa = ConvertOldPersistentStorage(_old_ind_persistent_storage); } if (IsSavegameVersionBefore(SLV_EXTEND_INDUSTRY_CARGO_SLOTS)) { LoadMoveAcceptsProduced(i, INDUSTRY_ORIGINAL_NUM_INPUTS, INDUSTRY_ORIGINAL_NUM_OUTPUTS); diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index aa23f4b93d..b739102f4f 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -395,6 +395,9 @@ enum SaveLoadVersion : uint16_t { SLV_PATH_CACHE_FORMAT, ///< 346 PR#12345 Vehicle path cache format changed. SLV_ANIMATED_TILE_STATE_IN_MAP, ///< 347 PR#13082 Animated tile state saved for improved performance. SLV_INCREASE_HOUSE_LIMIT, ///< 348 PR#12288 Increase house limit to 4096. + SLV_VARIABLE_PERSISTENT_STORAGE, ///< 349 PR#10670 NewGRF persistent storage moved from fixed array to dynamic. + + SLV_VEHICLE_STORAGE, ///< 350 PR#10670 Addition of persistent storage for vehicles. SL_MAX_VERSION, ///< Highest possible saveload version }; diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 998e488ab4..0ce2115931 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -182,7 +182,8 @@ struct FlowSaveLoad { typedef std::pair > StationCargoPair; -static OldPersistentStorage _old_st_persistent_storage; +/** Old persistent storage for stations was a fixed array of 16 elements. */ +static std::array _old_st_persistent_storage; /** * Swap the temporary packets with the packets without specific destination in @@ -399,9 +400,7 @@ public: /* Before savegame version 161, persistent storages were not stored in a pool. */ if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_145) && st->facilities & FACIL_AIRPORT) { /* Store the old persistent storage. The GRFID will be added later. */ - assert(PersistentStorage::CanAllocateItem()); - st->airport.psa = new PersistentStorage(0, 0, TileIndex{}); - std::copy(std::begin(_old_st_persistent_storage.storage), std::end(_old_st_persistent_storage.storage), std::begin(st->airport.psa->storage)); + st->airport.psa = ConvertOldPersistentStorage(_old_st_persistent_storage); } auto end = std::next(std::begin(st->goods), std::min(this->GetNumCargo(), std::size(st->goods))); @@ -610,7 +609,7 @@ public: SLE_CONDVAR(Station, airport.layout, SLE_UINT8, SLV_145, SL_MAX_VERSION), SLE_VAR(Station, airport.flags, SLE_UINT64), SLE_CONDVAR(Station, airport.rotation, SLE_UINT8, SLV_145, SL_MAX_VERSION), - SLEG_CONDARR("storage", _old_st_persistent_storage.storage, SLE_UINT32, 16, SLV_145, SLV_161), + SLEG_CONDARR("storage", _old_st_persistent_storage, SLE_FILE_U32 | SLE_VAR_I32, 16, SLV_145, SLV_161), SLE_CONDREF(Station, airport.psa, REF_STORAGE, SLV_161, SL_MAX_VERSION), SLE_VAR(Station, indtype, SLE_UINT8), @@ -709,6 +708,7 @@ struct STNNChunkHandler : ChunkHandler { { const std::vector slt = SlCompatTableHeader(_station_desc, _station_sl_compat); + _old_st_persistent_storage.fill(0); _old_num_flows = 0; int index; diff --git a/src/saveload/storage_sl.cpp b/src/saveload/storage_sl.cpp index 772ef76989..8ca915d748 100644 --- a/src/saveload/storage_sl.cpp +++ b/src/saveload/storage_sl.cpp @@ -16,11 +16,51 @@ #include "../safeguards.h" +/** + * Convert old fixed-sized array of persistent storage. + * @param old_storage Span containing range of old persistent storage. + * @returns Pointer to pool-allocated PersistentStorage object. + */ +PersistentStorage *ConvertOldPersistentStorage(std::span old_storage) +{ + /* Find last non-zero value to truncate the storage. */ + auto last = std::find_if(std::rbegin(old_storage), std::rend(old_storage), [](uint32_t value) { return value != 0; }).base(); + if (last == std::begin(old_storage)) return nullptr; + + assert(PersistentStorage::CanAllocateItem()); + PersistentStorage *ps = new PersistentStorage(0, 0, TileIndex{}); + + ps->storage.reserve(std::distance(std::begin(old_storage), last)); + for (auto it = std::begin(old_storage); it != last; ++it) { + ps->storage.push_back(*it); + } + + return ps; +} + +class SlPersistentStorage : public VectorSaveLoadHandler { +public: + struct PersistentStorageWrapper { + int32_t value; + }; + + inline static const SaveLoad description[] = { + SLE_VAR(PersistentStorageWrapper, value, SLE_INT32), + }; + inline const static SaveLoadCompatTable compat_description = {}; + + std::vector &GetVector(PersistentStorage *ps) const override { return ps->storage; } +}; + +/** Old persistent storage was a fixed array of up to 256 elements. */ +static std::array _old_persistent_storage; + /** Description of the data to save and load in #PersistentStorage. */ static const SaveLoad _storage_desc[] = { SLE_CONDVAR(PersistentStorage, grfid, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDARR(PersistentStorage, storage, SLE_UINT32, 16, SLV_161, SLV_EXTEND_PERSISTENT_STORAGE), - SLE_CONDARR(PersistentStorage, storage, SLE_UINT32, 256, SLV_EXTEND_PERSISTENT_STORAGE, SL_MAX_VERSION), + SLEG_CONDARR("storage", _old_persistent_storage, SLE_FILE_U32 | SLE_VAR_I32, 16, SLV_161, SLV_EXTEND_PERSISTENT_STORAGE), + SLEG_CONDARR("storage", _old_persistent_storage, SLE_FILE_U32 | SLE_VAR_I32, 256, SLV_EXTEND_PERSISTENT_STORAGE, SLV_VARIABLE_PERSISTENT_STORAGE), + SLEG_CONDSTRUCTLIST("storage", SlPersistentStorage, SLV_VARIABLE_PERSISTENT_STORAGE, SL_MAX_VERSION), }; /** Persistent storage data. */ @@ -31,12 +71,21 @@ struct PSACChunkHandler : ChunkHandler { { const std::vector slt = SlCompatTableHeader(_storage_desc, _storage_sl_compat); + _old_persistent_storage.fill(0); int index; while ((index = SlIterateArray()) != -1) { assert(PersistentStorage::CanAllocateItem()); PersistentStorage *ps = new (index) PersistentStorage(0, 0, TileIndex{}); SlObject(ps, slt); + + if (IsSavegameVersionBefore(SLV_VARIABLE_PERSISTENT_STORAGE)) { + auto last = std::find_if(std::rbegin(_old_persistent_storage), std::rend(_old_persistent_storage), [](uint32_t value) { return value != 0; }).base(); + ps->storage.reserve(std::distance(std::begin(_old_persistent_storage), last)); + for (auto it = std::begin(_old_persistent_storage); it != last; ++it) { + ps->storage.push_back(*it); + } + } } } diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 504494391b..f959e54e94 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -767,6 +767,7 @@ public: SLE_CONDVAR(Vehicle, depot_unbunching_last_departure, SLE_UINT64, SLV_DEPOT_UNBUNCHING, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, depot_unbunching_next_departure, SLE_UINT64, SLV_DEPOT_UNBUNCHING, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, round_trip_time, SLE_INT32, SLV_DEPOT_UNBUNCHING, SL_MAX_VERSION), + SLE_CONDREF(Vehicle, psa, REF_STORAGE, SLV_VEHICLE_STORAGE, SL_MAX_VERSION), }; inline const static SaveLoadCompatTable compat_description = _vehicle_common_sl_compat; diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 86a119bcf7..049139f3b3 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -79,6 +79,13 @@ class NIHVehicle : public NIHelper { VehicleResolverObject ro(v->engine_type, v, VehicleResolverObject::WO_CACHED); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } + + std::span GetPSA(uint index, uint32_t) const override + { + const Vehicle *v = Vehicle::Get(index); + if (v->psa == nullptr) return {}; + return v->psa->storage; + } }; static const NIFeature _nif_vehicle = { @@ -367,7 +374,7 @@ class NIHIndustry : public NIHelper { return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } - const std::span GetPSA(uint index, uint32_t) const override + std::span GetPSA(uint index, uint32_t) const override { const Industry *i = (const Industry *)this->GetInstance(index); if (i->psa == nullptr) return {}; @@ -538,7 +545,7 @@ class NIHAirport : public NIHelper { return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } - const std::span GetPSA(uint index, uint32_t) const override + std::span GetPSA(uint index, uint32_t) const override { const Station *st = (const Station *)this->GetInstance(index); if (st->airport.psa == nullptr) return {}; @@ -583,7 +590,7 @@ class NIHTown : public NIHelper { return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } - const std::span GetPSA(uint index, uint32_t grfid) const override + std::span GetPSA(uint index, uint32_t grfid) const override { Town *t = Town::Get(index); diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 40bb5bc0da..a6f9030a2a 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -901,6 +901,8 @@ Vehicle::~Vehicle() * it may happen that vehicle chain is deleted when visible */ if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty(); + delete this->psa; + Vehicle *v = this->Next(); this->SetNext(nullptr); diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 22b6e2222f..fa43861ea3 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -367,6 +367,8 @@ public: mutable MutableSpriteCache sprite_cache; ///< Cache of sprites and values related to recalculating them, see #MutableSpriteCache + struct PersistentStorage *psa; ///< Persistent storage + /** * Calculates the weight value that this vehicle will have when fully loaded with its current cargo. * @return Weight value in tonnes.