diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index 839f57e621..ae42224839 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -2,8 +2,11 @@ #include +#include + #include #include +#include #include #include "apps/openmw/mwbase/environment.hpp" @@ -170,6 +173,31 @@ namespace MWLua MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(*it); } + static std::optional findBoneWorldTransform( + const osg::ref_ptr parentNode, const std::string_view boneName) + { + if (!parentNode) + return std::nullopt; + osg::Group* parentNodeGroup = parentNode->asGroup(); + if (!parentNodeGroup) + return std::nullopt; + + for (unsigned int i = 0; i < parentNodeGroup->getNumChildren(); ++i) + { + osg::ref_ptr child = parentNodeGroup->getChild(i); + + // asMatrixTransform will break if its not a bone + if (child->getName() == boneName) + { + return osg::computeLocalToWorld(child->getParentalNodePaths()[0]); + } + + return findBoneWorldTransform(child, boneName); + } + + return std::nullopt; + } + void addActorBindings(sol::table actor, const Context& context) { sol::state_view lua = context.sol(); @@ -195,7 +223,33 @@ namespace MWLua { "CarriedRight", MWWorld::InventoryStore::Slot_CarriedRight }, { "CarriedLeft", MWWorld::InventoryStore::Slot_CarriedLeft }, { "Ammunition", MWWorld::InventoryStore::Slot_Ammunition } })); + actor["getBonePosition"] = [](const Object& o, std::string_view boneName) -> sol::optional { + const MWWorld::Class& cls = o.ptr().getClass(); + if (!cls.isActor()) + throw std::runtime_error("Actor expected"); + std::optional boneTransform + = findBoneWorldTransform(o.ptr().getRefData().getBaseNode(), boneName); + + if (!boneTransform.has_value()) + return sol::nullopt; + + return static_cast(boneTransform.value().getTrans()); + }; + actor["getBoneRotation"] = [](const Object& o, std::string_view boneName) -> sol::optional { + const MWWorld::Class& cls = o.ptr().getClass(); + if (!cls.isActor()) + throw std::runtime_error("Actor expected"); + + std::optional boneTransform + = findBoneWorldTransform(o.ptr().getRefData().getBaseNode(), boneName); + + if (!boneTransform.has_value()) + return sol::nullopt; + + return boneTransform.value().getRotate(); + // return Misc::Convert::makeOsgQuat(pos.rot); + }; actor["getStance"] = [](const Object& o) { const MWWorld::Class& cls = o.ptr().getClass(); if (cls.isActor())