#include "physics/TargetingLineOfSightAdapter.h" #include "physics/World3D.h" #include #include #include #include namespace eve::physics { namespace { template eve::Result failure(eve::DiagnosticCode code, std::string message) { return eve::Result::failure(eve::Diagnostic::error(code, std::move(message))); } } // namespace eve::Result TargetingLineOfSightAdapter::addWorld(World3D* world) { if (!world) return failure(eve::DiagnosticCode::InvalidArgument, "Physics LOS cannot register a null World3D"); if (!world->isValid()) return failure(eve::DiagnosticCode::NotFound, "Physics LOS cannot register an invalid World3D"); for (auto it = worlds_.begin(); it != worlds_.end();) { auto lifetime = it->lifetime.lock(); if (!lifetime) { it = worlds_.erase(it); continue; } if (it->world == world) return eve::Result::success(eve::Status::success(eve::StatusCode::NoOp)); return failure(eve::DiagnosticCode::Conflict, "Physics LOS already has a different active World3D"); } worlds_.push_back({world, world->queryLifetime_}); return eve::Result::success(eve::Status::success(eve::StatusCode::Applied)); } eve::Result TargetingLineOfSightAdapter::removeWorld(World3D* world) { if (!world) return failure(eve::DiagnosticCode::InvalidArgument, "Physics LOS cannot remove a null World3D"); const auto before = worlds_.size(); std::erase_if(worlds_, [world](const RegisteredWorld& entry) { return entry.world == world; }); const auto code = before == worlds_.size() ? eve::StatusCode::NoOp : eve::StatusCode::Applied; return eve::Result::success(eve::Status::success(code)); } eve::Result TargetingLineOfSightAdapter::query(const sensing::TargetLocation& from, const sensing::TargetLocation& to) const { const auto* fromPoint = std::get_if(&from); const auto* toPoint = std::get_if(&to); if (!fromPoint || !toPoint || !fromPoint->isValid() || !toPoint->isValid() || fromPoint->space() != sensing::CoordinateSpace::World3D || toPoint->space() != sensing::CoordinateSpace::World3D) return failure( eve::DiagnosticCode::Unsupported, "Physics LOS supports only two valid World3D points in the same space"); if (!std::isfinite(fromPoint->x()) || !std::isfinite(fromPoint->y()) || !std::isfinite(fromPoint->z()) || !std::isfinite(toPoint->x()) || !std::isfinite(toPoint->y()) || !std::isfinite(toPoint->z())) return failure(eve::DiagnosticCode::InvalidArgument, "Physics LOS points must be finite"); World3D* activeWorld = nullptr; std::shared_ptr activeLifetime; for (const RegisteredWorld& entry : worlds_) { auto lifetime = entry.lifetime.lock(); World3D* world = entry.world; if (!lifetime || !world || !world->isValid()) continue; if (activeWorld) return failure(eve::DiagnosticCode::Conflict, "Physics LOS has more than one valid active World3D"); activeWorld = world; activeLifetime = std::move(lifetime); } if (!activeWorld) return failure(eve::DiagnosticCode::Unsupported, "Physics LOS has no valid active World3D"); activeWorld->rayCast(fromPoint->x(), fromPoint->y(), fromPoint->z(), toPoint->x(), toPoint->y(), toPoint->z()); if (activeWorld->hasRayHit()) return eve::Result::success(sensing::LineOfSightResult{false, std::nullopt}); return eve::Result::success(sensing::LineOfSightResult{true, std::nullopt}); } } // namespace eve::physics