Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
/*
* common.h
* -----------
* This file contains functions or macros that are used across the entire project.
* It is therefore extremely important that this header file be referenced in all
* the other header files in the project.
*
* Autor: Malte Thiesen
*/
#ifndef SWORD25_COMMON_H
#define SWORD25_COMMON_H
// Global constants
#define DEBUG
// Includes
#include "common/array.h"
#include "common/file.h"
#include "sword25/kernel/common.h"
#include "common/debug.h"
#endif

View File

@@ -0,0 +1,83 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#include "common/config-manager.h"
#include "common/fs.h"
#include "common/textconsole.h"
#include "sword25/kernel/filesystemutil.h"
#include "sword25/kernel/persistenceservice.h"
namespace Sword25 {
Common::Path FileSystemUtil::getUserdataDirectoryPath() {
// FIXME: This code is a hack which bypasses the savefile API,
// and should eventually be removed.
Common::Path path = ConfMan.getPath("savepath");
if (path.empty()) {
error("No save path has been defined");
}
return path;
}
Common::String FileSystemUtil::getUserdataDirectory() {
// Return the path using / separator
return getUserdataDirectoryPath().toString('/');
}
Common::String FileSystemUtil::getPathSeparator() {
// FIXME: This code is a hack which bypasses the savefile API,
// and should eventually be removed.
return Common::String("/");
}
bool FileSystemUtil::fileExists(const Common::String &filename) {
Common::File f;
if (f.exists(Common::Path(filename)))
return true;
// Check if the file exists in the save folder
Common::FSNode folder(PersistenceService::getSavegameDirectory());
Common::FSNode fileNode = folder.getChild(getPathFilename(filename));
return fileNode.exists();
}
Common::String FileSystemUtil::getPathFilename(const Common::String &path) {
for (int i = path.size() - 1; i >= 0; --i) {
if ((path[i] == '/') || (path[i] == '\\')) {
return Common::String(&path.c_str()[i + 1]);
}
}
return path;
}
} // End of namespace Sword25

View File

@@ -0,0 +1,98 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
/*
*
* The class BS_FileSystemUtil represents a wrapper for file system specific
* operations that do not have equivalents in the C/C++ libraries.
*
* Each supported platform must implement this interface, and the method
* BS_FileSystemUtil Singleton::instance()
*/
#ifndef SWORD25_FILESYSTEMUTIL_H
#define SWORD25_FILESYSTEMUTIL_H
// -----------------------------------------------------------------------------
// Includes
// -----------------------------------------------------------------------------
#include "common/system.h"
#include "common/str.h"
#include "common/str-array.h"
#include "sword25/kernel/common.h"
namespace Sword25 {
// -----------------------------------------------------------------------------
// Class definitions
// -----------------------------------------------------------------------------
class FileSystemUtil {
public:
/**
* This function returns the path of the directory in which all user data is to be stored.
*
* These are for example Screenshots, game saves, configuration files, log files, ...
* @return Returns the name of the directory for user data.
*/
static Common::Path getUserdataDirectoryPath();
/**
* This function returns the name of the directory in which all user data is to be stored.
*
* These are for example Screenshots, game saves, configuration files, log files, ...
* @return Returns the name of the directory for user data.
*/
static Common::String getUserdataDirectory();
/**
* @return Returns the path separator
*/
static Common::String getPathSeparator();
/**
* @param Filename The path to a file.
* @return Returns true if the file exists.
*/
static bool fileExists(const Common::String &filename);
/**
* Gets the filename from a path and filename
* @param Filename The full path and filename
* @return Returns just the filename
*/
static Common::String getPathFilename(const Common::String &path);
};
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,143 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#include "common/textconsole.h"
#include "sword25/kernel/inputpersistenceblock.h"
namespace Sword25 {
InputPersistenceBlock::InputPersistenceBlock(const void *data, uint dataLength, int version) :
_data(static_cast<const byte *>(data), dataLength),
_errorState(NONE),
_version(version) {
_iter = _data.begin();
}
InputPersistenceBlock::~InputPersistenceBlock() {
if (_iter != _data.end())
warning("Persistence block was not read to the end.");
}
void InputPersistenceBlock::read(int16 &value) {
int32 v;
read(v);
value = static_cast<int16>(v);
}
void InputPersistenceBlock::read(int32 &value) {
if (checkMarker(SINT_MARKER)) {
value = (int32)READ_LE_UINT32(_iter);
_iter += 4;
} else {
value = 0;
}
}
void InputPersistenceBlock::read(uint32 &value) {
if (checkMarker(UINT_MARKER)) {
value = READ_LE_UINT32(_iter);
_iter += 4;
} else {
value = 0;
}
}
void InputPersistenceBlock::read(float &value) {
if (checkMarker(FLOAT_MARKER)) {
uint32 tmp[1];
tmp[0] = READ_LE_UINT32(_iter);
value = ((float *)tmp)[0];
_iter += 4;
} else {
value = 0.0f;
}
}
void InputPersistenceBlock::read(bool &value) {
if (checkMarker(BOOL_MARKER)) {
uint uintBool = READ_LE_UINT32(_iter);
_iter += 4;
value = uintBool != 0;
} else {
value = false;
}
}
void InputPersistenceBlock::readString(Common::String &value) {
value = "";
if (checkMarker(STRING_MARKER)) {
uint32 size;
read(size);
if (checkBlockSize(size)) {
value = Common::String(reinterpret_cast<const char *>(&*_iter), size);
_iter += size;
}
}
}
void InputPersistenceBlock::readByteArray(Common::Array<byte> &value) {
if (checkMarker(BLOCK_MARKER)) {
uint32 size;
read(size);
if (checkBlockSize(size)) {
value = Common::Array<byte>(_iter, size);
_iter += size;
}
}
}
bool InputPersistenceBlock::checkBlockSize(int size) {
if (_data.end() - _iter >= size) {
return true;
} else {
_errorState = END_OF_DATA;
error("Unexpected end of persistence block.");
return false;
}
}
bool InputPersistenceBlock::checkMarker(byte marker) {
if (!isGood() || !checkBlockSize(1))
return false;
if (*_iter++ == marker) {
return true;
} else {
_errorState = OUT_OF_SYNC;
error("Wrong type marker found in persistence block.");
return false;
}
}
} // End of namespace Sword25

View File

@@ -0,0 +1,81 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#ifndef SWORD25_INPUTPERSISTENCEBLOCK_H
#define SWORD25_INPUTPERSISTENCEBLOCK_H
#include "common/array.h"
#include "sword25/kernel/common.h"
#include "sword25/kernel/persistenceblock.h"
namespace Sword25 {
class InputPersistenceBlock : public PersistenceBlock {
public:
enum ErrorState {
NONE,
END_OF_DATA,
OUT_OF_SYNC
};
InputPersistenceBlock(const void *data, uint dataLength, int version);
virtual ~InputPersistenceBlock();
void read(int16 &value);
void read(int32 &value);
void read(uint32 &value);
void read(float &value);
void read(bool &value);
void readString(Common::String &value);
void readByteArray(Common::Array<byte> &value);
bool isGood() const {
return _errorState == NONE;
}
ErrorState getErrorState() const {
return _errorState;
}
int getVersion() const { return _version; }
private:
bool checkMarker(byte marker);
bool checkBlockSize(int size);
Common::Array<byte> _data;
Common::Array<byte>::const_iterator _iter;
ErrorState _errorState;
int _version;
};
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,193 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#include "common/system.h"
#include "sword25/sword25.h" // for kDebugScript
#include "sword25/gfx/graphicengine.h"
#include "sword25/fmv/movieplayer.h"
#include "sword25/input/inputengine.h"
#include "sword25/kernel/kernel.h"
#include "sword25/kernel/persistenceservice.h"
#include "sword25/math/geometry.h"
#include "sword25/package/packagemanager.h"
#include "sword25/script/luascript.h"
#include "sword25/sfx/soundengine.h"
namespace Sword25 {
Kernel *Kernel::_instance = 0;
Kernel::Kernel() :
_resourceManager(NULL),
_initSuccess(false),
_gfx(0),
_sfx(0),
_input(0),
_package(0),
_script(0),
_fmv(0),
_rnd("sword25")
{
_instance = this;
// Create the resource manager
_resourceManager = new ResourceManager(this);
// Initialize the script engine
_script = new LuaScriptEngine(this);
if (!_script || !_script->init()) {
_initSuccess = false;
return;
}
// Register kernel script bindings
if (!registerScriptBindings()) {
error("Script bindings could not be registered.");
_initSuccess = false;
return;
}
debugC(kDebugScript, "Script bindings registered.");
_input = new InputEngine(this);
assert(_input);
_gfx = new GraphicEngine(this);
assert(_gfx);
_sfx = new SoundEngine(this);
assert(_sfx);
_package = new PackageManager(this);
assert(_package);
_geometry = new Geometry(this);
assert(_geometry);
_fmv = new MoviePlayer(this);
assert(_fmv);
_initSuccess = true;
}
Kernel::~Kernel() {
// Services are de-registered in reverse order of creation
delete _input;
_input = 0;
delete _gfx;
_gfx = 0;
delete _sfx;
_sfx = 0;
delete _package;
_package = 0;
delete _geometry;
_geometry = 0;
delete _fmv;
_fmv = 0;
delete _script;
_script = 0;
// Resource-Manager freigeben
delete _resourceManager;
}
/**
* Returns a random number
* @param Min The minimum allowed value
* @param Max The maximum allowed value
*/
int Kernel::getRandomNumber(int min, int max) {
assert(min <= max);
return min + _rnd.getRandomNumber(max - min + 1);
}
/**
* Returns the elapsed time since startup in milliseconds
*/
uint Kernel::getMilliTicks() {
return g_system->getMillis();
}
/**
* Returns a pointer to the active Gfx Service, or NULL if no Gfx service is active.
*/
GraphicEngine *Kernel::getGfx() {
return _gfx;
}
/**
* Returns a pointer to the active Sfx Service, or NULL if no Sfx service is active.
*/
SoundEngine *Kernel::getSfx() {
return _sfx;
}
/**
* Returns a pointer to the active input service, or NULL if no input service is active.
*/
InputEngine *Kernel::getInput() {
return _input;
}
/**
* Returns a pointer to the active package manager, or NULL if no manager is active.
*/
PackageManager *Kernel::getPackage() {
return _package;
}
/**
* Returns a pointer to the script engine, or NULL if it is not active.
*/
ScriptEngine *Kernel::getScript() {
return _script;
}
/**
* Returns a pointer to the movie player, or NULL if it is not active.
*/
MoviePlayer *Kernel::getFMV() {
return _fmv;
}
void Kernel::sleep(uint msecs) const {
g_system->delayMillis(msecs);
}
} // End of namespace Sword25

View File

@@ -0,0 +1,195 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
/*
* BS_Kernel
* ---------
* This is the main class of the engine.
* This class creates and manages all other Engine elements: the sound engine, graphics engine ...
* It is not necessary to release all the items individually, this is performed by the Kernel class.
*
* Autor: Malte Thiesen
*/
#ifndef SWORD25_KERNEL_H
#define SWORD25_KERNEL_H
#include "common/scummsys.h"
#include "common/random.h"
#include "common/stack.h"
#include "common/textconsole.h"
#include "common/util.h"
#include "engines/engine.h"
#include "sword25/kernel/common.h"
#include "sword25/kernel/resmanager.h"
namespace Sword25 {
// Class definitions
class Service;
class Geometry;
class GraphicEngine;
class ScriptEngine;
class SoundEngine;
class InputEngine;
class PackageManager;
class MoviePlayer;
/**
* This is the main engine class
*
* This class creates and manages all other engine components such as sound engine, graphics engine ...
* It is not necessary to release all the items individually, this is performed by the Kernel class.
*/
class Kernel {
public:
/**
* Returns the elapsed time since startup in milliseconds
*/
uint getMilliTicks();
/**
* Specifies whether the kernel was successfully initialized
*/
bool getInitSuccess() const {
return _initSuccess;
}
/**
* Returns a pointer to the BS_ResourceManager
*/
ResourceManager *getResourceManager() {
return _resourceManager;
}
/**
* Returns a random number
* @param Min The minimum allowed value
* @param Max The maximum allowed value
*/
int getRandomNumber(int min, int max);
/**
* Returns a pointer to the active Gfx Service, or NULL if no Gfx service is active
*/
GraphicEngine *getGfx();
/**
* Returns a pointer to the active Sfx Service, or NULL if no Sfx service is active
*/
SoundEngine *getSfx();
/**
* Returns a pointer to the active input service, or NULL if no input service is active
*/
InputEngine *getInput();
/**
* Returns a pointer to the active package manager, or NULL if no manager is active
*/
PackageManager *getPackage();
/**
* Returns a pointer to the script engine, or NULL if it is not active
*/
ScriptEngine *getScript();
/**
* Returns a pointer to the movie player, or NULL if it is not active
*/
MoviePlayer *getFMV();
/**
* Pauses for the specified amount of time
* @param Msecs The amount of time in milliseconds
*/
void sleep(uint msecs) const;
/**
* Returns the singleton instance for the kernel
*/
static Kernel *getInstance() {
if (!_instance)
_instance = new Kernel();
return _instance;
}
/**
* Destroys the kernel instance
* This method should only be called when the game is ended. No subsequent calls to any kernel
* methods should be done after calling this method.
*/
static void deleteInstance() {
if (_instance) {
delete _instance;
_instance = NULL;
}
}
/**
* Raises an error. This method is used in crashing testing.
*/
void crash() const {
error("Kernel::Crash");
}
private:
// -----------------------------------------------------------------------------
// Constructor / destructor
// Private singleton methods
// -----------------------------------------------------------------------------
Kernel();
virtual ~Kernel();
// -----------------------------------------------------------------------------
// Singleton instance
// -----------------------------------------------------------------------------
static Kernel *_instance;
bool _initSuccess; // Specifies whether the engine was set up correctly
// Random number generator
// -----------------------
Common::RandomSource _rnd;
// Resourcemanager
// ---------------
ResourceManager *_resourceManager;
GraphicEngine *_gfx;
SoundEngine *_sfx;
InputEngine *_input;
PackageManager *_package;
ScriptEngine *_script;
Geometry *_geometry;
MoviePlayer *_fmv;
bool registerScriptBindings();
};
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,474 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#include "sword25/kernel/common.h"
#include "sword25/kernel/kernel.h"
#include "sword25/kernel/filesystemutil.h"
#include "sword25/kernel/resmanager.h"
#include "sword25/kernel/persistenceservice.h"
#include "sword25/script/script.h"
#include "sword25/script/luabindhelper.h"
namespace Sword25 {
// Marks a function that should never be used
static int dummyFuncError(lua_State *L) {
error("Dummy function invoked by LUA");
return 1;
}
static int getMilliTicks(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
lua_pushnumber(L, pKernel->getMilliTicks());
return 1;
}
static int getTimer(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
lua_pushnumber(L, static_cast<lua_Number>(pKernel->getMilliTicks()) / 1000.0);
return 1;
}
static int startService(lua_State *L) {
// This function is used by system/boot.lua to init all services.
// However, we do nothing here, as we just hard code the init sequence.
lua_pushbooleancpp(L, true);
return 1;
}
static int sleep(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
pKernel->sleep(static_cast<uint>(luaL_checknumber(L, 1) * 1000));
return 0;
}
static int crash(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
pKernel->crash();
return 0;
}
static int executeFile(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
ScriptEngine *pSE = pKernel->getScript();
assert(pSE);
lua_pushbooleancpp(L, pSE->executeFile(luaL_checkstring(L, 1)));
return 0;
}
static int getUserdataDirectory(lua_State *L) {
lua_pushstring(L, FileSystemUtil::getUserdataDirectory().c_str());
return 1;
}
static int getPathSeparator(lua_State *L) {
lua_pushstring(L, FileSystemUtil::getPathSeparator().c_str());
return 1;
}
static int fileExists(lua_State *L) {
lua_pushbooleancpp(L, FileSystemUtil::fileExists(luaL_checkstring(L, 1)));
return 1;
}
static int createDirectory(lua_State *L) {
// ScummVM engines cannot create directories, so we do nothing here.
lua_pushbooleancpp(L, false);
return 1;
}
static int getWinCode(lua_State *L) {
lua_pushstring(L, "ScummVM");
return 1;
}
static int getSubversionRevision(lua_State *L) {
// ScummVM is 1337
lua_pushnumber(L, 1337);
return 1;
}
static int getUsedMemory(lua_State *L) {
// It doesn't really matter what this call returns,
// as it's used in a debug function.
lua_pushnumber(L, 0);
return 1;
}
static const char *KERNEL_LIBRARY_NAME = "Kernel";
static const luaL_reg KERNEL_FUNCTIONS[] = {
{"DisconnectService", dummyFuncError},
{"GetActiveServiceIdentifier", dummyFuncError},
{"GetSuperclassCount", dummyFuncError},
{"GetSuperclassIdentifier", dummyFuncError},
{"GetServiceCount", dummyFuncError},
{"GetServiceIdentifier", dummyFuncError},
{"GetMilliTicks", getMilliTicks},
{"GetTimer", getTimer},
{"StartService", startService},
{"Sleep", sleep},
{"Crash", crash},
{"ExecuteFile", executeFile},
{"GetUserdataDirectory", getUserdataDirectory},
{"GetPathSeparator", getPathSeparator},
{"FileExists", fileExists},
{"CreateDirectory", createDirectory},
{"GetWinCode", getWinCode},
{"GetSubversionRevision", getSubversionRevision},
{"GetUsedMemory", getUsedMemory},
{0, 0}
};
static int isVisible(lua_State *L) {
// This function apparently is not used by the game scripts
lua_pushbooleancpp(L, true);
return 1;
}
static int setVisible(lua_State *L) {
// This function apparently is not used by the game scripts
// pWindow->setVisible(lua_tobooleancpp(L, 1));
return 0;
}
static int getX(lua_State *L) {
// This function apparently is not used by the game scripts
lua_pushnumber(L, 0);
return 1;
}
static int getY(lua_State *L) {
// This function apparently is not used by the game scripts
lua_pushnumber(L, 0);
return 1;
}
static int setX(lua_State *L) {
// This is called by system/boot.lua with -1 as value.
// pWindow->setX(static_cast<int>(luaL_checknumber(L, 1)));
return 0;
}
static int setY(lua_State *L) {
// This is called by system/boot.lua with -1 as value.
// pWindow->setY(static_cast<int>(luaL_checknumber(L, 1)));
return 0;
}
static int getWidth(lua_State *L) {
// This function apparently is not used by the game scripts
lua_pushnumber(L, 800);
return 1;
}
static int getHeight(lua_State *L) {
// This function apparently is not used by the game scripts
lua_pushnumber(L, 600);
return 1;
}
static int setWidth(lua_State *L) {
// This is called by system/boot.lua with 800 as value.
// pWindow->setWidth(static_cast<int>(luaL_checknumber(L, 1)));
return 0;
}
static int setHeight(lua_State *L) {
// This is called by system/boot.lua with 600 as value.
// pWindow->setHeight(static_cast<int>(luaL_checknumber(L, 1)));
return 0;
}
static int getTitle(lua_State *L) {
// This function apparently is not used by the game scripts
lua_pushstring(L, "");
return 1;
}
static int setTitle(lua_State *L) {
// This is called by system/boot.lua and system/menu.lua, to
// set the window title to the (localized) game name.
// FIXME: Should we call OSystem::setWindowCaption() here?
// pWindow->setTitle(luaL_checkstring(L, 1));
return 0;
}
static int processMessages(lua_State *L) {
// This is called by the main loop in system/boot.lua,
// and the game keeps running as true is returned here.
// It terminates if we return false.
// TODO: We could do more stuff here if desired...
// TODO: We could always return true here, and leave quit handling
// to the closeWanted() opcode; see also the TODO comment in there.
lua_pushbooleancpp(L, !Engine::shouldQuit());
g_system->delayMillis(10);
return 1;
}
static int closeWanted(lua_State *L) {
// This is called by system/interface.lua to determine whether the
// user requested the game to close (e.g. by clicking the 'close' widget
// of the game window). As a consequence (i.e. this function returns true),
// a quit confirmation dialog is shown.
// TODO: ScummVM currently has a bug / misfeature where some engines provide
// quit confirmation dialogs, some don't; in addition, we have a global confirmation
// dialog (but the user has to explicitly activate that in the config).
// Anyway, this can lead to *two* confirmation dialogs being shown.
// If it wasn't for that, we could simply check for Engine::shouldQuit() here,
// and then invoke EventMan::resetQuit. But currently this would result in
// the user seeing two confirmation dialogs. Bad.
lua_pushbooleancpp(L, false);
return 1;
}
static const char *WINDOW_LIBRARY_NAME = "Window";
static const luaL_reg WINDOW_FUNCTIONS[] = {
{"IsVisible", isVisible},
{"SetVisible", setVisible},
{"GetX", getX},
{"SetX", setX},
{"GetY", getY},
{"SetY", setY},
{"GetClientX", dummyFuncError},
{"GetClientY", dummyFuncError},
{"GetWidth", getWidth},
{"GetHeight", getHeight},
{"SetWidth", setWidth},
{"SetHeight", setHeight},
{"GetTitle", getTitle},
{"SetTitle", setTitle},
{"ProcessMessages", processMessages},
{"CloseWanted", closeWanted},
{"WaitForFocus", dummyFuncError},
{"HasFocus", dummyFuncError},
{0, 0}
};
static int precacheResource(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
ResourceManager *pResource = pKernel->getResourceManager();
assert(pResource);
#ifdef PRECACHE_RESOURCES
lua_pushbooleancpp(L, pResource->precacheResource(luaL_checkstring(L, 1)));
#else
lua_pushbooleancpp(L, true);
#endif
return 1;
}
static int forcePrecacheResource(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
ResourceManager *pResource = pKernel->getResourceManager();
assert(pResource);
#ifdef PRECACHE_RESOURCES
lua_pushbooleancpp(L, pResource->precacheResource(luaL_checkstring(L, 1), true));
#else
lua_pushbooleancpp(L, true);
#endif
return 1;
}
static int getMaxMemoryUsage(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
ResourceManager *pResource = pKernel->getResourceManager();
assert(pResource);
// This is used for debugging, so it doesn't really matter.
// The default value set by the scripts is 256000000 bytes
lua_pushnumber(L, 256000000);
return 1;
}
static int setMaxMemoryUsage(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
ResourceManager *pResource = pKernel->getResourceManager();
assert(pResource);
// This call is ignored, we set a limit on the number of
// simultaneous resources loaded instead.
return 0;
}
static int emptyCache(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
ResourceManager *pResource = pKernel->getResourceManager();
assert(pResource);
pResource->emptyCache();
return 0;
}
static int dumpLockedResources(lua_State *L) {
Kernel *pKernel = Kernel::getInstance();
assert(pKernel);
ResourceManager *pResource = pKernel->getResourceManager();
assert(pResource);
pResource->dumpLockedResources();
return 0;
}
static const char *RESOURCE_LIBRARY_NAME = "Resource";
static const luaL_reg RESOURCE_FUNCTIONS[] = {
{"PrecacheResource", precacheResource},
{"ForcePrecacheResource", forcePrecacheResource},
{"GetMaxMemoryUsage", getMaxMemoryUsage},
{"SetMaxMemoryUsage", setMaxMemoryUsage},
{"EmptyCache", emptyCache},
{"IsLogCacheMiss", dummyFuncError},
{"SetLogCacheMiss", dummyFuncError},
{"DumpLockedResources", dumpLockedResources},
{0, 0}
};
static int reloadSlots(lua_State *L) {
PersistenceService::getInstance().reloadSlots();
lua_pushnil(L);
return 1;
}
static int getSlotCount(lua_State *L) {
lua_pushnumber(L, PersistenceService::getInstance().getSlotCount());
return 1;
}
static int isSlotOccupied(lua_State *L) {
lua_pushbooleancpp(L, PersistenceService::getInstance().isSlotOccupied(static_cast<uint>(luaL_checknumber(L, 1)) - 1));
return 1;
}
static int getSavegameDirectory(lua_State *L) {
lua_pushstring(L, PersistenceService::getInstance().getSavegameDirectory().toString('/').c_str());
return 1;
}
static int isSavegameCompatible(lua_State *L) {
lua_pushbooleancpp(L, PersistenceService::getInstance().isSavegameCompatible(
static_cast<uint>(luaL_checknumber(L, 1)) - 1));
return 1;
}
static int getSavegameDescription(lua_State *L) {
lua_pushstring(L, PersistenceService::getInstance().getSavegameDescription(
static_cast<uint>(luaL_checknumber(L, 1)) - 1).c_str());
return 1;
}
static int getSavegameFilename(lua_State *L) {
lua_pushstring(L, PersistenceService::getInstance().getSavegameFilename(static_cast<uint>(luaL_checknumber(L, 1)) - 1).c_str());
return 1;
}
static int loadGame(lua_State *L) {
lua_pushbooleancpp(L, PersistenceService::getInstance().loadGame(static_cast<uint>(luaL_checknumber(L, 1)) - 1));
return 1;
}
static int saveGame(lua_State *L) {
lua_pushbooleancpp(L, PersistenceService::getInstance().saveGame(static_cast<uint>(luaL_checknumber(L, 1)) - 1, luaL_checkstring(L, 2)));
return 1;
}
static const char *PERSISTENCE_LIBRARY_NAME = "Persistence";
static const luaL_reg PERSISTENCE_FUNCTIONS[] = {
{"ReloadSlots", reloadSlots},
{"GetSlotCount", getSlotCount},
{"IsSlotOccupied", isSlotOccupied},
{"GetSavegameDirectory", getSavegameDirectory},
{"IsSavegameCompatible", isSavegameCompatible},
{"GetSavegameDescription", getSavegameDescription},
{"GetSavegameFilename", getSavegameFilename},
{"LoadGame", loadGame},
{"SaveGame", saveGame},
{0, 0}
};
bool Kernel::registerScriptBindings() {
ScriptEngine *pScript = getScript();
assert(pScript);
lua_State *L = static_cast<lua_State *>(pScript->getScriptObject());
assert(L);
if (!LuaBindhelper::addFunctionsToLib(L, KERNEL_LIBRARY_NAME, KERNEL_FUNCTIONS)) return false;
if (!LuaBindhelper::addFunctionsToLib(L, WINDOW_LIBRARY_NAME, WINDOW_FUNCTIONS)) return false;
if (!LuaBindhelper::addFunctionsToLib(L, RESOURCE_LIBRARY_NAME, RESOURCE_FUNCTIONS)) return false;
if (!LuaBindhelper::addFunctionsToLib(L, PERSISTENCE_LIBRARY_NAME, PERSISTENCE_FUNCTIONS)) return false;
return true;
}
} // End of namespace Sword25

View File

@@ -0,0 +1,167 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#ifndef SWORD25_OBJECTREGISTRY_H
#define SWORD25_OBJECTREGISTRY_H
#include "common/func.h"
#include "common/hashmap.h"
#include "common/textconsole.h"
#include "sword25/kernel/common.h"
namespace Sword25 {
template<typename T>
class ObjectRegistry {
public:
ObjectRegistry() : _nextHandle(1) {}
virtual ~ObjectRegistry() {}
uint registerObject(T *objectPtr) {
// Null-Pointer können nicht registriert werden.
if (objectPtr == 0) {
error("Cannot register a null pointer.");
return 0;
}
// Falls das Objekt bereits registriert wurde, wird eine Warnung ausgeben und das Handle zurückgeben.
uint handle = findHandleByPtr(objectPtr);
if (handle != 0) {
warning("Tried to register a object that was already registered.");
return handle;
}
// Ansonsten wird das Objekt in beide Maps eingetragen und das neue Handle zurückgeben.
else {
_handle2PtrMap[_nextHandle] = objectPtr;
_ptr2HandleMap[objectPtr] = _nextHandle;
return _nextHandle++;
}
}
uint registerObject(T *objectPtr, uint handle) {
// Null-Pointer und Null-Handle können nicht registriert werden.
if (objectPtr == 0 || handle == 0) {
error("Cannot register a null pointer or a null handle.");
return 0;
}
// Falls das Objekt bereits registriert wurde, wird ein Fehler ausgegeben und 0 zurückgeben.
uint handleTest = findHandleByPtr(objectPtr);
if (handleTest != 0) {
error("Tried to register a object that was already registered.");
return 0;
}
// Falls das Handle bereits vergeben ist, wird ein Fehler ausgegeben und 0 zurückgegeben.
else if (findPtrByHandle(handle) != 0) {
error("Tried to register a handle that is already taken.");
return 0;
}
// Ansonsten wird das Objekt in beide Maps eingetragen und das gewünschte Handle zurückgeben.
else {
_handle2PtrMap[handle] = objectPtr;
_ptr2HandleMap[objectPtr] = handle;
// Falls das vergebene Handle größer oder gleich dem nächsten automatische vergebenen Handle ist, wird das nächste automatisch
// vergebene Handle erhöht.
if (handle >= _nextHandle)
_nextHandle = handle + 1;
return handle;
}
}
void deregisterObject(T *objectPtr) {
uint handle = findHandleByPtr(objectPtr);
if (handle != 0) {
// Registriertes Objekt aus beiden Maps entfernen.
_handle2PtrMap.erase(findHandleByPtr(objectPtr));
_ptr2HandleMap.erase(objectPtr);
} else {
warning("Tried to remove a object that was not registered.");
}
}
T *resolveHandle(uint handle) {
// Zum Handle gehöriges Objekt in der Hash-Map finden.
T *objectPtr = findPtrByHandle(handle);
// Pointer zurückgeben. Im Fehlerfall ist dieser 0.
return objectPtr;
}
uint resolvePtr(T *objectPtr) {
// Zum Pointer gehöriges Handle in der Hash-Map finden.
uint handle = findHandleByPtr(objectPtr);
// Handle zurückgeben. Im Fehlerfall ist dieses 0.
return handle;
}
protected:
struct ClassPointer_EqualTo {
bool operator()(const T *x, const T *y) const {
return x == y;
}
};
struct ClassPointer_Hash {
uint operator()(const T *x) const {
return *(uint *)&x;
}
};
typedef Common::HashMap<uint32, T *> HANDLE2PTR_MAP;
typedef Common::HashMap<T *, uint32, ClassPointer_Hash, ClassPointer_EqualTo> PTR2HANDLE_MAP;
HANDLE2PTR_MAP _handle2PtrMap;
PTR2HANDLE_MAP _ptr2HandleMap;
uint32 _nextHandle;
T *findPtrByHandle(uint handle) {
// Zum Handle gehörigen Pointer finden.
typename HANDLE2PTR_MAP::const_iterator it = _handle2PtrMap.find(handle);
// Pointer zurückgeben, oder, falls keiner gefunden wurde, 0 zurückgeben.
return (it != _handle2PtrMap.end()) ? it->_value : 0;
}
uint findHandleByPtr(T *objectPtr) {
// Zum Pointer gehöriges Handle finden.
typename PTR2HANDLE_MAP::const_iterator it = _ptr2HandleMap.find(objectPtr);
// Handle zurückgeben, oder, falls keines gefunden wurde, 0 zurückgeben.
return (it != _ptr2HandleMap.end()) ? it->_value : 0;
}
};
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,106 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#include "sword25/kernel/outputpersistenceblock.h"
namespace {
const uint INITIAL_BUFFER_SIZE = 1024 * 64;
}
namespace Sword25 {
OutputPersistenceBlock::OutputPersistenceBlock() {
_data.reserve(INITIAL_BUFFER_SIZE);
}
void OutputPersistenceBlock::write(const void *data, uint32 size) {
writeMarker(BLOCK_MARKER);
write(size);
rawWrite(data, size);
}
void OutputPersistenceBlock::write(int32 value) {
writeMarker(SINT_MARKER);
value = TO_LE_32(value);
rawWrite(&value, sizeof(value));
}
void OutputPersistenceBlock::write(uint32 value) {
writeMarker(UINT_MARKER);
value = TO_LE_32(value);
rawWrite(&value, sizeof(value));
}
void OutputPersistenceBlock::write(float value) {
writeMarker(FLOAT_MARKER);
uint32 tmp[1];
((float *)tmp)[0] = value;
tmp[0] = TO_LE_32(tmp[0]);
rawWrite(&value, sizeof(value));
}
void OutputPersistenceBlock::write(bool value) {
writeMarker(BOOL_MARKER);
uint uintBool = value ? 1 : 0;
uintBool = TO_LE_32(uintBool);
rawWrite(&uintBool, sizeof(uintBool));
}
void OutputPersistenceBlock::writeString(const Common::String &string) {
writeMarker(STRING_MARKER);
write((uint32)string.size());
rawWrite(string.c_str(), string.size());
}
void OutputPersistenceBlock::writeByteArray(Common::Array<byte> &value) {
writeMarker(BLOCK_MARKER);
write((uint32)value.size());
rawWrite(&value[0], value.size());
}
void OutputPersistenceBlock::writeMarker(byte marker) {
_data.push_back(marker);
}
void OutputPersistenceBlock::rawWrite(const void *dataPtr, size_t size) {
if (size > 0) {
uint oldSize = _data.size();
_data.resize(oldSize + size);
memcpy(&_data[oldSize], dataPtr, size);
}
}
} // End of namespace Sword25

View File

@@ -0,0 +1,67 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#ifndef SWORD25_OUTPUTPERSISTENCEBLOCK_H
#define SWORD25_OUTPUTPERSISTENCEBLOCK_H
#include "sword25/kernel/common.h"
#include "sword25/kernel/persistenceblock.h"
namespace Sword25 {
class OutputPersistenceBlock : public PersistenceBlock {
public:
OutputPersistenceBlock();
void write(const void *data, uint32 size);
void write(int32 value);
void write(uint32 value);
void write(float value);
void write(bool value);
void writeString(const Common::String &string);
void writeByteArray(Common::Array<byte> &value);
const void *getData() const {
return &_data[0];
}
uint getDataSize() const {
return _data.size();
}
private:
void writeMarker(byte marker);
void rawWrite(const void *dataPtr, size_t size);
Common::Array<byte> _data;
};
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,49 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#ifndef SWORD25_PERSISTABLE_H
#define SWORD25_PERSISTABLE_H
namespace Sword25 {
class OutputPersistenceBlock;
class InputPersistenceBlock;
class Persistable {
public:
virtual ~Persistable() {}
virtual bool persist(OutputPersistenceBlock &writer) = 0;
virtual bool unpersist(InputPersistenceBlock &reader) = 0;
};
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,77 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#ifndef SWORD25_PERSISTENCEBLOCK_H
#define SWORD25_PERSISTENCEBLOCK_H
#include "sword25/kernel/common.h"
namespace Sword25 {
class PersistenceBlock {
public:
static uint getSInt32Size() {
return sizeof(signed int) + sizeof(byte);
}
static uint getUInt32Size() {
return sizeof(uint) + sizeof(byte);
}
static uint getFloat32Size() {
return sizeof(float) + sizeof(byte);
}
static uint getBoolSize() {
return sizeof(byte) + sizeof(byte);
}
static uint getStringSize(const Common::String &string) {
return static_cast<uint>(sizeof(uint) + string.size() + sizeof(byte));
}
protected:
enum {
SINT_MARKER,
UINT_MARKER,
FLOAT_MARKER,
STRING_MARKER,
BOOL_MARKER,
BLOCK_MARKER
};
};
#define CTASSERT(ex) typedef char ctassert_type[(ex) ? 1 : -1]
CTASSERT(sizeof(byte) == 1);
CTASSERT(sizeof(signed int) == 4);
CTASSERT(sizeof(uint) == 4);
CTASSERT(sizeof(float) == 4);
#undef CTASSERT
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,437 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#include "common/fs.h"
#include "common/savefile.h"
#include "common/compression/deflate.h"
#include "sword25/kernel/kernel.h"
#include "sword25/kernel/persistenceservice.h"
#include "sword25/kernel/inputpersistenceblock.h"
#include "sword25/kernel/outputpersistenceblock.h"
#include "sword25/kernel/filesystemutil.h"
#include "sword25/gfx/graphicengine.h"
#include "sword25/sfx/soundengine.h"
#include "sword25/input/inputengine.h"
#include "sword25/math/regionregistry.h"
#include "sword25/script/script.h"
namespace Sword25 {
//static const char *SAVEGAME_EXTENSION = ".b25s";
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 *VERSIONIDOLD = "SCUMMVM1";
static const char *VERSIONID = "SCUMMVM2";
static const int VERSIONNUM = 3;
#define MAX_SAVEGAME_SIZE 100
char gameTarget[MAX_SAVEGAME_SIZE];
void setGameTarget(const char *target) {
strncpy(gameTarget, target, MAX_SAVEGAME_SIZE - 1);
}
static Common::String generateSavegameFilename(uint slotID) {
char buffer[MAX_SAVEGAME_SIZE+5];
snprintf(buffer, MAX_SAVEGAME_SIZE+5, "%s.%.3d", gameTarget, slotID);
return Common::String(buffer);
}
static Common::String formatTimestamp(TimeDate time) {
// In the original BS2.5 engine, this used a local object to show the date/time as as a string.
// For now in ScummVM it's being hardcoded to 'dd-MON-yyyy hh:mm:ss'
Common::String monthList[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
char buffer[100];
snprintf(buffer, 100, "%.2d-%s-%.4d %.2d:%.2d:%.2d",
time.tm_mday, monthList[time.tm_mon].c_str(), 1900 + time.tm_year,
time.tm_hour, time.tm_min, time.tm_sec
);
return Common::String(buffer);
}
static Common::String loadString(Common::InSaveFile *in, uint maxSize = 999) {
Common::String result;
char ch = (char)in->readByte();
while (ch != '\0') {
result += ch;
if (result.size() >= maxSize)
break;
ch = (char)in->readByte();
}
return result;
}
struct SavegameInformation {
bool isOccupied;
bool isCompatible;
Common::String description;
int version;
uint gamedataLength;
uint gamedataOffset;
uint gamedataUncompressedLength;
SavegameInformation() {
clear();
}
void clear() {
isOccupied = false;
isCompatible = false;
description = "";
gamedataLength = 0;
gamedataOffset = 0;
gamedataUncompressedLength = 0;
}
};
struct PersistenceService::Impl {
SavegameInformation _savegameInformations[SLOT_COUNT];
Impl() {
reloadSlots();
}
void reloadSlots() {
// Iterate through all the saved games, and read their thumbnails.
for (uint i = 0; i < SLOT_COUNT; ++i) {
readSlotSavegameInformation(i);
}
}
void readSlotSavegameInformation(uint slotID) {
// Get the information corresponding to the requested save slot.
SavegameInformation &curSavegameInfo = _savegameInformations[slotID];
curSavegameInfo.clear();
// Generate the save slot file name.
Common::String filename = generateSavegameFilename(slotID);
// Try to open the savegame for loading
Common::SaveFileManager *sfm = g_system->getSavefileManager();
Common::InSaveFile *file = sfm->openForLoading(filename);
if (file) {
// 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 gamedataUncompressedLength = loadString(file);
curSavegameInfo.gamedataUncompressedLength = atoi(gamedataUncompressedLength.c_str());
// If the header can be read in and is detected to be valid, we will have a valid file
if (storedMarker == FILE_MARKER) {
// The slot is marked as occupied.
curSavegameInfo.isOccupied = true;
// Check if the saved game is compatible with the current engine version.
curSavegameInfo.isCompatible = (curSavegameInfo.version <= VERSIONNUM);
// Load the save game description.
curSavegameInfo.description = gameDescription;
// The offset to the stored save game data within the file.
// This reflects the current position, as the header information
// is still followed by a space as separator.
curSavegameInfo.gamedataOffset = static_cast<uint>(file->pos());
}
delete file;
}
}
};
PersistenceService *persInstance = nullptr;
PersistenceService &PersistenceService::getInstance() {
if (!persInstance)
persInstance = new PersistenceService;
return *persInstance;
}
PersistenceService::PersistenceService() : _impl(new Impl) {
}
PersistenceService::~PersistenceService() {
delete _impl;
delete persInstance;
persInstance = nullptr;
}
void PersistenceService::reloadSlots() {
_impl->reloadSlots();
}
uint PersistenceService::getSlotCount() {
return SLOT_COUNT;
}
Common::Path PersistenceService::getSavegameDirectory() {
Common::FSNode node(FileSystemUtil::getUserdataDirectoryPath());
Common::FSNode childNode = node.getChild(SAVEGAME_DIRECTORY);
// Try and return the path using the savegame subfolder. But if doesn't exist, fall back on the data directory
if (childNode.exists())
return childNode.getPath();
return node.getPath();
}
namespace {
bool checkslotID(uint slotID) {
// Überprüfen, ob die Slot-ID zulässig ist.
if (slotID >= SLOT_COUNT) {
error("Tried to access an invalid slot (%d). Only slot ids from 0 to %d are allowed.", slotID, SLOT_COUNT - 1);
return false;
} else {
return true;
}
}
}
bool PersistenceService::isSlotOccupied(uint slotID) {
if (!checkslotID(slotID))
return false;
return _impl->_savegameInformations[slotID].isOccupied;
}
bool PersistenceService::isSavegameCompatible(uint slotID) {
if (!checkslotID(slotID))
return false;
return _impl->_savegameInformations[slotID].isCompatible;
}
Common::String &PersistenceService::getSavegameDescription(uint slotID) {
static Common::String emptyString;
if (!checkslotID(slotID))
return emptyString;
return _impl->_savegameInformations[slotID].description;
}
Common::String &PersistenceService::getSavegameFilename(uint slotID) {
static Common::String result;
if (!checkslotID(slotID))
return result;
result = generateSavegameFilename(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.
// Überprüfen, ob die Slot-ID zulässig ist.
if (slotID >= SLOT_COUNT) {
error("Tried to save to an invalid slot (%d). Only slot ids form 0 to %d are allowed.", slotID, SLOT_COUNT - 1);
return false;
}
// Dateinamen erzeugen.
Common::String filename = generateSavegameFilename(slotID);
// Spielstanddatei öffnen und die Headerdaten schreiben.
Common::SaveFileManager *sfm = g_system->getSavefileManager();
Common::OutSaveFile *file = sfm->openForSaving(filename);
file->writeString(FILE_MARKER);
file->writeByte(0);
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));
file->writeByte(0);
if (file->err()) {
error("Unable to write header data to savegame file \"%s\".", filename.c_str());
}
// Alle notwendigen Module persistieren.
OutputPersistenceBlock writer;
bool success = true;
success &= Kernel::getInstance()->getScript()->persist(writer);
success &= RegionRegistry::instance().persist(writer);
success &= Kernel::getInstance()->getGfx()->persist(writer);
success &= Kernel::getInstance()->getSfx()->persist(writer);
success &= Kernel::getInstance()->getInput()->persist(writer);
if (!success) {
error("Unable to persist modules for savegame file \"%s\".", filename.c_str());
}
// Write the save game data uncompressed, since the final saved game will be
// compressed anyway.
char sBuffer[10];
snprintf(sBuffer, 10, "%u", writer.getDataSize());
file->writeString(sBuffer);
file->writeByte(0);
snprintf(sBuffer, 10, "%u", writer.getDataSize());
file->writeString(sBuffer);
file->writeByte(0);
file->write(writer.getData(), writer.getDataSize());
// Get the screenshot
Common::SeekableReadStream *thumbnail = Kernel::getInstance()->getGfx()->getThumbnail();
if (thumbnail) {
byte *buffer = new byte[FILE_COPY_BUFFER_SIZE];
thumbnail->seek(0, SEEK_SET);
while (!thumbnail->eos()) {
int bytesRead = thumbnail->read(&buffer[0], FILE_COPY_BUFFER_SIZE);
file->write(&buffer[0], bytesRead);
}
delete[] buffer;
} else {
warning("The screenshot file \"%s\" does not exist. Savegame is written without a screenshot.", filename.c_str());
}
file->finalize();
delete file;
// Savegameinformationen für diesen Slot aktualisieren.
_impl->readSlotSavegameInformation(slotID);
// Empty the cache, to remove old thumbnails
Kernel::getInstance()->getResourceManager()->emptyThumbnailCache();
// Erfolg signalisieren.
return true;
}
bool PersistenceService::loadGame(uint slotID) {
Common::SaveFileManager *sfm = g_system->getSavefileManager();
Common::InSaveFile *file;
// Überprüfen, ob die Slot-ID zulässig ist.
if (slotID >= SLOT_COUNT) {
error("Tried to load from an invalid slot (%d). Only slot ids form 0 to %d are allowed.", slotID, SLOT_COUNT - 1);
return false;
}
SavegameInformation &curSavegameInfo = _impl->_savegameInformations[slotID];
// Überprüfen, ob der Slot belegt ist.
if (!curSavegameInfo.isOccupied) {
error("Tried to load from an empty slot (%d).", slotID);
return false;
}
// Überprüfen, ob der Spielstand im angegebenen Slot mit der aktuellen Engine-Version kompatibel ist.
// Im Debug-Modus wird dieser Test übersprungen. Für das Testen ist es hinderlich auf die Einhaltung dieser strengen Bedingung zu bestehen,
// da sich die Versions-ID bei jeder Codeänderung mitändert.
#ifndef DEBUG
if (!curSavegameInfo.isCompatible) {
error("Tried to load a savegame (%d) that is not compatible with this engine version.", slotID);
return false;
}
#endif
byte *compressedDataBuffer = new byte[curSavegameInfo.gamedataLength];
byte *uncompressedDataBuffer = new byte[curSavegameInfo.gamedataUncompressedLength];
Common::String filename = generateSavegameFilename(slotID);
file = sfm->openForLoading(filename);
file->seek(curSavegameInfo.gamedataOffset);
file->read(reinterpret_cast<char *>(&compressedDataBuffer[0]), curSavegameInfo.gamedataLength);
if (file->err()) {
error("Unable to load the gamedata from the savegame file \"%s\".", filename.c_str());
delete[] compressedDataBuffer;
delete[] uncompressedDataBuffer;
return false;
}
// Uncompress game data, if needed.
unsigned long uncompressedBufferSize = curSavegameInfo.gamedataUncompressedLength;
if (uncompressedBufferSize > curSavegameInfo.gamedataLength) {
// Older saved game, where the game data was compressed again.
if (!Common::inflateZlib(reinterpret_cast<byte *>(&uncompressedDataBuffer[0]), &uncompressedBufferSize,
reinterpret_cast<byte *>(&compressedDataBuffer[0]), curSavegameInfo.gamedataLength)) {
error("Unable to decompress the gamedata from savegame file \"%s\".", filename.c_str());
delete[] uncompressedDataBuffer;
delete[] compressedDataBuffer;
delete file;
return false;
}
} else {
// Newer saved game with uncompressed game data, copy it as-is.
memcpy(uncompressedDataBuffer, compressedDataBuffer, uncompressedBufferSize);
}
InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength, curSavegameInfo.version);
// Einzelne Engine-Module depersistieren.
bool success = true;
success &= Kernel::getInstance()->getScript()->unpersist(reader);
// Muss unbedingt nach Script passieren. Da sonst die bereits wiederhergestellten Regions per Garbage-Collection gekillt werden.
success &= RegionRegistry::instance().unpersist(reader);
success &= Kernel::getInstance()->getGfx()->unpersist(reader);
success &= Kernel::getInstance()->getSfx()->unpersist(reader);
success &= Kernel::getInstance()->getInput()->unpersist(reader);
delete[] compressedDataBuffer;
delete[] uncompressedDataBuffer;
delete file;
if (!success) {
error("Unable to unpersist the gamedata from savegame file \"%s\".", filename.c_str());
return false;
}
return true;
}
} // End of namespace Sword25

View File

@@ -0,0 +1,75 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#ifndef SWORD25_PERSISTENCESERVICE_H
#define SWORD25_PERSISTENCESERVICE_H
#include "sword25/kernel/common.h"
namespace Sword25 {
class PersistenceService {
public:
PersistenceService();
virtual ~PersistenceService();
// -----------------------------------------------------------------------------
// Singleton Method
// -----------------------------------------------------------------------------
static PersistenceService &getInstance();
// -----------------------------------------------------------------------------
// Interface
// -----------------------------------------------------------------------------
static uint getSlotCount();
static Common::Path getSavegameDirectory();
void reloadSlots();
bool isSlotOccupied(uint slotID);
bool isSavegameCompatible(uint slotID);
int getSavegameVersion(uint slotID);
Common::String &getSavegameDescription(uint slotID);
Common::String &getSavegameFilename(uint slotID);
bool saveGame(uint slotID, const Common::String &screenshotFilename);
bool loadGame(uint slotID);
private:
struct Impl;
Impl *_impl;
};
void setGameTarget(const char *target);
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,333 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#include "sword25/sword25.h" // for kDebugResource
#include "sword25/kernel/resmanager.h"
#include "sword25/kernel/resource.h"
#include "sword25/kernel/resservice.h"
#include "sword25/package/packagemanager.h"
namespace Sword25 {
// Sets the amount of resources that are simultaneously loaded.
// This needs to be a relatively high number, as all the animation
// frames in each scene are loaded as separate resources.
// Also, George's walk states are all loaded here (150 files)
#define SWORD25_RESOURCECACHE_MIN 400
// The maximum number of loaded resources. If more than these resources
// are loaded, the resource manager will start purging resources till it
// hits the minimum limit above
#define SWORD25_RESOURCECACHE_MAX 500
ResourceManager::~ResourceManager() {
// Clear all unlocked resources
emptyCache();
// All remaining resources are not released, so print warnings and release
Common::List<Resource *>::iterator iter = _resources.begin();
for (; iter != _resources.end(); ++iter) {
warning("Resource \"%s\" was not released.", (*iter)->getFileName().c_str());
// Set the lock count to zero
while ((*iter)->getLockCount() > 0) {
(*iter)->release();
};
// Delete the resource
delete(*iter);
}
}
/**
* Registers a RegisterResourceService. This method is the constructor of
* BS_ResourceService, and thus helps all resource services in the ResourceManager list
* @param pService Which service
*/
bool ResourceManager::registerResourceService(ResourceService *pService) {
if (!pService) {
error("Can't register NULL resource service.");
return false;
}
_resourceServices.push_back(pService);
return true;
}
/**
* Deletes resources as necessary until the specified memory limit is not being exceeded.
*/
void ResourceManager::deleteResourcesIfNecessary() {
// If enough memory is available, or no resources are loaded, then the function can immediately end
if (_resources.size() < SWORD25_RESOURCECACHE_MAX)
return;
// Keep deleting resources until the memory usage of the process falls below the set maximum limit.
// The list is processed backwards in order to first release those resources that have been
// not been accessed for the longest
Common::List<Resource *>::iterator iter = _resources.end();
do {
--iter;
// The resource may be released only if it isn't locked
if ((*iter)->getLockCount() == 0)
iter = deleteResource(*iter);
} while (iter != _resources.begin() && _resources.size() >= SWORD25_RESOURCECACHE_MIN);
// Are we still above the minimum? If yes, then start releasing locked resources
// FIXME: This code shouldn't be needed at all, but it seems like there is a bug
// in the resource lock code, and resources are not unlocked when changing rooms.
// Only image/animation resources are unlocked forcibly, thus this shouldn't have
// any impact on the game itself.
if (_resources.size() <= SWORD25_RESOURCECACHE_MIN)
return;
iter = _resources.end();
do {
--iter;
// Only unlock image/animation resources
if ((*iter)->getFileName().hasSuffix(".swf") ||
(*iter)->getFileName().hasSuffix(".png")) {
warning("Forcibly unlocking %s", (*iter)->getFileName().c_str());
// Forcibly unlock the resource
while ((*iter)->getLockCount() > 0)
(*iter)->release();
iter = deleteResource(*iter);
}
} while (iter != _resources.begin() && _resources.size() >= SWORD25_RESOURCECACHE_MIN);
}
/**
* Releases all resources that are not locked.
*/
void ResourceManager::emptyCache() {
// Scan through the resource list
Common::List<Resource *>::iterator iter = _resources.begin();
while (iter != _resources.end()) {
if ((*iter)->getLockCount() == 0) {
// Delete the resource
iter = deleteResource(*iter);
} else
++iter;
}
}
void ResourceManager::emptyThumbnailCache() {
// Scan through the resource list
Common::List<Resource *>::iterator iter = _resources.begin();
while (iter != _resources.end()) {
if ((*iter)->getFileName().hasPrefix("/saves")) {
// Unlock the thumbnail
while ((*iter)->getLockCount() > 0)
(*iter)->release();
// Delete the thumbnail
iter = deleteResource(*iter);
} else
++iter;
}
}
/**
* Returns a requested resource. If any error occurs, returns NULL
* @param FileName Filename of resource
*/
Resource *ResourceManager::requestResource(const Common::String &fileName) {
// Get the absolute path to the file
Common::String uniqueFileName = getUniqueFileName(fileName);
if (uniqueFileName.empty())
return NULL;
// Determine whether the resource is already loaded
// If the resource is found, it will be placed at the head of the resource list and returned
Resource *pResource = getResource(uniqueFileName);
if (!pResource)
pResource = loadResource(uniqueFileName);
if (pResource) {
moveToFront(pResource);
(pResource)->addReference();
return pResource;
}
return NULL;
}
#ifdef PRECACHE_RESOURCES
/**
* Loads a resource into the cache
* @param FileName The filename of the resource to be cached
* @param ForceReload Indicates whether the file should be reloaded if it's already in the cache.
* This is useful for files that may have changed in the interim
*/
bool ResourceManager::precacheResource(const Common::String &fileName, bool forceReload) {
// Get the absolute path to the file
Common::String uniqueFileName = getUniqueFileName(fileName);
if (uniqueFileName.empty())
return false;
Resource *resourcePtr = getResource(uniqueFileName);
if (forceReload && resourcePtr) {
if (resourcePtr->getLockCount()) {
error("Could not force precaching of \"%s\". The resource is locked.", fileName.c_str());
return false;
} else {
deleteResource(resourcePtr);
resourcePtr = 0;
}
}
if (!resourcePtr && loadResource(uniqueFileName) == NULL) {
// This isn't fatal - e.g. it can happen when loading saved games
debugC(kDebugResource, "Could not precache \"%s\",", fileName.c_str());
return false;
}
return true;
}
#endif
/**
* Moves a resource to the top of the resource list
* @param pResource The resource
*/
void ResourceManager::moveToFront(Resource *pResource) {
// Erase the resource from it's current position
_resources.erase(pResource->_iterator);
// Re-add the resource at the front of the list
_resources.push_front(pResource);
// Reset the resource iterator to the repositioned item
pResource->_iterator = _resources.begin();
}
/**
* Loads a resource and updates the m_UsedMemory total
*
* The resource must not already be loaded
* @param FileName The unique filename of the resource to be loaded
*/
Resource *ResourceManager::loadResource(const Common::String &fileName) {
// ResourceService finden, der die Resource laden kann.
for (uint i = 0; i < _resourceServices.size(); ++i) {
if (_resourceServices[i]->canLoadResource(fileName)) {
// If more memory is desired, memory must be released
deleteResourcesIfNecessary();
// Load the resource
Resource *pResource = _resourceServices[i]->loadResource(fileName);
if (!pResource) {
error("Responsible service could not load resource \"%s\".", fileName.c_str());
return NULL;
}
// Add the resource to the front of the list
_resources.push_front(pResource);
pResource->_iterator = _resources.begin();
// Also store the resource in the hash table for quick lookup
_resourceHashMap[pResource->getFileName()] = pResource;
return pResource;
}
}
// This isn't fatal - e.g. it can happen when loading saved games
debugC(kDebugResource, "Could not find a service that can load \"%s\".", fileName.c_str());
return NULL;
}
/**
* Returns the full path of a given resource filename.
* It will return an empty string if a path could not be created.
*/
Common::String ResourceManager::getUniqueFileName(const Common::String &fileName) const {
// Get a pointer to the package manager
PackageManager *pPackage = (PackageManager *)_kernelPtr->getPackage();
if (!pPackage) {
error("Could not get package manager.");
return Common::String();
}
// Absoluten Pfad der Datei bekommen und somit die Eindeutigkeit des Dateinamens sicherstellen
Common::String uniquefileName = pPackage->getAbsolutePath(fileName);
if (uniquefileName.empty())
error("Could not create absolute file name for \"%s\".", fileName.c_str());
return uniquefileName;
}
/**
* Deletes a resource, removes it from the lists, and updates m_UsedMemory
*/
Common::List<Resource *>::iterator ResourceManager::deleteResource(Resource *pResource) {
// Remove the resource from the hash table
_resourceHashMap.erase(pResource->_fileName);
// Delete the resource from the resource list
Common::List<Resource *>::iterator result = _resources.erase(pResource->_iterator);
// Delete the resource
delete pResource;
// Return the iterator
return result;
}
/**
* Returns a pointer to a loaded resource. If any error occurs, NULL will be returned.
* @param UniquefileName The absolute path and filename
*/
Resource *ResourceManager::getResource(const Common::String &uniquefileName) const {
// Determine whether the resource is already loaded
ResMap::iterator it = _resourceHashMap.find(uniquefileName);
if (it != _resourceHashMap.end())
return it->_value;
// Resource was not found, i.e. has not yet been loaded.
return NULL;
}
/**
* Writes the names of all currently locked resources to the log file
*/
void ResourceManager::dumpLockedResources() {
for (Common::List<Resource *>::iterator iter = _resources.begin(); iter != _resources.end(); ++iter) {
if ((*iter)->getLockCount() > 0) {
debugC(kDebugResource, "%s", (*iter)->getFileName().c_str());
}
}
}
} // End of namespace Sword25

View File

@@ -0,0 +1,145 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#ifndef SWORD25_RESOURCEMANAGER_H
#define SWORD25_RESOURCEMANAGER_H
#include "common/list.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "sword25/kernel/common.h"
namespace Sword25 {
//#define PRECACHE_RESOURCES
class ResourceService;
class Resource;
class Kernel;
class ResourceManager {
friend class Kernel;
public:
/**
* Returns a requested resource. If any error occurs, returns NULL
* @param FileName Filename of resource
*/
Resource *requestResource(const Common::String &fileName);
#ifdef PRECACHE_RESOURCES
/**
* Loads a resource into the cache
* @param FileName The filename of the resource to be cached
* @param ForceReload Indicates whether the file should be reloaded if it's already in the cache.
* This is useful for files that may have changed in the interim
*/
bool precacheResource(const Common::String &fileName, bool forceReload = false);
#endif
/**
* Registers a RegisterResourceService. This method is the constructor of
* BS_ResourceService, and thus helps all resource services in the ResourceManager list
* @param pService Which service
*/
bool registerResourceService(ResourceService *pService);
/**
* Releases all resources that are not locked.
**/
void emptyCache();
/**
* Removes all the savegame thumbnails from the cache
**/
void emptyThumbnailCache();
/**
* Writes the names of all currently locked resources to the log file
*/
void dumpLockedResources();
private:
/**
* Creates a new resource manager
* Only the BS_Kernel class can generate copies this class. Thus, the constructor is private
*/
ResourceManager(Kernel *pKernel) :
_kernelPtr(pKernel)
{}
virtual ~ResourceManager();
/**
* Moves a resource to the top of the resource list
* @param pResource The resource
*/
void moveToFront(Resource *pResource);
/**
* Loads a resource and updates the m_UsedMemory total
*
* The resource must not already be loaded
* @param FileName The unique filename of the resource to be loaded
*/
Resource *loadResource(const Common::String &fileName);
/**
* Returns the full path of a given resource filename.
* It will return an empty string if a path could not be created.
*/
Common::String getUniqueFileName(const Common::String &fileName) const;
/**
* Deletes a resource, removes it from the lists, and updates m_UsedMemory
*/
Common::List<Resource *>::iterator deleteResource(Resource *pResource);
/**
* Returns a pointer to a loaded resource. If any error occurs, NULL will be returned.
* @param UniqueFileName The absolute path and filename
*/
Resource *getResource(const Common::String &uniqueFileName) const;
/**
* Deletes resources as necessary until the specified memory limit is not being exceeded.
*/
void deleteResourcesIfNecessary();
Kernel *_kernelPtr;
Common::Array<ResourceService *> _resourceServices;
Common::List<Resource *> _resources;
typedef Common::HashMap<Common::String, Resource *> ResMap;
ResMap _resourceHashMap;
};
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,53 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#include "sword25/kernel/resource.h"
#include "sword25/kernel/kernel.h"
#include "sword25/package/packagemanager.h"
namespace Sword25 {
Resource::Resource(const Common::String &fileName, RESOURCE_TYPES type) :
_type(type),
_refCount(0) {
PackageManager *pPM = Kernel::getInstance()->getPackage();
assert(pPM);
_fileName = pPM->getAbsolutePath(fileName);
}
void Resource::release() {
if (_refCount) {
--_refCount;
} else
warning("Released unlocked resource \"%s\".", _fileName.c_str());
}
} // End of namespace Sword25

View File

@@ -0,0 +1,106 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#ifndef SWORD25_RESOURCE_H
#define SWORD25_RESOURCE_H
#include "common/list.h"
#include "common/str.h"
#include "sword25/kernel/common.h"
namespace Sword25 {
class Kernel;
class ResourceManager;
class Resource {
friend class ResourceManager;
public:
enum RESOURCE_TYPES {
TYPE_UNKNOWN,
TYPE_BITMAP,
TYPE_ANIMATION,
TYPE_SOUND,
TYPE_FONT
};
Resource(const Common::String &uniqueFileName, RESOURCE_TYPES type);
/**
* Prevents the resource from being released.
* @remarks This method allows a resource to be locked multiple times.
**/
void addReference() {
++_refCount;
}
/**
* Cancels a previous lock
* @remarks The resource can still be released more times than it was 'locked', although it is
* not recommended.
**/
void release();
/**
* Returns the current lock count for the resource
* @return The current lock count
**/
int getLockCount() const {
return _refCount;
}
/**
* Returns the absolute path of the given resource
*/
const Common::String &getFileName() const {
return _fileName;
}
/**
* Returns a resource's type
*/
uint getType() const {
return _type;
}
protected:
virtual ~Resource() {}
private:
Common::String _fileName; ///< The absolute filename
uint _refCount; ///< The number of locks
uint _type; ///< The type of the resource
Common::List<Resource *>::iterator _iterator; ///< Points to the resource position in the LRU list
};
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,69 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#ifndef SWORD25_RESOURCESERVICE_H
#define SWORD25_RESOURCESERVICE_H
#include "sword25/kernel/common.h"
#include "sword25/kernel/service.h"
#include "sword25/kernel/kernel.h"
#include "sword25/kernel/resmanager.h"
namespace Sword25 {
class Resource;
class ResourceService : public Service {
public:
ResourceService(Kernel *pKernel) : Service(pKernel) {
ResourceManager *pResource = pKernel->getResourceManager();
pResource->registerResourceService(this);
}
~ResourceService() override {}
/**
* Loads a resource
* @return Returns the resource if successful, otherwise NULL
*/
virtual Resource *loadResource(const Common::String &fileName) = 0;
/**
* Checks whether the given name can be loaded by the resource service
* @param FileName Dateiname
* @return Returns true if the resource can be loaded.
*/
virtual bool canLoadResource(const Common::String &fileName) = 0;
};
} // End of namespace Sword25
#endif

View File

@@ -0,0 +1,71 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
/*
* BS_Service
* -------------
* This is the base class for all engine services.
* A serivce is an essential part of the engine, ex. the graphics system.
* This was intended to allow, for example, different plug in modules for
* different kinds of hardware and/or systems.
* The services are created at runtime via the kernel method NewService and NEVER with new.
*
* Autor: Malte Thiesen
*/
#ifndef SWORD25_SERVICE_H
#define SWORD25_SERVICE_H
// Includes
#include "sword25/kernel/common.h"
namespace Sword25 {
// Klassendefinition
class Kernel;
class Service {
private:
Kernel *_pKernel;
protected:
Service(Kernel *pKernel) : _pKernel(pKernel) {}
Kernel *GetKernel() const {
return _pKernel;
}
public:
virtual ~Service() {}
};
} // End of namespace Sword25
#endif