diff options
Diffstat (limited to 'engines/sword25/script')
-rw-r--r-- | engines/sword25/script/lua_extensions.cpp | 75 | ||||
-rw-r--r-- | engines/sword25/script/luabindhelper.cpp | 427 | ||||
-rw-r--r-- | engines/sword25/script/luabindhelper.h | 128 | ||||
-rw-r--r-- | engines/sword25/script/luacallback.cpp | 180 | ||||
-rw-r--r-- | engines/sword25/script/luacallback.h | 78 | ||||
-rw-r--r-- | engines/sword25/script/luascript.cpp | 569 | ||||
-rw-r--r-- | engines/sword25/script/luascript.h | 116 | ||||
-rw-r--r-- | engines/sword25/script/script.h | 96 |
8 files changed, 1669 insertions, 0 deletions
diff --git a/engines/sword25/script/lua_extensions.cpp b/engines/sword25/script/lua_extensions.cpp new file mode 100644 index 0000000000..3c0d4570a2 --- /dev/null +++ b/engines/sword25/script/lua_extensions.cpp @@ -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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* + * 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/script/luascript.h" +#include "sword25/script/luabindhelper.h" + +namespace Sword25 { + +static int warning(lua_State *L) { +#ifdef DEBUG + int __startStackDepth = lua_gettop(L); +#endif + + luaL_checkstring(L, 1); + luaL_where(L, 1); + lua_pushstring(L, "WARNING - "); + lua_pushvalue(L, 1); + lua_concat(L, 3); + BS_Log::Log("%s\n", luaL_checkstring(L, -1)); + lua_pop(L, 1); + +#ifdef DEBUG + BS_ASSERT(__startStackDepth == lua_gettop(L)); +#endif + + return 0; +} + +static const luaL_reg GLOBAL_FUNCTIONS[] = { + {"warning", warning}, + {0, 0} +}; + +bool LuaScriptEngine::registerStandardLibExtensions() { + lua_State *L = _state; + BS_ASSERT(_state); + + if (!LuaBindhelper::addFunctionsToLib(L, "", GLOBAL_FUNCTIONS)) + return false; + + return true; +} + +} // End of namespace Sword25 diff --git a/engines/sword25/script/luabindhelper.cpp b/engines/sword25/script/luabindhelper.cpp new file mode 100644 index 0000000000..5367854218 --- /dev/null +++ b/engines/sword25/script/luabindhelper.cpp @@ -0,0 +1,427 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* + * 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/kernel.h" +#include "sword25/script/luabindhelper.h" +#include "sword25/script/luascript.h" + +#define BS_LOG_PREFIX "LUABINDHELPER" + +namespace { +const char *METATABLES_TABLE_NAME = "__METATABLES"; +const char *PERMANENTS_TABLE_NAME = "Permanents"; + +bool registerPermanent(lua_State *L, const Common::String &name) { + // A C function has to be on the stack + if (!lua_iscfunction(L, -1)) + return false; + + // Make sure that the Permanents-Table is on top of the stack + lua_getfield(L, LUA_REGISTRYINDEX, PERMANENTS_TABLE_NAME); + if (lua_isnil(L, -1)) { + // Permanents-Table does not yet exist, so it has to be created + + // Pop nil from the stack + lua_pop(L, 1); + + // Create Permanents-Table and insert a second reference to it on the stack + lua_newtable(L); + lua_pushvalue(L, -1); + + // Store the Permanents-Table in the registry. The second reference is left + // on the stack to be used in the connection + lua_setfield(L, LUA_REGISTRYINDEX, PERMANENTS_TABLE_NAME); + } + + // C function with the name of an index in the Permanents-Table + lua_insert(L, -2); + lua_setfield(L, -2, name.c_str()); + + // Remove the Permanents-Table from the stack + lua_pop(L, 1); + + return true; +} +} + +namespace Sword25 { + +/** + * Registers a set of functions into a Lua library. + * @param L A pointer to the Lua VM + * @param LibName The name of the library. + * If this is an empty string, the functions will be added to the global namespace. + * @param Functions An array of function pointers along with their names. + * The array must be terminated with the enry (0, 0) + * @return Returns true if successful, otherwise false. + */ +bool LuaBindhelper::addFunctionsToLib(lua_State *L, const Common::String &libName, const luaL_reg *functions) { +#ifdef DEBUG + int __startStackDepth = lua_gettop(L); +#endif + + // If the table name is empty, the functions are to be added to the global namespace + if (libName.size() == 0) { + for (; functions->name; ++functions) { + lua_pushstring(L, functions->name); + lua_pushcclosure(L, functions->func, 0); + lua_settable(L, LUA_GLOBALSINDEX); + + // Function is being permanently registed, so persistence can be ignored + lua_pushstring(L, functions->name); + lua_gettable(L, LUA_GLOBALSINDEX); + registerPermanent(L, functions->name); + } + } else { // If the table name is not empty, the functions are added to the given table + // Ensure that the library table exists + if (!createTable(L, libName)) return false; + + // Register each function into the table + for (; functions->name; ++functions) { + // Function registration + lua_pushstring(L, functions->name); + lua_pushcclosure(L, functions->func, 0); + lua_settable(L, -3); + + // Function is being permanently registed, so persistence can be ignored + lua_pushstring(L, functions->name); + lua_gettable(L, -2); + registerPermanent(L, libName + "." + functions->name); + } + + // Remove the library table from the Lua stack + lua_pop(L, 1); + } + +#ifdef DEBUG + BS_ASSERT(__startStackDepth == lua_gettop(L)); +#endif + + return true; +} + +/** + * Adds a set of constants to the Lua library + * @param L A pointer to the Lua VM + * @param LibName The name of the library. + * If this is an empty string, the functions will be added to the global namespace. + * @param Constants An array of the constant values along with their names. + * The array must be terminated with the enry (0, 0) + * @return Returns true if successful, otherwise false. + */ +bool LuaBindhelper::addConstantsToLib(lua_State *L, const Common::String &libName, const lua_constant_reg *constants) { +#ifdef DEBUG + int __startStackDepth = lua_gettop(L); +#endif + + // If the table is empty, the constants are added to the global namespace + if (libName.size() == 0) { + for (; constants->Name; ++constants) { + lua_pushstring(L, constants->Name); + lua_pushnumber(L, constants->Value); + lua_settable(L, LUA_GLOBALSINDEX); + } + } + // If the table name is nto empty, the constants are added to that table + else { + // Ensure that the library table exists + if (!createTable(L, libName)) return false; + + // Register each constant in the table + for (; constants->Name; ++constants) { + lua_pushstring(L, constants->Name); + lua_pushnumber(L, constants->Value); + lua_settable(L, -3); + } + + // Remove the library table from the Lua stack + lua_pop(L, 1); + } + +#ifdef DEBUG + BS_ASSERT(__startStackDepth == lua_gettop(L)); +#endif + + return true; +} + +/** + * Adds a set of methods to a Lua class + * @param L A pointer to the Lua VM + * @param ClassName The name of the class + * When the class name specified does not exist, it is created. + * @param Methods An array of function pointers along with their method names. + * The array must be terminated with the enry (0, 0) + * @return Returns true if successful, otherwise false. + */ +bool LuaBindhelper::addMethodsToClass(lua_State *L, const Common::String &className, const luaL_reg *methods) { +#ifdef DEBUG + int __startStackDepth = lua_gettop(L); +#endif + + // Load the metatable onto the Lua stack + if (!getMetatable(L, className)) return false; + + // Register each method in the Metatable + for (; methods->name; ++methods) { + lua_pushstring(L, methods->name); + lua_pushcclosure(L, methods->func, 0); + lua_settable(L, -3); + + // Function is being permanently registed, so persistence can be ignored + lua_pushstring(L, methods->name); + lua_gettable(L, -2); + registerPermanent(L, className + "." + methods->name); + } + + // Remove the metatable from the stack + lua_pop(L, 1); + +#ifdef DEBUG + BS_ASSERT(__startStackDepth == lua_gettop(L)); +#endif + + return true; +} + +/** + * Sets the garbage collector callback method when items of a particular class are deleted + * @param L A pointer to the Lua VM + * @param ClassName The name of the class + * When the class name specified does not exist, it is created. + * @param GCHandler A function pointer + * @return Returns true if successful, otherwise false. + */ +bool LuaBindhelper::setClassGCHandler(lua_State *L, const Common::String &className, lua_CFunction GCHandler) { +#ifdef DEBUG + int __startStackDepth = lua_gettop(L); +#endif + + // Load the metatable onto the Lua stack + if (!getMetatable(L, className)) return false; + + // Add the GC handler to the Metatable + lua_pushstring(L, "__gc"); + lua_pushcclosure(L, GCHandler, 0); + lua_settable(L, -3); + + // Function is being permanently registed, so persistence can be ignored + lua_pushstring(L, "__gc"); + lua_gettable(L, -2); + registerPermanent(L, className + ".__gc"); + + // Remove the metatable from the stack + lua_pop(L, 1); + +#ifdef DEBUG + BS_ASSERT(__startStackDepth == lua_gettop(L)); +#endif + + return true; +} + +} // End of namespace Sword25 + +namespace { +void pushMetatableTable(lua_State *L) { + // Push the Metatable table onto the stack + lua_getglobal(L, METATABLES_TABLE_NAME); + + // If the table doesn't yet exist, it must be created + if (lua_isnil(L, -1)) { + // Pop nil from stack + lua_pop(L, 1); + + // New table has been created, so add it to the global table and leave reference on stack + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, METATABLES_TABLE_NAME); + } +} +} + +namespace Sword25 { + +bool LuaBindhelper::getMetatable(lua_State *L, const Common::String &tableName) { + // Push the Metatable table onto the stack + pushMetatableTable(L); + + // Versuchen, die gewünschte Metatabelle auf den Stack zu legen. Wenn sie noch nicht existiert, muss sie erstellt werden. + lua_getfield(L, -1, tableName.c_str()); + if (lua_isnil(L, -1)) { + // Pop nil from stack + lua_pop(L, 1); + + // Create new table + lua_newtable(L); + + // Set the __index field in the table + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + // Flag the table as persisted. This ensures that objects within this table get stored + lua_pushbooleancpp(L, true); + lua_setfield(L, -2, "__persist"); + + // Set the table name and push it onto the stack + lua_pushvalue(L, -1); + lua_setfield(L, -3, tableName.c_str()); + } + + // Remove the Metatable table from the stack + lua_remove(L, -2); + + return true; +} + +bool LuaBindhelper::createTable(lua_State *L, const Common::String &tableName) { + const char *partBegin = tableName.c_str(); + + while (partBegin - tableName.c_str() < (int)tableName.size()) { + const char *partEnd = strchr(partBegin, '.'); + if (!partEnd) + partEnd = partBegin + strlen(partBegin); + Common::String subTableName(partBegin, partEnd); + + // Tables with an empty string as the name are not allowed + if (subTableName.size() == 0) + return false; + + // Verify that the table with the name already exists + // The first round will be searched in the global namespace, with later passages + // in the corresponding parent table in the stack + if (partBegin == tableName.c_str()) { + lua_pushstring(L, subTableName.c_str()); + lua_gettable(L, LUA_GLOBALSINDEX); + } else { + lua_pushstring(L, subTableName.c_str()); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) + lua_remove(L, -2); + } + + // If it doesn't exist, create table + if (lua_isnil(L, -1)) { + // Pop nil from stack + lua_pop(L, 1); + + // Create new table + lua_newtable(L); + lua_pushstring(L, subTableName.c_str()); + lua_pushvalue(L, -2); + if (partBegin == tableName.c_str()) + lua_settable(L, LUA_GLOBALSINDEX); + else { + lua_settable(L, -4); + lua_remove(L, -2); + } + } + + partBegin = partEnd + 1; + } + + return true; +} + +} // End of namespace Sword25 + +namespace { +Common::String getLuaValueInfo(lua_State *L, int stackIndex) { + switch (lua_type(L, stackIndex)) { + case LUA_TNUMBER: + lua_pushstring(L, lua_tostring(L, stackIndex)); + break; + + case LUA_TSTRING: + lua_pushfstring(L, "\"%s\"", lua_tostring(L, stackIndex)); + break; + + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, stackIndex) ? "true" : "false")); + break; + + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, stackIndex), lua_topointer(L, stackIndex)); + break; + } + + Common::String result(lua_tostring(L, -1)); + lua_pop(L, 1); + + return result; +} +} + +namespace Sword25 { + +Common::String LuaBindhelper::stackDump(lua_State *L) { + Common::String oss; + + int i = lua_gettop(L); + oss += "------------------- Stack Dump -------------------\n"; + + while (i) { + oss += i + ": " + getLuaValueInfo(L, i) + "\n"; + i--; + } + + oss += "-------------- Stack Dump Finished ---------------\n"; + + return oss; +} + +Common::String LuaBindhelper::tableDump(lua_State *L) { + Common::String oss; + + oss += "------------------- Table Dump -------------------\n"; + + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + // Get the value of the current element on top of the stack, including the index + oss += getLuaValueInfo(L, -2) + " : " + getLuaValueInfo(L, -1) + "\n"; + + // Pop value from the stack. The index is then ready for the next call to lua_next() + lua_pop(L, 1); + } + + oss += "-------------- Table Dump Finished ---------------\n"; + + return oss; +} + +} // End of namespace Sword25 diff --git a/engines/sword25/script/luabindhelper.h b/engines/sword25/script/luabindhelper.h new file mode 100644 index 0000000000..0dbaaa3186 --- /dev/null +++ b/engines/sword25/script/luabindhelper.h @@ -0,0 +1,128 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* + * 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_LUABINDHELPER_H +#define SWORD25_LUABINDHELPER_H + +#include "sword25/kernel/common.h" + +namespace Lua { + +extern "C" +{ +#include "sword25/util/lua/lua.h" +#include "sword25/util/lua/lauxlib.h" +} + +} + +using namespace Lua; + +namespace Sword25 { + +#define lua_pushbooleancpp(L, b) (lua_pushboolean(L, b ? 1 : 0)) +#define lua_tobooleancpp(L, i) (lua_toboolean(L, i) == 0 ? false : true) + +struct lua_constant_reg { + const char *Name; + lua_Number Value; +}; + +class LuaBindhelper { +public: + /** + * Registers a set of functions into a Lua library. + * @param L A pointer to the Lua VM + * @param LibName The name of the library. + * If this is an empty string, the functions will be added to the global namespace. + * @param Functions An array of function pointers along with their names. + * The array must be terminated with the enry (0, 0) + * @return Returns true if successful, otherwise false. + */ + static bool addFunctionsToLib(lua_State *L, const Common::String &libName, const luaL_reg *functions); + + /** + * Adds a set of constants to the Lua library + * @param L A pointer to the Lua VM + * @param LibName The name of the library. + * If this is an empty string, the functions will be added to the global namespace. + * @param Constants An array of the constant values along with their names. + * The array must be terminated with the enry (0, 0) + * @return Returns true if successful, otherwise false. + */ + static bool addConstantsToLib(lua_State *L, const Common::String &libName, const lua_constant_reg *constants); + + /** + * Adds a set of methods to a Lua class + * @param L A pointer to the Lua VM + * @param ClassName The name of the class + * When the class name specified does not exist, it is created. + * @param Methods An array of function pointers along with their method names. + * The array must be terminated with the enry (0, 0) + * @return Returns true if successful, otherwise false. + */ + static bool addMethodsToClass(lua_State *L, const Common::String &className, const luaL_reg *methods); + + /** + * Sets the garbage collector callback method when items of a particular class are deleted + * @param L A pointer to the Lua VM + * @param ClassName The name of the class + * When the class name specified does not exist, it is created. + * @param GCHandler A function pointer + * @return Returns true if successful, otherwise false. + */ + static bool setClassGCHandler(lua_State *L, const Common::String &className, lua_CFunction GCHandler); + + /** + * Returns a string containing a stack dump of the Lua stack + * @param L A pointer to the Lua VM + */ + static Common::String stackDump(lua_State *L); + + /** + * Returns a string that describes the contents of a table + * @param L A pointer to the Lua VM + * @remark The table must be on the Lua stack to be read out. + */ + static Common::String tableDump(lua_State *L); + + static bool getMetatable(lua_State *L, const Common::String &tableName); + +private: + static bool createTable(lua_State *L, const Common::String &tableName); +}; + +} // End of namespace Sword25 + +#endif diff --git a/engines/sword25/script/luacallback.cpp b/engines/sword25/script/luacallback.cpp new file mode 100644 index 0000000000..6d2e634632 --- /dev/null +++ b/engines/sword25/script/luacallback.cpp @@ -0,0 +1,180 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* + * 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/script/luacallback.h" +#include "sword25/script/luabindhelper.h" + +namespace Lua { + +extern "C" +{ +#include "sword25/util/lua/lua.h" +#include "sword25/util/lua/lauxlib.h" +} + +const char *CALLBACKTABLE_NAME = "__CALLBACKS"; + +} + +namespace Sword25 { + +#define BS_LOG_PREFIX "LUA" + +LuaCallback::LuaCallback(lua_State *L) { + // Create callback table + lua_newtable(L); + lua_setglobal(L, CALLBACKTABLE_NAME); +} + +LuaCallback::~LuaCallback() { +} + +void LuaCallback::registerCallbackFunction(lua_State *L, uint objectHandle) { + BS_ASSERT(lua_isfunction(L, -1)); + ensureObjectCallbackTableExists(L, objectHandle); + + // Store function in the callback object table store + lua_pushvalue(L, -2); + luaL_ref(L, -2); + + // Pop the function and object callback table from the stack + lua_pop(L, 2); +} + +void LuaCallback::unregisterCallbackFunction(lua_State *L, uint objectHandle) { + BS_ASSERT(lua_isfunction(L, -1)); + ensureObjectCallbackTableExists(L, objectHandle); + + // Iterate over all elements of the object callback table and remove the function from it + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + // The value of the current element is the top of the stack, including the index + + // If the value is identical to the function parameters, it is removed from the table + if (lua_equal(L, -1, -4)) { + lua_pushvalue(L, -2); + lua_pushnil(L); + lua_settable(L, -5); + + // The function was found, iteration can be stopped + lua_pop(L, 2); + break; + } else { + // Pop value from the stack. The index is then ready for the next call to lua_next() + lua_pop(L, 1); + } + } + + // Function and object table are popped from the stack + lua_pop(L, 2); +} + +void LuaCallback::removeAllObjectCallbacks(lua_State *L, uint objectHandle) { + pushCallbackTable(L); + + // Remove the object callback from the callback table + lua_pushnumber(L, objectHandle); + lua_pushnil(L); + lua_settable(L, -3); + + lua_pop(L, 1); +} + +void LuaCallback::invokeCallbackFunctions(lua_State *L, uint objectHandle) { + ensureObjectCallbackTableExists(L, objectHandle); + + // Iterate through the table and perform all the callbacks + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + // The value of the current element is at the top of the stack, including the index + + // If the value is a function, execute it + if (lua_type(L, -1) == LUA_TFUNCTION) { + // Pre-Function Call + // Derived classes can function in this parameter onto the stack. + // The return value indicates the number of parameters + int argumentCount = preFunctionInvokation(L); + + // Lua_pcall the function and the parameters pop themselves from the stack + if (lua_pcall(L, argumentCount, 0, 0) != 0) { + // An error has occurred + BS_LOG_ERRORLN("An error occured executing a callback function: %s", lua_tostring(L, -1)); + + // Pop error message from the stack + lua_pop(L, 1); + } + } else { + // Pop value from the stack. The index is then ready for the next call to lua_next() + lua_pop(L, 1); + } + } +} + +void LuaCallback::ensureObjectCallbackTableExists(lua_State *L, uint objectHandle) { + pushObjectCallbackTable(L, objectHandle); + + // If the table is nil, it must first be created + if (lua_isnil(L, -1)) { + // Pop nil from stack + lua_pop(L, 1); + + pushCallbackTable(L); + + // Create the table, and put the objectHandle into it + lua_newtable(L); + lua_pushnumber(L, objectHandle); + lua_pushvalue(L, -2); + lua_settable(L, -4); + + // Pop the callback table from the stack + lua_remove(L, -2); + } +} + +void LuaCallback::pushCallbackTable(lua_State *L) { + lua_getglobal(L, CALLBACKTABLE_NAME); +} + +void LuaCallback::pushObjectCallbackTable(lua_State *L, uint objectHandle) { + pushCallbackTable(L); + + // Push Object Callback table onto the stack + lua_pushnumber(L, objectHandle); + lua_gettable(L, -2); + + // Pop the callback table from the stack + lua_remove(L, -2); +} + +} // End of namespace Sword25 diff --git a/engines/sword25/script/luacallback.h b/engines/sword25/script/luacallback.h new file mode 100644 index 0000000000..0a5dec17d9 --- /dev/null +++ b/engines/sword25/script/luacallback.h @@ -0,0 +1,78 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* + * 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_LUACALLBACK_H +#define SWORD25_LUACALLBACK_H + +#include "sword25/kernel/common.h" + +namespace Lua { + +struct lua_State; + +} + +using namespace Lua; + +namespace Sword25 { + +class LuaCallback { +public: + LuaCallback(lua_State *L); + virtual ~LuaCallback(); + + // Funktion muss auf dem Lua-Stack liegen. + void registerCallbackFunction(lua_State *L, uint objectHandle); + + // Funktion muss auf dem Lua-Stack liegen. + void unregisterCallbackFunction(lua_State *L, uint objectHandle); + + void removeAllObjectCallbacks(lua_State *L, uint objectHandle); + + void invokeCallbackFunctions(lua_State *L, uint objectHandle); + +protected: + virtual int preFunctionInvokation(lua_State *L) { + return 0; + } + +private: + void ensureObjectCallbackTableExists(lua_State *L, uint objectHandle); + void pushCallbackTable(lua_State *L); + void pushObjectCallbackTable(lua_State *L, uint objectHandle); +}; + +} // End of namespace Sword25 + +#endif diff --git a/engines/sword25/script/luascript.cpp b/engines/sword25/script/luascript.cpp new file mode 100644 index 0000000000..82166f7c25 --- /dev/null +++ b/engines/sword25/script/luascript.cpp @@ -0,0 +1,569 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* + * This code is based on Broken Sword 2.5 engine + * + * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer + * + * Licensed under GNU GPL v2 + * + */ + +#define BS_LOG_PREFIX "LUA" + +#include "common/array.h" +#include "common/debug-channels.h" + +#include "sword25/sword25.h" +#include "sword25/package/packagemanager.h" +#include "sword25/script/luascript.h" +#include "sword25/script/luabindhelper.h" + +#include "sword25/kernel/outputpersistenceblock.h" +#include "sword25/kernel/inputpersistenceblock.h" + +namespace Lua { + +extern "C" { +#include "sword25/util/lua/lua.h" +#include "sword25/util/lua/lualib.h" +#include "sword25/util/lua/lauxlib.h" +#include "sword25/util/pluto/pluto.h" +} + +} + +namespace Sword25 { + +using namespace Lua; + +LuaScriptEngine::LuaScriptEngine(Kernel *KernelPtr) : + ScriptEngine(KernelPtr), + _state(0), + _pcallErrorhandlerRegistryIndex(0) { +} + +LuaScriptEngine::~LuaScriptEngine() { + // Lua de-initialisation + if (_state) + lua_close(_state); +} + +Service *LuaScriptEngine_CreateObject(Kernel *KernelPtr) { + return new LuaScriptEngine(KernelPtr); +} + +namespace { +int panicCB(lua_State *L) { + BS_LOG_ERRORLN("Lua panic. Error message: %s", lua_isnil(L, -1) ? "" : lua_tostring(L, -1)); + return 0; +} + +void debugHook(lua_State *L, lua_Debug *ar) { + if (!lua_getinfo(L, "Sn", ar)) + return; + + debug("LUA: %s %s: %s %d", ar->namewhat, ar->name, ar->short_src, ar->currentline); +} +} + +bool LuaScriptEngine::init() { + // Lua-State initialisation, as well as standard libaries initialisation + _state = luaL_newstate(); + if (!_state || ! registerStandardLibs() || !registerStandardLibExtensions()) { + BS_LOG_ERRORLN("Lua could not be initialized."); + return false; + } + + // Register panic callback function + lua_atpanic(_state, panicCB); + + // Error handler for lua_pcall calls + // The code below contains a local error handler function + const char errorHandlerCode[] = + "local function ErrorHandler(message) " + " return message .. '\\n' .. debug.traceback('', 2) " + "end " + "return ErrorHandler"; + + // Compile the code + if (luaL_loadbuffer(_state, errorHandlerCode, strlen(errorHandlerCode), "PCALL ERRORHANDLER") != 0) { + // An error occurred, so dislay the reason and exit + BS_LOG_ERRORLN("Couldn't compile luaL_pcall errorhandler:\n%s", lua_tostring(_state, -1)); + lua_pop(_state, 1); + + return false; + } + // Running the code, the error handler function sets the top of the stack + if (lua_pcall(_state, 0, 1, 0) != 0) { + // An error occurred, so dislay the reason and exit + BS_LOG_ERRORLN("Couldn't prepare luaL_pcall errorhandler:\n%s", lua_tostring(_state, -1)); + lua_pop(_state, 1); + + return false; + } + + // Place the error handler function in the Lua registry, and remember the index + _pcallErrorhandlerRegistryIndex = luaL_ref(_state, LUA_REGISTRYINDEX); + + // Initialise the Pluto-Persistence library + luaopen_pluto(_state); + lua_pop(_state, 1); + + // Initialize debugging callback + if (DebugMan.isDebugChannelEnabled(kDebugScript)) { + int mask = 0; + if ((gDebugLevel & 1) != 0) + mask |= LUA_MASKCALL; + if ((gDebugLevel & 2) != 0) + mask |= LUA_MASKRET; + if ((gDebugLevel & 4) != 0) + mask |= LUA_MASKLINE; + + if (mask != 0) + lua_sethook(_state, debugHook, mask, 0); + } + + BS_LOGLN("Lua initialized."); + + return true; +} + +bool LuaScriptEngine::executeFile(const Common::String &fileName) { +#ifdef DEBUG + int __startStackDepth = lua_gettop(_state); +#endif + debug(2, "LuaScriptEngine::executeFile(%s)", fileName.c_str()); + + // Get a pointer to the package manager + PackageManager *pPackage = static_cast<PackageManager *>(Kernel::GetInstance()->GetService("package")); + BS_ASSERT(pPackage); + + // File read + uint fileSize; + byte *fileData = pPackage->getFile(fileName, &fileSize); + if (!fileData) { + BS_LOG_ERRORLN("Couldn't read \"%s\".", fileName.c_str()); +#ifdef DEBUG + BS_ASSERT(__startStackDepth == lua_gettop(_state)); +#endif + return false; + } + + // Run the file content + if (!executeBuffer(fileData, fileSize, "@" + pPackage->getAbsolutePath(fileName))) { + // Release file buffer + delete[] fileData; +#ifdef DEBUG + BS_ASSERT(__startStackDepth == lua_gettop(_state)); +#endif + return false; + } + + // Release file buffer + delete[] fileData; + +#ifdef DEBUG + BS_ASSERT(__startStackDepth == lua_gettop(_state)); +#endif + + return true; +} + +bool LuaScriptEngine::executeString(const Common::String &code) { + return executeBuffer((byte *)code.c_str(), code.size(), "???"); +} + +namespace { + +void removeForbiddenFunctions(lua_State *L) { + static const char *FORBIDDEN_FUNCTIONS[] = { + "dofile", + 0 + }; + + const char **iterator = FORBIDDEN_FUNCTIONS; + while (*iterator) { + lua_pushnil(L); + lua_setfield(L, LUA_GLOBALSINDEX, *iterator); + ++iterator; + } +} +} + +bool LuaScriptEngine::registerStandardLibs() { + luaL_openlibs(_state); + removeForbiddenFunctions(_state); + return true; +} + +bool LuaScriptEngine::executeBuffer(const byte *data, uint size, const Common::String &name) const { + // Compile buffer + if (luaL_loadbuffer(_state, (const char *)data, size, name.c_str()) != 0) { + BS_LOG_ERRORLN("Couldn't compile \"%s\":\n%s", name.c_str(), lua_tostring(_state, -1)); + lua_pop(_state, 1); + + return false; + } + + // Error handling function to be executed after the function is put on the stack + lua_rawgeti(_state, LUA_REGISTRYINDEX, _pcallErrorhandlerRegistryIndex); + lua_insert(_state, -2); + + // Run buffer contents + if (lua_pcall(_state, 0, 0, -2) != 0) { + BS_LOG_ERRORLN("An error occured while executing \"%s\":\n%s.", + name.c_str(), + lua_tostring(_state, -1)); + lua_pop(_state, 2); + + return false; + } + + // Remove the error handler function from the stack + lua_pop(_state, 1); + + return true; +} + +void LuaScriptEngine::setCommandLine(const Common::StringArray &commandLineParameters) { + lua_newtable(_state); + + for (size_t i = 0; i < commandLineParameters.size(); ++i) { + lua_pushnumber(_state, i + 1); + lua_pushstring(_state, commandLineParameters[i].c_str()); + lua_settable(_state, -3); + } + + lua_setglobal(_state, "CommandLine"); +} + +namespace { +const char *PERMANENTS_TABLE_NAME = "Permanents"; + +// This array contains the name of global Lua objects that should not be persisted +const char *STANDARD_PERMANENTS[] = { + "string", + "xpcall", + "package", + "tostring", + "print", + "os", + "unpack", + "require", + "getfenv", + "setmetatable", + "next", + "assert", + "tonumber", + "io", + "rawequal", + "collectgarbage", + "getmetatable", + "module", + "rawset", + "warning", + "math", + "debug", + "pcall", + "table", + "newproxy", + "type", + "coroutine", + "select", + "gcinfo", + "pairs", + "rawget", + "loadstring", + "ipairs", + "_VERSION", + "setfenv", + "load", + "error", + "loadfile", + + "pairs_next", + "ipairs_next", + "pluto", + "Cfg", + "Translator", + "Persistence", + "CommandLine", + 0 +}; + +enum PERMANENT_TABLE_TYPE { + PTT_PERSIST, + PTT_UNPERSIST +}; + +bool pushPermanentsTable(lua_State *L, PERMANENT_TABLE_TYPE tableType) { + // Permanents-Table + lua_newtable(L); + + // All standard permanents are inserted into this table + uint Index = 0; + while (STANDARD_PERMANENTS[Index]) { + // Permanents are placed onto the stack; if it does not exist, it is simply ignored + lua_getglobal(L, STANDARD_PERMANENTS[Index]); + if (!lua_isnil(L, -1)) { + // Name of the element as a unique value on the stack + lua_pushstring(L, STANDARD_PERMANENTS[Index]); + + // If it is loaded, then it can be used + // In this case, the position of name and object are reversed on the stack + if (tableType == PTT_UNPERSIST) + lua_insert(L, -2); + + // Make an entry in the table + lua_settable(L, -3); + } else { + // Pop nil value from stack + lua_pop(L, 1); + } + + ++Index; + } + + // All registered C functions to be inserted into the table + // BS_LuaBindhelper places in the register a table in which all registered C functions + // are stored + + // Table is put on the stack + lua_getfield(L, LUA_REGISTRYINDEX, PERMANENTS_TABLE_NAME); + + if (!lua_isnil(L, -1)) { + // Iterate over all elements of the table + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + // Value and index duplicated on the stack and changed in the sequence + lua_pushvalue(L, -1); + lua_pushvalue(L, -3); + + // If it is loaded, then it can be used + // In this case, the position of name and object are reversed on the stack + if (tableType == PTT_UNPERSIST) + lua_insert(L, -2); + + // Make an entry in the results table + lua_settable(L, -6); + + // Pop value from the stack. The index is then ready for the next call to lua_next() + lua_pop(L, 1); + } + } + + // Pop the C-Permanents table from the stack + lua_pop(L, 1); + + // coroutine.yield must be registered in the extra-Permanents table because they + // are inactive coroutine C functions on the stack + + // Function coroutine.yield placed on the stack + lua_getglobal(L, "coroutine"); + lua_pushstring(L, "yield"); + lua_gettable(L, -2); + + // Store coroutine.yield with it's own unique value in the Permanents table + lua_pushstring(L, "coroutine.yield"); + + if (tableType == PTT_UNPERSIST) + lua_insert(L, -2); + + lua_settable(L, -4); + + // Coroutine table is popped from the stack + lua_pop(L, 1); + + return true; +} +} + +namespace { +int chunkwriter(lua_State *L, const void *p, size_t sz, void *ud) { + Common::Array<byte> & chunkData = *reinterpret_cast<Common::Array<byte> * >(ud); + const byte *buffer = reinterpret_cast<const byte *>(p); + + while (sz--) + chunkData.push_back(*buffer++); + + return 1; +} +} + +bool LuaScriptEngine::persist(OutputPersistenceBlock &writer) { + // Empty the Lua stack. pluto_persist() xepects that the stack is empty except for its parameters + lua_settop(_state, 0); + + // Garbage Collection erzwingen. + lua_gc(_state, LUA_GCCOLLECT, 0); + + // Permanents-Table is set on the stack + // pluto_persist expects these two items on the Lua stack + pushPermanentsTable(_state, PTT_PERSIST); + lua_getglobal(_state, "_G"); + + // Lua persists and stores the data in a Common::Array + Common::Array<byte> chunkData; + pluto_persist(_state, chunkwriter, &chunkData); + + // Persistenzdaten in den Writer schreiben. + writer.write(&chunkData[0], chunkData.size()); + + // Die beiden Tabellen vom Stack nehmen. + lua_pop(_state, 2); + + return true; +} + +namespace { + +struct ChunkreaderData { + void *BufferPtr; + size_t Size; + bool BufferReturned; +}; + +const char *chunkreader(lua_State *L, void *ud, size_t *sz) { + ChunkreaderData &cd = *reinterpret_cast<ChunkreaderData *>(ud); + + if (!cd.BufferReturned) { + cd.BufferReturned = true; + *sz = cd.Size; + return reinterpret_cast<const char *>(cd.BufferPtr); + } else { + return 0; + } +} + +void clearGlobalTable(lua_State *L, const char **exceptions) { + // Iterate over all elements of the global table + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + // Now the value and the index of the current element is on the stack + // This value does not interest us, so it is popped from the stack + lua_pop(L, 1); + + // Determine whether the item is set to nil, so you want to remove from the global table. + // For this will determine whether the element name is a string and is present in + // the list of exceptions + bool setElementToNil = true; + if (lua_isstring(L, -1)) { + const char *indexString = lua_tostring(L, -1); + const char **exceptionsWalker = exceptions; + while (*exceptionsWalker) { + if (strcmp(indexString, *exceptionsWalker) == 0) + setElementToNil = false; + ++exceptionsWalker; + } + } + + // If the above test showed that the item should be removed, it is removed by setting the value to nil. + if (setElementToNil) { + lua_pushvalue(L, -1); + lua_pushnil(L); + lua_settable(L, LUA_GLOBALSINDEX); + } + } + + // Pop the Global table from the stack + lua_pop(L, 1); + + // Perform garbage collection, so that all removed elements are deleted + lua_gc(L, LUA_GCCOLLECT, 0); +} +} + +bool LuaScriptEngine::unpersist(InputPersistenceBlock &reader) { + // Empty the Lua stack. pluto_persist() xepects that the stack is empty except for its parameters + lua_settop(_state, 0); + + // Permanents table is placed on the stack. This has already happened at this point, because + // to create the table all permanents must be accessible. This is the case only for the + // beginning of the function, because the global table is emptied below + pushPermanentsTable(_state, PTT_UNPERSIST); + + // All items from global table of _G and __METATABLES are removed. + // After a garbage collection is performed, and thus all managed objects deleted + + // __METATABLES is not immediately removed becausen the Metatables are needed + // for the finalisers of objects. + static const char *clearExceptionsFirstPass[] = { + "_G", + "__METATABLES", + 0 + }; + clearGlobalTable(_state, clearExceptionsFirstPass); + + // In the second pass, the Metatables are removed + static const char *clearExceptionsSecondPass[] = { + "_G", + 0 + }; + clearGlobalTable(_state, clearExceptionsSecondPass); + + // Persisted Lua data + Common::Array<byte> chunkData; + reader.read(chunkData); + + // Chunk-Reader initialisation. It is used with pluto_unpersist to restore read data + ChunkreaderData cd; + cd.BufferPtr = &chunkData[0]; + cd.Size = chunkData.size(); + cd.BufferReturned = false; + + pluto_unpersist(_state, chunkreader, &cd); + + // Permanents-Table is removed from stack + lua_remove(_state, -2); + + // The read elements in the global table about + lua_pushnil(_state); + while (lua_next(_state, -2) != 0) { + // The referenec to the global table (_G) must not be overwritten, or ticks from Lua total + bool isGlobalReference = lua_isstring(_state, -2) && strcmp(lua_tostring(_state, -2), "_G") == 0; + if (!isGlobalReference) { + lua_pushvalue(_state, -2); + lua_pushvalue(_state, -2); + + lua_settable(_state, LUA_GLOBALSINDEX); + } + + // Pop value from the stack. The index is then ready for the next call to lua_next() + lua_pop(_state, 1); + } + + // The table with the loaded data is popped from the stack + lua_pop(_state, 1); + + // Force garbage collection + lua_gc(_state, LUA_GCCOLLECT, 0); + + return true; +} + +} // End of namespace Sword25 diff --git a/engines/sword25/script/luascript.h b/engines/sword25/script/luascript.h new file mode 100644 index 0000000000..f557ae45f1 --- /dev/null +++ b/engines/sword25/script/luascript.h @@ -0,0 +1,116 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* + * 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_LUASCRIPT_H +#define SWORD25_LUASCRIPT_H + +#include "common/str.h" +#include "common/str-array.h" +#include "sword25/kernel/common.h" +#include "sword25/script/script.h" + +namespace Lua { + +struct lua_State; + +} + +using namespace Lua; + +namespace Sword25 { + +class Kernel; + +class LuaScriptEngine : public ScriptEngine { +public: + LuaScriptEngine(Kernel *KernelPtr); + virtual ~LuaScriptEngine(); + + /** + * Initialises the scripting engine + * @return Returns true if successful, otherwise false. + */ + virtual bool init(); + + /** + * Loads a script file and executes it + * @param FileName The filename of the script + * @return Returns true if successful, otherwise false. + */ + virtual bool executeFile(const Common::String &fileName); + + /** + * Execute a string of script code + * @param Code A string of script code + * @return Returns true if successful, otherwise false. + */ + virtual bool executeString(const Common::String &code); + + /** + * Returns a pointer to the main object of the scripting language + * @remark Using this method breaks the encapsulation of the language + */ + virtual void *getScriptObject() { + return _state; + } + + /** + * Makes the command line parameters for the scripting environment available + * @param CommandLineParameters An array containing all the command line parameters + * @remark How the command line parameters will be used by scripts is + * dependant on the particular implementation. + */ + virtual void setCommandLine(const Common::StringArray &commandLineParameters); + + /** + * @remark The Lua stack is cleared by this method + */ + virtual bool persist(OutputPersistenceBlock &writer); + /** + * @remark The Lua stack is cleared by this method + */ + virtual bool unpersist(InputPersistenceBlock &reader); + +private: + lua_State *_state; + int _pcallErrorhandlerRegistryIndex; + + bool registerStandardLibs(); + bool registerStandardLibExtensions(); + bool executeBuffer(const byte *data, uint size, const Common::String &name) const; +}; + +} // End of namespace Sword25 + +#endif diff --git a/engines/sword25/script/script.h b/engines/sword25/script/script.h new file mode 100644 index 0000000000..2f72cf0cc8 --- /dev/null +++ b/engines/sword25/script/script.h @@ -0,0 +1,96 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* + * 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_SCRIPT_H +#define SWORD25_SCRIPT_H + +#include "common/array.h" +#include "common/str.h" +#include "sword25/kernel/common.h" +#include "sword25/kernel/service.h" +#include "sword25/kernel/persistable.h" + +namespace Sword25 { + +class Kernel; +class OutputPersistenceBlock; +class BS_InputPersistenceBlock; + +class ScriptEngine : public Service, public Persistable { +public: + ScriptEngine(Kernel *KernelPtr) : Service(KernelPtr) {}; + virtual ~ScriptEngine() {}; + + // ----------------------------------------------------------------------------- + // This method must be implemented by the script engine + // ----------------------------------------------------------------------------- + + /** + * Initialises the scrip tengine. Returns true if successful, false otherwise. + */ + virtual bool init() = 0; + + /** + * Loads a script file and executes it. + * @param FileName The script filename + */ + virtual bool executeFile(const Common::String &fileName) = 0; + + /** + * Executes a specified script fragment + * @param Code String of script code + */ + virtual bool executeString(const Common::String &code) = 0; + + /** + * Returns a pointer to the main object of the script engine + * Note: Using this method breaks the encapsulation of the language from the rest of the engine. + */ + virtual void *getScriptObject() = 0; + + /** + * Makes the command line parameters for the script environment available + * Note: How the command line parameters will be used by scripts is dependant on the + * particular implementation. + * @param CommandLineParameters List containing the command line parameters + */ + virtual void setCommandLine(const Common::Array<Common::String> &commandLineParameters) = 0; + + virtual bool persist(OutputPersistenceBlock &writer) = 0; + virtual bool unpersist(InputPersistenceBlock &reader) = 0; +}; + +} // End of namespace Sword25 + +#endif |