|
|
|
@ -1,6 +1,9 @@
|
|
|
|
|
#include "luabindings.hpp"
|
|
|
|
|
|
|
|
|
|
#include <components/lua/luastate.hpp>
|
|
|
|
|
#include <components/detournavigator/navigator.hpp>
|
|
|
|
|
#include <components/detournavigator/navigatorutils.hpp>
|
|
|
|
|
#include <components/settings/settings.hpp>
|
|
|
|
|
|
|
|
|
|
#include "../mwbase/environment.hpp"
|
|
|
|
|
#include "../mwbase/world.hpp"
|
|
|
|
@ -122,6 +125,144 @@ namespace MWLua
|
|
|
|
|
api["containers"] = LObjectList{worldView->getContainersInScene()};
|
|
|
|
|
api["doors"] = LObjectList{worldView->getDoorsInScene()};
|
|
|
|
|
api["items"] = LObjectList{worldView->getItemsInScene()};
|
|
|
|
|
|
|
|
|
|
api["NAVIGATOR_FLAGS"] = LuaUtil::makeStrictReadOnly(
|
|
|
|
|
context.mLua->tableFromPairs<std::string_view, DetourNavigator::Flag>({
|
|
|
|
|
{"Walk", DetourNavigator::Flag_walk},
|
|
|
|
|
{"Swim", DetourNavigator::Flag_swim},
|
|
|
|
|
{"OpenDoor", DetourNavigator::Flag_openDoor},
|
|
|
|
|
{"UsePathgrid", DetourNavigator::Flag_usePathgrid},
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
api["COLLISION_SHAPE_TYPE"] = LuaUtil::makeStrictReadOnly(
|
|
|
|
|
context.mLua->tableFromPairs<std::string_view, DetourNavigator::CollisionShapeType>({
|
|
|
|
|
{"Aabb", DetourNavigator::CollisionShapeType::Aabb},
|
|
|
|
|
{"RotatingBox", DetourNavigator::CollisionShapeType::RotatingBox},
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
api["FIND_PATH_STATUS"] = LuaUtil::makeStrictReadOnly(
|
|
|
|
|
context.mLua->tableFromPairs<std::string_view, DetourNavigator::Status>({
|
|
|
|
|
{"Success", DetourNavigator::Status::Success},
|
|
|
|
|
{"PartialPath", DetourNavigator::Status::PartialPath},
|
|
|
|
|
{"NavMeshNotFound", DetourNavigator::Status::NavMeshNotFound},
|
|
|
|
|
{"StartPolygonNotFound", DetourNavigator::Status::StartPolygonNotFound},
|
|
|
|
|
{"EndPolygonNotFound", DetourNavigator::Status::EndPolygonNotFound},
|
|
|
|
|
{"MoveAlongSurfaceFailed", DetourNavigator::Status::MoveAlongSurfaceFailed},
|
|
|
|
|
{"FindPathOverPolygonsFailed", DetourNavigator::Status::FindPathOverPolygonsFailed},
|
|
|
|
|
{"GetPolyHeightFailed", DetourNavigator::Status::GetPolyHeightFailed},
|
|
|
|
|
{"InitNavMeshQueryFailed", DetourNavigator::Status::InitNavMeshQueryFailed},
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
static const DetourNavigator::AgentBounds defaultAgentBounds {
|
|
|
|
|
DetourNavigator::defaultCollisionShapeType,
|
|
|
|
|
Settings::Manager::getVector3("default actor pathfind half extents", "Game"),
|
|
|
|
|
};
|
|
|
|
|
static const float defaultStepSize = 2 * std::max(defaultAgentBounds.mHalfExtents.x(), defaultAgentBounds.mHalfExtents.y());
|
|
|
|
|
static constexpr DetourNavigator::Flags defaultIncludeFlags = DetourNavigator::Flag_walk
|
|
|
|
|
| DetourNavigator::Flag_swim
|
|
|
|
|
| DetourNavigator::Flag_openDoor
|
|
|
|
|
| DetourNavigator::Flag_usePathgrid;
|
|
|
|
|
|
|
|
|
|
api["findPath"] = [] (const osg::Vec3f& source, const osg::Vec3f& destination,
|
|
|
|
|
const sol::optional<sol::table>& options)
|
|
|
|
|
{
|
|
|
|
|
DetourNavigator::AgentBounds agentBounds = defaultAgentBounds;
|
|
|
|
|
float stepSize = defaultStepSize;
|
|
|
|
|
DetourNavigator::Flags includeFlags = defaultIncludeFlags;
|
|
|
|
|
DetourNavigator::AreaCosts areaCosts {};
|
|
|
|
|
float destinationTolerance = 1;
|
|
|
|
|
|
|
|
|
|
if (options.has_value())
|
|
|
|
|
{
|
|
|
|
|
if (const auto& t = options->get<sol::optional<sol::table>>("agentBounds"))
|
|
|
|
|
{
|
|
|
|
|
if (const auto& v = t->get<sol::optional<DetourNavigator::CollisionShapeType>>("shapeType"))
|
|
|
|
|
agentBounds.mShapeType = *v;
|
|
|
|
|
if (const auto& v = t->get<sol::optional<osg::Vec3f>>("halfExtents"))
|
|
|
|
|
{
|
|
|
|
|
agentBounds.mHalfExtents = *v;
|
|
|
|
|
stepSize = 2 * std::max(v->x(), v->y());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (const auto& v = options->get<sol::optional<float>>("stepSize"))
|
|
|
|
|
stepSize = *v;
|
|
|
|
|
if (const auto& v = options->get<sol::optional<DetourNavigator::Flags>>("includeFlags"))
|
|
|
|
|
includeFlags = *v;
|
|
|
|
|
if (const auto& t = options->get<sol::optional<sol::table>>("areaCosts"))
|
|
|
|
|
{
|
|
|
|
|
if (const auto& v = t->get<sol::optional<float>>("water"))
|
|
|
|
|
areaCosts.mWater = *v;
|
|
|
|
|
if (const auto& v = t->get<sol::optional<float>>("door"))
|
|
|
|
|
areaCosts.mDoor = *v;
|
|
|
|
|
if (const auto& v = t->get<sol::optional<float>>("pathgrid"))
|
|
|
|
|
areaCosts.mPathgrid = *v;
|
|
|
|
|
if (const auto& v = t->get<sol::optional<float>>("ground"))
|
|
|
|
|
areaCosts.mGround = *v;
|
|
|
|
|
}
|
|
|
|
|
if (const auto& v = options->get<sol::optional<float>>("destinationTolerance"))
|
|
|
|
|
destinationTolerance = *v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<osg::Vec3f> result;
|
|
|
|
|
|
|
|
|
|
const DetourNavigator::Status status = DetourNavigator::findPath(
|
|
|
|
|
*MWBase::Environment::get().getWorld()->getNavigator(), agentBounds, stepSize, source,
|
|
|
|
|
destination, includeFlags, areaCosts, destinationTolerance, std::back_inserter(result));
|
|
|
|
|
|
|
|
|
|
return std::make_tuple(status, std::move(result));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
api["findRandomPointAroundCircle"] = [] (const osg::Vec3f& position, float maxRadius,
|
|
|
|
|
const sol::optional<sol::table>& options)
|
|
|
|
|
{
|
|
|
|
|
DetourNavigator::AgentBounds agentBounds = defaultAgentBounds;
|
|
|
|
|
DetourNavigator::Flags includeFlags = defaultIncludeFlags;
|
|
|
|
|
|
|
|
|
|
if (options.has_value())
|
|
|
|
|
{
|
|
|
|
|
if (const auto& t = options->get<sol::optional<sol::table>>("agentBounds"))
|
|
|
|
|
{
|
|
|
|
|
if (const auto& v = t->get<sol::optional<DetourNavigator::CollisionShapeType>>("shapeType"))
|
|
|
|
|
agentBounds.mShapeType = *v;
|
|
|
|
|
if (const auto& v = t->get<sol::optional<osg::Vec3f>>("halfExtents"))
|
|
|
|
|
agentBounds.mHalfExtents = *v;
|
|
|
|
|
}
|
|
|
|
|
if (const auto& v = options->get<sol::optional<DetourNavigator::Flags>>("includeFlags"))
|
|
|
|
|
includeFlags = *v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr auto getRandom = []
|
|
|
|
|
{
|
|
|
|
|
return Misc::Rng::rollProbability(MWBase::Environment::get().getWorld()->getPrng());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return DetourNavigator::findRandomPointAroundCircle(*MWBase::Environment::get().getWorld()->getNavigator(),
|
|
|
|
|
agentBounds, position, maxRadius, includeFlags, getRandom);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
api["castNavigationRay"] = [] (const osg::Vec3f& from, const osg::Vec3f& to,
|
|
|
|
|
const sol::optional<sol::table>& options)
|
|
|
|
|
{
|
|
|
|
|
DetourNavigator::AgentBounds agentBounds = defaultAgentBounds;
|
|
|
|
|
DetourNavigator::Flags includeFlags = defaultIncludeFlags;
|
|
|
|
|
|
|
|
|
|
if (options.has_value())
|
|
|
|
|
{
|
|
|
|
|
if (const auto& t = options->get<sol::optional<sol::table>>("agentBounds"))
|
|
|
|
|
{
|
|
|
|
|
if (const auto& v = t->get<sol::optional<DetourNavigator::CollisionShapeType>>("shapeType"))
|
|
|
|
|
agentBounds.mShapeType = *v;
|
|
|
|
|
if (const auto& v = t->get<sol::optional<osg::Vec3f>>("halfExtents"))
|
|
|
|
|
agentBounds.mHalfExtents = *v;
|
|
|
|
|
}
|
|
|
|
|
if (const auto& v = options->get<sol::optional<DetourNavigator::Flags>>("includeFlags"))
|
|
|
|
|
includeFlags = *v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DetourNavigator::raycast(*MWBase::Environment::get().getWorld()->getNavigator(),
|
|
|
|
|
agentBounds, from, to, includeFlags);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return LuaUtil::makeReadOnly(api);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|