diff --git a/apps/openmw/mwlua/types/activator.cpp b/apps/openmw/mwlua/types/activator.cpp index 88cf4d0f29..72baeffac5 100644 --- a/apps/openmw/mwlua/types/activator.cpp +++ b/apps/openmw/mwlua/types/activator.cpp @@ -23,7 +23,7 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(activator); + addRecordFunctionBinding(activator, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Activator"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/apparatus.cpp b/apps/openmw/mwlua/types/apparatus.cpp index 0747d97d4c..10bdbcdd29 100644 --- a/apps/openmw/mwlua/types/apparatus.cpp +++ b/apps/openmw/mwlua/types/apparatus.cpp @@ -30,7 +30,7 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(apparatus); + addRecordFunctionBinding(apparatus, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Apparatus"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/armor.cpp b/apps/openmw/mwlua/types/armor.cpp index 7c5b477e10..0368a89b21 100644 --- a/apps/openmw/mwlua/types/armor.cpp +++ b/apps/openmw/mwlua/types/armor.cpp @@ -37,7 +37,7 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(armor); + addRecordFunctionBinding(armor, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Armor"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/book.cpp b/apps/openmw/mwlua/types/book.cpp index 02602bd6a7..651ba8fd4f 100644 --- a/apps/openmw/mwlua/types/book.cpp +++ b/apps/openmw/mwlua/types/book.cpp @@ -32,7 +32,7 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(book); + addRecordFunctionBinding(book, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Book"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/clothing.cpp b/apps/openmw/mwlua/types/clothing.cpp index 35634d5fc1..947b997f71 100644 --- a/apps/openmw/mwlua/types/clothing.cpp +++ b/apps/openmw/mwlua/types/clothing.cpp @@ -36,7 +36,7 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(clothing); + addRecordFunctionBinding(clothing, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Clothing"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/container.cpp b/apps/openmw/mwlua/types/container.cpp index cd6d2e3d24..21ec2f04dc 100644 --- a/apps/openmw/mwlua/types/container.cpp +++ b/apps/openmw/mwlua/types/container.cpp @@ -48,7 +48,7 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(container); + addRecordFunctionBinding(container, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Container"); record[sol::meta_function::to_string] = [](const ESM::Container& rec) -> std::string { diff --git a/apps/openmw/mwlua/types/creature.cpp b/apps/openmw/mwlua/types/creature.cpp index ecba2b7eba..be6786b4ca 100644 --- a/apps/openmw/mwlua/types/creature.cpp +++ b/apps/openmw/mwlua/types/creature.cpp @@ -23,7 +23,7 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(creature); + addRecordFunctionBinding(creature, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Creature"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/door.cpp b/apps/openmw/mwlua/types/door.cpp index db54a77277..7dee2d7af3 100644 --- a/apps/openmw/mwlua/types/door.cpp +++ b/apps/openmw/mwlua/types/door.cpp @@ -43,7 +43,7 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(door); + addRecordFunctionBinding(door, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Door"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/ingredient.cpp b/apps/openmw/mwlua/types/ingredient.cpp index ed66ec9a9b..69b4a670fb 100644 --- a/apps/openmw/mwlua/types/ingredient.cpp +++ b/apps/openmw/mwlua/types/ingredient.cpp @@ -24,7 +24,7 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(ingredient); + addRecordFunctionBinding(ingredient, context); sol::usertype record = context.mLua->sol().new_usertype(("ESM3_Ingredient")); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/light.cpp b/apps/openmw/mwlua/types/light.cpp index bc9630289b..347bb61641 100644 --- a/apps/openmw/mwlua/types/light.cpp +++ b/apps/openmw/mwlua/types/light.cpp @@ -23,7 +23,7 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(light); + addRecordFunctionBinding(light, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Light"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/lockpick.cpp b/apps/openmw/mwlua/types/lockpick.cpp index c5d9c6983d..786471461a 100644 --- a/apps/openmw/mwlua/types/lockpick.cpp +++ b/apps/openmw/mwlua/types/lockpick.cpp @@ -23,7 +23,7 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(lockpick); + addRecordFunctionBinding(lockpick, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Lockpick"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/misc.cpp b/apps/openmw/mwlua/types/misc.cpp index 7b0b5934ec..c565094022 100644 --- a/apps/openmw/mwlua/types/misc.cpp +++ b/apps/openmw/mwlua/types/misc.cpp @@ -23,7 +23,7 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(miscellaneous); + addRecordFunctionBinding(miscellaneous, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Miscellaneous"); diff --git a/apps/openmw/mwlua/types/npc.cpp b/apps/openmw/mwlua/types/npc.cpp index 71d611f99c..31dc87095f 100644 --- a/apps/openmw/mwlua/types/npc.cpp +++ b/apps/openmw/mwlua/types/npc.cpp @@ -25,7 +25,7 @@ namespace MWLua { addNpcStatsBindings(npc, context); - addRecordFunctionBinding(npc); + addRecordFunctionBinding(npc, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_NPC"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/potion.cpp b/apps/openmw/mwlua/types/potion.cpp index c14d84024c..3ab15f2691 100644 --- a/apps/openmw/mwlua/types/potion.cpp +++ b/apps/openmw/mwlua/types/potion.cpp @@ -41,7 +41,7 @@ namespace MWLua { void addPotionBindings(sol::table potion, const Context& context) { - addRecordFunctionBinding(potion); + addRecordFunctionBinding(potion, context); // Creates a new potion struct but does not store it in MWWorld::ESMStore. // Global scripts can use world.createRecord to add the potion to the world. diff --git a/apps/openmw/mwlua/types/probe.cpp b/apps/openmw/mwlua/types/probe.cpp index e042e4a0ab..668e58c98c 100644 --- a/apps/openmw/mwlua/types/probe.cpp +++ b/apps/openmw/mwlua/types/probe.cpp @@ -23,7 +23,7 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(probe); + addRecordFunctionBinding(probe, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Probe"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/repair.cpp b/apps/openmw/mwlua/types/repair.cpp index f38b7e2992..75d0a17c49 100644 --- a/apps/openmw/mwlua/types/repair.cpp +++ b/apps/openmw/mwlua/types/repair.cpp @@ -23,7 +23,7 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(repair); + addRecordFunctionBinding(repair, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Repair"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/static.cpp b/apps/openmw/mwlua/types/static.cpp index ad7ee6b640..76dac4fa00 100644 --- a/apps/openmw/mwlua/types/static.cpp +++ b/apps/openmw/mwlua/types/static.cpp @@ -23,7 +23,7 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(stat); + addRecordFunctionBinding(stat, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Static"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/types.hpp b/apps/openmw/mwlua/types/types.hpp index 284bc95d39..01d0766289 100644 --- a/apps/openmw/mwlua/types/types.hpp +++ b/apps/openmw/mwlua/types/types.hpp @@ -4,6 +4,7 @@ #include #include +#include #include "apps/openmw/mwbase/environment.hpp" #include "apps/openmw/mwbase/world.hpp" @@ -13,6 +14,16 @@ #include "../context.hpp" #include "../object.hpp" +namespace sol +{ + // Ensure sol does not try to create the automatic Container or usertype bindings for Store. + // They include write operations and we want the store to be read-only. + template + struct is_automagical> : std::false_type + { + }; +} + namespace MWLua { // `getLiveCellRefType()` is not exactly what we usually mean by "type" because some refids have special meaning. @@ -53,12 +64,33 @@ namespace MWLua void addLightBindings(sol::table light, const Context& context); template - void addRecordFunctionBinding(sol::table table) + void addRecordFunctionBinding(sol::table table, const Context& context) { const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); table["record"] = sol::overload([](const Object& obj) -> const T* { return obj.ptr().get()->mBase; }, [&store](std::string_view id) -> const T* { return store.find(ESM::RefId::deserializeText(id)); }); + + // Define a custom user type for the store. + // Provide the interface of a read-only array. + using StoreT = MWWorld::Store; + sol::state_view& lua = context.mLua->sol(); + sol::usertype storeT = lua.new_usertype(std::string(T::getRecordType()) + "WorldStore"); + storeT[sol::meta_function::to_string] = [](const StoreT& store) { + return "{" + std::to_string(store.getSize()) + " " + std::string(T::getRecordType()) + " records}"; + }; + storeT[sol::meta_function::length] = [](const StoreT& store) { return store.getSize(); }; + storeT[sol::meta_function::index] = [](const StoreT& store, size_t index) -> const T& { + if (index > 0 && index <= store.getSize()) + return store.at(index - 1); // Translate from Lua's 1-based indexing. + else + throw std::runtime_error("Index out of range"); + }; + storeT[sol::meta_function::pairs] = lua["ipairsForArray"].template get(); + storeT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get(); + + // Provide access to the store. + table["records"] = [&store]() { return &store; }; } } diff --git a/apps/openmw/mwlua/types/weapon.cpp b/apps/openmw/mwlua/types/weapon.cpp index b333f4ef57..aa781c58ea 100644 --- a/apps/openmw/mwlua/types/weapon.cpp +++ b/apps/openmw/mwlua/types/weapon.cpp @@ -40,7 +40,7 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - addRecordFunctionBinding(weapon); + addRecordFunctionBinding(weapon, context); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Weapon"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 79142b44f0..8cba1467d8 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -205,6 +205,11 @@ namespace MWWorld { return mShared.end(); } + template + const T& TypedDynamicStore::at(size_t index) const + { + return *mShared.at(index); + } template size_t TypedDynamicStore::getSize() const diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index dbcf4c5a98..d6e713207e 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -209,6 +209,7 @@ namespace MWWorld iterator begin() const; iterator end() const; + const T& at(size_t index) const; size_t getSize() const override; int getDynamicSize() const override; diff --git a/files/lua_api/openmw/types.lua b/files/lua_api/openmw/types.lua index d7c0cd9517..14067fde16 100644 --- a/files/lua_api/openmw/types.lua +++ b/files/lua_api/openmw/types.lua @@ -466,6 +466,11 @@ -- @param #any objectOrRecordId -- @return #CreatureRecord +--- +-- Returns a read-only list of all @{#CreatureRecord}s in the world database. +-- @function [parent=#Creature] records +-- @return #list<#CreatureRecord> + --- -- @type CreatureRecord -- @field #string name @@ -502,6 +507,11 @@ -- @param #any objectOrRecordId -- @return #NpcRecord +--- +-- Returns a read-only list of all @{#NpcRecord}s in the world database. +-- @function [parent=#Npc] records +-- @return #list<#NpcRecord> + --- -- @type NpcRecord -- @field #string name @@ -564,6 +574,11 @@ -- @param #any objectOrRecordId -- @return #ArmorRecord +--- +-- Returns a read-only list of all @{#ArmorRecord}s in the world database. +-- @function [parent=#Armor] records +-- @return #list<#ArmorRecord> + --- -- @type ArmorRecord -- @field #string id Record id @@ -634,6 +649,11 @@ -- @param #any objectOrRecordId -- @return #BookRecord +--- +-- Returns a read-only list of all @{#BookRecord}s in the world database. +-- @function [parent=#Book] records +-- @return #list<#BookRecord> + --- -- @type BookRecord -- @field #string id The record ID of the book @@ -687,6 +707,11 @@ -- @param #any objectOrRecordId -- @return #ClothingRecord +--- +-- Returns a read-only list of all @{#ClothingRecord}s in the world database. +-- @function [parent=#Clothing] records +-- @return #list<#ClothingRecord> + --- -- @type ClothingRecord -- @field #string id Record id @@ -723,6 +748,11 @@ -- @param #any objectOrRecordId -- @return #IngredientRecord +--- +-- Returns a read-only list of all @{#IngredientRecord}s in the world database. +-- @function [parent=#Ingredient] records +-- @return #list<#IngredientRecord> + --- -- @type IngredientRecord -- @field #string id Record id @@ -755,6 +785,11 @@ -- @param #any objectOrRecordId -- @return #LightRecord +--- +-- Returns a read-only list of all @{#LightRecord}s in the world database. +-- @function [parent=#Light] records +-- @return #list<#LightRecord> + --- -- @type LightRecord -- @field #string id Record id @@ -792,6 +827,11 @@ -- @param #any objectOrRecordId -- @return #MiscellaneousRecord +--- +-- Returns a read-only list of all @{#MiscellaneousRecord}s in the world database. +-- @function [parent=#Miscellaneous] records +-- @return #list<#MiscellaneousRecord> + --- -- @type MiscellaneousRecord -- @field #string id The record ID of the miscellaneous item @@ -823,6 +863,11 @@ -- @param #any objectOrRecordId -- @return #PotionRecord +--- +-- Returns a read-only list of all @{#PotionRecord}s in the world database. +-- @function [parent=#Potion] records +-- @return #list<#PotionRecord> + --- -- Creates a @{#PotionRecord} without adding it to the world database. -- Use @{openmw_world#(world).createRecord} to add the record to the world. @@ -882,6 +927,11 @@ -- @param #any objectOrRecordId -- @return #WeaponRecord +--- +-- Returns a read-only list of all @{#WeaponRecord}s in the world database. +-- @function [parent=#Weapon] records +-- @return #list<#WeaponRecord> + --- -- @type WeaponRecord -- @field #string id Record id @@ -938,6 +988,11 @@ -- @param #any objectOrRecordId -- @return #ApparatusRecord +--- +-- Returns a read-only list of all @{#ApparatusRecord}s in the world database. +-- @function [parent=#Apparatus] records +-- @return #list<#ApparatusRecord> + --- -- @type ApparatusRecord -- @field #string id The record ID of the apparatus @@ -970,6 +1025,11 @@ -- @param #any objectOrRecordId -- @return #LockpickRecord +--- +-- Returns a read-only list of all @{#LockpickRecord}s in the world database. +-- @function [parent=#Lockpick] records +-- @return #list<#LockpickRecord> + --- -- @type LockpickRecord -- @field #string id The record ID of the lockpick @@ -1002,6 +1062,11 @@ -- @param #any objectOrRecordId -- @return #ProbeRecord +--- +-- Returns a read-only list of all @{#ProbeRecord}s in the world database. +-- @function [parent=#Probe] records +-- @return #list<#ProbeRecord> + --- -- @type ProbeRecord -- @field #string id The record ID of the probe @@ -1034,6 +1099,11 @@ -- @param #any objectOrRecordId -- @return #RepairRecord +--- +-- Returns a read-only list of all @{#RepairRecord}s in the world database. +-- @function [parent=#Repair] records +-- @return #list<#RepairRecord> + --- -- @type RepairRecord -- @field #string id The record ID of the repair tool @@ -1064,6 +1134,11 @@ -- @param #any objectOrRecordId -- @return #ActivatorRecord +--- +-- Returns a read-only list of all @{#ActivatorRecord}s in the world database. +-- @function [parent=#Activator] records +-- @return #list<#ActivatorRecord> + --- -- @type ActivatorRecord -- @field #string id Record id @@ -1107,6 +1182,11 @@ -- @param #any objectOrRecordId -- @return #ContainerRecord +--- +-- Returns a read-only list of all @{#ContainerRecord}s in the world database. +-- @function [parent=#Container] records +-- @return #list<#ContainerRecord> + --- -- @type ContainerRecord -- @field #string id Record id @@ -1157,6 +1237,11 @@ -- @param #any objectOrRecordId -- @return #DoorRecord +--- +-- Returns a read-only list of all @{#DoorRecord}s in the world database. +-- @function [parent=#Door] records +-- @return #list<#DoorRecord> + --- -- @type DoorRecord -- @field #string id Record id @@ -1186,6 +1271,11 @@ -- @param #any objectOrRecordId -- @return #StaticRecord +--- +-- Returns a read-only list of all @{#StaticRecord}s in the world database. +-- @function [parent=#Static] records +-- @return #list<#StaticRecord> + --- -- @type StaticRecord -- @field #string id Record id