qstbak/Questionable/Questionable.Navigation/SmartNavTaskMapper.cs
2026-08-22 10:25:22 +10:00

279 lines
9.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Plugin.Services;
using Questionable.Controller.Steps;
using Questionable.Controller.Steps.Common;
using Questionable.Controller.Steps.Interactions;
using Questionable.Controller.Steps.Movement;
using Questionable.Controller.Steps.Shared;
using Questionable.Data;
using Questionable.Model.Questing;
using SmartNav;
namespace Questionable.Navigation;
internal sealed class SmartNavTaskMapper(IClientState clientState, TerritoryData territoryData)
{
private const float SurfaceExitRise = 3f;
public IEnumerable<ITask> MapInstructions(IReadOnlyList<NavInstruction> instructions, QuestStep? step = null, ETravelMode travelMode = ETravelMode.Auto)
{
for (int i = 0; i < instructions.Count; i++)
{
foreach (ITask item in Map(instructions[i], NextTravelInstruction(instructions, i), step))
{
if (item is MoveTask task && !(instructions[i] is NavInstruction.Swim))
{
yield return ApplyTravelMode(task, travelMode);
}
else
{
yield return item;
}
}
}
}
private static NavInstruction? NextTravelInstruction(IReadOnlyList<NavInstruction> instructions, int i)
{
for (int j = i + 1; j < instructions.Count; j++)
{
NavInstruction navInstruction = instructions[j];
if ((!(navInstruction is NavInstruction.Land) && !(navInstruction is NavInstruction.Unmount) && !(navInstruction is NavInstruction.WaitForTerritory) && !(navInstruction is NavInstruction.WaitForNavmesh)) || 1 == 0)
{
return instructions[j];
}
}
return null;
}
private IEnumerable<ITask> Map(NavInstruction instruction, NavInstruction? nextTravel, QuestStep? step)
{
NavInstruction.Teleport teleport = instruction as NavInstruction.Teleport;
if ((object)teleport == null)
{
if (!(instruction is NavInstruction.AethernetHop aethernetHop))
{
if (!(instruction is NavInstruction.Move move))
{
if (!(instruction is NavInstruction.Swim swim))
{
if (!(instruction is NavInstruction.DiveEntry dive))
{
if (!(instruction is NavInstruction.Surface surface))
{
if (!(instruction is NavInstruction.Land))
{
if (!(instruction is NavInstruction.Unmount))
{
NavInstruction.WaitForTerritory waitForTerritory = instruction as NavInstruction.WaitForTerritory;
if ((object)waitForTerritory == null)
{
if (!(instruction is NavInstruction.WaitForNavmesh))
{
if (!(instruction is NavInstruction.InteractWarp interactWarp))
{
if (!(instruction is NavInstruction.UseTeleportTicket useTeleportTicket))
{
if (!(instruction is NavInstruction.SubRegionTransport subRegionTransport))
{
throw new InvalidOperationException($"Unmapped NavInstruction: {instruction}");
}
yield return new SubRegionTransport.Task(subRegionTransport.From, subRegionTransport.To, subRegionTransport.Territory);
}
else
{
yield return new TicketTeleport.Task(useTeleportTicket.ItemId, useTeleportTicket.Territory);
}
}
else
{
yield return new WarpInteract.Task(interactWarp.NpcDataId, interactWarp.WarpRowId, interactWarp.FromTerritory, interactWarp.ToTerritory);
}
}
else
{
yield return new WaitNavmesh.Task();
}
}
else
{
yield return new WaitCondition.Task(() => waitForTerritory.Acceptable.Contains(clientState.TerritoryType), waitForTerritory.Description);
}
}
else
{
yield return new Mount.UnmountTask();
}
}
else
{
yield return new LandTask();
}
}
else
{
ushort territory = surface.Territory;
Vector3 position = surface.Position;
position.Y = surface.Position.Y + 3f;
Vector3 destination = position;
bool? mount = true;
string targetNodeId = surface.TargetNodeId;
string approachNodeId = surface.ApproachNodeId;
yield return new MoveTask(territory, destination, mount, MountRequired: false, DismountRequired: false, null, null, DisableNavmesh: true, null, Fly: true, Land: false, IgnoreDistanceToObject: false, RestartNavigation: true, EInteractionType.None, SmartNavRouted: true, AllowZoneTransition: false, targetNodeId, approachNodeId);
}
}
else
{
yield return new Dive.Task
{
SmartNavRouted = true
};
ushort territory2 = dive.Territory;
Vector3 position = dive.Position;
position.Y = dive.Position.Y - 25f;
Vector3 destination2 = position;
string approachNodeId = dive.TargetNodeId;
string targetNodeId = dive.ApproachNodeId;
yield return new MoveTask(territory2, destination2, null, MountRequired: false, DismountRequired: false, null, null, DisableNavmesh: true, null, Fly: true, Land: false, IgnoreDistanceToObject: false, RestartNavigation: true, EInteractionType.None, SmartNavRouted: true, AllowZoneTransition: false, approachNodeId, targetNodeId);
}
}
else if (swim.IsFinal && step != null)
{
Vector3 destination3 = step.Position ?? swim.Position;
yield return new MoveTask(step, destination3)with
{
Fly = true,
Land = false,
SmartNavRouted = true,
RouteTargetNodeId = swim.TargetNodeId,
RouteApproachNodeId = swim.ApproachNodeId
};
}
else
{
NavInstruction.Swim swim2 = swim;
ushort territory3 = swim2.Territory;
Vector3 position2 = swim2.Position;
float? stopDistance = swim2.StopDistance;
string targetNodeId = swim2.TargetNodeId;
string approachNodeId = swim2.ApproachNodeId;
yield return new MoveTask(territory3, position2, null, MountRequired: false, DismountRequired: false, stopDistance, null, DisableNavmesh: false, null, Fly: true, Land: false, IgnoreDistanceToObject: false, RestartNavigation: true, EInteractionType.None, SmartNavRouted: true, AllowZoneTransition: false, targetNodeId, approachNodeId);
}
}
else if (move.IsFinal && step != null)
{
Vector3 destination4 = step.Position ?? move.Position;
MoveTask moveTask = new MoveTask(step, destination4)with
{
Fly = (move.Fly || step.Fly == true)
};
MoveTask moveTask2 = moveTask;
bool flag = move.Fly || step.Land == true;
if (!flag)
{
EArrivalMode arrivalMode = step.ArrivalMode;
bool flag2 = (uint)(arrivalMode - 2) <= 1u;
flag = flag2;
}
moveTask2.Land = flag;
moveTask.SmartNavRouted = true;
moveTask.RouteTargetNodeId = move.TargetNodeId;
moveTask.RouteApproachNodeId = move.ApproachNodeId;
yield return moveTask;
if (step != null)
{
bool? fly = step.Fly;
if (fly.HasValue && fly == true && (step.Land ?? false))
{
yield return new LandTask();
}
}
if (step.ArrivalMode == EArrivalMode.StayMounted && !step.DismountRequired)
{
yield return new Mount.MountTask(step.TerritoryId, Mount.EMountIf.Always);
}
else if (step.ArrivalMode == EArrivalMode.Dismount && !step.MountRequired)
{
yield return new Mount.UnmountTask();
}
}
else
{
NavInstruction.Move move2 = move;
ushort territory4 = move2.Territory;
Vector3 position3 = move2.Position;
bool? mount2 = move2.Mount;
float? stopDistance2 = move2.StopDistance;
uint? dataId = move2.DataId;
bool disableNavmesh = move2.DisableNavmesh;
bool flag = move2.Fly;
bool flag2 = move2.LandAtTarget;
bool allowZoneTransition = move2.AllowZoneTransition;
string approachNodeId = move2.TargetNodeId;
string targetNodeId = move2.ApproachNodeId;
yield return new MoveTask(territory4, position3, mount2, MountRequired: false, DismountRequired: false, stopDistance2, dataId, disableNavmesh, null, flag, flag2, IgnoreDistanceToObject: false, RestartNavigation: true, EInteractionType.None, SmartNavRouted: true, allowZoneTransition, approachNodeId, targetNodeId);
}
}
else
{
yield return new AethernetRide.Task(aethernetHop.From, aethernetHop.To);
}
yield break;
}
yield return new AetheryteTeleport.Task(teleport.Target, teleport.ExpectedTerritory);
if (AetheryteTeleport.MoveAwayFromAetheryteExecutor.AppliesTo(teleport.Target) && (nextTravel as NavInstruction.AethernetHop)?.From != teleport.Target)
{
yield return new WaitCondition.Task(() => clientState.TerritoryType == teleport.ExpectedTerritory, "Wait(territory: " + territoryData.GetNameAndId(teleport.ExpectedTerritory) + ")");
yield return new AetheryteTeleport.MoveAwayFromAetheryte(teleport.Target);
}
}
private static MoveTask ApplyTravelMode(MoveTask task, ETravelMode travelMode)
{
if (travelMode == ETravelMode.Auto)
{
return task;
}
if (task.MountRequired)
{
return task with
{
Mount = true,
Fly = (travelMode == ETravelMode.Flying && task.Fly),
Land = (travelMode == ETravelMode.Flying && task.Land)
};
}
if (task.DismountRequired)
{
return task with
{
Mount = false,
Fly = false,
Land = false
};
}
return travelMode switch
{
ETravelMode.OnFoot => task with
{
Mount = false,
Fly = false,
Land = false
},
ETravelMode.GroundMount => task with
{
Mount = true,
Fly = false,
Land = false
},
ETravelMode.Flying => task with
{
Mount = true
},
_ => task,
};
}
}