1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-06-21 04:11:33 +00:00

Check class validity before using it.

This commit is contained in:
Mads Buvik Sandvei 2023-05-21 12:54:17 +02:00
parent 87250bfabf
commit 448658ce5b

View file

@ -31,7 +31,17 @@ namespace MWLua
// class returned via 'types.Actor.spells(obj)' in Lua // class returned via 'types.Actor.spells(obj)' in Lua
struct ActorSpells struct ActorSpells
{ {
const ObjectVariant mActor; bool isActor() const { return !mActor.ptr().isEmpty() && mActor.ptr().getClass().isActor(); }
MWMechanics::Spells* getStore() const
{
if (!isActor())
return nullptr;
const MWWorld::Ptr& ptr = mActor.ptr();
return &ptr.getClass().getCreatureStats(ptr).getSpells();
}
ObjectVariant mActor;
}; };
template <typename Store> template <typename Store>
@ -39,26 +49,68 @@ namespace MWLua
{ {
using Collection = typename Store::Collection; using Collection = typename Store::Collection;
using Iterator = typename Collection::const_iterator; using Iterator = typename Collection::const_iterator;
const ObjectVariant mActor;
Store* store = nullptr; ActorStore(ObjectVariant actor)
Iterator it = Iterator(); : mActor(actor)
int index = 0; , mIterator()
, mIndex(0)
{
reset();
}
bool isActor() const { return !mActor.ptr().isEmpty() && mActor.ptr().getClass().isActor(); }
void reset() void reset()
{ {
index = 0; mIndex = 0;
it = store->begin(); auto* store = getStore();
if (store)
mIterator = store->begin();
} }
bool isEnd() { return it == store->end(); } bool isEnd() const
{
auto* store = getStore();
if (store)
return mIterator == store->end();
return true;
}
void advance() void advance()
{ {
it++; auto* store = getStore();
index++; if (store)
{
mIterator++;
mIndex++;
} }
}
Store* getStore() const;
ObjectVariant mActor;
Iterator mIterator;
int mIndex;
}; };
template <>
MWMechanics::MagicEffects* ActorStore<MWMechanics::MagicEffects>::getStore() const
{
if (!isActor())
return nullptr;
const MWWorld::Ptr& ptr = mActor.ptr();
return &ptr.getClass().getCreatureStats(ptr).getMagicEffects();
}
template <>
MWMechanics::ActiveSpells* ActorStore<MWMechanics::ActiveSpells>::getStore() const
{
if (!isActor())
return nullptr;
const MWWorld::Ptr& ptr = mActor.ptr();
return &ptr.getClass().getCreatureStats(ptr).getActiveSpells();
}
struct ActiveEffect struct ActiveEffect
{ {
MWMechanics::EffectKey key; MWMechanics::EffectKey key;
@ -336,19 +388,21 @@ namespace MWLua
= &MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>(); = &MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>();
// types.Actor.spells(o) // types.Actor.spells(o)
actor["spells"] = [](const sol::object actor) { return ActorSpells{ ObjectVariant(actor) }; }; actor["spells"] = [](const sol::object actor) {
auto spells = ActorSpells{ ObjectVariant(actor) };
if (!spells.isActor())
throw std::runtime_error("Actor expected");
return spells;
};
auto spellsT = context.mLua->sol().new_usertype<ActorSpells>("ActorSpells"); auto spellsT = context.mLua->sol().new_usertype<ActorSpells>("ActorSpells");
spellsT[sol::meta_function::to_string] spellsT[sol::meta_function::to_string]
= [](const ActorSpells& spells) { return "ActorSpells[" + spells.mActor.object().toString() + "]"; }; = [](const ActorSpells& spells) { return "ActorSpells[" + spells.mActor.object().toString() + "]"; };
actor["activeSpells"] = [](const sol::object actor) { actor["activeSpells"] = [](const sol::object actor) {
ActorActiveSpells store = { ObjectVariant(actor) }; auto spells = ActorActiveSpells{ ObjectVariant(actor) };
auto ptr = store.mActor.ptr(); if (!spells.isActor())
if (!ptr.isEmpty()) throw std::runtime_error("Actor expected");
{ return spells;
store.store = &ptr.getClass().getCreatureStats(ptr).getActiveSpells();
}
return store;
}; };
auto activeSpellsT = context.mLua->sol().new_usertype<ActorActiveSpells>("ActorActiveSpells"); auto activeSpellsT = context.mLua->sol().new_usertype<ActorActiveSpells>("ActorActiveSpells");
activeSpellsT[sol::meta_function::to_string] = [](const ActorActiveSpells& spells) { activeSpellsT[sol::meta_function::to_string] = [](const ActorActiveSpells& spells) {
@ -356,13 +410,10 @@ namespace MWLua
}; };
actor["activeEffects"] = [](const sol::object actor) { actor["activeEffects"] = [](const sol::object actor) {
ActorActiveEffects store = { ObjectVariant(actor) }; auto effects = ActorActiveEffects{ ObjectVariant(actor) };
auto ptr = store.mActor.ptr(); if (!effects.isActor())
if (!ptr.isEmpty()) throw std::runtime_error("Actor expected");
{ return effects;
store.store = &ptr.getClass().getCreatureStats(ptr).getMagicEffects();
}
return store;
}; };
auto activeEffectsT = context.mLua->sol().new_usertype<ActorActiveEffects>("ActorActiveEffects"); auto activeEffectsT = context.mLua->sol().new_usertype<ActorActiveEffects>("ActorActiveEffects");
activeEffectsT[sol::meta_function::to_string] = [](const ActorActiveEffects& effects) { activeEffectsT[sol::meta_function::to_string] = [](const ActorActiveEffects& effects) {
@ -416,22 +467,26 @@ namespace MWLua
// #(types.Actor.spells(o)) // #(types.Actor.spells(o))
spellsT[sol::meta_function::length] = [](const ActorSpells& spells) -> size_t { spellsT[sol::meta_function::length] = [](const ActorSpells& spells) -> size_t {
const MWWorld::Ptr& ptr = spells.mActor.ptr(); if (auto* store = spells.getStore())
return ptr.getClass().getCreatureStats(ptr).getSpells().count(); return store->count();
return 0;
}; };
// types.Actor.spells(o)[i] // types.Actor.spells(o)[i]
spellsT[sol::meta_function::index] = sol::overload( spellsT[sol::meta_function::index] = sol::overload(
[](const ActorSpells& spells, size_t index) -> const ESM::Spell* { [](const ActorSpells& spells, size_t index) -> sol::optional<const ESM::Spell*> {
const MWWorld::Ptr& ptr = spells.mActor.ptr(); if (auto* store = spells.getStore())
return ptr.getClass().getCreatureStats(ptr).getSpells().at(index - 1); if (index <= store->count())
return store->at(index - 1);
return sol::nullopt;
}, },
[spellStore](const ActorSpells& spells, std::string_view spellId) -> sol::optional<const ESM::Spell*> { [spellStore](const ActorSpells& spells, std::string_view spellId) -> sol::optional<const ESM::Spell*> {
const MWWorld::Ptr& ptr = spells.mActor.ptr(); if (auto* store = spells.getStore())
{
const ESM::Spell* spell = spellStore->find(ESM::RefId::deserializeText(spellId)); const ESM::Spell* spell = spellStore->find(ESM::RefId::deserializeText(spellId));
if (ptr.getClass().getCreatureStats(ptr).getSpells().hasSpell(spell)) if (store->hasSpell(spell))
return spell; return spell;
else }
return sol::nullopt; return sol::nullopt;
}); });
@ -447,6 +502,7 @@ namespace MWLua
throw std::runtime_error("Local scripts can modify only spells of the actor they are attached to."); throw std::runtime_error("Local scripts can modify only spells of the actor they are attached to.");
context.mLuaManager->addAction([obj = spells.mActor.object(), id = toSpellId(spellOrId)]() { context.mLuaManager->addAction([obj = spells.mActor.object(), id = toSpellId(spellOrId)]() {
const MWWorld::Ptr& ptr = obj.ptr(); const MWWorld::Ptr& ptr = obj.ptr();
if (ptr.getClass().isActor())
ptr.getClass().getCreatureStats(ptr).getSpells().add(id); ptr.getClass().getCreatureStats(ptr).getSpells().add(id);
}); });
}; };
@ -457,6 +513,7 @@ namespace MWLua
throw std::runtime_error("Local scripts can modify only spells of the actor they are attached to."); throw std::runtime_error("Local scripts can modify only spells of the actor they are attached to.");
context.mLuaManager->addAction([obj = spells.mActor.object(), id = toSpellId(spellOrId)]() { context.mLuaManager->addAction([obj = spells.mActor.object(), id = toSpellId(spellOrId)]() {
const MWWorld::Ptr& ptr = obj.ptr(); const MWWorld::Ptr& ptr = obj.ptr();
if (ptr.getClass().isActor())
ptr.getClass().getCreatureStats(ptr).getSpells().remove(id); ptr.getClass().getCreatureStats(ptr).getSpells().remove(id);
}); });
}; };
@ -467,6 +524,7 @@ namespace MWLua
throw std::runtime_error("Local scripts can modify only spells of the actor they are attached to."); throw std::runtime_error("Local scripts can modify only spells of the actor they are attached to.");
context.mLuaManager->addAction([obj = spells.mActor.object()]() { context.mLuaManager->addAction([obj = spells.mActor.object()]() {
const MWWorld::Ptr& ptr = obj.ptr(); const MWWorld::Ptr& ptr = obj.ptr();
if (ptr.getClass().isActor())
ptr.getClass().getCreatureStats(ptr).getSpells().clear(); ptr.getClass().getCreatureStats(ptr).getSpells().clear();
}); });
}; };
@ -480,8 +538,8 @@ namespace MWLua
return sol::as_function([lua, &self]() mutable -> std::pair<sol::object, sol::object> { return sol::as_function([lua, &self]() mutable -> std::pair<sol::object, sol::object> {
if (!self.isEnd()) if (!self.isEnd())
{ {
auto result = sol::make_object(lua, self.it->getId()); auto result = sol::make_object(lua, self.mIterator->getId());
auto index = sol::make_object(lua, self.index); auto index = sol::make_object(lua, self.mIndex + 1);
self.advance(); self.advance();
return { index, result }; return { index, result };
} }
@ -495,9 +553,9 @@ namespace MWLua
// types.Actor.activeSpells(o):isSpellActive(id) // types.Actor.activeSpells(o):isSpellActive(id)
activeSpellsT["isSpellActive"] = [](const ActorActiveSpells& spells, const sol::object& spellOrId) -> bool { activeSpellsT["isSpellActive"] = [](const ActorActiveSpells& spells, const sol::object& spellOrId) -> bool {
auto id = toSpellId(spellOrId); auto id = toSpellId(spellOrId);
const MWWorld::Ptr& ptr = spells.mActor.object().ptr(); if (auto* store = spells.getStore())
auto& activeSpells = ptr.getClass().getCreatureStats(ptr).getActiveSpells(); return store->isSpellActive(id);
return activeSpells.isSpellActive(id); return false;
}; };
// pairs(types.Actor.activeEffects(o)) // pairs(types.Actor.activeEffects(o))
@ -509,10 +567,10 @@ namespace MWLua
return sol::as_function([lua, &self]() mutable -> std::pair<sol::object, sol::object> { return sol::as_function([lua, &self]() mutable -> std::pair<sol::object, sol::object> {
if (!self.isEnd()) if (!self.isEnd())
{ {
ActiveEffect effect = ActiveEffect{ self.it->first, self.it->second }; ActiveEffect effect = ActiveEffect{ self.mIterator->first, self.mIterator->second };
auto result = sol::make_object(lua, effect); auto result = sol::make_object(lua, effect);
auto key = sol::make_object(lua, self.it->first.toString()); auto key = sol::make_object(lua, self.mIterator->first.toString());
self.advance(); self.advance();
return { key, result }; return { key, result };
} }
@ -524,8 +582,11 @@ namespace MWLua
}; };
// types.Actor.activeEffects(o):getEffect(id, ?arg) // types.Actor.activeEffects(o):getEffect(id, ?arg)
activeEffectsT["getEffect"] = [](const ActorActiveEffects& self, std::string_view idStr, activeEffectsT["getEffect"] = [](const ActorActiveEffects& effects, std::string_view idStr,
sol::optional<std::string_view> argStr) -> sol::optional<ActiveEffect> { sol::optional<std::string_view> argStr) -> sol::optional<ActiveEffect> {
if (!effects.isActor())
return sol::nullopt;
auto id = ESM::MagicEffect::effectStringToId("sEffect" + std::string(idStr)); auto id = ESM::MagicEffect::effectStringToId("sEffect" + std::string(idStr));
auto* rec = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(id); auto* rec = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(id);
@ -543,7 +604,8 @@ namespace MWLua
} }
MWMechanics::EffectParam param; MWMechanics::EffectParam param;
if (self.store->get(key, param)) if (auto* store = effects.getStore())
if (store->get(key, param))
return ActiveEffect{ key, param }; return ActiveEffect{ key, param };
return sol::nullopt; return sol::nullopt;
}; };