1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-21 11:39:44 +00:00

Move std::variant<SelfObject*, LObject, GObject> from mwlua/stats.cpp to mwlua/objectvariant.hpp

This commit is contained in:
Petr Mikheev 2023-03-06 02:31:58 +01:00
parent 0b385d5db9
commit 2bfffb3063
6 changed files with 139 additions and 121 deletions

View file

@ -59,7 +59,7 @@ add_openmw_dir (mwscript
) )
add_openmw_dir (mwlua add_openmw_dir (mwlua
luamanagerimp object worldview userdataserializer eventqueue luamanagerimp object worldview userdataserializer eventqueue objectvariant
luabindings localscripts playerscripts objectbindings cellbindings luabindings localscripts playerscripts objectbindings cellbindings
camerabindings uibindings inputbindings nearbybindings postprocessingbindings stats debugbindings camerabindings uibindings inputbindings nearbybindings postprocessingbindings stats debugbindings
types/types types/door types/actor types/container types/weapon types/npc types/creature types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair types/armor types/light types/static types/clothing types/types types/door types/actor types/container types/weapon types/npc types/creature types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair types/armor types/light types/static types/clothing

View file

@ -33,7 +33,7 @@ namespace sol
{ {
}; };
template <> template <>
struct is_automagical<MWLua::LocalScripts::SelfObject> : std::false_type struct is_automagical<MWLua::SelfObject> : std::false_type
{ {
}; };
template <> template <>

View file

@ -16,6 +16,46 @@ namespace MWLua
{ {
struct Context; struct Context;
struct SelfObject : public LObject
{
class CachedStat
{
public:
using Setter = void (*)(int, std::string_view, const MWWorld::Ptr&, const sol::object&);
private:
Setter mSetter; // Function that updates a stat's property
int mIndex; // Optional index to disambiguate the stat
std::string_view mProp; // Name of the stat's property
public:
CachedStat(Setter setter, int index, std::string_view prop)
: mSetter(setter)
, mIndex(index)
, mProp(std::move(prop))
{
}
void operator()(const MWWorld::Ptr& ptr, const sol::object& object) const
{
mSetter(mIndex, mProp, ptr, object);
}
bool operator<(const CachedStat& other) const
{
return std::tie(mSetter, mIndex, mProp) < std::tie(other.mSetter, other.mIndex, other.mProp);
}
};
SelfObject(const LObject& obj)
: LObject(obj)
, mIsActive(false)
{
}
MWBase::LuaManager::ActorControls mControls;
std::map<CachedStat, sol::object> mStatsCache;
bool mIsActive;
};
class LocalScripts : public LuaUtil::ScriptsContainer class LocalScripts : public LuaUtil::ScriptsContainer
{ {
public: public:
@ -25,46 +65,6 @@ namespace MWLua
MWBase::LuaManager::ActorControls* getActorControls() { return &mData.mControls; } MWBase::LuaManager::ActorControls* getActorControls() { return &mData.mControls; }
const MWWorld::Ptr& getPtr() const { return mData.ptr(); } const MWWorld::Ptr& getPtr() const { return mData.ptr(); }
struct SelfObject : public LObject
{
class CachedStat
{
public:
using Setter = void (*)(int, std::string_view, const MWWorld::Ptr&, const sol::object&);
private:
Setter mSetter; // Function that updates a stat's property
int mIndex; // Optional index to disambiguate the stat
std::string_view mProp; // Name of the stat's property
public:
CachedStat(Setter setter, int index, std::string_view prop)
: mSetter(setter)
, mIndex(index)
, mProp(std::move(prop))
{
}
void operator()(const MWWorld::Ptr& ptr, const sol::object& object) const
{
mSetter(mIndex, mProp, ptr, object);
}
bool operator<(const CachedStat& other) const
{
return std::tie(mSetter, mIndex, mProp) < std::tie(other.mSetter, other.mIndex, other.mProp);
}
};
SelfObject(const LObject& obj)
: LObject(obj)
, mIsActive(false)
{
}
MWBase::LuaManager::ActorControls mControls;
std::map<CachedStat, sol::object> mStatsCache;
bool mIsActive;
};
struct OnActive struct OnActive
{ {
}; };

View file

@ -0,0 +1,55 @@
#ifndef MWLUA_OBJECTVARIANT_H
#define MWLUA_OBJECTVARIANT_H
#include <variant>
#include "localscripts.hpp"
#include "object.hpp"
namespace MWLua
{
class ObjectVariant
{
public:
explicit ObjectVariant(const sol::object& obj)
{
if (obj.is<SelfObject>())
mVariant.emplace<SelfObject*>(obj.as<SelfObject*>());
else if (obj.is<LObject>())
mVariant.emplace<LObject>(obj.as<LObject>());
else
mVariant.emplace<GObject>(obj.as<GObject>());
}
bool isSelfObject() const { return std::holds_alternative<SelfObject*>(mVariant); }
bool isLObject() const { return std::holds_alternative<LObject>(mVariant); }
bool isGObject() const { return std::holds_alternative<GObject>(mVariant); }
SelfObject* asSelfObject() const
{
if (!isSelfObject())
throw std::runtime_error("Allowed only in local scripts for 'openmw.self'.");
return std::get<SelfObject*>(mVariant);
}
const MWWorld::Ptr& ptr() const
{
return std::visit(
[](auto&& variant) -> const MWWorld::Ptr& {
using T = std::decay_t<decltype(variant)>;
if constexpr (std::is_same_v<T, SelfObject*>)
return variant->ptr();
else
return variant.ptr();
},
mVariant);
}
private:
std::variant<SelfObject*, LObject, GObject> mVariant;
};
} // namespace MWLua
#endif // MWLUA_OBJECTVARIANT_H

View file

@ -18,14 +18,17 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "objectvariant.hpp"
namespace namespace
{ {
using SelfObject = MWLua::SelfObject;
using ObjectVariant = MWLua::ObjectVariant;
template <class T> template <class T>
auto addIndexedAccessor(int index) auto addIndexedAccessor(int index)
{ {
return sol::overload([index](MWLua::LocalScripts::SelfObject& o) { return T::create(&o, index); }, return [index](const sol::object& o) { return T::create(ObjectVariant(o), index); };
[index](const MWLua::LObject& o) { return T::create(o, index); },
[index](const MWLua::GObject& o) { return T::create(o, index); });
} }
template <class T, class G> template <class T, class G>
@ -35,50 +38,18 @@ namespace
[=](const T& stat, const sol::object& value) { stat.cache(context, prop, value); }); [=](const T& stat, const sol::object& value) { stat.cache(context, prop, value); });
} }
using SelfObject = MWLua::LocalScripts::SelfObject;
using StatObject = std::variant<SelfObject*, MWLua::LObject, MWLua::GObject>;
SelfObject* asSelfObject(const StatObject& obj)
{
if (!std::holds_alternative<SelfObject*>(obj))
throw std::runtime_error("Changing stats allowed only in local scripts for 'openmw.self'.");
return std::get<SelfObject*>(obj);
}
const MWLua::Object* getObject(const StatObject& obj)
{
return std::visit(
[](auto&& variant) -> const MWLua::Object* {
using T = std::decay_t<decltype(variant)>;
if constexpr (std::is_same_v<T, SelfObject*>)
return variant;
else if constexpr (std::is_same_v<T, MWLua::LObject>)
return &variant;
else if constexpr (std::is_same_v<T, MWLua::GObject>)
return &variant;
},
obj);
}
template <class G> template <class G>
sol::object getValue(const MWLua::Context& context, const StatObject& obj, SelfObject::CachedStat::Setter setter, sol::object getValue(const MWLua::Context& context, const ObjectVariant& obj, SelfObject::CachedStat::Setter setter,
int index, std::string_view prop, G getter) int index, std::string_view prop, G getter)
{ {
return std::visit( if (obj.isSelfObject())
[&](auto&& variant) { {
using T = std::decay_t<decltype(variant)>; SelfObject* self = obj.asSelfObject();
if constexpr (std::is_same_v<T, SelfObject*>) auto it = self->mStatsCache.find({ setter, index, prop });
{ if (it != self->mStatsCache.end())
auto it = variant->mStatsCache.find({ setter, index, prop }); return it->second;
if (it != variant->mStatsCache.end()) }
return it->second; return sol::make_object(context.mLua->sol(), getter(obj.ptr()));
return sol::make_object(context.mLua->sol(), getter(variant));
}
else if constexpr (std::is_same_v<T, MWLua::LObject>)
return sol::make_object(context.mLua->sol(), getter(&variant));
else if constexpr (std::is_same_v<T, MWLua::GObject>)
return sol::make_object(context.mLua->sol(), getter(&variant));
},
obj);
} }
} }
@ -111,9 +82,9 @@ namespace MWLua
class LevelStat class LevelStat
{ {
StatObject mObject; ObjectVariant mObject;
LevelStat(StatObject object) LevelStat(ObjectVariant object)
: mObject(std::move(object)) : mObject(std::move(object))
{ {
} }
@ -121,15 +92,13 @@ namespace MWLua
public: public:
sol::object getCurrent(const Context& context) const sol::object getCurrent(const Context& context) const
{ {
return getValue(context, mObject, &LevelStat::setValue, 0, "current", [](const MWLua::Object* obj) { return getValue(context, mObject, &LevelStat::setValue, 0, "current",
const auto& ptr = obj->ptr(); [](const MWWorld::Ptr& ptr) { return ptr.getClass().getCreatureStats(ptr).getLevel(); });
return ptr.getClass().getCreatureStats(ptr).getLevel();
});
} }
void setCurrent(const Context& context, const sol::object& value) const void setCurrent(const Context& context, const sol::object& value) const
{ {
SelfObject* obj = asSelfObject(mObject); SelfObject* obj = mObject.asSelfObject();
if (obj->mStatsCache.empty()) if (obj->mStatsCache.empty())
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id())); context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{ &LevelStat::setValue, 0, "current" }] = value; obj->mStatsCache[SelfObject::CachedStat{ &LevelStat::setValue, 0, "current" }] = value;
@ -137,15 +106,15 @@ namespace MWLua
sol::object getProgress(const Context& context) const sol::object getProgress(const Context& context) const
{ {
const auto& ptr = getObject(mObject)->ptr(); const auto& ptr = mObject.ptr();
if (!ptr.getClass().isNpc()) if (!ptr.getClass().isNpc())
return sol::nil; return sol::nil;
return sol::make_object(context.mLua->sol(), ptr.getClass().getNpcStats(ptr).getLevelProgress()); return sol::make_object(context.mLua->sol(), ptr.getClass().getNpcStats(ptr).getLevelProgress());
} }
static std::optional<LevelStat> create(StatObject object, int index) static std::optional<LevelStat> create(ObjectVariant object, int index)
{ {
if (!getObject(object)->ptr().getClass().isActor()) if (!object.ptr().getClass().isActor())
return {}; return {};
return LevelStat{ std::move(object) }; return LevelStat{ std::move(object) };
} }
@ -160,10 +129,10 @@ namespace MWLua
class DynamicStat class DynamicStat
{ {
StatObject mObject; ObjectVariant mObject;
int mIndex; int mIndex;
DynamicStat(StatObject object, int index) DynamicStat(ObjectVariant object, int index)
: mObject(std::move(object)) : mObject(std::move(object))
, mIndex(index) , mIndex(index)
{ {
@ -174,22 +143,21 @@ namespace MWLua
sol::object get(const Context& context, std::string_view prop, G getter) const sol::object get(const Context& context, std::string_view prop, G getter) const
{ {
return getValue( return getValue(
context, mObject, &DynamicStat::setValue, mIndex, prop, [this, getter](const MWLua::Object* obj) { context, mObject, &DynamicStat::setValue, mIndex, prop, [this, getter](const MWWorld::Ptr& ptr) {
const auto& ptr = obj->ptr();
return (ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex).*getter)(); return (ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex).*getter)();
}); });
} }
static std::optional<DynamicStat> create(StatObject object, int index) static std::optional<DynamicStat> create(ObjectVariant object, int index)
{ {
if (!getObject(object)->ptr().getClass().isActor()) if (!object.ptr().getClass().isActor())
return {}; return {};
return DynamicStat{ std::move(object), index }; return DynamicStat{ std::move(object), index };
} }
void cache(const Context& context, std::string_view prop, const sol::object& value) const void cache(const Context& context, std::string_view prop, const sol::object& value) const
{ {
SelfObject* obj = asSelfObject(mObject); SelfObject* obj = mObject.asSelfObject();
if (obj->mStatsCache.empty()) if (obj->mStatsCache.empty())
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id())); context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{ &DynamicStat::setValue, mIndex, prop }] = value; obj->mStatsCache[SelfObject::CachedStat{ &DynamicStat::setValue, mIndex, prop }] = value;
@ -212,10 +180,10 @@ namespace MWLua
class AttributeStat class AttributeStat
{ {
StatObject mObject; ObjectVariant mObject;
int mIndex; int mIndex;
AttributeStat(StatObject object, int index) AttributeStat(ObjectVariant object, int index)
: mObject(std::move(object)) : mObject(std::move(object))
, mIndex(index) , mIndex(index)
{ {
@ -226,8 +194,7 @@ namespace MWLua
sol::object get(const Context& context, std::string_view prop, G getter) const sol::object get(const Context& context, std::string_view prop, G getter) const
{ {
return getValue( return getValue(
context, mObject, &AttributeStat::setValue, mIndex, prop, [this, getter](const MWLua::Object* obj) { context, mObject, &AttributeStat::setValue, mIndex, prop, [this, getter](const MWWorld::Ptr& ptr) {
const auto& ptr = obj->ptr();
return (ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex).*getter)(); return (ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex).*getter)();
}); });
} }
@ -240,16 +207,16 @@ namespace MWLua
return std::max(0.f, base - damage + modifier); // Should match AttributeValue::getModified return std::max(0.f, base - damage + modifier); // Should match AttributeValue::getModified
} }
static std::optional<AttributeStat> create(StatObject object, int index) static std::optional<AttributeStat> create(ObjectVariant object, int index)
{ {
if (!getObject(object)->ptr().getClass().isActor()) if (!object.ptr().getClass().isActor())
return {}; return {};
return AttributeStat{ std::move(object), index }; return AttributeStat{ std::move(object), index };
} }
void cache(const Context& context, std::string_view prop, const sol::object& value) const void cache(const Context& context, std::string_view prop, const sol::object& value) const
{ {
SelfObject* obj = asSelfObject(mObject); SelfObject* obj = mObject.asSelfObject();
if (obj->mStatsCache.empty()) if (obj->mStatsCache.empty())
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id())); context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{ &AttributeStat::setValue, mIndex, prop }] = value; obj->mStatsCache[SelfObject::CachedStat{ &AttributeStat::setValue, mIndex, prop }] = value;
@ -275,10 +242,10 @@ namespace MWLua
class SkillStat class SkillStat
{ {
StatObject mObject; ObjectVariant mObject;
int mIndex; int mIndex;
SkillStat(StatObject object, int index) SkillStat(ObjectVariant object, int index)
: mObject(std::move(object)) : mObject(std::move(object))
, mIndex(index) , mIndex(index)
{ {
@ -304,8 +271,7 @@ namespace MWLua
sol::object get(const Context& context, std::string_view prop, G getter) const sol::object get(const Context& context, std::string_view prop, G getter) const
{ {
return getValue( return getValue(
context, mObject, &SkillStat::setValue, mIndex, prop, [this, getter](const MWLua::Object* obj) { context, mObject, &SkillStat::setValue, mIndex, prop, [this, getter](const MWWorld::Ptr& ptr) {
const auto& ptr = obj->ptr();
return (ptr.getClass().getNpcStats(ptr).getSkill(mIndex).*getter)(); return (ptr.getClass().getNpcStats(ptr).getSkill(mIndex).*getter)();
}); });
} }
@ -321,22 +287,21 @@ namespace MWLua
sol::object getProgress(const Context& context) const sol::object getProgress(const Context& context) const
{ {
return getValue( return getValue(
context, mObject, &SkillStat::setValue, mIndex, "progress", [this](const MWLua::Object* obj) { context, mObject, &SkillStat::setValue, mIndex, "progress", [this](const MWWorld::Ptr& ptr) {
const auto& ptr = obj->ptr();
return getProgress(ptr, mIndex, ptr.getClass().getNpcStats(ptr).getSkill(mIndex)); return getProgress(ptr, mIndex, ptr.getClass().getNpcStats(ptr).getSkill(mIndex));
}); });
} }
static std::optional<SkillStat> create(StatObject object, int index) static std::optional<SkillStat> create(ObjectVariant object, int index)
{ {
if (!getObject(object)->ptr().getClass().isNpc()) if (!object.ptr().getClass().isNpc())
return {}; return {};
return SkillStat{ std::move(object), index }; return SkillStat{ std::move(object), index };
} }
void cache(const Context& context, std::string_view prop, const sol::object& value) const void cache(const Context& context, std::string_view prop, const sol::object& value) const
{ {
SelfObject* obj = asSelfObject(mObject); SelfObject* obj = mObject.asSelfObject();
if (obj->mStatsCache.empty()) if (obj->mStatsCache.empty())
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id())); context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{ &SkillStat::setValue, mIndex, prop }] = value; obj->mStatsCache[SelfObject::CachedStat{ &SkillStat::setValue, mIndex, prop }] = value;

View file

@ -119,8 +119,6 @@ namespace MWLua
}; };
} }
using SelfObject = LocalScripts::SelfObject;
void addActorBindings(sol::table actor, const Context& context) void addActorBindings(sol::table actor, const Context& context)
{ {
actor["STANCE"] actor["STANCE"]