diff --git a/data/lua/core.lua b/data/lua/core.lua index 049a9edda50..aca080c0455 100644 --- a/data/lua/core.lua +++ b/data/lua/core.lua @@ -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]========] diff --git a/src/scripting/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index e9e7cfb0366..a195dcb05d8 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -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[] { diff --git a/src/scripting/lua_common.cpp b/src/scripting/lua_common.cpp index dcb22ec950f..1794c3dc3aa 100644 --- a/src/scripting/lua_common.cpp +++ b/src/scripting/lua_common.cpp @@ -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; diff --git a/src/scripting/lua_kernel_base.cpp b/src/scripting/lua_kernel_base.cpp index 3833d03c9eb..4103212e87e 100644 --- a/src/scripting/lua_kernel_base.cpp +++ b/src/scripting/lua_kernel_base.cpp @@ -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);