#include "luabindings.hpp" #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwphysics/raycasting.hpp" #include "luamanagerimp.hpp" #include "worldview.hpp" namespace sol { template <> struct is_automagical : std::false_type {}; } namespace MWLua { sol::table initNearbyPackage(const Context& context) { sol::table api(context.mLua->sol(), sol::create); WorldView* worldView = context.mWorldView; sol::usertype rayResult = context.mLua->sol().new_usertype("RayCastingResult"); rayResult["hit"] = sol::readonly_property([](const MWPhysics::RayCastingResult& r) { return r.mHit; }); rayResult["hitPos"] = sol::readonly_property([](const MWPhysics::RayCastingResult& r) -> sol::optional { if (r.mHit) return r.mHitPos; else return sol::nullopt; }); rayResult["hitNormal"] = sol::readonly_property([](const MWPhysics::RayCastingResult& r) -> sol::optional { if (r.mHit) return r.mHitNormal; else return sol::nullopt; }); rayResult["hitObject"] = sol::readonly_property([worldView](const MWPhysics::RayCastingResult& r) -> sol::optional { if (r.mHitObject.isEmpty()) return sol::nullopt; else return LObject(getId(r.mHitObject), worldView->getObjectRegistry()); }); api["COLLISION_TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ {"World", MWPhysics::CollisionType_World}, {"Door", MWPhysics::CollisionType_Door}, {"Actor", MWPhysics::CollisionType_Actor}, {"HeightMap", MWPhysics::CollisionType_HeightMap}, {"Projectile", MWPhysics::CollisionType_Projectile}, {"Water", MWPhysics::CollisionType_Water}, {"Default", MWPhysics::CollisionType_Default}, {"AnyPhysical", MWPhysics::CollisionType_AnyPhysical}, {"Camera", MWPhysics::CollisionType_CameraOnly}, {"VisualOnly", MWPhysics::CollisionType_VisualOnly}, })); api["castRay"] = [](const osg::Vec3f& from, const osg::Vec3f& to, sol::optional options) { MWWorld::Ptr ignore; int collisionType = MWPhysics::CollisionType_Default; float radius = 0; if (options) { sol::optional ignoreObj = options->get>("ignore"); if (ignoreObj) ignore = ignoreObj->ptr(); collisionType = options->get>("collisionType").value_or(collisionType); radius = options->get>("radius").value_or(0); } const MWPhysics::RayCastingInterface* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting(); if (radius <= 0) return rayCasting->castRay(from, to, ignore, std::vector(), collisionType); else { if (!ignore.isEmpty()) throw std::logic_error("Currently castRay doesn't support `ignore` when radius > 0"); return rayCasting->castSphere(from, to, radius, collisionType); } }; // TODO: async raycasting /*api["asyncCastRay"] = [luaManager = context.mLuaManager]( const Callback& luaCallback, const osg::Vec3f& from, const osg::Vec3f& to, sol::optional options) { std::function callback = luaManager->wrapLuaCallback(luaCallback); MWPhysics::RayCastingInterface* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting(); // Handle options the same way as in `castRay`. // NOTE: `callback` is not thread safe. If MWPhysics works in separate thread, it must put results to a queue // and use this callback from the main thread at the beginning of the next frame processing. rayCasting->asyncCastRay(callback, from, to, ignore, std::vector(), collisionType); };*/ api["castRenderingRay"] = [manager=context.mLuaManager](const osg::Vec3f& from, const osg::Vec3f& to) { if (!manager->isProcessingInputEvents()) { throw std::logic_error("castRenderingRay can be used only in player scripts during processing of input events; " "use asyncCastRenderingRay instead."); } MWPhysics::RayCastingResult res; MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false); return res; }; api["asyncCastRenderingRay"] = [manager=context.mLuaManager](const LuaUtil::Callback& callback, const osg::Vec3f& from, const osg::Vec3f& to) { manager->addAction([manager, callback, from, to] { MWPhysics::RayCastingResult res; MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false); manager->queueCallback(callback, sol::make_object(callback.mFunc.lua_state(), res)); }); }; api["activators"] = LObjectList{worldView->getActivatorsInScene()}; api["actors"] = LObjectList{worldView->getActorsInScene()}; api["containers"] = LObjectList{worldView->getContainersInScene()}; api["doors"] = LObjectList{worldView->getDoorsInScene()}; api["items"] = LObjectList{worldView->getItemsInScene()}; return LuaUtil::makeReadOnly(api); } }