253 lines
7.1 KiB
C++
253 lines
7.1 KiB
C++
/* 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/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/debug.h"
|
|
#include "common/textconsole.h"
|
|
#include "common/lua/lua.h"
|
|
#include "common/lua/lualib.h"
|
|
#include "common/lua/lauxlib.h"
|
|
|
|
#include "tetraedge/te/te_lua_context.h"
|
|
|
|
namespace Tetraedge {
|
|
|
|
//#define TETRAEDGE_LUA_DEBUG 1
|
|
|
|
//static lua_State *globalState = nullptr;
|
|
|
|
static int luaPanicFunction(lua_State *state) {
|
|
const char *msg = lua_tolstring(state, -1, nullptr);
|
|
warning("Lua: %s", msg);
|
|
lua_settop(state, -2);
|
|
return 1;
|
|
}
|
|
|
|
#ifdef TETRAEDGE_LUA_DEBUG
|
|
static void luaDebugHook(lua_State *L, lua_Debug *ar) {
|
|
if (!lua_getinfo(L, "Sn", ar))
|
|
return;
|
|
debug("LUA: %s %d", ar->source, ar->currentline);
|
|
}
|
|
#endif
|
|
|
|
|
|
TeLuaContext::TeLuaContext() : _luaState(nullptr) {
|
|
_luaState = lua_open();
|
|
luaL_openlibs(_luaState);
|
|
lua_atpanic(_luaState, luaPanicFunction);
|
|
}
|
|
|
|
TeLuaContext::~TeLuaContext() {
|
|
destroy();
|
|
}
|
|
|
|
void TeLuaContext::addBindings(void(*fn)(lua_State *)) {
|
|
fn(_luaState);
|
|
}
|
|
|
|
void TeLuaContext::create() {
|
|
_luaState = lua_open();
|
|
luaL_openlibs(_luaState);
|
|
lua_atpanic(_luaState, luaPanicFunction);
|
|
#ifdef TETRAEDGE_LUA_DEBUG
|
|
lua_sethook(_luaState, luaDebugHook, LUA_MASKCALL | LUA_MASKLINE, 0);
|
|
#endif
|
|
}
|
|
|
|
void TeLuaContext::destroy() {
|
|
if (_luaState)
|
|
lua_close(_luaState);
|
|
_luaState = nullptr;
|
|
}
|
|
|
|
TeVariant TeLuaContext::global(const Common::String &name) {
|
|
lua_getglobal(_luaState, name.c_str());
|
|
TeVariant retval;
|
|
int type = lua_type(_luaState, -1);
|
|
if (type == LUA_TBOOLEAN) {
|
|
int result = lua_toboolean(_luaState, -1);
|
|
lua_settop(_luaState, -2);
|
|
return TeVariant(result > 0);
|
|
} else if (type == LUA_TNUMBER) {
|
|
double result = lua_tonumber(_luaState, -1);
|
|
lua_settop(_luaState, -2);
|
|
return TeVariant(result);
|
|
} else if (type == LUA_TSTRING) {
|
|
const char *str = lua_tolstring(_luaState, -1, nullptr);
|
|
lua_settop(_luaState, -2);
|
|
return TeVariant(str);
|
|
}
|
|
if (type != LUA_TNIL)
|
|
warning("TeLuaContext::global: Unexpected type %d for global %s", type, name.c_str());
|
|
else
|
|
debug("TeLuaContext::global: Request for nil global %s", name.c_str());
|
|
return TeVariant();
|
|
}
|
|
|
|
void TeLuaContext::setGlobal(const Common::String &name, int val) {
|
|
lua_pushinteger(_luaState, val);
|
|
lua_setglobal(_luaState, name.c_str());
|
|
}
|
|
|
|
void TeLuaContext::setGlobal(const Common::String &name, bool val) {
|
|
lua_pushboolean(_luaState, val);
|
|
lua_setglobal(_luaState, name.c_str());
|
|
}
|
|
|
|
void TeLuaContext::setGlobal(const Common::String &name, const Common::String &val) {
|
|
lua_pushstring(_luaState, val.c_str());
|
|
lua_setglobal(_luaState, name.c_str());
|
|
}
|
|
|
|
void TeLuaContext::removeGlobal(const Common::String &name) {
|
|
lua_pushnil(_luaState);
|
|
lua_setglobal(_luaState, name.c_str());
|
|
}
|
|
|
|
void TeLuaContext::registerCFunction(const Common::String &name, int(*fn)(lua_State *)) {
|
|
lua_pushcclosure(_luaState, fn, 0);
|
|
lua_setglobal(_luaState, name.c_str());
|
|
}
|
|
|
|
void TeLuaContext::setInRegistry(const Common::String &name, TeLuaGUI *gui) {
|
|
lua_pushstring(_luaState, name.c_str());
|
|
lua_pushlightuserdata(_luaState, gui);
|
|
lua_settable(_luaState, LUA_REGISTRYINDEX);
|
|
}
|
|
|
|
// Types for save file. Aligned with the Lua types at type of
|
|
// writing, but don't save them just in case they could change.
|
|
enum TeLuaSaveVarType {
|
|
None = 0,
|
|
Boolean = 1,
|
|
Number = 3,
|
|
String = 4
|
|
};
|
|
|
|
//#define TETRAEDGE_LUA_DEBUG_SAVELOAD
|
|
|
|
Common::Error TeLuaContext::syncState(Common::Serializer &s) {
|
|
// Save/Load globals. The format of saving is:
|
|
// [type][name][val] [type][name][val]...
|
|
// Vals can be string, number (uint32), or boolean (byte)
|
|
// The type of "None" (0) is the end of the list (and has no name/val).
|
|
if (s.isSaving()) {
|
|
#ifdef TETRAEDGE_LUA_DEBUG_SAVELOAD
|
|
debug("TeLuaContext::syncState: --- Saving globals: ---");
|
|
#endif
|
|
lua_pushvalue(_luaState, LUA_GLOBALSINDEX);
|
|
lua_pushnil(_luaState);
|
|
int nextresult = lua_next(_luaState, -2);
|
|
while (true) {
|
|
if (nextresult == 0) {
|
|
TeLuaSaveVarType stype = None;
|
|
s.syncAsUint32LE(stype);
|
|
lua_settop(_luaState, -2);
|
|
break;
|
|
}
|
|
uint vtype = lua_type(_luaState, -1);
|
|
Common::String name = lua_tolstring(_luaState, -2, nullptr);
|
|
if (vtype == LUA_TBOOLEAN) {
|
|
TeLuaSaveVarType stype = Boolean;
|
|
s.syncAsUint32LE(stype);
|
|
s.syncString(name);
|
|
bool val = lua_toboolean(_luaState, -1);
|
|
s.syncAsByte(val);
|
|
#ifdef TETRAEDGE_LUA_DEBUG_SAVELOAD
|
|
debug("TeLuaContext::syncState: bool %s = %s", name.c_str(), val ? "true" : "false");
|
|
#endif
|
|
} else if (vtype == LUA_TNUMBER) {
|
|
TeLuaSaveVarType stype = Number;
|
|
s.syncAsUint32LE(stype);
|
|
s.syncString(name);
|
|
double val = lua_tonumber(_luaState, -1);
|
|
s.syncAsDoubleLE(val);
|
|
#ifdef TETRAEDGE_LUA_DEBUG_SAVELOAD
|
|
debug("TeLuaContext::syncState: num %s = %f", name.c_str(), val);
|
|
#endif
|
|
} else if (vtype == LUA_TSTRING) {
|
|
TeLuaSaveVarType stype = String;
|
|
s.syncAsUint32LE(stype);
|
|
s.syncString(name);
|
|
Common::String val = lua_tostring(_luaState, -1);
|
|
s.syncString(val);
|
|
#ifdef TETRAEDGE_LUA_DEBUG_SAVELOAD
|
|
debug("TeLuaContext::syncState: str %s = '%s'", name.c_str(), val.c_str());
|
|
#endif
|
|
}
|
|
lua_settop(_luaState, -2);
|
|
nextresult = lua_next(_luaState, -2);
|
|
}
|
|
} else {
|
|
#ifdef TETRAEDGE_LUA_DEBUG_SAVELOAD
|
|
debug("TeLuaContext::syncState: --- Loading globals: --- ");
|
|
#endif
|
|
// loading
|
|
TeLuaSaveVarType vtype = None;
|
|
s.syncAsUint32LE(vtype);
|
|
while (vtype != None) {
|
|
Common::String name;
|
|
s.syncString(name);
|
|
switch (vtype) {
|
|
case Boolean: {
|
|
byte b = 0;
|
|
s.syncAsByte(b);
|
|
lua_pushboolean(_luaState, b);
|
|
#ifdef TETRAEDGE_LUA_DEBUG_SAVELOAD
|
|
debug("TeLuaContext::syncState: bool %s = %s", name.c_str(), b ? "true" : "false");
|
|
#endif
|
|
break;
|
|
}
|
|
case Number: {
|
|
float d = 0;
|
|
s.syncAsDoubleLE(d);
|
|
lua_pushnumber(_luaState, d);
|
|
#ifdef TETRAEDGE_LUA_DEBUG_SAVELOAD
|
|
debug("TeLuaContext::syncState: num %s = %f", name.c_str(), d);
|
|
#endif
|
|
break;
|
|
}
|
|
case String: {
|
|
Common::String str;
|
|
s.syncString(str);
|
|
lua_pushstring(_luaState, str.c_str());
|
|
#ifdef TETRAEDGE_LUA_DEBUG_SAVELOAD
|
|
debug("TeLuaContext::syncState: str %s = '%s'", name.c_str(), str.c_str());
|
|
#endif
|
|
break;
|
|
}
|
|
default:
|
|
error("Unexpected lua type on load %d", (int)vtype);
|
|
}
|
|
lua_setglobal(_luaState, name.c_str());
|
|
s.syncAsUint32LE(vtype);
|
|
}
|
|
}
|
|
|
|
#ifdef TETRAEDGE_LUA_DEBUG_SAVELOAD
|
|
debug("TeLuaContext::syncState: -------- end --------");
|
|
#endif
|
|
|
|
return Common::kNoError;
|
|
}
|
|
|
|
} // end namespace Tetraedge
|