Changeset - r7609:2e734c4aad38
[Not reviewed]
master
0 7 2
rubidium - 17 years ago 2007-09-22 12:59:43
rubidium@openttd.org
(svn r11138) -Codechange: prepare some subsystems for persistent storage for NewGRFs.
9 files changed with 240 insertions and 18 deletions:
0 comments (0 inline, 0 general)
projects/openttd.vcproj
Show inline comments
 
@@ -568,12 +568,15 @@
 
				RelativePath=".\..\src\newgrf_spritegroup.h">
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_station.h">
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_storage.h">
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_text.h">
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_town.h">
 
			</File>
 
			<File
 
@@ -1119,12 +1122,15 @@
 
				RelativePath=".\..\src\newgrf_spritegroup.cpp">
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_station.cpp">
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_storage.cpp">
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_text.cpp">
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_town.cpp">
 
			</File>
 
			<File
projects/openttd_vs80.vcproj
Show inline comments
 
@@ -989,12 +989,16 @@
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_station.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_storage.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_text.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_town.h"
 
				>
 
@@ -1713,12 +1717,16 @@
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_station.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_storage.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_text.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\newgrf_town.cpp"
 
				>
source.list
Show inline comments
 
@@ -153,12 +153,13 @@ newgrf_engine.h
 
newgrf_house.h
 
newgrf_industries.h
 
newgrf_industrytiles.h
 
newgrf_sound.h
 
newgrf_spritegroup.h
 
newgrf_station.h
 
newgrf_storage.h
 
newgrf_text.h
 
newgrf_town.h
 
newgrf_townname.h
 
news.h
 
npf.h
 
music/null_m.h
 
@@ -344,12 +345,13 @@ newgrf_engine.cpp
 
newgrf_house.cpp
 
newgrf_industries.cpp
 
newgrf_industrytiles.cpp
 
newgrf_sound.cpp
 
newgrf_spritegroup.cpp
 
newgrf_station.cpp
 
newgrf_storage.cpp
 
newgrf_text.cpp
 
newgrf_town.cpp
 
newgrf_townname.cpp
 

	
 
# Map Accessors
 
bridge_map.cpp
src/command.cpp
Show inline comments
 
@@ -12,12 +12,13 @@
 
#include "gui.h"
 
#include "command.h"
 
#include "player.h"
 
#include "network/network.h"
 
#include "variables.h"
 
#include "genworld.h"
 
#include "newgrf_storage.h"
 

	
 
const char *_cmd_text = NULL;
 

	
 
/**
 
 * Helper macro to define the header of all command handler macros.
 
 *
 
@@ -570,12 +571,13 @@ bool DoCommandP(TileIndex tile, uint32 p
 
		} else {
 
			ShowEstimatedCostOrIncome(res.GetCost(), x, y);
 
		}
 

	
 
		_docommand_recursive = 0;
 
		_cmd_text = NULL;
 
		ClearStorageChanges(false);
 
		return false;
 
	}
 

	
 

	
 
	if (!((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
 
		/* first test if the command can be executed. */
 
@@ -600,12 +602,13 @@ bool DoCommandP(TileIndex tile, uint32 p
 
		PlayerID pbck = _local_player;
 
		if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = PLAYER_FIRST;
 
		NetworkSend_Command(tile, p1, p2, cmd, 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 */
 

	
 
	/* update last build coordinate of player. */
 
	if (tile != 0 && IsValidPlayer(_current_player)) {
 
@@ -640,12 +643,13 @@ bool DoCommandP(TileIndex tile, uint32 p
 
	}
 

	
 
	_docommand_recursive = 0;
 

	
 
	if (callback) callback(true, tile, p1, p2);
 
	_cmd_text = NULL;
 
	ClearStorageChanges(true);
 
	return true;
 

	
 
show_error:
 
	/* show error message if the command fails? */
 
	if (IsLocalPlayer() && error_part1 != 0 && my_cmd) {
 
		ShowErrorMessage(_error_message, error_part1, x, y);
 
@@ -653,12 +657,13 @@ show_error:
 

	
 
callb_err:
 
	_docommand_recursive = 0;
 

	
 
	if (callback) callback(false, tile, p1, p2);
 
	_cmd_text = NULL;
 
	ClearStorageChanges(false);
 
	return false;
 
}
 

	
 

	
 
CommandCost CommandCost::AddCost(CommandCost ret)
 
{
src/newgrf_spritegroup.cpp
Show inline comments
 
@@ -73,13 +73,13 @@ void InitializeSpriteGroupPool()
 
{
 
	_SpriteGroup_pool.CleanPool();
 

	
 
	_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)
 
{
 
	/* Return common variables */
 
	switch (variable) {
 
@@ -95,13 +95,13 @@ static inline uint32 GetVariable(const R
 
		case 0x18: return object->callback_param2;
 
		case 0x1A: return UINT_MAX;
 
		case 0x1B: return GB(_display_opt, 0, 6);
 
		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);
 
	}
 
}
 

	
 
@@ -134,15 +134,13 @@ static U EvalAdjustT(const Deterministic
 
		case DSGA_OP_UDIV: return value == 0 ? (U)last_value : (U)last_value / (U)value;
 
		case DSGA_OP_UMOD: return value == 0 ? (U)last_value : (U)last_value % (U)value;
 
		case DSGA_OP_MUL:  return last_value * 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;
 
	}
 
}
 

	
 

	
 
@@ -159,26 +157,26 @@ static inline const SpriteGroup *Resolve
 
		DeterministicSpriteGroupAdjust *adjust = &group->g.determ.adjusts[i];
 

	
 
		/* Try to get the variable. We shall assume it is available, unless told otherwise. */
 
		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 {
 
				value = subgroup->g.callback.result;
 
			}
 
		} else {
 
			value = GetVariable(object, adjust->variable, adjust->parameter, &available);
 
		}
 

	
 
		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) {
 
			case DSG_SIZE_BYTE:  value = EvalAdjustT<uint8, int8>(adjust, last_value, value); break;
 
			case DSG_SIZE_WORD:  value = EvalAdjustT<uint16, int16>(adjust, last_value, value); break;
 
			case DSG_SIZE_DWORD: value = EvalAdjustT<uint32, int32>(adjust, last_value, value); break;
 
@@ -213,17 +211,17 @@ static inline const SpriteGroup *Resolve
 
		}
 
		return &nvarzero;
 
	}
 

	
 
	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);
 
}
 

	
 

	
 
static inline const SpriteGroup *ResolveRandom(const SpriteGroup *group, ResolverObject *object)
 
{
 
	uint32 mask;
 
@@ -251,25 +249,22 @@ static inline const SpriteGroup *Resolve
 
		object->SetTriggers(object, waiting_triggers);
 
	}
 

	
 
	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);
 
		case SGT_RANDOMIZED:    return ResolveRandom(group, object);
 
		default:                return group;
 
	}
src/newgrf_spritegroup.h
Show inline comments
 
@@ -4,24 +4,24 @@
 

	
 
#ifndef NEWGRF_SPRITEGROUP_H
 
#define NEWGRF_SPRITEGROUP_H
 

	
 
#include "town.h"
 
#include "industry.h"
 
#include "newgrf_storage.h"
 

	
 
/**
 
 * Gets the value of a so-called newgrf "register".
 
 * @param i index of the register
 
 * @pre i < 0x110
 
 * @return the value of the register
 
 */
 
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;
 

	
 

	
 
/* 'Real' sprite groups contain a list of other result or callback sprite
 
@@ -240,10 +240,10 @@ struct ResolverObject {
 
	uint32 (*GetVariable)(const struct ResolverObject*, byte, byte, bool*);
 
	const SpriteGroup *(*ResolveReal)(const struct ResolverObject*, const SpriteGroup*);
 
};
 

	
 

	
 
/* 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 */
src/newgrf_storage.cpp
Show inline comments
 
new file 100644
 
/* $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();
 
}
src/newgrf_storage.h
Show inline comments
 
new file 100644
 
/* $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 */
src/openttd.cpp
Show inline comments
 
@@ -58,12 +58,13 @@
 
#include "clear_map.h"
 
#include "fontcache.h"
 
#include "newgrf.h"
 
#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"
 
#include "sound/sound_driver.hpp"
 
#include "music/music_driver.hpp"
 
#include "video/video_driver.hpp"
 
@@ -974,12 +975,14 @@ void SwitchMode(int new_mode)
 
/* State controlling game loop.
 
 * The state must not be changed from anywhere
 
 * but here.
 
 * That check is enforced in DoCommand. */
 
void StateGameLoop()
 
{
 
	ClearStorageChanges(false);
 

	
 
	/* dont execute the state loop during pause */
 
	if (_pause_game) return;
 
	if (IsGeneratingWorld()) return;
 

	
 
	if (_game_mode == GM_EDITOR) {
 
		RunTileLoop();
0 comments (0 inline, 0 general)