|
|
|
@ -36,6 +36,8 @@ distribution.
|
|
|
|
|
#include "DataDefs.h"
|
|
|
|
|
#include "DataIdentity.h"
|
|
|
|
|
|
|
|
|
|
#include "modules/World.h"
|
|
|
|
|
|
|
|
|
|
#include "LuaWrapper.h"
|
|
|
|
|
#include "LuaTools.h"
|
|
|
|
|
|
|
|
|
@ -339,6 +341,213 @@ static const luaL_Reg dfhack_funcs[] = {
|
|
|
|
|
{ NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Per-world persistent configuration storage.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static PersistentDataItem persistent_by_struct(lua_State *state, int idx)
|
|
|
|
|
{
|
|
|
|
|
lua_getfield(state, idx, "entry_id");
|
|
|
|
|
int id = lua_tointeger(state, -1);
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
|
|
|
|
|
PersistentDataItem ref = Core::getInstance().getWorld()->GetPersistentData(id);
|
|
|
|
|
|
|
|
|
|
if (ref.isValid())
|
|
|
|
|
{
|
|
|
|
|
lua_getfield(state, idx, "key");
|
|
|
|
|
const char *str = lua_tostring(state, -1);
|
|
|
|
|
if (!str || str != ref.key())
|
|
|
|
|
luaL_argerror(state, idx, "inconsistent id and key");
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ref;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int read_persistent(lua_State *state, PersistentDataItem ref, bool create)
|
|
|
|
|
{
|
|
|
|
|
if (!ref.isValid())
|
|
|
|
|
{
|
|
|
|
|
lua_pushnil(state);
|
|
|
|
|
lua_pushstring(state, "entry not found");
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (create)
|
|
|
|
|
lua_createtable(state, 0, 4);
|
|
|
|
|
|
|
|
|
|
lua_pushvalue(state, lua_upvalueindex(1));
|
|
|
|
|
lua_setmetatable(state, -2);
|
|
|
|
|
|
|
|
|
|
lua_pushinteger(state, ref.entry_id());
|
|
|
|
|
lua_setfield(state, -2, "entry_id");
|
|
|
|
|
lua_pushstring(state, ref.key().c_str());
|
|
|
|
|
lua_setfield(state, -2, "key");
|
|
|
|
|
lua_pushstring(state, ref.val().c_str());
|
|
|
|
|
lua_setfield(state, -2, "value");
|
|
|
|
|
|
|
|
|
|
lua_createtable(state, PersistentDataItem::NumInts, 0);
|
|
|
|
|
for (int i = 0; i < PersistentDataItem::NumInts; i++)
|
|
|
|
|
{
|
|
|
|
|
lua_pushinteger(state, ref.ival(i));
|
|
|
|
|
lua_rawseti(state, -2, i+1);
|
|
|
|
|
}
|
|
|
|
|
lua_setfield(state, -2, "ints");
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PersistentDataItem get_persistent(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
luaL_checkany(state, 1);
|
|
|
|
|
|
|
|
|
|
if (lua_istable(state, 1))
|
|
|
|
|
{
|
|
|
|
|
if (!lua_getmetatable(state, 1) ||
|
|
|
|
|
!lua_rawequal(state, -1, lua_upvalueindex(1)))
|
|
|
|
|
luaL_argerror(state, 1, "invalid table type");
|
|
|
|
|
|
|
|
|
|
lua_settop(state, 1);
|
|
|
|
|
|
|
|
|
|
return persistent_by_struct(state, 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const char *str = luaL_checkstring(state, 1);
|
|
|
|
|
|
|
|
|
|
return Core::getInstance().getWorld()->GetPersistentData(str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dfhack_persistent_get(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
auto ref = get_persistent(state);
|
|
|
|
|
|
|
|
|
|
return read_persistent(state, ref, !lua_istable(state, 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dfhack_persistent_delete(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
auto ref = get_persistent(state);
|
|
|
|
|
|
|
|
|
|
bool ok = Core::getInstance().getWorld()->DeletePersistentData(ref);
|
|
|
|
|
|
|
|
|
|
lua_pushboolean(state, ok);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dfhack_persistent_get_all(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
const char *str = luaL_checkstring(state, 1);
|
|
|
|
|
bool prefix = (lua_gettop(state)>=2 ? lua_toboolean(state,2) : false);
|
|
|
|
|
|
|
|
|
|
std::vector<PersistentDataItem> data;
|
|
|
|
|
Core::getInstance().getWorld()->GetPersistentData(&data, str, prefix);
|
|
|
|
|
|
|
|
|
|
if (data.empty())
|
|
|
|
|
{
|
|
|
|
|
lua_pushnil(state);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lua_createtable(state, data.size(), 0);
|
|
|
|
|
for (size_t i = 0; i < data.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
read_persistent(state, data[i], true);
|
|
|
|
|
lua_rawseti(state, -2, i+1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dfhack_persistent_save(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
lua_settop(state, 2);
|
|
|
|
|
luaL_checktype(state, 1, LUA_TTABLE);
|
|
|
|
|
bool add = lua_toboolean(state, 2);
|
|
|
|
|
|
|
|
|
|
lua_getfield(state, 1, "key");
|
|
|
|
|
const char *str = lua_tostring(state, -1);
|
|
|
|
|
if (!str)
|
|
|
|
|
luaL_argerror(state, 1, "no key field");
|
|
|
|
|
|
|
|
|
|
lua_settop(state, 1);
|
|
|
|
|
|
|
|
|
|
PersistentDataItem ref;
|
|
|
|
|
bool added = false;
|
|
|
|
|
|
|
|
|
|
if (add)
|
|
|
|
|
{
|
|
|
|
|
ref = Core::getInstance().getWorld()->AddPersistentData(str);
|
|
|
|
|
added = true;
|
|
|
|
|
}
|
|
|
|
|
else if (lua_getmetatable(state, 1))
|
|
|
|
|
{
|
|
|
|
|
if (!lua_rawequal(state, -1, lua_upvalueindex(1)))
|
|
|
|
|
return luaL_argerror(state, 1, "invalid table type");
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
|
|
|
|
|
ref = persistent_by_struct(state, 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ref = Core::getInstance().getWorld()->GetPersistentData(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ref.isValid())
|
|
|
|
|
{
|
|
|
|
|
ref = Core::getInstance().getWorld()->AddPersistentData(str);
|
|
|
|
|
if (!ref.isValid())
|
|
|
|
|
luaL_error(state, "cannot create persistent entry");
|
|
|
|
|
added = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_getfield(state, 1, "value");
|
|
|
|
|
if (const char *str = lua_tostring(state, -1))
|
|
|
|
|
ref.val() = str;
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
|
|
|
|
|
lua_getfield(state, 1, "ints");
|
|
|
|
|
if (lua_istable(state, -1))
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < PersistentDataItem::NumInts; i++)
|
|
|
|
|
{
|
|
|
|
|
lua_rawgeti(state, -1, i+1);
|
|
|
|
|
if (lua_isnumber(state, -1))
|
|
|
|
|
ref.ival(i) = lua_tointeger(state, -1);
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
|
|
|
|
|
read_persistent(state, ref, false);
|
|
|
|
|
lua_pushboolean(state, added);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const luaL_Reg dfhack_persistent_funcs[] = {
|
|
|
|
|
{ "get", dfhack_persistent_get },
|
|
|
|
|
{ "delete", dfhack_persistent_delete },
|
|
|
|
|
{ "get_all", dfhack_persistent_get_all },
|
|
|
|
|
{ "save", dfhack_persistent_save },
|
|
|
|
|
{ NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void OpenPersistent(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
luaL_getsubtable(state, lua_gettop(state), "persistent");
|
|
|
|
|
|
|
|
|
|
lua_dup(state);
|
|
|
|
|
luaL_setfuncs(state, dfhack_persistent_funcs, 1);
|
|
|
|
|
|
|
|
|
|
lua_dup(state);
|
|
|
|
|
lua_setfield(state, -2, "__index");
|
|
|
|
|
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
if (!state)
|
|
|
|
@ -354,6 +563,9 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
|
|
|
|
|
// Create and initialize the dfhack global
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
luaL_setfuncs(state, dfhack_funcs, 0);
|
|
|
|
|
|
|
|
|
|
OpenPersistent(state);
|
|
|
|
|
|
|
|
|
|
lua_setglobal(state, "dfhack");
|
|
|
|
|
|
|
|
|
|
// load dfhack.lua
|
|
|
|
|