diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index d844670eca..26cd10155f 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -231,7 +231,11 @@ namespace MWLua sol::usertype cells = context.mLua->sol().new_usertype("Cells"); cells[sol::meta_function::length] = [cells3Store, cells4Store](const CellsStore&) { return cells3Store->getSize() + cells4Store->getSize(); }; - cells[sol::meta_function::index] = [cells3Store, cells4Store](const CellsStore&, size_t index) -> GCell { + cells[sol::meta_function::index] + = [cells3Store, cells4Store](const CellsStore&, size_t index) -> sol::optional { + if (index > cells3Store->getSize() + cells3Store->getSize() || index == 0) + return sol::nullopt; + index--; // Translate from Lua's 1-based indexing. if (index < cells3Store->getSize()) { diff --git a/apps/openmw/mwlua/magicbindings.cpp b/apps/openmw/mwlua/magicbindings.cpp index 4d4f111ab1..afcc5bc54a 100644 --- a/apps/openmw/mwlua/magicbindings.cpp +++ b/apps/openmw/mwlua/magicbindings.cpp @@ -243,9 +243,13 @@ namespace MWLua = [](const SpellStore& store) { return "ESM3_SpellStore{" + std::to_string(store.getSize()) + " spells}"; }; spellStoreT[sol::meta_function::length] = [](const SpellStore& store) { return store.getSize(); }; spellStoreT[sol::meta_function::index] = sol::overload( - [](const SpellStore& store, size_t index) -> const ESM::Spell* { return store.at(index - 1); }, + [](const SpellStore& store, size_t index) -> const ESM::Spell* { + if (index == 0 || index > store.getSize()) + return nullptr; + return store.at(index - 1); + }, [](const SpellStore& store, std::string_view spellId) -> const ESM::Spell* { - return store.find(ESM::RefId::deserializeText(spellId)); + return store.search(ESM::RefId::deserializeText(spellId)); }); spellStoreT[sol::meta_function::pairs] = lua["ipairsForArray"].template get(); spellStoreT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get(); @@ -262,9 +266,13 @@ namespace MWLua }; enchantmentStoreT[sol::meta_function::length] = [](const EnchantmentStore& store) { return store.getSize(); }; enchantmentStoreT[sol::meta_function::index] = sol::overload( - [](const EnchantmentStore& store, size_t index) -> const ESM::Enchantment* { return store.at(index - 1); }, + [](const EnchantmentStore& store, size_t index) -> const ESM::Enchantment* { + if (index == 0 || index > store.getSize()) + return nullptr; + return store.at(index - 1); + }, [](const EnchantmentStore& store, std::string_view enchantmentId) -> const ESM::Enchantment* { - return store.find(ESM::RefId::deserializeText(enchantmentId)); + return store.search(ESM::RefId::deserializeText(enchantmentId)); }); enchantmentStoreT[sol::meta_function::pairs] = lua["ipairsForArray"].template get(); enchantmentStoreT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get(); @@ -280,10 +288,10 @@ namespace MWLua return "ESM3_MagicEffectStore{" + std::to_string(store.getSize()) + " effects}"; }; magicEffectStoreT[sol::meta_function::index] = sol::overload( - [](const MagicEffectStore& store, int id) -> const ESM::MagicEffect* { return store.find(id); }, + [](const MagicEffectStore& store, int id) -> const ESM::MagicEffect* { return store.search(id); }, [](const MagicEffectStore& store, std::string_view id) -> const ESM::MagicEffect* { int index = ESM::MagicEffect::indexNameToIndex(id); - return store.find(index); + return store.search(index); }); auto magicEffectsIter = [magicEffectStore](sol::this_state lua, const sol::object& /*store*/, sol::optional id) -> std::tuple { @@ -665,20 +673,20 @@ namespace MWLua // types.Actor.spells(o)[i] spellsT[sol::meta_function::index] = sol::overload( - [](const ActorSpells& spells, size_t index) -> sol::optional { + [](const ActorSpells& spells, size_t index) -> const ESM::Spell* { if (auto* store = spells.getStore()) - if (index <= store->count()) + if (index <= store->count() && index > 0) return store->at(index - 1); - return sol::nullopt; + return nullptr; }, - [spellStore](const ActorSpells& spells, std::string_view spellId) -> sol::optional { + [spellStore](const ActorSpells& spells, std::string_view spellId) -> const ESM::Spell* { if (auto* store = spells.getStore()) { - const ESM::Spell* spell = spellStore->find(ESM::RefId::deserializeText(spellId)); - if (store->hasSpell(spell)) + const ESM::Spell* spell = spellStore->search(ESM::RefId::deserializeText(spellId)); + if (spell && store->hasSpell(spell)) return spell; } - return sol::nullopt; + return nullptr; }); // pairs(types.Actor.spells(o)) diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index a7b2252a31..ee746001ae 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -136,11 +136,11 @@ namespace MWLua listT[sol::meta_function::to_string] = [](const ListT& list) { return "{" + std::to_string(list.mIds->size()) + " objects}"; }; listT[sol::meta_function::length] = [](const ListT& list) { return list.mIds->size(); }; - listT[sol::meta_function::index] = [](const ListT& list, size_t index) { + listT[sol::meta_function::index] = [](const ListT& list, size_t index) -> sol::optional { if (index > 0 && index <= list.mIds->size()) return ObjectT((*list.mIds)[index - 1]); else - throw std::runtime_error("Index out of range"); + return sol::nullopt; }; listT[sol::meta_function::pairs] = lua["ipairsForArray"].template get(); listT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get(); diff --git a/apps/openmw/mwlua/soundbindings.cpp b/apps/openmw/mwlua/soundbindings.cpp index 355ede9f27..b5dae8a7a8 100644 --- a/apps/openmw/mwlua/soundbindings.cpp +++ b/apps/openmw/mwlua/soundbindings.cpp @@ -169,9 +169,13 @@ namespace MWLua = [](const SoundStore& store) { return "ESM3_SoundStore{" + std::to_string(store.getSize()) + " sounds}"; }; soundStoreT[sol::meta_function::length] = [](const SoundStore& store) { return store.getSize(); }; soundStoreT[sol::meta_function::index] = sol::overload( - [](const SoundStore& store, size_t index) -> const ESM::Sound* { return store.at(index - 1); }, + [](const SoundStore& store, size_t index) -> const ESM::Sound* { + if (index == 0 || index > store.getSize()) + return nullptr; + return store.at(index - 1); + }, [](const SoundStore& store, std::string_view soundId) -> const ESM::Sound* { - return store.find(ESM::RefId::deserializeText(soundId)); + return store.search(ESM::RefId::deserializeText(soundId)); }); soundStoreT[sol::meta_function::pairs] = lua["ipairsForArray"].template get(); soundStoreT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get(); diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index 5e44b47f1a..c0eb61bfc7 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -48,13 +48,13 @@ namespace MWLua }; sol::usertype quests = context.mLua->sol().new_usertype("Quests"); quests[sol::meta_function::to_string] = [](const Quests& quests) { return "Quests"; }; - quests[sol::meta_function::index] = sol::overload([](const Quests& quests, std::string_view questId) -> Quest { + quests[sol::meta_function::index] = [](const Quests& quests, std::string_view questId) -> sol::optional { ESM::RefId quest = ESM::RefId::deserializeText(questId); - const ESM::Dialogue* dial = MWBase::Environment::get().getESMStore()->get().find(quest); - if (dial->mType != ESM::Dialogue::Journal) - throw std::runtime_error("Not a quest:" + std::string(questId)); + const ESM::Dialogue* dial = MWBase::Environment::get().getESMStore()->get().search(quest); + if (dial == nullptr || dial->mType != ESM::Dialogue::Journal) + return sol::nullopt; return Quest{ .mQuestId = quest, .mMutable = quests.mMutable }; - }); + }; quests[sol::meta_function::pairs] = [journal](const Quests& quests) { std::vector ids; for (auto it = journal->questBegin(); it != journal->questEnd(); ++it) diff --git a/apps/openmw/mwlua/types/types.hpp b/apps/openmw/mwlua/types/types.hpp index 8cd126b007..8fc0932dfe 100644 --- a/apps/openmw/mwlua/types/types.hpp +++ b/apps/openmw/mwlua/types/types.hpp @@ -77,7 +77,7 @@ namespace MWLua const MWWorld::Store& store = MWBase::Environment::get().getESMStore()->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)); }); + [&store](std::string_view id) -> const T* { return store.search(ESM::RefId::deserializeText(id)); }); // Define a custom user type for the store. // Provide the interface of a read-only array. @@ -89,6 +89,8 @@ namespace MWLua }; 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 nullptr; return store.at(index - 1); // Translate from Lua's 1-based indexing. }; storeT[sol::meta_function::pairs] = lua["ipairsForArray"].template get();