mirror of https://github.com/OpenTTD/OpenTTD
Merge c4931c3a6e
into 59354576d4
commit
02c6f3e9b6
|
@ -421,7 +421,7 @@ uint32_t CommandCost::textref_stack[16];
|
||||||
*/
|
*/
|
||||||
void CommandCost::UseTextRefStack(const GRFFile *grffile, uint num_registers)
|
void CommandCost::UseTextRefStack(const GRFFile *grffile, uint num_registers)
|
||||||
{
|
{
|
||||||
extern TemporaryStorageArray<int32_t, 0x110> _temp_store;
|
extern TemporaryStorageArray _temp_store;
|
||||||
|
|
||||||
assert(num_registers < lengthof(textref_stack));
|
assert(num_registers < lengthof(textref_stack));
|
||||||
this->textref_stack_grffile = grffile;
|
this->textref_stack_grffile = grffile;
|
||||||
|
|
|
@ -195,7 +195,7 @@ public:
|
||||||
* @param grfid Parameter for the PSA. Only required for items with parameters.
|
* @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.
|
* @return Span of the storage array or an empty span when not present.
|
||||||
*/
|
*/
|
||||||
virtual const std::span<int32_t> GetPSA([[maybe_unused]] uint index, [[maybe_unused]] uint32_t grfid) const
|
virtual std::span<const int32_t> GetPSA([[maybe_unused]] uint index, [[maybe_unused]] uint32_t grfid) const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -477,9 +477,11 @@ struct NewGRFInspectWindow : Window {
|
||||||
} else {
|
} else {
|
||||||
this->DrawString(r, i++, "Persistent storage:");
|
this->DrawString(r, i++, "Persistent storage:");
|
||||||
}
|
}
|
||||||
assert(psa.size() % 4 == 0);
|
for (uint index = 0; const int32_t &value : psa) {
|
||||||
for (size_t j = 0; j < psa.size(); j += 4) {
|
if (value != 0) {
|
||||||
this->DrawString(r, i++, fmt::format(" {}: {} {} {} {}", j, psa[j], psa[j + 1], psa[j + 2], psa[j + 3]));
|
this->DrawString(r, i++, fmt::format(" {:02x}: {:08x} ({})", index, value, value));
|
||||||
|
}
|
||||||
|
++index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "newgrf_railtype.h"
|
#include "newgrf_railtype.h"
|
||||||
#include "newgrf_roadtype.h"
|
#include "newgrf_roadtype.h"
|
||||||
#include "ship.h"
|
#include "ship.h"
|
||||||
|
#include "newgrf_debug.h"
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
|
@ -315,6 +316,23 @@ static uint8_t MapAircraftMovementAction(const Aircraft *v)
|
||||||
return this->v == nullptr ? 0 : this->v->waiting_triggers;
|
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<Vehicle *>(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)
|
/* 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;
|
default: return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 0x7C: return (v->psa != nullptr) ? v->psa->GetValue(parameter) : 0;
|
||||||
|
|
||||||
case 0xFE:
|
case 0xFE:
|
||||||
case 0xFF: {
|
case 0xFF: {
|
||||||
uint16_t modflags = 0;
|
uint16_t modflags = 0;
|
||||||
|
|
|
@ -41,6 +41,7 @@ struct VehicleScopeResolver : public ScopeResolver {
|
||||||
uint32_t GetRandomBits() const override;
|
uint32_t GetRandomBits() const override;
|
||||||
uint32_t GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const override;
|
uint32_t GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const override;
|
||||||
uint32_t GetTriggers() const override;
|
uint32_t GetTriggers() const override;
|
||||||
|
void StorePSA(uint pos, int32_t value) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Resolver for a vehicle (chain) */
|
/** Resolver for a vehicle (chain) */
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
SpriteGroupPool _spritegroup_pool("SpriteGroup");
|
SpriteGroupPool _spritegroup_pool("SpriteGroup");
|
||||||
INSTANTIATE_POOL_METHODS(SpriteGroup)
|
INSTANTIATE_POOL_METHODS(SpriteGroup)
|
||||||
|
|
||||||
TemporaryStorageArray<int32_t, 0x110> _temp_store;
|
TemporaryStorageArray _temp_store;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
*/
|
*/
|
||||||
inline uint32_t GetRegister(uint i)
|
inline uint32_t GetRegister(uint i)
|
||||||
{
|
{
|
||||||
extern TemporaryStorageArray<int32_t, 0x110> _temp_store;
|
extern TemporaryStorageArray _temp_store;
|
||||||
return _temp_store.GetValue(i);
|
return _temp_store.GetValue(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,11 +39,47 @@ BasePersistentStorageArray::~BasePersistentStorageArray()
|
||||||
* arrays, which saves quite a few clears, etc. after callbacks.
|
* arrays, which saves quite a few clears, etc. after callbacks.
|
||||||
* @param storage the array that has changed
|
* @param storage the array that has changed
|
||||||
*/
|
*/
|
||||||
void AddChangedPersistentStorage(BasePersistentStorageArray *storage)
|
static void AddChangedPersistentStorage(BasePersistentStorageArray *storage)
|
||||||
{
|
{
|
||||||
_changed_storage_arrays->insert(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<StorageType>(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
|
* Clear temporary changes made since the last call to SwitchMode, and
|
||||||
* set whether subsequent changes shall be persistent or temporary.
|
* set whether subsequent changes shall be persistent or temporary.
|
||||||
|
|
|
@ -60,60 +60,30 @@ private:
|
||||||
/**
|
/**
|
||||||
* Class for persistent storage of data.
|
* Class for persistent storage of data.
|
||||||
* On #ClearChanges that data is either reverted or saved.
|
* 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 <typename TYPE, uint SIZE>
|
|
||||||
struct PersistentStorageArray : BasePersistentStorageArray {
|
struct PersistentStorageArray : BasePersistentStorageArray {
|
||||||
using StorageType = std::array<TYPE, SIZE>;
|
using StorageType = std::vector<int32_t>;
|
||||||
|
static constexpr size_t SIZE = 256;
|
||||||
|
|
||||||
StorageType storage{}; ///< Memory for the storage array
|
StorageType storage{}; ///< Memory for the storage array
|
||||||
std::unique_ptr<StorageType> prev_storage{}; ///< Temporary memory to store previous state so it can be reverted, e.g. for command tests.
|
std::unique_ptr<StorageType> prev_storage{}; ///< Temporary memory to store previous state so it can be reverted, e.g. for command tests.
|
||||||
|
|
||||||
/**
|
void StoreValue(uint pos, int32_t value);
|
||||||
* 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<StorageType>(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value from a given position.
|
* Gets the value from a given position.
|
||||||
* @param pos the position to get the data from
|
* @param pos the position to get the data from
|
||||||
* @return the data from that position
|
* @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 */
|
/* Out of the scope of the array */
|
||||||
if (pos >= SIZE) return 0;
|
if (pos >= std::size(this->storage)) return 0;
|
||||||
|
|
||||||
return this->storage[pos];
|
return this->storage[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearChanges() override
|
inline void ClearChanges() override
|
||||||
{
|
{
|
||||||
if (this->prev_storage) {
|
if (this->prev_storage) {
|
||||||
this->storage = *this->prev_storage;
|
this->storage = *this->prev_storage;
|
||||||
|
@ -126,12 +96,11 @@ struct PersistentStorageArray : BasePersistentStorageArray {
|
||||||
/**
|
/**
|
||||||
* Class for temporary storage of data.
|
* Class for temporary storage of data.
|
||||||
* On #ClearChanges that data is always zero-ed.
|
* On #ClearChanges that data is always zero-ed.
|
||||||
* @tparam TYPE the type of variable to store.
|
|
||||||
* @tparam SIZE the size of the array.
|
|
||||||
*/
|
*/
|
||||||
template <typename TYPE, uint SIZE>
|
|
||||||
struct TemporaryStorageArray {
|
struct TemporaryStorageArray {
|
||||||
using StorageType = std::array<TYPE, SIZE>;
|
static constexpr size_t SIZE = 0x110;
|
||||||
|
|
||||||
|
using StorageType = std::array<int32_t, SIZE>;
|
||||||
using StorageInitType = std::array<uint16_t, SIZE>;
|
using StorageInitType = std::array<uint16_t, SIZE>;
|
||||||
|
|
||||||
StorageType storage{}; ///< Memory for the storage array
|
StorageType storage{}; ///< Memory for the storage array
|
||||||
|
@ -143,7 +112,7 @@ struct TemporaryStorageArray {
|
||||||
* @param pos the position to write at
|
* @param pos the position to write at
|
||||||
* @param value the value to write
|
* @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 */
|
/* Out of the scope of the array */
|
||||||
if (pos >= SIZE) return;
|
if (pos >= SIZE) return;
|
||||||
|
@ -157,7 +126,7 @@ struct TemporaryStorageArray {
|
||||||
* @param pos the position to get the data from
|
* @param pos the position to get the data from
|
||||||
* @return the data from that position
|
* @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 */
|
/* Out of the scope of the array */
|
||||||
if (pos >= SIZE) return 0;
|
if (pos >= SIZE) return 0;
|
||||||
|
@ -170,7 +139,7 @@ struct TemporaryStorageArray {
|
||||||
return this->storage[pos];
|
return this->storage[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearChanges()
|
inline void ClearChanges()
|
||||||
{
|
{
|
||||||
/* Increment init_key to invalidate all storage */
|
/* Increment init_key to invalidate all storage */
|
||||||
this->init_key++;
|
this->init_key++;
|
||||||
|
@ -182,10 +151,6 @@ struct TemporaryStorageArray {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddChangedPersistentStorage(BasePersistentStorageArray *storage);
|
|
||||||
|
|
||||||
typedef PersistentStorageArray<int32_t, 16> OldPersistentStorage;
|
|
||||||
|
|
||||||
typedef uint32_t PersistentStorageID;
|
typedef uint32_t PersistentStorageID;
|
||||||
|
|
||||||
struct PersistentStorage;
|
struct PersistentStorage;
|
||||||
|
@ -196,7 +161,7 @@ extern PersistentStoragePool _persistent_storage_pool;
|
||||||
/**
|
/**
|
||||||
* Class for pooled persistent storage of data.
|
* Class for pooled persistent storage of data.
|
||||||
*/
|
*/
|
||||||
struct PersistentStorage : PersistentStorageArray<int32_t, 256>, 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! */
|
/** 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)
|
PersistentStorage(const uint32_t new_grfid, uint8_t feature, TileIndex tile)
|
||||||
{
|
{
|
||||||
|
@ -206,6 +171,7 @@ struct PersistentStorage : PersistentStorageArray<int32_t, 256>, PersistentStora
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(std::tuple_size_v<decltype(OldPersistentStorage::storage)> <= std::tuple_size_v<decltype(PersistentStorage::storage)>);
|
/* storage_sl.cpp */
|
||||||
|
PersistentStorage *ConvertOldPersistentStorage(std::span<const int32_t> old_storage);
|
||||||
|
|
||||||
#endif /* NEWGRF_STORAGE_H */
|
#endif /* NEWGRF_STORAGE_H */
|
||||||
|
|
|
@ -797,7 +797,7 @@ void RestoreTextRefStackBackup(struct TextRefStack *backup)
|
||||||
*/
|
*/
|
||||||
void StartTextRefStackUsage(const GRFFile *grffile, uint8_t numEntries, const uint32_t *values)
|
void StartTextRefStackUsage(const GRFFile *grffile, uint8_t numEntries, const uint32_t *values)
|
||||||
{
|
{
|
||||||
extern TemporaryStorageArray<int32_t, 0x110> _temp_store;
|
extern TemporaryStorageArray _temp_store;
|
||||||
|
|
||||||
_newgrf_textrefstack.ResetStack(grffile);
|
_newgrf_textrefstack.ResetStack(grffile);
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "../subsidy_base.h"
|
#include "../subsidy_base.h"
|
||||||
#include "../subsidy_func.h"
|
#include "../subsidy_func.h"
|
||||||
#include "../newgrf.h"
|
#include "../newgrf.h"
|
||||||
|
#include "../newgrf_debug.h"
|
||||||
#include "../newgrf_station.h"
|
#include "../newgrf_station.h"
|
||||||
#include "../engine_func.h"
|
#include "../engine_func.h"
|
||||||
#include "../rail_gui.h"
|
#include "../rail_gui.h"
|
||||||
|
@ -290,6 +291,11 @@ static void InitializeWindowsAndCaches()
|
||||||
it->tile = t->xy;
|
it->tile = t->xy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (Vehicle *v : Vehicle::Iterate()) {
|
||||||
|
if (v->psa != nullptr) {
|
||||||
|
v->psa->feature = GetGrfSpecFeature(v->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (RoadVehicle *rv : RoadVehicle::Iterate()) {
|
for (RoadVehicle *rv : RoadVehicle::Iterate()) {
|
||||||
if (rv->IsFrontEngine()) {
|
if (rv->IsFrontEngine()) {
|
||||||
rv->CargoChanged();
|
rv->CargoChanged();
|
||||||
|
@ -2798,16 +2804,7 @@ bool AfterLoadGame()
|
||||||
for (Industry *ind : Industry::Iterate()) {
|
for (Industry *ind : Industry::Iterate()) {
|
||||||
assert(ind->psa != nullptr);
|
assert(ind->psa != nullptr);
|
||||||
|
|
||||||
/* Check if the old storage was empty. */
|
if (!ind->psa->storage.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) {
|
|
||||||
ind->psa->grfid = _industry_mngr.GetGRFID(ind->type);
|
ind->psa->grfid = _industry_mngr.GetGRFID(ind->type);
|
||||||
} else {
|
} else {
|
||||||
delete ind->psa;
|
delete ind->psa;
|
||||||
|
@ -2821,21 +2818,11 @@ bool AfterLoadGame()
|
||||||
if (!(st->facilities & FACIL_AIRPORT)) continue;
|
if (!(st->facilities & FACIL_AIRPORT)) continue;
|
||||||
assert(st->airport.psa != nullptr);
|
assert(st->airport.psa != nullptr);
|
||||||
|
|
||||||
/* Check if the old storage was empty. */
|
if (!st->airport.psa->storage.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) {
|
|
||||||
st->airport.psa->grfid = _airport_mngr.GetGRFID(st->airport.type);
|
st->airport.psa->grfid = _airport_mngr.GetGRFID(st->airport.type);
|
||||||
} else {
|
} else {
|
||||||
delete st->airport.psa;
|
delete st->airport.psa;
|
||||||
st->airport.psa = nullptr;
|
st->airport.psa = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
static OldPersistentStorage _old_ind_persistent_storage;
|
/** Old persistent storage for industries was a fixed array of 16 elements. */
|
||||||
|
static std::array<int32_t, 16> _old_ind_persistent_storage;
|
||||||
|
|
||||||
class SlIndustryAccepted : public VectorSaveLoadHandler<SlIndustryAccepted, Industry, Industry::AcceptedCargo, INDUSTRY_NUM_INPUTS> {
|
class SlIndustryAccepted : public VectorSaveLoadHandler<SlIndustryAccepted, Industry, Industry::AcceptedCargo, INDUSTRY_NUM_INPUTS> {
|
||||||
public:
|
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_supplier, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Industry, exclusive_consumer, 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_CONDREF(Industry, psa, REF_STORAGE, SLV_161, SL_MAX_VERSION),
|
||||||
|
|
||||||
SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION),
|
SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION),
|
||||||
|
@ -207,6 +208,7 @@ struct INDYChunkHandler : ChunkHandler {
|
||||||
{
|
{
|
||||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_industry_desc, _industry_sl_compat);
|
const std::vector<SaveLoad> slt = SlCompatTableHeader(_industry_desc, _industry_sl_compat);
|
||||||
|
|
||||||
|
_old_ind_persistent_storage.fill(0);
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
SlIndustryAccepted::ResetOldStructure();
|
SlIndustryAccepted::ResetOldStructure();
|
||||||
|
@ -219,9 +221,7 @@ struct INDYChunkHandler : ChunkHandler {
|
||||||
/* Before savegame version 161, persistent storages were not stored in a pool. */
|
/* Before savegame version 161, persistent storages were not stored in a pool. */
|
||||||
if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_76)) {
|
if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_76)) {
|
||||||
/* Store the old persistent storage. The GRFID will be added later. */
|
/* Store the old persistent storage. The GRFID will be added later. */
|
||||||
assert(PersistentStorage::CanAllocateItem());
|
i->psa = ConvertOldPersistentStorage(_old_ind_persistent_storage);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
if (IsSavegameVersionBefore(SLV_EXTEND_INDUSTRY_CARGO_SLOTS)) {
|
if (IsSavegameVersionBefore(SLV_EXTEND_INDUSTRY_CARGO_SLOTS)) {
|
||||||
LoadMoveAcceptsProduced(i, INDUSTRY_ORIGINAL_NUM_INPUTS, INDUSTRY_ORIGINAL_NUM_OUTPUTS);
|
LoadMoveAcceptsProduced(i, INDUSTRY_ORIGINAL_NUM_INPUTS, INDUSTRY_ORIGINAL_NUM_OUTPUTS);
|
||||||
|
|
|
@ -395,6 +395,9 @@ enum SaveLoadVersion : uint16_t {
|
||||||
SLV_PATH_CACHE_FORMAT, ///< 346 PR#12345 Vehicle path cache format changed.
|
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_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_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
|
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||||
};
|
};
|
||||||
|
|
|
@ -182,7 +182,8 @@ struct FlowSaveLoad {
|
||||||
|
|
||||||
typedef std::pair<const StationID, std::list<CargoPacket *> > StationCargoPair;
|
typedef std::pair<const StationID, std::list<CargoPacket *> > StationCargoPair;
|
||||||
|
|
||||||
static OldPersistentStorage _old_st_persistent_storage;
|
/** Old persistent storage for stations was a fixed array of 16 elements. */
|
||||||
|
static std::array<int32_t, 16> _old_st_persistent_storage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Swap the temporary packets with the packets without specific destination in
|
* 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. */
|
/* Before savegame version 161, persistent storages were not stored in a pool. */
|
||||||
if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_145) && st->facilities & FACIL_AIRPORT) {
|
if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_145) && st->facilities & FACIL_AIRPORT) {
|
||||||
/* Store the old persistent storage. The GRFID will be added later. */
|
/* Store the old persistent storage. The GRFID will be added later. */
|
||||||
assert(PersistentStorage::CanAllocateItem());
|
st->airport.psa = ConvertOldPersistentStorage(_old_st_persistent_storage);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto end = std::next(std::begin(st->goods), std::min(this->GetNumCargo(), std::size(st->goods)));
|
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_CONDVAR(Station, airport.layout, SLE_UINT8, SLV_145, SL_MAX_VERSION),
|
||||||
SLE_VAR(Station, airport.flags, SLE_UINT64),
|
SLE_VAR(Station, airport.flags, SLE_UINT64),
|
||||||
SLE_CONDVAR(Station, airport.rotation, SLE_UINT8, SLV_145, SL_MAX_VERSION),
|
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_CONDREF(Station, airport.psa, REF_STORAGE, SLV_161, SL_MAX_VERSION),
|
||||||
|
|
||||||
SLE_VAR(Station, indtype, SLE_UINT8),
|
SLE_VAR(Station, indtype, SLE_UINT8),
|
||||||
|
@ -709,6 +708,7 @@ struct STNNChunkHandler : ChunkHandler {
|
||||||
{
|
{
|
||||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_station_desc, _station_sl_compat);
|
const std::vector<SaveLoad> slt = SlCompatTableHeader(_station_desc, _station_sl_compat);
|
||||||
|
|
||||||
|
_old_st_persistent_storage.fill(0);
|
||||||
_old_num_flows = 0;
|
_old_num_flows = 0;
|
||||||
|
|
||||||
int index;
|
int index;
|
||||||
|
|
|
@ -16,11 +16,51 @@
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#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<const int32_t> 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<SlPersistentStorage, PersistentStorage, int32_t> {
|
||||||
|
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<int32_t> &GetVector(PersistentStorage *ps) const override { return ps->storage; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Old persistent storage was a fixed array of up to 256 elements. */
|
||||||
|
static std::array<int32_t, 256> _old_persistent_storage;
|
||||||
|
|
||||||
/** Description of the data to save and load in #PersistentStorage. */
|
/** Description of the data to save and load in #PersistentStorage. */
|
||||||
static const SaveLoad _storage_desc[] = {
|
static const SaveLoad _storage_desc[] = {
|
||||||
SLE_CONDVAR(PersistentStorage, grfid, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
SLE_CONDVAR(PersistentStorage, grfid, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
||||||
SLE_CONDARR(PersistentStorage, storage, SLE_UINT32, 16, SLV_161, SLV_EXTEND_PERSISTENT_STORAGE),
|
SLEG_CONDARR("storage", _old_persistent_storage, SLE_FILE_U32 | SLE_VAR_I32, 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, 256, SLV_EXTEND_PERSISTENT_STORAGE, SLV_VARIABLE_PERSISTENT_STORAGE),
|
||||||
|
SLEG_CONDSTRUCTLIST("storage", SlPersistentStorage, SLV_VARIABLE_PERSISTENT_STORAGE, SL_MAX_VERSION),
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Persistent storage data. */
|
/** Persistent storage data. */
|
||||||
|
@ -31,12 +71,21 @@ struct PSACChunkHandler : ChunkHandler {
|
||||||
{
|
{
|
||||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_storage_desc, _storage_sl_compat);
|
const std::vector<SaveLoad> slt = SlCompatTableHeader(_storage_desc, _storage_sl_compat);
|
||||||
|
|
||||||
|
_old_persistent_storage.fill(0);
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
while ((index = SlIterateArray()) != -1) {
|
while ((index = SlIterateArray()) != -1) {
|
||||||
assert(PersistentStorage::CanAllocateItem());
|
assert(PersistentStorage::CanAllocateItem());
|
||||||
PersistentStorage *ps = new (index) PersistentStorage(0, 0, TileIndex{});
|
PersistentStorage *ps = new (index) PersistentStorage(0, 0, TileIndex{});
|
||||||
SlObject(ps, slt);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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_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, 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_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;
|
inline const static SaveLoadCompatTable compat_description = _vehicle_common_sl_compat;
|
||||||
|
|
|
@ -79,6 +79,13 @@ class NIHVehicle : public NIHelper {
|
||||||
VehicleResolverObject ro(v->engine_type, v, VehicleResolverObject::WO_CACHED);
|
VehicleResolverObject ro(v->engine_type, v, VehicleResolverObject::WO_CACHED);
|
||||||
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
|
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::span<const int32_t> 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 = {
|
static const NIFeature _nif_vehicle = {
|
||||||
|
@ -367,7 +374,7 @@ class NIHIndustry : public NIHelper {
|
||||||
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
|
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::span<int32_t> GetPSA(uint index, uint32_t) const override
|
std::span<const int32_t> GetPSA(uint index, uint32_t) const override
|
||||||
{
|
{
|
||||||
const Industry *i = (const Industry *)this->GetInstance(index);
|
const Industry *i = (const Industry *)this->GetInstance(index);
|
||||||
if (i->psa == nullptr) return {};
|
if (i->psa == nullptr) return {};
|
||||||
|
@ -538,7 +545,7 @@ class NIHAirport : public NIHelper {
|
||||||
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
|
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::span<int32_t> GetPSA(uint index, uint32_t) const override
|
std::span<const int32_t> GetPSA(uint index, uint32_t) const override
|
||||||
{
|
{
|
||||||
const Station *st = (const Station *)this->GetInstance(index);
|
const Station *st = (const Station *)this->GetInstance(index);
|
||||||
if (st->airport.psa == nullptr) return {};
|
if (st->airport.psa == nullptr) return {};
|
||||||
|
@ -583,7 +590,7 @@ class NIHTown : public NIHelper {
|
||||||
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
|
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::span<int32_t> GetPSA(uint index, uint32_t grfid) const override
|
std::span<const int32_t> GetPSA(uint index, uint32_t grfid) const override
|
||||||
{
|
{
|
||||||
Town *t = Town::Get(index);
|
Town *t = Town::Get(index);
|
||||||
|
|
||||||
|
|
|
@ -901,6 +901,8 @@ Vehicle::~Vehicle()
|
||||||
* it may happen that vehicle chain is deleted when visible */
|
* it may happen that vehicle chain is deleted when visible */
|
||||||
if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty();
|
if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty();
|
||||||
|
|
||||||
|
delete this->psa;
|
||||||
|
|
||||||
Vehicle *v = this->Next();
|
Vehicle *v = this->Next();
|
||||||
this->SetNext(nullptr);
|
this->SetNext(nullptr);
|
||||||
|
|
||||||
|
|
|
@ -367,6 +367,8 @@ public:
|
||||||
|
|
||||||
mutable MutableSpriteCache sprite_cache; ///< Cache of sprites and values related to recalculating them, see #MutableSpriteCache
|
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.
|
* Calculates the weight value that this vehicle will have when fully loaded with its current cargo.
|
||||||
* @return Weight value in tonnes.
|
* @return Weight value in tonnes.
|
||||||
|
|
Loading…
Reference in New Issue