From 1947e3cd7524e9fd0826f4e429b7ca4df6d942cf Mon Sep 17 00:00:00 2001 From: MaxYari Date: Wed, 5 Mar 2025 09:38:59 +0100 Subject: [PATCH 1/5] WIP --- apps/openmw/mwlua/types/actor.cpp | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index 413a656e90..75e1f86bbf 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include #include @@ -170,6 +172,29 @@ 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; + const osg::Group* parentNodeGroup = parentNode->asGroup(); + if (!parentNodeGroup) + return; + + 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]); + } + + findBoneWorldTransform(child, boneName); + } + } + void addActorBindings(sol::table actor, const Context& context) { sol::state_view lua = context.sol(); @@ -195,7 +220,17 @@ namespace MWLua { "CarriedRight", MWWorld::InventoryStore::Slot_CarriedRight }, { "CarriedLeft", MWWorld::InventoryStore::Slot_CarriedLeft }, { "Ammunition", MWWorld::InventoryStore::Slot_Ammunition } })); + actor["getBonePosition"] = [](const SelfObject& self, std::string_view boneName) { + const MWWorld::Class& cls = self.ptr().getClass(); + if (!cls.isActor()) + throw std::runtime_error("Actor expected"); + std::optional boneTransform + = findBoneWorldTransform(self.ptr().getRefData().getBaseNode()->asGroup(), boneName); + return boneTransform; + // return o.ptr().getRefData().getPosition().asVec3(); + // return Misc::Convert::makeOsgQuat(pos.rot); + }; actor["getStance"] = [](const Object& o) { const MWWorld::Class& cls = o.ptr().getClass(); if (cls.isActor()) From 2c0c629795f95fbec46088d17081600aa84b019e Mon Sep 17 00:00:00 2001 From: MaxYari Date: Wed, 5 Mar 2025 09:48:21 +0100 Subject: [PATCH 2/5] lua bindings almost done --- apps/openmw/mwlua/types/actor.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index 75e1f86bbf..82c3b085b9 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "apps/openmw/mwbase/environment.hpp" @@ -226,9 +227,25 @@ namespace MWLua throw std::runtime_error("Actor expected"); std::optional boneTransform - = findBoneWorldTransform(self.ptr().getRefData().getBaseNode()->asGroup(), boneName); - return boneTransform; - // return o.ptr().getRefData().getPosition().asVec3(); + = findBoneWorldTransform(self.ptr().getRefData().getBaseNode(), boneName); + + if (!boneTransform.has_value()) + return sol::nil; + + return boneTransform.value().getTrans(); + }; + actor["getBoneRotation"] = [](const SelfObject& self, std::string_view boneName) { + const MWWorld::Class& cls = self.ptr().getClass(); + if (!cls.isActor()) + throw std::runtime_error("Actor expected"); + + std::optional boneTransform + = findBoneWorldTransform(self.ptr().getRefData().getBaseNode(), boneName); + + if (!boneTransform.has_value()) + return sol::nil; + + return boneTransform.value().getRotate(); // return Misc::Convert::makeOsgQuat(pos.rot); }; actor["getStance"] = [](const Object& o) { From 4b043386c3f5f6c9bf1d23986f6c53e45c24e471 Mon Sep 17 00:00:00 2001 From: MaxYari Date: Wed, 5 Mar 2025 10:23:40 +0100 Subject: [PATCH 3/5] Seems to be working --- apps/openmw/mwlua/types/actor.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index 82c3b085b9..98a846559e 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -177,14 +177,14 @@ namespace MWLua const osg::ref_ptr parentNode, const std::string_view boneName) { if (!parentNode) - return; - const osg::Group* parentNodeGroup = parentNode->asGroup(); + return std::nullopt; + osg::Group* parentNodeGroup = parentNode->asGroup(); if (!parentNodeGroup) - return; + return std::nullopt; for (unsigned int i = 0; i < parentNodeGroup->getNumChildren(); ++i) { - osg::ref_ptr child = parentNodeGroup->getChild(i); + osg::ref_ptr child = parentNodeGroup->getChild(i); // asMatrixTransform will break if its not a bone if (child->getName() == boneName) @@ -192,8 +192,10 @@ namespace MWLua return osg::computeLocalToWorld(child->getParentalNodePaths()[0]); } - findBoneWorldTransform(child, boneName); + return findBoneWorldTransform(child, boneName); } + + return std::nullopt; } void addActorBindings(sol::table actor, const Context& context) @@ -221,7 +223,7 @@ namespace MWLua { "CarriedRight", MWWorld::InventoryStore::Slot_CarriedRight }, { "CarriedLeft", MWWorld::InventoryStore::Slot_CarriedLeft }, { "Ammunition", MWWorld::InventoryStore::Slot_Ammunition } })); - actor["getBonePosition"] = [](const SelfObject& self, std::string_view boneName) { + actor["getBonePosition"] = [](const SelfObject& self, std::string_view boneName) -> sol::optional { const MWWorld::Class& cls = self.ptr().getClass(); if (!cls.isActor()) throw std::runtime_error("Actor expected"); @@ -230,11 +232,11 @@ namespace MWLua = findBoneWorldTransform(self.ptr().getRefData().getBaseNode(), boneName); if (!boneTransform.has_value()) - return sol::nil; + return sol::nullopt; return boneTransform.value().getTrans(); }; - actor["getBoneRotation"] = [](const SelfObject& self, std::string_view boneName) { + actor["getBoneRotation"] = [](const SelfObject& self, std::string_view boneName) -> sol::optional { const MWWorld::Class& cls = self.ptr().getClass(); if (!cls.isActor()) throw std::runtime_error("Actor expected"); @@ -243,7 +245,7 @@ namespace MWLua = findBoneWorldTransform(self.ptr().getRefData().getBaseNode(), boneName); if (!boneTransform.has_value()) - return sol::nil; + return sol::nullopt; return boneTransform.value().getRotate(); // return Misc::Convert::makeOsgQuat(pos.rot); From 5d5ad0c832ba39dab5f96d7b10a693c49b04f4eb Mon Sep 17 00:00:00 2001 From: MaxYari Date: Fri, 7 Mar 2025 21:09:16 +0100 Subject: [PATCH 4/5] Changed to global for testing. Since it a getter - probably should change to regular object. --- apps/openmw/mwlua/types/actor.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index 98a846559e..1a89d64dcf 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -223,26 +223,27 @@ namespace MWLua { "CarriedRight", MWWorld::InventoryStore::Slot_CarriedRight }, { "CarriedLeft", MWWorld::InventoryStore::Slot_CarriedLeft }, { "Ammunition", MWWorld::InventoryStore::Slot_Ammunition } })); - actor["getBonePosition"] = [](const SelfObject& self, std::string_view boneName) -> sol::optional { - const MWWorld::Class& cls = self.ptr().getClass(); - if (!cls.isActor()) - throw std::runtime_error("Actor expected"); + actor["getBonePosition"] = [](const GObject& o, std::string_view boneName) -> sol::optional { + const MWWorld::Class& cls = o.ptr().getClass(); + // Need to accept self OR a global object + /*if (!cls.isActor()) + throw std::runtime_error("Actor expected");*/ std::optional boneTransform - = findBoneWorldTransform(self.ptr().getRefData().getBaseNode(), boneName); + = findBoneWorldTransform(o.ptr().getRefData().getBaseNode(), boneName); if (!boneTransform.has_value()) return sol::nullopt; - return boneTransform.value().getTrans(); + return static_cast(boneTransform.value().getTrans()); }; - actor["getBoneRotation"] = [](const SelfObject& self, std::string_view boneName) -> sol::optional { - const MWWorld::Class& cls = self.ptr().getClass(); + actor["getBoneRotation"] = [](const GObject& 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(self.ptr().getRefData().getBaseNode(), boneName); + = findBoneWorldTransform(o.ptr().getRefData().getBaseNode(), boneName); if (!boneTransform.has_value()) return sol::nullopt; From 7c5d60837b8ff1c111cf357dbdc007c664a4c270 Mon Sep 17 00:00:00 2001 From: MaxYari Date: Sun, 9 Mar 2025 19:09:11 +0100 Subject: [PATCH 5/5] Can be used from any scripts --- apps/openmw/mwlua/types/actor.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index 1a89d64dcf..276abf01ad 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -223,11 +223,10 @@ namespace MWLua { "CarriedRight", MWWorld::InventoryStore::Slot_CarriedRight }, { "CarriedLeft", MWWorld::InventoryStore::Slot_CarriedLeft }, { "Ammunition", MWWorld::InventoryStore::Slot_Ammunition } })); - actor["getBonePosition"] = [](const GObject& o, std::string_view boneName) -> sol::optional { + actor["getBonePosition"] = [](const Object& o, std::string_view boneName) -> sol::optional { const MWWorld::Class& cls = o.ptr().getClass(); - // Need to accept self OR a global object - /*if (!cls.isActor()) - throw std::runtime_error("Actor expected");*/ + if (!cls.isActor()) + throw std::runtime_error("Actor expected"); std::optional boneTransform = findBoneWorldTransform(o.ptr().getRefData().getBaseNode(), boneName); @@ -237,7 +236,7 @@ namespace MWLua return static_cast(boneTransform.value().getTrans()); }; - actor["getBoneRotation"] = [](const GObject& o, std::string_view boneName) -> sol::optional { + 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");