mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-19 12:39:42 +00:00
Add error checking in MWLua::Action
This commit is contained in:
parent
5c5c71778a
commit
c7d6620c35
7 changed files with 63 additions and 20 deletions
|
@ -3,6 +3,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
#include <components/lua/luastate.hpp>
|
||||||
|
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
@ -12,14 +13,34 @@
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
Action::Action(LuaUtil::LuaState* state) {}
|
||||||
|
#else
|
||||||
|
Action::Action(LuaUtil::LuaState* state) : mCallerTraceback(state->debugTraceback()) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Action::safeApply(WorldView& w) const
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
apply(w);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Error in " << this->toString() << ": " << e.what();
|
||||||
|
#ifdef NDEBUG
|
||||||
|
Log(Debug::Error) << "Traceback is available only in debug builds";
|
||||||
|
#else
|
||||||
|
Log(Debug::Error) << "Caller " << mCallerTraceback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TeleportAction::apply(WorldView& worldView) const
|
void TeleportAction::apply(WorldView& worldView) const
|
||||||
{
|
{
|
||||||
MWWorld::CellStore* cell = worldView.findCell(mCell, mPos);
|
MWWorld::CellStore* cell = worldView.findCell(mCell, mPos);
|
||||||
if (!cell)
|
if (!cell)
|
||||||
{
|
throw std::runtime_error(std::string("cell not found: '") + mCell + "'");
|
||||||
Log(Debug::Error) << "LuaManager::applyTeleport -> cell not found: '" << mCell << "'";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
MWWorld::Ptr obj = worldView.getObjectRegistry()->getPtr(mObject, false);
|
MWWorld::Ptr obj = worldView.getObjectRegistry()->getPtr(mObject, false);
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
#include "worldview.hpp"
|
#include "worldview.hpp"
|
||||||
|
|
||||||
|
namespace LuaUtil
|
||||||
|
{
|
||||||
|
class LuaState;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -16,17 +21,27 @@ namespace MWLua
|
||||||
class Action
|
class Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Action(LuaUtil::LuaState* state);
|
||||||
virtual ~Action() {}
|
virtual ~Action() {}
|
||||||
|
|
||||||
|
void safeApply(WorldView&) const;
|
||||||
virtual void apply(WorldView&) const = 0;
|
virtual void apply(WorldView&) const = 0;
|
||||||
|
virtual std::string toString() const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::string mCallerTraceback;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class TeleportAction final : public Action
|
class TeleportAction final : public Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TeleportAction(ObjectId object, std::string cell, const osg::Vec3f& pos, const osg::Vec3f& rot)
|
TeleportAction(LuaUtil::LuaState* state, ObjectId object, std::string cell, const osg::Vec3f& pos, const osg::Vec3f& rot)
|
||||||
: mObject(object), mCell(std::move(cell)), mPos(pos), mRot(rot) {}
|
: Action(state), mObject(object), mCell(std::move(cell)), mPos(pos), mRot(rot) {}
|
||||||
|
|
||||||
void apply(WorldView&) const override;
|
void apply(WorldView&) const override;
|
||||||
|
std::string toString() const override { return "TeleportAction"; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ObjectId mObject;
|
ObjectId mObject;
|
||||||
|
@ -41,9 +56,11 @@ namespace MWLua
|
||||||
using Item = std::variant<std::string, ObjectId>; // recordId or ObjectId
|
using Item = std::variant<std::string, ObjectId>; // recordId or ObjectId
|
||||||
using Equipment = std::map<int, Item>; // slot to item
|
using Equipment = std::map<int, Item>; // slot to item
|
||||||
|
|
||||||
SetEquipmentAction(ObjectId actor, Equipment equipment) : mActor(actor), mEquipment(std::move(equipment)) {}
|
SetEquipmentAction(LuaUtil::LuaState* state, ObjectId actor, Equipment equipment)
|
||||||
|
: Action(state), mActor(actor), mEquipment(std::move(equipment)) {}
|
||||||
|
|
||||||
void apply(WorldView&) const override;
|
void apply(WorldView&) const override;
|
||||||
|
std::string toString() const override { return "SetEquipmentAction"; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ObjectId mActor;
|
ObjectId mActor;
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace MWLua
|
||||||
selfAPI["controls"] = sol::readonly_property([](SelfObject& self) { return &self.mControls; });
|
selfAPI["controls"] = sol::readonly_property([](SelfObject& self) { return &self.mControls; });
|
||||||
selfAPI["isActive"] = [](SelfObject& self) { return &self.mIsActive; };
|
selfAPI["isActive"] = [](SelfObject& self) { return &self.mIsActive; };
|
||||||
selfAPI["enableAI"] = [](SelfObject& self, bool v) { self.mControls.mDisableAI = !v; };
|
selfAPI["enableAI"] = [](SelfObject& self, bool v) { self.mControls.mDisableAI = !v; };
|
||||||
selfAPI["setEquipment"] = [manager=context.mLuaManager](const SelfObject& obj, sol::table equipment)
|
selfAPI["setEquipment"] = [context](const SelfObject& obj, sol::table equipment)
|
||||||
{
|
{
|
||||||
if (!obj.ptr().getClass().hasInventoryStore(obj.ptr()))
|
if (!obj.ptr().getClass().hasInventoryStore(obj.ptr()))
|
||||||
{
|
{
|
||||||
|
@ -56,7 +56,7 @@ namespace MWLua
|
||||||
else
|
else
|
||||||
eqp[slot] = value.as<std::string>();
|
eqp[slot] = value.as<std::string>();
|
||||||
}
|
}
|
||||||
manager->addAction(std::make_unique<SetEquipmentAction>(obj.id(), std::move(eqp)));
|
context.mLuaManager->addAction(std::make_unique<SetEquipmentAction>(context.mLua, obj.id(), std::move(eqp)));
|
||||||
};
|
};
|
||||||
selfAPI["getCombatTarget"] = [worldView=context.mWorldView](SelfObject& self) -> sol::optional<LObject>
|
selfAPI["getCombatTarget"] = [worldView=context.mWorldView](SelfObject& self) -> sol::optional<LObject>
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,8 +28,7 @@ namespace MWLua
|
||||||
api["API_REVISION"] = 9;
|
api["API_REVISION"] = 9;
|
||||||
api["quit"] = [lua]()
|
api["quit"] = [lua]()
|
||||||
{
|
{
|
||||||
std::string traceback = lua->sol()["debug"]["traceback"]().get<std::string>();
|
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();
|
||||||
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << traceback;
|
|
||||||
MWBase::Environment::get().getStateManager()->requestQuit();
|
MWBase::Environment::get().getStateManager()->requestQuit();
|
||||||
};
|
};
|
||||||
api["sendGlobalEvent"] = [context](std::string eventName, const sol::object& eventData)
|
api["sendGlobalEvent"] = [context](std::string eventName, const sol::object& eventData)
|
||||||
|
|
|
@ -188,11 +188,11 @@ namespace MWLua
|
||||||
mUIMessages.clear();
|
mUIMessages.clear();
|
||||||
|
|
||||||
for (std::unique_ptr<Action>& action : mActionQueue)
|
for (std::unique_ptr<Action>& action : mActionQueue)
|
||||||
action->apply(mWorldView);
|
action->safeApply(mWorldView);
|
||||||
mActionQueue.clear();
|
mActionQueue.clear();
|
||||||
|
|
||||||
if (mTeleportPlayerAction)
|
if (mTeleportPlayerAction)
|
||||||
mTeleportPlayerAction->apply(mWorldView);
|
mTeleportPlayerAction->safeApply(mWorldView);
|
||||||
mTeleportPlayerAction.reset();
|
mTeleportPlayerAction.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -179,16 +179,16 @@ namespace MWLua
|
||||||
localScripts->removeScript(*scriptId);
|
localScripts->removeScript(*scriptId);
|
||||||
};
|
};
|
||||||
|
|
||||||
objectT["teleport"] = [luaManager=context.mLuaManager](const GObject& object, std::string_view cell,
|
objectT["teleport"] = [context](const GObject& object, std::string_view cell,
|
||||||
const osg::Vec3f& pos, const sol::optional<osg::Vec3f>& optRot)
|
const osg::Vec3f& pos, const sol::optional<osg::Vec3f>& optRot)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = object.ptr();
|
MWWorld::Ptr ptr = object.ptr();
|
||||||
osg::Vec3f rot = optRot ? *optRot : ptr.getRefData().getPosition().asRotationVec3();
|
osg::Vec3f rot = optRot ? *optRot : ptr.getRefData().getPosition().asRotationVec3();
|
||||||
auto action = std::make_unique<TeleportAction>(object.id(), std::string(cell), pos, rot);
|
auto action = std::make_unique<TeleportAction>(context.mLua, object.id(), std::string(cell), pos, rot);
|
||||||
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||||
luaManager->addTeleportPlayerAction(std::move(action));
|
context.mLuaManager->addTeleportPlayerAction(std::move(action));
|
||||||
else
|
else
|
||||||
luaManager->addAction(std::move(action));
|
context.mLuaManager->addAction(std::move(action));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -352,7 +352,7 @@ namespace MWLua
|
||||||
|
|
||||||
if constexpr (std::is_same_v<ObjectT, GObject>)
|
if constexpr (std::is_same_v<ObjectT, GObject>)
|
||||||
{ // Only for global scripts
|
{ // Only for global scripts
|
||||||
objectT["setEquipment"] = [manager=context.mLuaManager](const GObject& obj, sol::table equipment)
|
objectT["setEquipment"] = [context](const GObject& obj, sol::table equipment)
|
||||||
{
|
{
|
||||||
if (!obj.ptr().getClass().hasInventoryStore(obj.ptr()))
|
if (!obj.ptr().getClass().hasInventoryStore(obj.ptr()))
|
||||||
{
|
{
|
||||||
|
@ -360,7 +360,8 @@ namespace MWLua
|
||||||
throw std::runtime_error(ptrToString(obj.ptr()) + " has no equipment slots");
|
throw std::runtime_error(ptrToString(obj.ptr()) + " has no equipment slots");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
manager->addAction(std::make_unique<SetEquipmentAction>(obj.id(), parseEquipmentTable(equipment)));
|
context.mLuaManager->addAction(std::make_unique<SetEquipmentAction>(
|
||||||
|
context.mLua, obj.id(), parseEquipmentTable(equipment)));
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
@ -35,6 +35,11 @@ namespace LuaUtil
|
||||||
// Returns underlying sol::state.
|
// Returns underlying sol::state.
|
||||||
sol::state& sol() { return mLua; }
|
sol::state& sol() { return mLua; }
|
||||||
|
|
||||||
|
// Can be used by a C++ function that is called from Lua to get the Lua traceback.
|
||||||
|
// Makes no sense if called not from Lua code.
|
||||||
|
// Note: It is a slow function, should be used for debug purposes only.
|
||||||
|
std::string debugTraceback() { return mLua["debug"]["traceback"]().get<std::string>(); }
|
||||||
|
|
||||||
// A shortcut to create a new Lua table.
|
// A shortcut to create a new Lua table.
|
||||||
sol::table newTable() { return sol::table(mLua, sol::create); }
|
sol::table newTable() { return sol::table(mLua, sol::create); }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue