mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-12 03:36:42 +00:00
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:
parent
c32a3ea0d3
commit
15a16e556c
@ -72,7 +72,10 @@ static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSiz
|
|||||||
|
|
||||||
// Seek to the actual PNG image
|
// Seek to the actual PNG image
|
||||||
loadString(*file); // Marker (BS25SAVEGAME)
|
loadString(*file); // Marker (BS25SAVEGAME)
|
||||||
loadString(*file); // Version
|
Common::String storedVersionID = loadString(*file); // Version
|
||||||
|
if (storedVersionID != "SCUMMVM1")
|
||||||
|
loadString(*file);
|
||||||
|
|
||||||
loadString(*file); // Description
|
loadString(*file); // Description
|
||||||
uint32 compressedGamedataSize = atoi(loadString(*file).c_str());
|
uint32 compressedGamedataSize = atoi(loadString(*file).c_str());
|
||||||
loadString(*file); // Uncompressed game data size
|
loadString(*file); // Uncompressed game data size
|
||||||
|
@ -35,9 +35,10 @@
|
|||||||
|
|
||||||
namespace Sword25 {
|
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),
|
_data(static_cast<const byte *>(data), dataLength),
|
||||||
_errorState(NONE) {
|
_errorState(NONE),
|
||||||
|
_version(version) {
|
||||||
_iter = _data.begin();
|
_iter = _data.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ public:
|
|||||||
OUT_OF_SYNC
|
OUT_OF_SYNC
|
||||||
};
|
};
|
||||||
|
|
||||||
InputPersistenceBlock(const void *data, uint dataLength);
|
InputPersistenceBlock(const void *data, uint dataLength, int version);
|
||||||
virtual ~InputPersistenceBlock();
|
virtual ~InputPersistenceBlock();
|
||||||
|
|
||||||
void read(int16 &value);
|
void read(int16 &value);
|
||||||
@ -64,6 +64,8 @@ public:
|
|||||||
return _errorState;
|
return _errorState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getVersion() const { return _version; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool checkMarker(byte marker);
|
bool checkMarker(byte marker);
|
||||||
bool checkBlockSize(int size);
|
bool checkBlockSize(int size);
|
||||||
@ -72,6 +74,8 @@ private:
|
|||||||
Common::Array<byte> _data;
|
Common::Array<byte> _data;
|
||||||
Common::Array<byte>::const_iterator _iter;
|
Common::Array<byte>::const_iterator _iter;
|
||||||
ErrorState _errorState;
|
ErrorState _errorState;
|
||||||
|
|
||||||
|
int _version;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Sword25
|
} // End of namespace Sword25
|
||||||
|
@ -50,7 +50,9 @@ static const char *SAVEGAME_DIRECTORY = "saves";
|
|||||||
static const char *FILE_MARKER = "BS25SAVEGAME";
|
static const char *FILE_MARKER = "BS25SAVEGAME";
|
||||||
static const uint SLOT_COUNT = 18;
|
static const uint SLOT_COUNT = 18;
|
||||||
static const uint FILE_COPY_BUFFER_SIZE = 1024 * 10;
|
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
|
#define MAX_SAVEGAME_SIZE 100
|
||||||
|
|
||||||
@ -99,6 +101,7 @@ struct SavegameInformation {
|
|||||||
bool isOccupied;
|
bool isOccupied;
|
||||||
bool isCompatible;
|
bool isCompatible;
|
||||||
Common::String description;
|
Common::String description;
|
||||||
|
int version;
|
||||||
uint gamedataLength;
|
uint gamedataLength;
|
||||||
uint gamedataOffset;
|
uint gamedataOffset;
|
||||||
uint gamedataUncompressedLength;
|
uint gamedataUncompressedLength;
|
||||||
@ -147,9 +150,15 @@ struct PersistenceService::Impl {
|
|||||||
// Read in the header
|
// Read in the header
|
||||||
Common::String storedMarker = loadString(file);
|
Common::String storedMarker = loadString(file);
|
||||||
Common::String storedVersionID = 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 gameDescription = loadString(file);
|
||||||
Common::String gameDataLength = loadString(file);
|
Common::String gamedataLength = loadString(file);
|
||||||
curSavegameInfo.gamedataLength = atoi(gameDataLength.c_str());
|
curSavegameInfo.gamedataLength = atoi(gamedataLength.c_str());
|
||||||
Common::String gamedataUncompressedLength = loadString(file);
|
Common::String gamedataUncompressedLength = loadString(file);
|
||||||
curSavegameInfo.gamedataUncompressedLength = atoi(gamedataUncompressedLength.c_str());
|
curSavegameInfo.gamedataUncompressedLength = atoi(gamedataUncompressedLength.c_str());
|
||||||
|
|
||||||
@ -158,7 +167,7 @@ struct PersistenceService::Impl {
|
|||||||
// The slot is marked as occupied.
|
// The slot is marked as occupied.
|
||||||
curSavegameInfo.isOccupied = true;
|
curSavegameInfo.isOccupied = true;
|
||||||
// Check if the saved game is compatible with the current engine version.
|
// 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.
|
// Load the save game description.
|
||||||
curSavegameInfo.description = gameDescription;
|
curSavegameInfo.description = gameDescription;
|
||||||
// The offset to the stored save game data within the file.
|
// The offset to the stored save game data within the file.
|
||||||
@ -242,6 +251,12 @@ Common::String &PersistenceService::getSavegameFilename(uint slotID) {
|
|||||||
return result;
|
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) {
|
bool PersistenceService::saveGame(uint slotID, const Common::String &screenshotFilename) {
|
||||||
// FIXME: This code is a hack which bypasses the savefile API,
|
// FIXME: This code is a hack which bypasses the savefile API,
|
||||||
// and should eventually be removed.
|
// and should eventually be removed.
|
||||||
@ -264,6 +279,11 @@ bool PersistenceService::saveGame(uint slotID, const Common::String &screenshotF
|
|||||||
file->writeString(VERSIONID);
|
file->writeString(VERSIONID);
|
||||||
file->writeByte(0);
|
file->writeByte(0);
|
||||||
|
|
||||||
|
char buf[20];
|
||||||
|
snprintf(buf, 20, "%d", VERSIONNUM);
|
||||||
|
file->writeString(buf);
|
||||||
|
file->writeByte(0);
|
||||||
|
|
||||||
TimeDate dt;
|
TimeDate dt;
|
||||||
g_system->getTimeAndDate(dt);
|
g_system->getTimeAndDate(dt);
|
||||||
file->writeString(formatTimestamp(dt));
|
file->writeString(formatTimestamp(dt));
|
||||||
@ -385,7 +405,7 @@ bool PersistenceService::loadGame(uint slotID) {
|
|||||||
memcpy(uncompressedDataBuffer, compressedDataBuffer, uncompressedBufferSize);
|
memcpy(uncompressedDataBuffer, compressedDataBuffer, uncompressedBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength);
|
InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength, curSavegameInfo.version);
|
||||||
|
|
||||||
// Einzelne Engine-Module depersistieren.
|
// Einzelne Engine-Module depersistieren.
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
@ -57,6 +57,7 @@ public:
|
|||||||
void reloadSlots();
|
void reloadSlots();
|
||||||
bool isSlotOccupied(uint slotID);
|
bool isSlotOccupied(uint slotID);
|
||||||
bool isSavegameCompatible(uint slotID);
|
bool isSavegameCompatible(uint slotID);
|
||||||
|
int getSavegameVersion(uint slotID);
|
||||||
Common::String &getSavegameDescription(uint slotID);
|
Common::String &getSavegameDescription(uint slotID);
|
||||||
Common::String &getSavegameFilename(uint slotID);
|
Common::String &getSavegameFilename(uint slotID);
|
||||||
|
|
||||||
|
@ -33,6 +33,8 @@
|
|||||||
#include "sword25/sfx/soundengine.h"
|
#include "sword25/sfx/soundengine.h"
|
||||||
#include "sword25/package/packagemanager.h"
|
#include "sword25/package/packagemanager.h"
|
||||||
#include "sword25/kernel/resource.h"
|
#include "sword25/kernel/resource.h"
|
||||||
|
#include "sword25/kernel/inputpersistenceblock.h"
|
||||||
|
#include "sword25/kernel/outputpersistenceblock.h"
|
||||||
|
|
||||||
#include "audio/decoders/vorbis.h"
|
#include "audio/decoders/vorbis.h"
|
||||||
|
|
||||||
@ -202,18 +204,30 @@ bool SoundEngine::playSound(const Common::String &fileName, SOUND_TYPES type, fl
|
|||||||
return true;
|
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);
|
Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(fileName);
|
||||||
#ifdef USE_VORBIS
|
#ifdef USE_VORBIS
|
||||||
Audio::SeekableAudioStream *stream = Audio::makeVorbisStream(in, DisposeAfterUse::YES);
|
Audio::SeekableAudioStream *stream = Audio::makeVorbisStream(in, DisposeAfterUse::YES);
|
||||||
#endif
|
#endif
|
||||||
uint id;
|
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);
|
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
|
#ifdef USE_VORBIS
|
||||||
_mixer->playStream(getType(type), &(handle->handle), stream, -1, (byte)(volume * 255), (int8)(pan * 127));
|
_mixer->playStream(getType(type), &(handle->handle), stream, -1, (byte)(volume * 255), (int8)(pan * 127));
|
||||||
#endif
|
#endif
|
||||||
@ -311,16 +325,61 @@ bool SoundEngine::canLoadResource(const Common::String &fileName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SoundEngine::persist(OutputPersistenceBlock &writer) {
|
bool SoundEngine::persist(OutputPersistenceBlock &writer) {
|
||||||
warning("STUB: SoundEngine::persist()");
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SoundEngine::unpersist(InputPersistenceBlock &reader) {
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,6 +65,15 @@ struct SndHandle {
|
|||||||
Audio::SoundHandle handle;
|
Audio::SoundHandle handle;
|
||||||
sndHandleType type;
|
sndHandleType type;
|
||||||
uint32 id;
|
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
|
* @remark If more control is needed over the playing, eg. changing the sound parameters
|
||||||
* for Volume and Panning, then PlaySoundEx should be used.
|
* 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
|
* Sets the volume of a playing sound
|
||||||
|
Loading…
x
Reference in New Issue
Block a user