Fix: Don't allow right-click to close world generation progress window. (#13084)
[openttd-github.git] / src / newgrf_storage.h
blob3d5ab0ac049bfb3c303bd959d2d46808dbe61e12
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
8 /** @file newgrf_storage.h Functionality related to the temporary and persistent storage arrays for NewGRFs. */
10 #ifndef NEWGRF_STORAGE_H
11 #define NEWGRF_STORAGE_H
13 #include "core/alloc_func.hpp"
14 #include "core/pool_type.hpp"
15 #include "tile_type.h"
17 /**
18 * Mode switches to the behaviour of persistent storage array.
20 enum PersistentStorageMode {
21 PSM_ENTER_GAMELOOP, ///< Enter the gameloop, changes will be permanent.
22 PSM_LEAVE_GAMELOOP, ///< Leave the gameloop, changes will be temporary.
23 PSM_ENTER_COMMAND, ///< Enter command scope, changes will be permanent.
24 PSM_LEAVE_COMMAND, ///< Leave command scope, revert to previous mode.
25 PSM_ENTER_TESTMODE, ///< Enter command test mode, changes will be temporary.
26 PSM_LEAVE_TESTMODE, ///< Leave command test mode, revert to previous mode.
29 /**
30 * Base class for all persistent NewGRF storage arrays. Nothing fancy, only here
31 * so we have a generalised access to the virtual methods.
33 struct BasePersistentStorageArray {
34 uint32_t grfid; ///< GRFID associated to this persistent storage. A value of zero means "default".
35 uint8_t feature; ///< NOSAVE: Used to identify in the owner of the array in debug output.
36 TileIndex tile; ///< NOSAVE: Used to identify in the owner of the array in debug output.
38 virtual ~BasePersistentStorageArray();
40 static void SwitchMode(PersistentStorageMode mode, bool ignore_prev_mode = false);
42 protected:
43 /**
44 * Discard temporary changes.
46 virtual void ClearChanges() = 0;
48 /**
49 * Check whether currently changes to the storage shall be persistent or
50 * temporary till the next call to ClearChanges().
52 static bool AreChangesPersistent() { return (gameloop || command) && !testmode; }
54 private:
55 static bool gameloop;
56 static bool command;
57 static bool testmode;
60 /**
61 * Class for persistent storage of data.
62 * On #ClearChanges that data is either reverted or saved.
63 * @tparam TYPE the type of variable to store.
64 * @tparam SIZE the size of the array.
66 template <typename TYPE, uint SIZE>
67 struct PersistentStorageArray : BasePersistentStorageArray {
68 using StorageType = std::array<TYPE, SIZE>;
70 StorageType storage{}; ///< Memory for the storage array
71 std::unique_ptr<StorageType> prev_storage{}; ///< Temporary memory to store previous state so it can be reverted, e.g. for command tests.
73 /**
74 * Stores some value at a given position.
75 * If there is no backup of the data that backup is made and then
76 * we write the data.
77 * @param pos the position to write at
78 * @param value the value to write
80 void StoreValue(uint pos, int32_t value)
82 /* Out of the scope of the array */
83 if (pos >= SIZE) return;
85 /* The value hasn't changed, so we pretend nothing happened.
86 * Saves a few cycles and such and it's pretty easy to check. */
87 if (this->storage[pos] == value) return;
89 /* We do not have made a backup; lets do so */
90 if (AreChangesPersistent()) {
91 assert(!this->prev_storage);
92 } else if (!this->prev_storage) {
93 this->prev_storage = std::make_unique<StorageType>(this->storage);
95 /* We only need to register ourselves when we made the backup
96 * as that is the only time something will have changed */
97 AddChangedPersistentStorage(this);
100 this->storage[pos] = value;
104 * Gets the value from a given position.
105 * @param pos the position to get the data from
106 * @return the data from that position
108 TYPE GetValue(uint pos) const
110 /* Out of the scope of the array */
111 if (pos >= SIZE) return 0;
113 return this->storage[pos];
116 void ClearChanges() override
118 if (this->prev_storage) {
119 this->storage = *this->prev_storage;
120 this->prev_storage.reset();
127 * Class for temporary storage of data.
128 * On #ClearChanges that data is always zero-ed.
129 * @tparam TYPE the type of variable to store.
130 * @tparam SIZE the size of the array.
132 template <typename TYPE, uint SIZE>
133 struct TemporaryStorageArray {
134 using StorageType = std::array<TYPE, SIZE>;
135 using StorageInitType = std::array<uint16_t, SIZE>;
137 StorageType storage{}; ///< Memory for the storage array
138 StorageInitType init{}; ///< Storage has been assigned, if this equals 'init_key'.
139 uint16_t init_key = 1; ///< Magic key to 'init'.
142 * Stores some value at a given position.
143 * @param pos the position to write at
144 * @param value the value to write
146 void StoreValue(uint pos, int32_t value)
148 /* Out of the scope of the array */
149 if (pos >= SIZE) return;
151 this->storage[pos] = value;
152 this->init[pos] = this->init_key;
156 * Gets the value from a given position.
157 * @param pos the position to get the data from
158 * @return the data from that position
160 TYPE GetValue(uint pos) const
162 /* Out of the scope of the array */
163 if (pos >= SIZE) return 0;
165 if (this->init[pos] != this->init_key) {
166 /* Unassigned since last call to ClearChanges */
167 return 0;
170 return this->storage[pos];
173 void ClearChanges()
175 /* Increment init_key to invalidate all storage */
176 this->init_key++;
177 if (this->init_key == 0) {
178 /* When init_key wraps around, we need to reset everything */
179 this->init = {};
180 this->init_key = 1;
185 void AddChangedPersistentStorage(BasePersistentStorageArray *storage);
187 typedef PersistentStorageArray<int32_t, 16> OldPersistentStorage;
189 typedef uint32_t PersistentStorageID;
191 struct PersistentStorage;
192 typedef Pool<PersistentStorage, PersistentStorageID, 1, 0xFF000> PersistentStoragePool;
194 extern PersistentStoragePool _persistent_storage_pool;
197 * Class for pooled persistent storage of data.
199 struct PersistentStorage : PersistentStorageArray<int32_t, 256>, PersistentStoragePool::PoolItem<&_persistent_storage_pool> {
200 /** We don't want GCC to zero our struct! It already is zeroed and has an index! */
201 PersistentStorage(const uint32_t new_grfid, uint8_t feature, TileIndex tile)
203 this->grfid = new_grfid;
204 this->feature = feature;
205 this->tile = tile;
209 static_assert(std::tuple_size_v<decltype(OldPersistentStorage::storage)> <= std::tuple_size_v<decltype(PersistentStorage::storage)>);
211 #endif /* NEWGRF_STORAGE_H */