8bool finitePosition(
const std::array<double, 3>&
position) {
9 return std::all_of(
position.begin(),
position.end(), [](
double value) { return std::isfinite(value); });
14 std::unique_ptr<INavigationRequestFactory> requestFactory)
15 : provider_(std::move(provider)), requestFactory_(std::move(requestFactory)) {}
18 std::unique_ptr<INavigationProvider> provider, std::unique_ptr<INavigationRequestFactory> requestFactory) {
19 if (!provider || !requestFactory)
22 "npc_ai.navigation"));
28 for (
const auto& [task, ticket] : active_) {
30 provider_->abandon(ticket);
39 std::string& inOutMemoryJson) {
41 if (active_.contains(taskKey))
43 "navigation task already owns an active ticket", {}, {},
44 "npc_ai.navigation"));
48 !finitePosition(
request.value().destination) || !std::isfinite(
request.value().agentRadius) ||
49 !std::isfinite(
request.value().acceptanceRadius) ||
request.value().agentRadius <= 0.0 ||
52 "navigation request factory returned an invalid request", {}, {},
53 "npc_ai.navigation"));
54 auto ticket = provider_->begin(
request.value());
56 if (!ticket.value().isValid()) {
58 "navigation provider returned an invalid ticket", {}, {},
59 "npc_ai.navigation"));
61 active_.emplace(taskKey, ticket.value());
62 inOutMemoryJson =
"{\"phase\":\"pending\"}";
67 std::string& inOutMemoryJson) {
69 if (
found == active_.end())
71 "navigation task has no active ticket", {}, {},
72 "npc_ai.navigation"));
73 auto progress = provider_->poll(
found->second,
context.simulationTick);
75 if (!finitePosition(progress.
value().desiredVelocity) || !std::isfinite(progress.
value().remainingDistance) ||
76 progress.
value().remainingDistance < 0.0)
78 "navigation provider returned invalid progress", {}, {},
79 "npc_ai.navigation"));
80 switch (progress.
value().phase) {
82 inOutMemoryJson =
"{\"phase\":\"pending\"}";
85 inOutMemoryJson =
"{\"phase\":\"moving\"}";
89 inOutMemoryJson =
"{\"phase\":\"arrived\"}";
93 inOutMemoryJson =
"{\"phase\":\"unreachable\"}";
97 inOutMemoryJson =
"{\"phase\":\"cancelled\"}";
101 "navigation provider returned an unknown phase", {}, {},
102 "npc_ai.navigation"));
106 std::string_view memoryJson)
noexcept {
110 if (
found == active_.end())
return;
111 provider_->abandon(
found->second);
112 active_.erase(
found);
const GltfImportRequest & request
std::array< float, 3 > position
const VegetationPresetContext & context
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
ITaskService adapter for asynchronous move-to requests.
NavigationTaskService(const NavigationTaskService &)=delete
~NavigationTaskService() override
Navigation task service.
void stop(const TaskContext &context, const TaskSpec &spec, StopReason reason, std::string_view memoryJson) noexcept override
Stops .
Result< void > start(const TaskContext &context, const TaskSpec &spec, std::string &inOutMemoryJson) override
Starts .
static Result< std::unique_ptr< NavigationTaskService > > create(std::unique_ptr< INavigationProvider > provider, std::unique_ptr< INavigationRequestFactory > requestFactory)
Validates and transfers both required owners into a task service.
Result< TaskStatus > tick(const TaskContext &context, const TaskSpec &spec, std::string &inOutMemoryJson) override
Tick.
StopReason
StopReason public API.