From a778dff61dc0d56fc73a8a10a6304da20c472ba1 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Tue, 30 May 2023 01:44:09 +0200 Subject: [PATCH] Add Lua functions to get the current load order and search objects by RefNum/FormId --- apps/openmw/mwlua/luabindings.cpp | 30 +++++++++++++++++++++++++++- apps/openmw/mwlua/nearbybindings.cpp | 7 +++++++ files/lua_api/openmw/core.lua | 24 ++++++++++++++++++++++ files/lua_api/openmw/nearby.lua | 7 +++++++ files/lua_api/openmw/world.lua | 7 +++++++ 5 files changed, 74 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index 04df6b6b16..9d1416b813 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -88,7 +88,7 @@ namespace MWLua { auto* lua = context.mLua; sol::table api(lua->sol(), sol::create); - api["API_REVISION"] = 38; + api["API_REVISION"] = 39; api["quit"] = [lua]() { Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback(); MWBase::Environment::get().getStateManager()->requestQuit(); @@ -97,6 +97,28 @@ namespace MWLua context.mLuaEvents->addGlobalEvent( { std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) }); }; + api["getContentList"] = [](sol::this_state lua) -> sol::table { + const std::vector& contentList = MWBase::Environment::get().getWorld()->getContentFiles(); + sol::table res(lua, sol::create); + int i = 1; + for (const std::string& s : contentList) + res[i++] = Misc::StringUtils::lowerCase(s); + return res; + }; + api["getContentFileIndex"] = [](std::string_view contentFile) -> sol::optional { + const std::vector& contentList = MWBase::Environment::get().getWorld()->getContentFiles(); + for (size_t i = 0; i < contentList.size(); ++i) + if (Misc::StringUtils::ciEqual(contentList[i], contentFile)) + return i + 1; + return sol::nullopt; + }; + api["getFormId"] = [](std::string_view contentFile, unsigned int index) -> std::string { + const std::vector& contentList = MWBase::Environment::get().getWorld()->getContentFiles(); + for (size_t i = 0; i < contentList.size(); ++i) + if (Misc::StringUtils::ciEqual(contentList[i], contentFile)) + return ESM::RefId(ESM::FormIdRefId(ESM::FormId{ index, int(i) })).serializeText(); + throw std::runtime_error("Content file not found: " + std::string(contentFile)); + }; addTimeBindings(api, context, false); api["magic"] = initCoreMagicBindings(context); api["l10n"] = LuaUtil::initL10nLoader(lua->sol(), MWBase::Environment::get().getL10nManager()); @@ -189,6 +211,12 @@ namespace MWLua MWWorld::Ptr newPtr = ptr.getClass().copyToCell(ptr, *cell, count.value_or(1)); return GObject(newPtr); }; + api["getObjectByFormId"] = [](std::string_view formIdStr) -> GObject { + ESM::RefId refId = ESM::RefId::deserializeText(formIdStr); + if (!refId.is()) + throw std::runtime_error("FormId expected, got " + std::string(formIdStr) + "; use core.getFormId"); + return GObject(refId.getIf()->getValue()); + }; // Creates a new record in the world database. api["createRecord"] = sol::overload( diff --git a/apps/openmw/mwlua/nearbybindings.cpp b/apps/openmw/mwlua/nearbybindings.cpp index c9f9163648..88c4907d81 100644 --- a/apps/openmw/mwlua/nearbybindings.cpp +++ b/apps/openmw/mwlua/nearbybindings.cpp @@ -124,6 +124,13 @@ namespace MWLua }); }; + api["getObjectByFormId"] = [](std::string_view formIdStr) -> LObject { + ESM::RefId refId = ESM::RefId::deserializeText(formIdStr); + if (!refId.is()) + throw std::runtime_error("FormId expected, got " + std::string(formIdStr) + "; use core.getFormId"); + return LObject(refId.getIf()->getValue()); + }; + api["activators"] = LObjectList{ worldView->getActivatorsInScene() }; api["actors"] = LObjectList{ worldView->getActorsInScene() }; api["containers"] = LObjectList{ worldView->getContainersInScene() }; diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index fa56a1c80e..9661d7bb14 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -102,6 +102,30 @@ -- print( myMsg('Hello {name}!', {name='World'}) ) +--- +-- Return the current load order (list of content file names). +-- @function [parent=#core] getContentList +-- @return #list<#string> + +--- +-- Return the index of a specific content file in the load order (or `nil` if there is no such content file). +-- @function [parent=#core] getContentFileIndex +-- @param #string contentFile +-- @return #number + +--- +-- Construct FormId string from content file name and the index in the file. +-- @function [parent=#core] getFormId +-- @param #string contentFile +-- @param #number index +-- @return #string +-- @usage if obj.recordId == core.getFormId('Skyrim.esm', 0x4d7da) then ... end +-- @usage -- local scripts +-- local obj = nearby.getObjectByFormId(core.getFormId('Morrowind.esm', 128964)) +-- @usage -- global scripts +-- local obj = world.getObjectByFormId(core.getFormId('Morrowind.esm', 128964)) + + --- -- Any object that exists in the game world and has a specific location. -- Player, actors, items, and statics are game objects. diff --git a/files/lua_api/openmw/nearby.lua b/files/lua_api/openmw/nearby.lua index e28f867d38..27fa442621 100644 --- a/files/lua_api/openmw/nearby.lua +++ b/files/lua_api/openmw/nearby.lua @@ -26,6 +26,13 @@ -- Everything that can be picked up in the nearby. -- @field [parent=#nearby] openmw.core#ObjectList items +--- +-- Return an object by RefNum/FormId. +-- @function [parent=#nearby] getObjectByFormId +-- @param #string formId String returned by `core.getFormId` +-- @return openmw.core#GameObject +-- @usage local obj = nearby.getObjectByFormId(core.getFormId('Morrowind.esm', 128964)) + --- -- @type COLLISION_TYPE -- @field [parent=#COLLISION_TYPE] #number World diff --git a/files/lua_api/openmw/world.lua b/files/lua_api/openmw/world.lua index 2cc80063fd..0977825313 100644 --- a/files/lua_api/openmw/world.lua +++ b/files/lua_api/openmw/world.lua @@ -65,6 +65,13 @@ -- @function [parent=#world] isWorldPaused -- @return #boolean +--- +-- Return an object by RefNum/FormId. +-- @function [parent=#world] getObjectByFormId +-- @param #string formId String returned by `core.getFormId` +-- @return openmw.core#GameObject +-- @usage local obj = world.getObjectByFormId(core.getFormId('Morrowind.esm', 128964)) + --- -- Create a new instance of the given record. -- After creation the object is in the disabled state. Use :teleport to place to the world or :moveInto to put it into a container or an inventory.