164 lines
4.9 KiB
C#
164 lines
4.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using Microsoft.Extensions.Logging;
|
|
using Questionable.Controller.Steps;
|
|
using Questionable.Controller.Steps.Movement;
|
|
using SmartNav;
|
|
|
|
namespace Questionable.Navigation;
|
|
|
|
internal sealed class SmartNavRouteEnqueuer(NavRouter navRouter, PlayerNavStateBuilder playerNavStateBuilder, RouteInstructionBuilder instructionBuilder, SmartNavTaskMapper taskMapper, SmartNavReRouteService reRouteService, ILogger<SmartNavRouteEnqueuer> logger)
|
|
{
|
|
public void Enqueue(TaskQueue taskQueue, uint territoryId, Vector3 position, float? fallbackStopDistance = null)
|
|
{
|
|
if (!TryEnqueueRouted(taskQueue, territoryId, position))
|
|
{
|
|
taskQueue.Enqueue(new MoveTask((ushort)territoryId, position, null, MountRequired: false, DismountRequired: false, fallbackStopDistance));
|
|
reRouteService.SetDestination(territoryId, position);
|
|
}
|
|
}
|
|
|
|
public bool TryEnqueueRouted(TaskQueue taskQueue, uint territoryId, Vector3 position)
|
|
{
|
|
PlayerNavState playerNavState = playerNavStateBuilder.Build();
|
|
if (playerNavState == null)
|
|
{
|
|
return false;
|
|
}
|
|
RouteResult routeResult = navRouter.FindRoute(playerNavState, territoryId, position);
|
|
if (routeResult.Segments.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
logger.LogDebug("SmartNav routing with {Count} segments", routeResult.Segments.Count);
|
|
foreach (ITask item in taskMapper.MapInstructions(instructionBuilder.Build(routeResult, territoryId)))
|
|
{
|
|
taskQueue.Enqueue(item);
|
|
}
|
|
reRouteService.SetDestination(territoryId, position);
|
|
return true;
|
|
}
|
|
|
|
public bool TryEnqueueToTerritory(TaskQueue taskQueue, uint territoryId, Vector3 position)
|
|
{
|
|
PlayerNavState playerNavState = playerNavStateBuilder.Build();
|
|
if (playerNavState == null)
|
|
{
|
|
return false;
|
|
}
|
|
RouteResult routeResult = navRouter.FindRoute(playerNavState, territoryId, position);
|
|
if (routeResult.Segments.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
List<NavInstruction> list = instructionBuilder.Build(routeResult, territoryId).TakeWhile((NavInstruction x) => !(x is NavInstruction.Move move) || !move.IsFinal).ToList();
|
|
if (list.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
logger.LogDebug("SmartNav routing to territory {TerritoryId} with {Count} segments; leaving final movement to the caller", territoryId, routeResult.Segments.Count);
|
|
foreach (ITask item in taskMapper.MapInstructions(list))
|
|
{
|
|
taskQueue.Enqueue(item);
|
|
}
|
|
reRouteService.SetDestination(territoryId, position);
|
|
return true;
|
|
}
|
|
|
|
public IReadOnlyList<ITask> BuildRoutedTasks(uint territoryId, Vector3 position)
|
|
{
|
|
reRouteService.SetDestination(territoryId, position);
|
|
PlayerNavState playerNavState = playerNavStateBuilder.Build();
|
|
if (playerNavState != null)
|
|
{
|
|
RouteResult routeResult = navRouter.FindRoute(playerNavState, territoryId, position);
|
|
if (routeResult.Segments.Count > 0)
|
|
{
|
|
logger.LogDebug("SmartNav routing with {Count} segments", routeResult.Segments.Count);
|
|
List<ITask> list = new List<ITask>();
|
|
list.AddRange(taskMapper.MapInstructions(instructionBuilder.Build(routeResult, territoryId)));
|
|
return new global::_003C_003Ez__ReadOnlyList<ITask>(list);
|
|
}
|
|
}
|
|
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new MoveTask((ushort)territoryId, position));
|
|
}
|
|
|
|
public bool RouteStartsWithTeleport(uint territoryId, Vector3 position)
|
|
{
|
|
PlayerNavState playerNavState = playerNavStateBuilder.Build();
|
|
if (playerNavState == null)
|
|
{
|
|
return false;
|
|
}
|
|
RouteResult routeResult = navRouter.FindRoute(playerNavState, territoryId, position);
|
|
if (routeResult.Segments.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
foreach (NavInstruction item in instructionBuilder.Build(routeResult, territoryId))
|
|
{
|
|
bool? flag = StartsWithTeleport(item);
|
|
if (flag.HasValue)
|
|
{
|
|
return flag == true;
|
|
}
|
|
}
|
|
return false;
|
|
static bool? StartsWithTeleport(NavInstruction instruction)
|
|
{
|
|
if (instruction is NavInstruction.Teleport)
|
|
{
|
|
return true;
|
|
}
|
|
if (instruction is NavInstruction.UseTeleportTicket)
|
|
{
|
|
return true;
|
|
}
|
|
if (instruction is NavInstruction.Move)
|
|
{
|
|
return false;
|
|
}
|
|
if (instruction is NavInstruction.AethernetHop)
|
|
{
|
|
return false;
|
|
}
|
|
if (instruction is NavInstruction.InteractWarp)
|
|
{
|
|
return false;
|
|
}
|
|
if (instruction is NavInstruction.SubRegionTransport)
|
|
{
|
|
return false;
|
|
}
|
|
if (instruction is NavInstruction.Land)
|
|
{
|
|
return null;
|
|
}
|
|
if (instruction is NavInstruction.Unmount)
|
|
{
|
|
return null;
|
|
}
|
|
if (instruction is NavInstruction.WaitForTerritory)
|
|
{
|
|
return null;
|
|
}
|
|
if (!(instruction is NavInstruction.WaitForNavmesh))
|
|
{
|
|
throw new InvalidOperationException($"Unclassified NavInstruction: {instruction}");
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void ClearDestination()
|
|
{
|
|
reRouteService.ClearDestination();
|
|
}
|
|
|
|
public void SetDestination(uint territoryId, Vector3 position)
|
|
{
|
|
reRouteService.SetDestination(territoryId, position);
|
|
}
|
|
}
|