Files
scummvm-cursorfix/engines/tetraedge/te/te_lua_context.cpp
2026-02-02 04:50:13 +01:00

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