SWORD25: Implement persistence functions for soundengine

Now sound is properly saved/restored. Implemented savegame versioning.
Compatibility with old saves pertained.
This commit is contained in:
Eugene Sandulenko 2011-06-28 22:55:14 +03:00
parent c32a3ea0d3
commit 15a16e556c
7 changed files with 115 additions and 18 deletions

View File

@ -72,7 +72,10 @@ static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSiz
// Seek to the actual PNG image
loadString(*file); // Marker (BS25SAVEGAME)
loadString(*file); // Version
Common::String storedVersionID = loadString(*file); // Version
if (storedVersionID != "SCUMMVM1")
loadString(*file);
loadString(*file); // Description
uint32 compressedGamedataSize = atoi(loadString(*file).c_str());
loadString(*file); // Uncompressed game data size

View File

@ -35,9 +35,10 @@
namespace Sword25 {
InputPersistenceBlock::InputPersistenceBlock(const void *data, uint dataLength) :
InputPersistenceBlock::InputPersistenceBlock(const void *data, uint dataLength, int version) :
_data(static_cast<const byte *>(data), dataLength),
_errorState(NONE) {
_errorState(NONE),
_version(version) {
_iter = _data.begin();
}

View File

@ -46,7 +46,7 @@ public:
OUT_OF_SYNC
};
InputPersistenceBlock(const void *data, uint dataLength);
InputPersistenceBlock(const void *data, uint dataLength, int version);
virtual ~InputPersistenceBlock();
void read(int16 &value);
@ -64,6 +64,8 @@ public:
return _errorState;
}
int getVersion() const { return _version; }
private:
bool checkMarker(byte marker);
bool checkBlockSize(int size);
@ -72,6 +74,8 @@ private:
Common::Array<byte> _data;
Common::Array<byte>::const_iterator _iter;
ErrorState _errorState;
int _version;
};
} // End of namespace Sword25

View File

@ -50,7 +50,9 @@ static const char *SAVEGAME_DIRECTORY = "saves";
static const char *FILE_MARKER = "BS25SAVEGAME";
static const uint SLOT_COUNT = 18;
static const uint FILE_COPY_BUFFER_SIZE = 1024 * 10;
static const char *VERSIONID = "SCUMMVM1";
static const char *VERSIONIDOLD = "SCUMMVM1";
static const char *VERSIONID = "SCUMMVM2";
static const int VERSIONNUM = 2;
#define MAX_SAVEGAME_SIZE 100
@ -99,6 +101,7 @@ struct SavegameInformation {
bool isOccupied;
bool isCompatible;
Common::String description;
int version;
uint gamedataLength;
uint gamedataOffset;
uint gamedataUncompressedLength;
@ -147,9 +150,15 @@ struct PersistenceService::Impl {
// Read in the header
Common::String storedMarker = loadString(file);
Common::String storedVersionID = loadString(file);
if (storedVersionID == VERSIONIDOLD) {
curSavegameInfo.version = 1;
} else {
Common::String versionNum = loadString(file);
curSavegameInfo.version = atoi(versionNum.c_str());
}
Common::String gameDescription = loadString(file);
Common::String gameDataLength = loadString(file);
curSavegameInfo.gamedataLength = atoi(gameDataLength.c_str());
Common::String gamedataLength = loadString(file);
curSavegameInfo.gamedataLength = atoi(gamedataLength.c_str());
Common::String gamedataUncompressedLength = loadString(file);
curSavegameInfo.gamedataUncompressedLength = atoi(gamedataUncompressedLength.c_str());
@ -158,7 +167,7 @@ struct PersistenceService::Impl {
// The slot is marked as occupied.
curSavegameInfo.isOccupied = true;
// Check if the saved game is compatible with the current engine version.
curSavegameInfo.isCompatible = (storedVersionID == Common::String(VERSIONID));
curSavegameInfo.isCompatible = (curSavegameInfo.version <= VERSIONNUM);
// Load the save game description.
curSavegameInfo.description = gameDescription;
// The offset to the stored save game data within the file.
@ -242,6 +251,12 @@ Common::String &PersistenceService::getSavegameFilename(uint slotID) {
return result;
}
int PersistenceService::getSavegameVersion(uint slotID) {
if (!checkslotID(slotID))
return -1;
return _impl->_savegameInformations[slotID].version;
}
bool PersistenceService::saveGame(uint slotID, const Common::String &screenshotFilename) {
// FIXME: This code is a hack which bypasses the savefile API,
// and should eventually be removed.
@ -264,6 +279,11 @@ bool PersistenceService::saveGame(uint slotID, const Common::String &screenshotF
file->writeString(VERSIONID);
file->writeByte(0);
char buf[20];
snprintf(buf, 20, "%d", VERSIONNUM);
file->writeString(buf);
file->writeByte(0);
TimeDate dt;
g_system->getTimeAndDate(dt);
file->writeString(formatTimestamp(dt));
@ -385,7 +405,7 @@ bool PersistenceService::loadGame(uint slotID) {
memcpy(uncompressedDataBuffer, compressedDataBuffer, uncompressedBufferSize);
}
InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength);
InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength, curSavegameInfo.version);
// Einzelne Engine-Module depersistieren.
bool success = true;

View File

@ -57,6 +57,7 @@ public:
void reloadSlots();
bool isSlotOccupied(uint slotID);
bool isSavegameCompatible(uint slotID);
int getSavegameVersion(uint slotID);
Common::String &getSavegameDescription(uint slotID);
Common::String &getSavegameFilename(uint slotID);

View File

@ -33,6 +33,8 @@
#include "sword25/sfx/soundengine.h"
#include "sword25/package/packagemanager.h"
#include "sword25/kernel/resource.h"
#include "sword25/kernel/inputpersistenceblock.h"
#include "sword25/kernel/outputpersistenceblock.h"
#include "audio/decoders/vorbis.h"
@ -202,18 +204,30 @@ bool SoundEngine::playSound(const Common::String &fileName, SOUND_TYPES type, fl
return true;
}
uint SoundEngine::playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume, float pan, bool loop, int loopStart, int loopEnd, uint layer) {
uint SoundEngine::playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume, float pan, bool loop, int loopStart, int loopEnd, uint layer, uint handleId) {
Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(fileName);
#ifdef USE_VORBIS
Audio::SeekableAudioStream *stream = Audio::makeVorbisStream(in, DisposeAfterUse::YES);
#endif
uint id;
SndHandle *handle = getHandle(&id);
SndHandle *handle;
if (handleId == 0x1337)
handle = getHandle(&id);
else
handle = &_handles[handleId];
handle->fileName = fileName;
handle->sndType = type;
handle->volume = volume;
handle->pan = pan;
handle->loop = loop;
handle->loopStart = loopStart;
handle->loopEnd = loopEnd;
handle->layer = layer;
debugC(1, kDebugSound, "SoundEngine::playSoundEx(%s, %d, %f, %f, %d, %d, %d, %d)", fileName.c_str(), type, volume, pan, loop, loopStart, loopEnd, layer);
handle->type = kAllocatedHandle;
#ifdef USE_VORBIS
_mixer->playStream(getType(type), &(handle->handle), stream, -1, (byte)(volume * 255), (int8)(pan * 127));
#endif
@ -311,16 +325,61 @@ bool SoundEngine::canLoadResource(const Common::String &fileName) {
}
bool SoundEngine::persist(OutputPersistenceBlock &writer) {
warning("STUB: SoundEngine::persist()");
bool SoundEngine::persist(OutputPersistenceBlock &writer) {
writer.write(_maxHandleId);
for (uint i = 0; i < SOUND_HANDLES; i++) {
writer.write(_handles[i].id);
writer.writeString(_handles[i].fileName);
writer.write((int)_handles[i].sndType);
writer.write(_handles[i].volume);
writer.write(_handles[i].pan);
writer.write(_handles[i].loop);
writer.write(_handles[i].loopStart);
writer.write(_handles[i].loopEnd);
writer.write(_handles[i].layer);
}
return true;
}
bool SoundEngine::unpersist(InputPersistenceBlock &reader) {
warning("STUB: SoundEngine::unpersist()");
_mixer->stopAll();
return true;
if (reader.getVersion() < 2)
return true;
reader.read(_maxHandleId);
for (uint i = 0; i < SOUND_HANDLES; i++) {
reader.read(_handles[i].id);
Common::String fileName;
int sndType;
float volume;
float pan;
bool loop;
int loopStart;
int loopEnd;
uint layer;
reader.readString(fileName);
reader.read(sndType);
reader.read(volume);
reader.read(pan);
reader.read(loop);
reader.read(loopStart);
reader.read(loopEnd);
reader.read(layer);
if (reader.isGood()) {
playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i);
} else
return false;
}
return reader.isGood();
}

View File

@ -65,6 +65,15 @@ struct SndHandle {
Audio::SoundHandle handle;
sndHandleType type;
uint32 id;
Common::String fileName;
int sndType;
float volume;
float pan;
bool loop;
int loopStart;
int loopEnd;
uint layer;
};
@ -176,7 +185,7 @@ public:
* @remark If more control is needed over the playing, eg. changing the sound parameters
* for Volume and Panning, then PlaySoundEx should be used.
*/
uint playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume = 1.0f, float pan = 0.0f, bool loop = false, int loopStart = -1, int loopEnd = -1, uint layer = 0);
uint playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume = 1.0f, float pan = 0.0f, bool loop = false, int loopStart = -1, int loopEnd = -1, uint layer = 0, uint handleId = 0x1337);
/**
* Sets the volume of a playing sound