Reputation: 43
I am currently building a program that lets me implement Lua scripts.
I want to get into serialization of those scripts, by accessing only the global variable of a lua_State
by name and by value.
My Lua script looks like this:
TESTVALUE1 = 10
--TESTVALUE2 = 5.5
--TESTVALUE3 = "TEST"
--TESTVALUE4 = {hallo=5, x=5.4, y="y", t={5, 8}}
function Setup(object) -- Setup is executed once the GameObject is completely loaded the associated object is given to store in a global if needed
end
function Update(deltatime) -- deltatime is the frametime
end
function Render() -- Called every frame, put your render functions inside!
end
And my serialization in C++ looks like this:
void serialize(std::ofstream &file) {
if (file.is_open() && file.good()) {
// Writing script name and path to the file
file.write((char *)&path, sizeof(path));
file.write((char *)&name, sizeof(name));
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
char value_type = 0;
std::string name = lua_tostring(L, -2);
lua_getglobal(L, name.c_str());
if (lua_isfunction(L, -1)) {
lua_pop(L, 2);
continue;
}
if (lua_isinteger(L, -1)) {
file.write((char *)&name, sizeof(name));
int val = lua_tointeger(L, -1);
value_type = 1;
file.write((char *)&value_type, sizeof(value_type));
file.write((char *)&val, sizeof(val));
} else if (lua_isnumber(L, -1)) {
file.write((char *)&name, sizeof(name));
float val = lua_tonumber(L, -1);
value_type = 2;
file.write((char *)&value_type, sizeof(value_type));
file.write((char *)&val, sizeof(val));
} else if (lua_isstring(L, -1)) {
file.write((char *)&name, sizeof(name));
std::string val = lua_tostring(L, -1);
value_type = 3;
file.write((char *)&value_type, sizeof(value_type));
file.write((char *)&val, sizeof(val));
} else if (lua_istable(L, -1)) {
file.write((char *)&name, sizeof(name));
value_type = 4;
file.write((char *)&value_type, sizeof(value_type));
int top = lua_gettop(L);
serializetable(file, top);
} else {
file.write((char *)&name, sizeof(name));
file.write((char *)&value_type, sizeof(value_type));
}
lua_pop(L, 2);
}
lua_pop(L, 1);
}
}
If I just print out all the names of my global variables, I get this:
setmetatable
dofile
os
rawget
require
package
utf8
_G
_VERSION
load
pairs
warn
tostring
type
pcall
collectgarbage
loadfile
rawset
rawequal
assert
print
next
xpcall
string
coroutine
Render
ipairs
Update
Setup
error
select
debug
math
tonumber
rawlen
TESTVALUE1
getmetatable
io
table
So, there are much more than just my TESTVALUE1
, Setup
, Update
, and Render
globals. Is there a way to get rid of the others?
I can skip functions by checking with lua_isfunction(L, -1)
, but some of these are not functions and crash my code.
Upvotes: 0
Views: 46
Reputation: 43
I fixed it and found the problem. By getting the global table with lua_pushglobaltable(L); i cannot access the global variables with lua_getglobal(L, key.c_str()) anymore i now did it like this:
lua_pushglobaltable(L);
int idx = lua_gettop(L);
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
char value_type = 0;
std::string key = lua_tostring(L, -2);
size = key.size();
lua_pushstring(L, key.c_str());
lua_gettable(L, idx);
this this code the value of the given key is now on top of the stack. Before it was always nil ... therefore my if-else statements were totally ignored and i got errors working with that nil value. now i can just skip every function I encounter.
Upvotes: 0
Reputation: 27359
A simple approach is to remap the global environment to an empty table before running your file.
_ENV = setmetatable({}, {__index = _G})
An equivalent C code is:
lua_newtable(L); // new global environment
lua_createtable(L, 0, 1); // new metatable
lua_getglobal(L, LUA_GNAME); // _G
lua_setfield(L, -2, "__index"); // { __index = _G }
lua_setmetatable(L, -2); // setmetatable(...)
lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); // _ENV = ...
Upvotes: 1