using System.Collections.Generic; using System.Numerics; using System.Threading; using System.Threading.Tasks; using Dalamud.Plugin; using Dalamud.Plugin.Ipc; using Dalamud.Plugin.Ipc.Exceptions; using Microsoft.Extensions.Logging; namespace Questionable.External; internal sealed class NavmeshIpc { private readonly IDalamudPluginInterface _pluginInterface; private readonly ILogger _logger; private readonly ICallGateSubscriber _isNavReady; private readonly ICallGateSubscriber>> _navPathfind; private readonly ICallGateSubscriber _navPathfindInProgress; private readonly ICallGateSubscriber _navNumQueuedRequests; private readonly ICallGateSubscriber, bool, object> _pathMoveTo; private readonly ICallGateSubscriber _pathStop; private readonly ICallGateSubscriber _pathIsRunning; private readonly ICallGateSubscriber> _pathListWaypoints; private readonly ICallGateSubscriber _pathSetTolerance; private readonly ICallGateSubscriber _queryPointOnFloor; private readonly ICallGateSubscriber _queryNearestPoint; private readonly ICallGateSubscriber _buildProgress; public bool IsReady { get { try { return _isNavReady.InvokeFunc(); } catch (IpcError) { return false; } } } public bool IsPathRunning { get { try { return _pathIsRunning.InvokeFunc(); } catch (IpcError) { return false; } } } public bool IsPathfindInProgress { get { try { return _navPathfindInProgress.InvokeFunc(); } catch (IpcError) { return false; } } } public int NumQueuedPathfindRequests { get { try { return _navNumQueuedRequests.InvokeFunc(); } catch (IpcError) { return 0; } } } public NavmeshIpc(IDalamudPluginInterface pluginInterface, ILogger logger) { _pluginInterface = pluginInterface; _logger = logger; _isNavReady = pluginInterface.GetIpcSubscriber("vnavmesh.Nav.IsReady"); _navPathfind = pluginInterface.GetIpcSubscriber>>("vnavmesh.Nav.PathfindCancelable"); _navPathfindInProgress = pluginInterface.GetIpcSubscriber("vnavmesh.Nav.PathfindInProgress"); _navNumQueuedRequests = pluginInterface.GetIpcSubscriber("vnavmesh.Nav.PathfindNumQueued"); _pathMoveTo = pluginInterface.GetIpcSubscriber, bool, object>("vnavmesh.Path.MoveTo"); _pathStop = pluginInterface.GetIpcSubscriber("vnavmesh.Path.Stop"); _pathIsRunning = pluginInterface.GetIpcSubscriber("vnavmesh.Path.IsRunning"); _pathListWaypoints = pluginInterface.GetIpcSubscriber>("vnavmesh.Path.ListWaypoints"); _pathSetTolerance = pluginInterface.GetIpcSubscriber("vnavmesh.Path.SetTolerance"); _queryPointOnFloor = pluginInterface.GetIpcSubscriber("vnavmesh.Query.Mesh.PointOnFloor"); _queryNearestPoint = pluginInterface.GetIpcSubscriber("vnavmesh.Query.Mesh.NearestPoint"); _buildProgress = pluginInterface.GetIpcSubscriber("vnavmesh.Nav.BuildProgress"); } public void Stop() { try { _pathStop.InvokeAction(); } catch (IpcError exception) { _logger.LogWarning(exception, "Could not stop navigating via navmesh"); } } public Task> Pathfind(Vector3 localPlayerPosition, Vector3 targetPosition, bool fly, CancellationToken cancellationToken) { try { _pathSetTolerance.InvokeAction(0.25f); return _navPathfind.InvokeFunc(localPlayerPosition, targetPosition, fly, cancellationToken); } catch (IpcError exception) { _logger.LogWarning(exception, "Could not pathfind via navmesh"); return Task.FromException>(exception); } } public Task> PathfindWithTolerance(Vector3 localPlayerPosition, Vector3 targetPosition, bool fly, float tolerance, CancellationToken cancellationToken) { try { _pathSetTolerance.InvokeAction(0.25f); return _pluginInterface.GetIpcSubscriber>>("vnavmesh.Nav.PathfindWithTolerance").InvokeFunc(localPlayerPosition, targetPosition, fly, tolerance, cancellationToken); } catch (IpcError exception) { _logger.LogWarning(exception, "Could not pathfind with tolerance via navmesh"); return Task.FromException>(exception); } } public void MoveTo(List position, bool fly) { Stop(); try { _pathMoveTo.InvokeAction(position, fly); } catch (IpcError exception) { _logger.LogWarning(exception, "Could not move via navmesh"); } } public Vector3? GetPointOnFloor(Vector3 position, bool unlandable) { try { return _queryPointOnFloor.InvokeFunc(position, unlandable, 0.2f); } catch (IpcError) { return null; } } public Vector3? GetPointOnFloor(Vector3 position, bool unlandable, float halfExtentXZ) { try { return _queryPointOnFloor.InvokeFunc(position, unlandable, halfExtentXZ); } catch (IpcError) { return null; } } public Vector3? FindNearestMeshPoint(Vector3 position, float halfExtentXZ, float halfExtentY) { try { return _queryNearestPoint.InvokeFunc(position, halfExtentXZ, halfExtentY); } catch (IpcError) { return null; } } public List GetWaypoints() { if (IsPathRunning) { try { return _pathListWaypoints.InvokeFunc(); } catch (IpcError) { return new List(); } } return new List(); } public int GetBuildProgress() { try { float num = _buildProgress.InvokeFunc(); if (num < 0f) { return 100; } return (int)(num * 100f); } catch (IpcError) { return 0; } } }