diff --git a/apps/openmw/mwlua/uibindings.cpp b/apps/openmw/mwlua/uibindings.cpp index 4333ae5072..248f82f28a 100644 --- a/apps/openmw/mwlua/uibindings.cpp +++ b/apps/openmw/mwlua/uibindings.cpp @@ -166,6 +166,21 @@ namespace MWLua else return sol::nullopt; }; + { + auto pairs = [](LuaUi::Content& content) + { + auto next = [](LuaUi::Content& content, size_t i) -> sol::optional> + { + if (i < content.size()) + return std::make_tuple(i + 1, content.at(i)); + else + return sol::nullopt; + }; + return std::make_tuple(next, content, 0); + }; + uiContent[sol::meta_function::ipairs] = pairs; + uiContent[sol::meta_function::pairs] = pairs; + } auto element = context.mLua->sol().new_usertype("Element"); element["layout"] = sol::property( @@ -233,6 +248,21 @@ namespace MWLua options.mInteractive = LuaUtil::getValueOrDefault(LuaUtil::getFieldOrNil(opt, "interactive"), true); context.mLuaManager->addAction(std::make_unique(name, afterName, options, context.mLua)); }; + { + auto pairs = [layers](const sol::object&) + { + auto next = [](const sol::table& l, size_t i) -> sol::optional> + { + if (i < LuaUi::Layers::size()) + return std::make_tuple(i + 1, LuaUi::Layers::at(i)); + else + return sol::nullopt; + }; + return std::make_tuple(next, layers, 0); + }; + layers[sol::meta_function::pairs] = pairs; + layers[sol::meta_function::ipairs] = pairs; + } api["layers"] = LuaUtil::makeReadOnly(layers); sol::table typeTable = context.mLua->newTable(); diff --git a/components/lua/luastate.cpp b/components/lua/luastate.cpp index 13e1421116..dbd792224f 100644 --- a/components/lua/luastate.cpp +++ b/components/lua/luastate.cpp @@ -59,6 +59,23 @@ namespace LuaUtil mLua["writeToLog"] = [](std::string_view s) { Log(Debug::Level::Info) << s; }; mLua["cmetatable"] = [](const sol::table& v) -> sol::object { return v[sol::metatable_key]; }; + + // Some fixes for compatibility between different Lua versions + if (mLua["unpack"] == sol::nil) + mLua["unpack"] = mLua["table"]["unpack"]; + else if (mLua["table"]["unpack"] == sol::nil) + mLua["table"]["unpack"] = mLua["unpack"]; + if (LUA_VERSION_NUM <= 501) + { + mLua.script(R"( + local _pairs = pairs + local _ipairs = ipairs + local _cmeta = cmetatable + pairs = function(v) return ((_cmeta(v) or v).__pairs or _pairs)(v) end + ipairs = function(v) return ((_cmeta(v) or v).__ipairs or _ipairs)(v) end + )"); + } + mLua.script(R"( local _pairs = pairs local _ipairs = ipairs @@ -78,22 +95,6 @@ namespace LuaUtil function ipairsForReadOnly(v) return _ipairs(_cmeta(v).__index) end )"); - // Some fixes for compatibility between different Lua versions - if (mLua["unpack"] == sol::nil) - mLua["unpack"] = mLua["table"]["unpack"]; - else if (mLua["table"]["unpack"] == sol::nil) - mLua["table"]["unpack"] = mLua["unpack"]; - if (LUA_VERSION_NUM <= 501) - { - mLua.script(R"( - local _pairs = pairs - local _ipairs = ipairs - local _cmeta = cmetatable - pairs = function(v) return ((_cmeta(v) or v).__pairs or _pairs)(v) end - ipairs = function(v) return ((_cmeta(v) or v).__ipairs or _ipairs)(v) end - )"); - } - mSandboxEnv = sol::table(mLua, sol::create); mSandboxEnv["_VERSION"] = mLua["_VERSION"]; for (const std::string& s : safeFunctions) diff --git a/docs/source/generate_luadoc.sh b/docs/source/generate_luadoc.sh index 99e387cf0f..b3ec10ba97 100755 --- a/docs/source/generate_luadoc.sh +++ b/docs/source/generate_luadoc.sh @@ -67,4 +67,3 @@ cd $FILES_DIR/builtin_scripts $DOCUMENTOR_PATH -f doc -d $OUTPUT_DIR openmw_aux/*lua $DOCUMENTOR_PATH -f doc -d $OUTPUT_DIR scripts/omw/ai.lua $DOCUMENTOR_PATH -f doc -d $OUTPUT_DIR scripts/omw/camera.lua - diff --git a/docs/source/reference/lua-scripting/api.rst b/docs/source/reference/lua-scripting/api.rst index 41fd52253f..0681c63dea 100644 --- a/docs/source/reference/lua-scripting/api.rst +++ b/docs/source/reference/lua-scripting/api.rst @@ -25,6 +25,7 @@ Lua API reference openmw_aux_time interface_ai interface_camera + iterables - :ref:`Engine handlers reference` diff --git a/docs/source/reference/lua-scripting/iterables.rst b/docs/source/reference/lua-scripting/iterables.rst new file mode 100644 index 0000000000..208b7f1c92 --- /dev/null +++ b/docs/source/reference/lua-scripting/iterables.rst @@ -0,0 +1,50 @@ +Iterable types +============== + +List Iterable +------------- + +An iterable with defined size and order. + +.. code-block:: Lua + + -- can iterate over the list with pairs + for i, v in pairs(list) do + -- ... + end + +.. code-block:: Lua + + -- can iterate over the list with ipairs + for i, v in ipairs(list) do + -- ... + end + +.. code-block:: Lua + + -- can get total size with the size # operator + local length = #list + +.. code-block:: Lua + + -- can index the list with numbers + for i = 1, length do + list[i] + end + +Map Iterable +------------ + +An iterable with undefined order. + +.. code-block:: Lua + + -- can iterate over the map with pairs + for k, v in pairs(map) do + -- ... + end + +.. code-block:: Lua + + -- can index the map by key + map[key] diff --git a/docs/source/reference/lua-scripting/overview.rst b/docs/source/reference/lua-scripting/overview.rst index e6024a27a1..e07abee899 100644 --- a/docs/source/reference/lua-scripting/overview.rst +++ b/docs/source/reference/lua-scripting/overview.rst @@ -498,7 +498,7 @@ At some moment it will send the 'DamagedByDarkPower' event to all nearby actors: local nearby = require('openmw.nearby') local function onActivated() - for i, actor in nearby.actors:ipairs() do + for i, actor in ipairs(nearby.actors) do local dist = (self.position - actor.position):length() if dist < 500 then local damage = (1 - dist / 500) * 200 diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index e7e657a853..84e2b4faae 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -289,9 +289,9 @@ ------------------------------------------------------------------------------- --- List of GameObjects. +-- List of GameObjects. Implements [iterables#List](iterables.html#List) of #GameObject -- @type ObjectList --- @extends #list<#GameObject> +-- @list <#GameObject> ------------------------------------------------------------------------------- -- Filter list with a Query. diff --git a/files/lua_api/openmw/ui.lua b/files/lua_api/openmw/ui.lua index d4f305b96e..478b9235a5 100644 --- a/files/lua_api/openmw/ui.lua +++ b/files/lua_api/openmw/ui.lua @@ -64,12 +64,16 @@ -- @field #Content content Optional @{openmw.ui#Content} of children layouts --- --- Layers +-- Layers. Implements [iterables#List](iterables.html#List) of #string. -- @type Layers +-- @list <#string> -- @usage -- ui.layers.insertAfter('HUD', 'NewLayer', { interactive = true }) -- local fourthLayerName = ui.layers[4] -- local windowsIndex = ui.layers.indexOf('Windows') +-- for i, name in ipairs(ui.layers) do +-- print('layer', i, name) +-- end --- -- Index of the layer with the givent name. Returns nil if the layer doesn't exist @@ -85,7 +89,8 @@ -- @param #table options Table with a boolean `interactive` field (default is true). Layers with interactive = false will ignore all mouse interactions. --- --- Content. An array-like container, which allows to reference elements by their name +-- Content. An array-like container, which allows to reference elements by their name. +-- Implements [iterables#List](iterables.html#List) of #Layout and [iterables#Map](iterables.html#Map) of #string to #Layout. -- @type Content -- @list <#Layout> -- @usage