summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2007-09-22 12:59:43 +0000
committerrubidium <rubidium@openttd.org>2007-09-22 12:59:43 +0000
commitc68c83dffa2edbf854935effedeac0c4697d5db7 (patch)
treeabf69599a75ef23c1a5e3ed954a9d8866fe64a27
parent47dd4989a8dabe485d87743468b3eddb18e19bb6 (diff)
downloadopenttd-c68c83dffa2edbf854935effedeac0c4697d5db7.tar.xz
(svn r11138) -Codechange: prepare some subsystems for persistent storage for NewGRFs.
-rw-r--r--projects/openttd.vcproj6
-rw-r--r--projects/openttd_vs80.vcproj8
-rw-r--r--source.list2
-rw-r--r--src/command.cpp5
-rw-r--r--src/newgrf_spritegroup.cpp23
-rw-r--r--src/newgrf_spritegroup.h8
-rw-r--r--src/newgrf_storage.cpp27
-rw-r--r--src/newgrf_storage.h176
-rw-r--r--src/openttd.cpp3
9 files changed, 240 insertions, 18 deletions
diff --git a/projects/openttd.vcproj b/projects/openttd.vcproj
index 0a7e6bb26..e47fba85f 100644
--- a/projects/openttd.vcproj
+++ b/projects/openttd.vcproj
@@ -571,6 +571,9 @@
RelativePath=".\..\src\newgrf_station.h">
</File>
<File
+ RelativePath=".\..\src\newgrf_storage.h">
+ </File>
+ <File
RelativePath=".\..\src\newgrf_text.h">
</File>
<File
@@ -1122,6 +1125,9 @@
RelativePath=".\..\src\newgrf_station.cpp">
</File>
<File
+ RelativePath=".\..\src\newgrf_storage.cpp">
+ </File>
+ <File
RelativePath=".\..\src\newgrf_text.cpp">
</File>
<File
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
index 2a79f1c91..70f1cd775 100644
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -992,6 +992,10 @@
>
</File>
<File
+ RelativePath=".\..\src\newgrf_storage.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\newgrf_text.h"
>
</File>
@@ -1716,6 +1720,10 @@
>
</File>
<File
+ RelativePath=".\..\src\newgrf_storage.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\newgrf_text.cpp"
>
</File>
diff --git a/source.list b/source.list
index b2ecd8dee..7c8ff5180 100644
--- a/source.list
+++ b/source.list
@@ -156,6 +156,7 @@ newgrf_industrytiles.h
newgrf_sound.h
newgrf_spritegroup.h
newgrf_station.h
+newgrf_storage.h
newgrf_text.h
newgrf_town.h
newgrf_townname.h
@@ -347,6 +348,7 @@ newgrf_industrytiles.cpp
newgrf_sound.cpp
newgrf_spritegroup.cpp
newgrf_station.cpp
+newgrf_storage.cpp
newgrf_text.cpp
newgrf_town.cpp
newgrf_townname.cpp
diff --git a/src/command.cpp b/src/command.cpp
index ca7f950cf..4370f9b19 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -15,6 +15,7 @@
#include "network/network.h"
#include "variables.h"
#include "genworld.h"
+#include "newgrf_storage.h"
const char *_cmd_text = NULL;
@@ -573,6 +574,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
_docommand_recursive = 0;
_cmd_text = NULL;
+ ClearStorageChanges(false);
return false;
}
@@ -603,6 +605,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = pbck;
_docommand_recursive = 0;
_cmd_text = NULL;
+ ClearStorageChanges(false);
return true;
}
#endif /* ENABLE_NETWORK */
@@ -643,6 +646,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
if (callback) callback(true, tile, p1, p2);
_cmd_text = NULL;
+ ClearStorageChanges(true);
return true;
show_error:
@@ -656,6 +660,7 @@ callb_err:
if (callback) callback(false, tile, p1, p2);
_cmd_text = NULL;
+ ClearStorageChanges(false);
return false;
}
diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp
index 9dcc674d8..bc71ca19f 100644
--- a/src/newgrf_spritegroup.cpp
+++ b/src/newgrf_spritegroup.cpp
@@ -76,7 +76,7 @@ void InitializeSpriteGroupPool()
_spritegroup_count = 0;
}
-uint32 _temp_store[0x110];
+TemporaryStorageArray<uint, 0x110> _temp_store;
static inline uint32 GetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
@@ -98,7 +98,7 @@ static inline uint32 GetVariable(const ResolverObject *object, byte variable, by
case 0x1C: return object->last_value;
case 0x20: return _opt.landscape == LT_ARCTIC ? GetSnowLine() : 0xFF;
- case 0x7D: return _temp_store[parameter];
+ case 0x7D: return _temp_store.Get(parameter);
/* Not a common variable, so evalute the feature specific variables */
default: return object->GetVariable(object, variable, parameter, available);
@@ -137,9 +137,7 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust *adjust, U last_value,
case DSGA_OP_AND: return last_value & value;
case DSGA_OP_OR: return last_value | value;
case DSGA_OP_XOR: return last_value ^ value;
- case DSGA_OP_STO:
- if (value < lengthof(_temp_store)) _temp_store[value] = last_value;
- return last_value;
+ case DSGA_OP_STO: _temp_store.Store(value, last_value); return last_value;
case DSGA_OP_RST: return value;
default: return value;
}
@@ -162,7 +160,7 @@ static inline const SpriteGroup *ResolveVariable(const SpriteGroup *group, Resol
bool available = true;
if (adjust->variable == 0x7E) {
ResolverObject subobject = *object;
- const SpriteGroup *subgroup = Resolve(adjust->subroutine, &subobject, false);
+ const SpriteGroup *subgroup = Resolve(adjust->subroutine, &subobject);
if (subgroup == NULL || subgroup->type != SGT_CALLBACK) {
value = CALLBACK_FAILED;
} else {
@@ -175,7 +173,7 @@ static inline const SpriteGroup *ResolveVariable(const SpriteGroup *group, Resol
if (!available) {
/* Unsupported property: skip further processing and return either
* the group from the first range or the default group. */
- return Resolve(group->g.determ.num_ranges > 0 ? group->g.determ.ranges[0].group : group->g.determ.default_group, object, false);
+ return Resolve(group->g.determ.num_ranges > 0 ? group->g.determ.ranges[0].group : group->g.determ.default_group, object);
}
switch (group->g.determ.size) {
@@ -216,11 +214,11 @@ static inline const SpriteGroup *ResolveVariable(const SpriteGroup *group, Resol
for (i = 0; i < group->g.determ.num_ranges; i++) {
if (group->g.determ.ranges[i].low <= value && value <= group->g.determ.ranges[i].high) {
- return Resolve(group->g.determ.ranges[i].group, object, false);
+ return Resolve(group->g.determ.ranges[i].group, object);
}
}
- return Resolve(group->g.determ.default_group, object, false);
+ return Resolve(group->g.determ.default_group, object);
}
@@ -254,19 +252,16 @@ static inline const SpriteGroup *ResolveRandom(const SpriteGroup *group, Resolve
mask = (group->g.random.num_groups - 1) << group->g.random.lowest_randbit;
index = (object->GetRandomBits(object) & mask) >> group->g.random.lowest_randbit;
- return Resolve(group->g.random.groups[index], object, false);
+ return Resolve(group->g.random.groups[index], object);
}
/* ResolverObject (re)entry point */
-const SpriteGroup *Resolve(const SpriteGroup *group, ResolverObject *object, bool first_call)
+const SpriteGroup *Resolve(const SpriteGroup *group, ResolverObject *object)
{
/* We're called even if there is no group, so quietly return nothing */
if (group == NULL) return NULL;
- /* Zero the temporary storage to make sure there are no desyncs */
- if (first_call) memset(_temp_store, 0, sizeof(_temp_store));
-
switch (group->type) {
case SGT_REAL: return object->ResolveReal(object, group);
case SGT_DETERMINISTIC: return ResolveVariable(group, object);
diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h
index f1b17cbbe..50b75b849 100644
--- a/src/newgrf_spritegroup.h
+++ b/src/newgrf_spritegroup.h
@@ -7,6 +7,7 @@
#include "town.h"
#include "industry.h"
+#include "newgrf_storage.h"
/**
* Gets the value of a so-called newgrf "register".
@@ -16,9 +17,8 @@
*/
static inline uint32 GetRegister(uint i)
{
- assert(i < 0x110);
- extern uint32 _temp_store[0x110];
- return _temp_store[i];
+ extern TemporaryStorageArray<uint, 0x110> _temp_store;
+ return _temp_store.Get(i);
}
struct SpriteGroup;
@@ -243,7 +243,7 @@ struct ResolverObject {
/* Base sprite group resolver */
-const SpriteGroup *Resolve(const SpriteGroup *group, ResolverObject *object, bool first_call = true);
+const SpriteGroup *Resolve(const SpriteGroup *group, ResolverObject *object);
#endif /* NEWGRF_SPRITEGROUP_H */
diff --git a/src/newgrf_storage.cpp b/src/newgrf_storage.cpp
new file mode 100644
index 000000000..c5c06b2f9
--- /dev/null
+++ b/src/newgrf_storage.cpp
@@ -0,0 +1,27 @@
+/* $Id$ */
+
+/** @file newgrf_storage.cpp Functionality related to the temporary and persistent storage arrays for NewGRFs. */
+
+#include "stdafx.h"
+#include "helpers.hpp"
+#include "newgrf_storage.h"
+#include <set>
+
+/** The changed storage arrays */
+static std::set<BaseStorageArray*> _changed_storage_arrays;
+
+void AddChangedStorage(BaseStorageArray *storage)
+{
+ _changed_storage_arrays.insert(storage);
+}
+
+void ClearStorageChanges(bool keep_changes)
+{
+ /* Loop over all changes arrays */
+ for (std::set<BaseStorageArray*>::iterator it = _changed_storage_arrays.begin(); it != _changed_storage_arrays.end(); it++) {
+ (*it)->ClearChanges(keep_changes);
+ }
+
+ /* And then clear that array */
+ _changed_storage_arrays.clear();
+}
diff --git a/src/newgrf_storage.h b/src/newgrf_storage.h
new file mode 100644
index 000000000..93aab09dc
--- /dev/null
+++ b/src/newgrf_storage.h
@@ -0,0 +1,176 @@
+/* $Id$ */
+
+/** @file newgrf_storage.h Functionality related to the temporary and persistent storage arrays for NewGRFs. */
+
+#ifndef NEWGRF_STORAGE_H
+#define NEWGRF_STORAGE_H
+
+/**
+ * Base class for all NewGRF storage arrays. Nothing fancy, only here
+ * so we have a generalised class to use.
+ */
+struct BaseStorageArray
+{
+ /** The needed destructor */
+ virtual ~BaseStorageArray() {}
+
+ /**
+ * Clear the changes made since the last ClearChanges.
+ * This can be done in two ways:
+ * - saving the changes permanently
+ * - reverting to the previous version
+ * @param keep_changes do we save or revert the changes since the last ClearChanges?
+ */
+ virtual void ClearChanges(bool keep_changes) {}
+};
+
+/**
+ * Class for persistent storage of data.
+ * On ClearChanges that data is either reverted or saved.
+ * @param TYPE the type of variable to store.
+ * @param SIZE the size of the array.
+ */
+template <typename TYPE, uint SIZE>
+struct PersistentStorageArray : BaseStorageArray {
+ TYPE storage[SIZE]; ///< Memory to for the storage array
+ TYPE *prev_storage; ///< Memory to store "old" states so we can revert them on the performance of test cases for commands etc.
+
+ /** Simply construct the array */
+ PersistentStorageArray() : prev_storage(NULL)
+ {
+ memset(this->storage, 0, sizeof(this->storage));
+ }
+
+ /** And free all data related to it */
+ ~PersistentStorageArray()
+ {
+ free(this->prev_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 Store(uint pos, TYPE 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 (this->prev_storage != NULL) {
+ this->prev_storage = MallocT<TYPE>(SIZE);
+ if (this->prev_storage == NULL) return;
+
+ memcpy(this->prev_storage, this->storage, sizeof(this->storage));
+
+ /* We only need to register ourselves when we made the backup
+ * as that is the only time something will have changed */
+ AddChangedStorage(this);
+ }
+
+ this->storage[pos] = value;
+ }
+
+ /**
+ * Gets the value from a given position.
+ * @param pos the position to get the data from
+ * @return the data from that position
+ */
+ TYPE Get(uint pos)
+ {
+ /* Out of the scope of the array */
+ if (pos >= SIZE) return 0;
+
+ return this->storage[pos];
+ }
+
+ void ClearChanges(bool keep_changes)
+ {
+ assert(this->prev_storage != NULL);
+
+ if (!keep_changes) {
+ memcpy(this->storage, this->prev_storage, sizeof(this->storage));
+ }
+ free(this->prev_storage);
+ }
+};
+
+
+/**
+ * Class for temporary storage of data.
+ * On ClearChanges that data is always zero-ed.
+ * @param TYPE the type of variable to store.
+ * @param SIZE the size of the array.
+ */
+template <typename TYPE, uint SIZE>
+struct TemporaryStorageArray : BaseStorageArray {
+ TYPE storage[SIZE]; ///< Memory to for the storage array
+
+ /** Simply construct the array */
+ TemporaryStorageArray()
+ {
+ memset(this->storage, 0, sizeof(this->storage));
+ }
+
+ /**
+ * Stores some value at a given position.
+ * @param pos the position to write at
+ * @param value the value to write
+ */
+ void Store(uint pos, TYPE value)
+ {
+ /* Out of the scope of the array */
+ if (pos >= SIZE) return;
+
+ this->storage[pos] = value;
+ AddChangedStorage(this);
+ }
+
+ /**
+ * Gets the value from a given position.
+ * @param pos the position to get the data from
+ * @return the data from that position
+ */
+ TYPE Get(uint pos)
+ {
+ /* Out of the scope of the array */
+ if (pos >= SIZE) return 0;
+
+ return this->storage[pos];
+ }
+
+ void ClearChanges(bool keep_changes)
+ {
+ memset(this->storage, 0, sizeof(this->storage));
+ }
+};
+
+/**
+ * Add the changed storage array to the list of changed arrays.
+ * This is done so we only have to revert/save the changed
+ * arrays, which saves quite a few clears, etc. after callbacks.
+ * @param storage the array that has changed
+ */
+void AddChangedStorage(BaseStorageArray *storage);
+
+
+/**
+ * Clear the changes made since the last ClearStorageChanges.
+ * This is done for *all* storages that have been registered to with
+ * AddChangedStorage since the previous ClearStorageChanges.
+ *
+ * This can be done in two ways:
+ * - saving the changes permanently
+ * - reverting to the previous version
+ * @param keep_changes do we save or revert the changes since the last ClearChanges?
+ */
+void ClearStorageChanges(bool keep_changes);
+
+#endif /* NEWGRF_STORAGE_H */
diff --git a/src/openttd.cpp b/src/openttd.cpp
index bed5dbdb0..4098c7547 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -61,6 +61,7 @@
#include "newgrf_config.h"
#include "newgrf_house.h"
#include "newgrf_commons.h"
+#include "newgrf_storage.h"
#include "player_face.h"
#include "group.h"
#include "blitter/factory.hpp"
@@ -977,6 +978,8 @@ void SwitchMode(int new_mode)
* That check is enforced in DoCommand. */
void StateGameLoop()
{
+ ClearStorageChanges(false);
+
/* dont execute the state loop during pause */
if (_pause_game) return;
if (IsGeneratingWorld()) return;