Lua: Add a few more useful functions to the WML module and make WML table conversion a little more robust

- New functions: wml.find_child, wml.attribute_count, wml.equal, wml.valid
- When converting a Lua table to WML, the engine will no longer accept invalid attributes
- Use of wml.tovconfig in plugin or map generation scripts is deprecated (it already doesn't quite work properly in those contexts but still could've been used as a way to test a table's validity as WML)
This commit is contained in:
Celtic Minstrel 2019-12-01 17:39:51 -05:00
parent 680e7741ff
commit 86f66a5825
4 changed files with 84 additions and 3 deletions

View file

@ -21,7 +21,7 @@ end
local function ensure_config(cfg)
if type(cfg) == 'table' then
return true
return wml.valid(cfg)
end
if type(cfg) == 'userdata' then
if getmetatable(cfg) == 'wml object' then return true end
@ -35,6 +35,7 @@ end
--! Returns the first subtag of @a cfg with the given @a name.
--! If @a id is not nil, the "id" attribute of the subtag has to match too.
--! The function also returns the index of the subtag in the array.
--! Returns nil if no matching subtag is found
function wml.get_child(cfg, name, id)
ensure_config(cfg)
for i,v in ipairs(cfg) do
@ -48,6 +49,7 @@ end
--! Returns the nth subtag of @a cfg with the given @a name.
--! (Indices start at 1, as always with Lua.)
--! The function also returns the index of the subtag in the array.
--! Returns nil if no matching subtag is found
function wml.get_nth_child(cfg, name, n)
ensure_config(cfg)
for i,v in ipairs(cfg) do
@ -58,6 +60,36 @@ function wml.get_nth_child(cfg, name, n)
end
end
--! Returns the first subtag of @a cfg with the given @a name that matches the @a filter.
--! If @a name is omitted, any subtag can match regardless of its name.
--! The function also returns the index of the subtag in the array.
--! Returns nil if no matching subtag is found
function wml.find_child(cfg, name, filter)
ensure_config(cfg)
if filter == nil then
filter = name
name = nil
end
for i,v in ipairs(cfg) do
if name == nil or v[1] == name then
local w = v[2]
if wml.matches_filter(w, filter) then return w, i end
end
end
end
--! Returns the number of attributes of the config
function wml.attribute_count(cfg)
ensure_config(cfg)
local count = 0
for k,v in pairs(cfg) do
if type(k) == 'string' then
count = count + 1
end
end
return count
end
--! Returns the number of subtags of @a with the given @a name.
function wml.child_count(cfg, name)
ensure_config(cfg)
@ -130,6 +162,8 @@ wml.tag = setmetatable({}, create_tag_mt)
--[========[Config / Vconfig Unified Handling]========]
-- These are slated to be moved to game kernel only
function wml.literal(cfg)
if type(cfg) == "userdata" then
return cfg.__literal
@ -562,6 +596,28 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
if type(side) == 'number' then side = wesnoth.sides[side] end
return side.starting_location
end
else
--[========[Backwards compatibility for wml.tovconfig]========]
local fake_vconfig_mt = {
__index = function(self, key)
if key == '__literal' or key == '__parsed' or key == '__shallow_literal' or key == '__shallow_parsed' then
return self
end
return self[key]
end
}
local function tovconfig_fake(cfg)
ensure_config(cfg)
return setmetatable(cfg, fake_vconfig_mt)
end
wesnoth.tovconfig = wesnoth.deprecate_api('wesnoth.tovconfig', 'wml.valid', 1, null, tovconfig_fake, 'tovconfig is now deprecated in plugin or map generation contexts; if you need to check whether a table is valid as a WML object, use wml.valid instead.')
wml.tovconfig = wesnoth.deprecate_api('wml.tovconfig', 'wml.valid', 1, null, tovconfig_fake, 'tovconfig is now deprecated in plugin or map generation contexts; if you need to check whether a table is valid as a WML object, use wml.valid instead.')
wml.literal = wesnoth.deprecate_api('wml.literal', '(no replacement)', 1, null, wml.literal, 'Since vconfigs are not supported outside of the game kernel, this function is redundant and will be removed from plugin and map generation contexts. It will continue to work in the game kernel.')
wml.parsed = wesnoth.deprecate_api('wml.parsed', '(no replacement)', 1, null, wml.parsed, 'Since vconfigs are not supported outside of the game kernel, this function is redundant and will be removed from plugin and map generation contexts. It will continue to work in the game kernel.')
wml.shallow_literal = wesnoth.deprecate_api('wml.shallow_literal', '(no replacement)', 1, null, wml.shallow_literal, 'Since vconfigs are not supported outside of the game kernel, this function is redundant and will be removed from plugin and map generation contexts. It will continue to work in the game kernel.')
wml.shallow_parsed = wesnoth.deprecate_api('wml.shallow_parsed', '(no replacement)', 1, null, wml.shallow_parsed, 'Since vconfigs are not supported outside of the game kernel, this function is redundant and will be removed from plugin and map generation contexts. It will continue to work in the game kernel.')
end
--[========[GUI2 Dialog Manipulations]========]

View file

@ -4296,6 +4296,12 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
lua_setfield(L, -2, "current");
lua_pop(L, 1);
// Add tovconfig to the WML module
lua_getglobal(L, "wml");
lua_pushcfunction(L, &lua_common::intf_tovconfig);
lua_setfield(L, -2, "tovconfig");
lua_pop(L, 1);
// Create the units module
cmd_log_ << "Adding units module...\n";
static luaL_Reg const unit_callbacks[] {

View file

@ -781,7 +781,9 @@ bool luaW_toconfig(lua_State *L, int index, config &cfg)
int indextype = lua_type(L, -2);
if (indextype == LUA_TNUMBER) continue;
if (indextype != LUA_TSTRING) return_misformed();
config::attribute_value &v = cfg[lua_tostring(L, -2)];
const char* m = lua_tostring(L, -2);
if(!m || !config::valid_attribute(m)) return_misformed();
config::attribute_value &v = cfg[m];
if (lua_istable(L, -1)) {
int subindex = lua_absindex(L, -1);
std::ostringstream str;

View file

@ -329,6 +329,22 @@ static int intf_wml_patch(lua_State* L) {
return 1;
}
static int intf_wml_equal(lua_State* L) {
config left = luaW_checkconfig(L, 1);
config right = luaW_checkconfig(L, 2);
lua_pushboolean(L, left == right);
return 1;
}
static int intf_wml_valid(lua_State* L) {
config test;
if(luaW_toconfig(L, 1, test)) {
// The validate_wml call is PROBABLY redundant, but included just in case validation changes and toconfig isn't updated to match
lua_pushboolean(L, test.validate_wml());
} else lua_pushboolean(L, false);
return 1;
}
/**
* Logs a message
* Arg 1: (optional) Logger
@ -668,9 +684,10 @@ lua_kernel_base::lua_kernel_base()
{ "merge", &intf_wml_merge},
{ "diff", &intf_wml_diff},
{ "patch", &intf_wml_patch},
{ "equal", &intf_wml_equal},
{ "valid", &intf_wml_valid},
{ "matches_filter", &intf_wml_matches_filter},
{ "tostring", &intf_wml_tostring},
{ "tovconfig", &lua_common::intf_tovconfig},
{ nullptr, nullptr },
};
lua_newtable(L);