Example #1
0
void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, bool keepIndex) {
#define LOAD_ENTRY(name, func, val) { \
	uint32 _prevPosition = (uint32)_savegame->pos(); \
	func; \
	uint32 _count = (uint32)_savegame->pos() - _prevPosition; \
	debugC(kLastExpressDebugSavegame, "Savegame: Reading " #name ": %d bytes", _count); \
	if (_count != val) \
		error("SaveLoad::readEntry: Number of bytes read (%d) differ from expected count (%d)", _count, val); \
}

#define LOAD_ENTRY_ONLY(name, func) { \
	uint32 _prevPosition = (uint32)_savegame->pos(); \
	func; \
	uint32 _count = (uint32)_savegame->pos() - _prevPosition; \
	debugC(kLastExpressDebugSavegame, "Savegame: Reading " #name ": %d bytes", _count); \
}

	if (!type || !entity || !val)
		error("SaveLoad::readEntry: Invalid parameters passed!");

	// Load entry header
	SavegameEntryHeader entry;
	Common::Serializer ser(_savegame, NULL);
	entry.saveLoadWithSerializer(ser);

	if (!entry.isValid())
		error("SaveLoad::readEntry: entry header is invalid!");

	// Init type, entity & value
	*type = entry.type;
	*val = entry.value;

	// Save position
	uint32 originalPosition = (uint32)_savegame->pos();

	// Load game data
	LOAD_ENTRY("entity index", ser.syncAsUint32LE(*entity), 4);
	LOAD_ENTRY("state", getState()->saveLoadWithSerializer(ser), 4 + 4 + 4 + 4 + 1 + 4 + 4);
	LOAD_ENTRY("selected item", getInventory()->saveSelectedItem(ser), 4);
	LOAD_ENTRY("positions", getEntities()->savePositions(ser), 4 * 1000);
	LOAD_ENTRY("compartments", getEntities()->saveCompartments(ser), 4 * 16 * 2);
	LOAD_ENTRY("progress", getProgress().saveLoadWithSerializer(ser), 4 * 128);
	LOAD_ENTRY("events", getState()->syncEvents(ser), 512);
	LOAD_ENTRY("inventory", getInventory()->saveLoadWithSerializer(ser), 7 * 32);
	LOAD_ENTRY("objects", getObjects()->saveLoadWithSerializer(ser), 5 * 128);
	LOAD_ENTRY("entities", getEntities()->saveLoadWithSerializer(ser), 1262 * 40);
	LOAD_ENTRY_ONLY("sound", getSound()->saveLoadWithSerializer(ser));
	LOAD_ENTRY_ONLY("savepoints", getSavePoints()->saveLoadWithSerializer(ser));

	// Update chapter
	getProgress().chapter = entry.chapter;

	// Skip padding
	uint32 offset = _savegame->pos() - originalPosition;
	if (offset & 0xF) {
		_savegame->seek((~offset & 0xF) + 1, SEEK_SET);
	}
}
Example #2
0
uint32 SaveLoad::init(GameId id, bool resetHeaders) {
	initStream();

	// Load game data
	loadStream(id);

	// Get the main header
	Common::Serializer ser(_savegame, NULL);
	SavegameMainHeader mainHeader;
	mainHeader.saveLoadWithSerializer(ser);
	if (!mainHeader.isValid())
		error("SaveLoad::init - Savegame seems to be corrupted (invalid header)");

	// Reset cached entry headers if needed
	if (resetHeaders) {
		clear();

		SavegameEntryHeader *entryHeader = new SavegameEntryHeader();
		entryHeader->time = kTimeCityParis;
		entryHeader->chapter = kChapter1;

		_gameHeaders.push_back(entryHeader);
	}

	// Read the list of entry headers
	if (_savegame->size() > 32) {
		while (_savegame->pos() < _savegame->size() && !_savegame->eos() && !_savegame->err()) {

			// Update sound queue while we go through the savegame
			getSound()->updateQueue();

			SavegameEntryHeader *entry = new SavegameEntryHeader();
			entry->saveLoadWithSerializer(ser);

			if (!entry->isValid())
				break;

			_gameHeaders.push_back(entry);

			_savegame->seek(entry->offset, SEEK_CUR);
		}
	}

	// return the index to the current save game entry (we store count + 1 entries, so we're good)
	return mainHeader.count;
}
Example #3
0
//////////////////////////////////////////////////////////////////////////
// Entries
//////////////////////////////////////////////////////////////////////////
void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) {
#define WRITE_ENTRY(name, func, val) { \
	uint32 _prevPosition = (uint32)_savegame->pos(); \
	func; \
	uint32 _count = (uint32)_savegame->pos() - _prevPosition; \
	debugC(kLastExpressDebugSavegame, "Savegame: Writing " #name ": %d bytes", _count); \
	if (_count != val)\
		error("SaveLoad::writeEntry: Number of bytes written (%d) differ from expected count (%d)", _count, val); \
}

	if (!_savegame)
		error("SaveLoad::writeEntry: savegame stream is invalid");

	SavegameEntryHeader header;

	header.type = type;
	header.time = (uint32)getState()->time;
	header.chapter = getProgress().chapter;
	header.value = value;

	// Save position
	uint32 originalPosition = (uint32)_savegame->pos();

	// Write header
	Common::Serializer ser(NULL, _savegame);
	header.saveLoadWithSerializer(ser);

	// Write game data
	WRITE_ENTRY("entity index", ser.syncAsUint32LE(entity), 4);
	WRITE_ENTRY("state", getState()->saveLoadWithSerializer(ser), 4 + 4 + 4 + 4 + 1 + 4 + 4);
	WRITE_ENTRY("selected item", getInventory()->saveSelectedItem(ser), 4);
	WRITE_ENTRY("positions", getEntities()->savePositions(ser), 4 * 1000);
	WRITE_ENTRY("compartments", getEntities()->saveCompartments(ser), 4 * 16 * 2);
	WRITE_ENTRY("progress", getProgress().saveLoadWithSerializer(ser), 4 * 128);
	WRITE_ENTRY("events", getState()->syncEvents(ser), 512);
	WRITE_ENTRY("inventory", getInventory()->saveLoadWithSerializer(ser), 7 * 32);
	WRITE_ENTRY("objects", getObjects()->saveLoadWithSerializer(ser), 5 * 128);
	WRITE_ENTRY("entities", getEntities()->saveLoadWithSerializer(ser), 1262 * 40);
	WRITE_ENTRY("sound", getSound()->saveLoadWithSerializer(ser), 3 * 4 + getSound()->count() * 64);
	WRITE_ENTRY("savepoints", getSavePoints()->saveLoadWithSerializer(ser), 128 * 16 + 4 + getSavePoints()->count() * 16);

	header.offset = (uint32)_savegame->pos() - (originalPosition + 32);

	// Add padding if necessary
	while (header.offset & 0xF) {
		_savegame->writeByte(0);
		header.offset++;
	}

	// Save end position
	uint32 endPosition = (uint32)_savegame->pos();

	// Validate entry header
	if (!header.isValid())
		error("SaveLoad::writeEntry: entry header is invalid");

	// Save the header with the updated info
	_savegame->seek(originalPosition);
	header.saveLoadWithSerializer(ser);

	// Move back to the end of the entry
	_savegame->seek(endPosition);
}
Example #4
0
// Save game
void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) {
	if (getState()->scene <= kSceneIntro)
		return;

	// Validate main header
	SavegameMainHeader header;
	if (!loadMainHeader(_savegame, &header)) {
		debugC(2, kLastExpressDebugSavegame, "SaveLoad::saveGame - Cannot load main header: %s", getFilename(getMenu()->getGameId()).c_str());
		return;
	}

	if (!_savegame)
		error("SaveLoad::saveGame: savegame stream is invalid");

	// Validate the current entry if it exists
	if (header.count > 0) {
		_savegame->seek(header.offsetEntry);

		// Load entry header
		SavegameEntryHeader entry;
		Common::Serializer ser(_savegame, NULL);
		entry.saveLoadWithSerializer(ser);

		if (!entry.isValid()) {
			warning("SaveLoad::saveGame: Invalid entry. This savegame might be corrupted!");
			_savegame->seek(header.offset);
		} else if (getState()->time < entry.time || (type == kSavegameTypeTickInterval && getState()->time == entry.time)) {
			// Not ready to save a game, skipping!
			return;
		} else if ((type == kSavegameTypeTime || type == kSavegameTypeEvent)
			&& (entry.type == kSavegameTypeTickInterval && (getState()->time - entry.time) < 450)) {
			_savegame->seek(header.offsetEntry);
			--header.count;
		} else {
			_savegame->seek(header.offset);
		}
	} else {
		// Seek to the next savegame entry
		_savegame->seek(header.offset);
	}

	if (type != kSavegameTypeEvent2 && type != kSavegameTypeAuto)
		header.offsetEntry = (uint32)_savegame->pos();

	// Write the savegame entry
	writeEntry(type, entity, value);

	if (!header.keepIndex)
		++header.count;

	if (type == kSavegameTypeEvent2 || type == kSavegameTypeAuto) {
		header.keepIndex = 1;
	} else {
		header.keepIndex = 0;
		header.offset = (uint32)_savegame->pos();

		// Save ticks
		_gameTicksLastSavegame = getState()->timeTicks;
	}

	// Validate the main header
	if (!header.isValid())
		error("SaveLoad::saveGame: main game header is invalid!");

	// Write the main header
	_savegame->seek(0);
	Common::Serializer ser(NULL, _savegame);
	header.saveLoadWithSerializer(ser);

	flushStream(getMenu()->getGameId());
}