Update movement logic to handle cases where you're stopped too far away
authorLiza Carvelli <liza@carvel.li>
Thu, 29 Aug 2024 13:45:16 +0000 (15:45 +0200)
committerLiza Carvelli <liza@carvel.li>
Thu, 29 Aug 2024 13:45:16 +0000 (15:45 +0200)
QuestPaths/4.x - Stormblood/Aether Currents/The Ruby Sea/2632_The Palace of Lost Souls.json
QuestPaths/4.x - Stormblood/Custom Deliveries/Kurenai/2704_Fathoms Below.json
QuestPaths/4.x - Stormblood/Custom Deliveries/Kurenai/2705_A Part of Your World.json
QuestPaths/4.x - Stormblood/Custom Deliveries/Kurenai/2706_The Elixir of Life.json
QuestPaths/4.x - Stormblood/MSQ/A3.1-Ruby Sea/2484_In Soroban We Trust.json
QuestPaths/4.x - Stormblood/MSQ/A3.1-Ruby Sea/2486_In Darkness the Magatama Dreams.json
QuestPaths/quest-v1.json
Questionable.Model/Questing/QuestStep.cs
Questionable/Controller/MovementController.cs
Questionable/Controller/Steps/Shared/MoveTo.cs
Questionable/Functions/GameFunctions.cs

index 7425f2d3c231ec7944dfacc59e7c7dc626c5c390..fe72918a6bccf11ab522cf776954e8124e5e3ce2 100644 (file)
@@ -50,7 +50,8 @@
           },
           "TerritoryId": 613,
           "InteractionType": "WalkTo",
-          "$": "Sui-no-Sato, NE inside"
+          "$": "Sui-no-Sato, NE inside",
+          "RestartNavigationIfCancelled": false
         },
         {
           "Position": {
           },
           "TerritoryId": 613,
           "InteractionType": "WalkTo",
-          "$": "Sui-no-Sato, NE outside"
+          "$": "Sui-no-Sato, NE outside",
+          "RestartNavigationIfCancelled": false
         },
         {
           "DataId": 1023280,
index ef577617b5ea81d2878703c64539d7029b5e5c8b..75966772df724a482ba0ef68a714b67b7fd89a71 100644 (file)
@@ -23,7 +23,8 @@
           },
           "TerritoryId": 613,
           "InteractionType": "WalkTo",
-          "$": "Sui-no-Sato, NE outside"
+          "$": "Sui-no-Sato, NE outside",
+          "RestartNavigationIfCancelled": false
         },
         {
           "DataId": 1023280,
index 834a2cc13bb7db4a52e1936badf3d894f31c8198..1fe6387267b9bf7d1d18fdc0a38d4ac1b698d96a 100644 (file)
@@ -85,7 +85,8 @@
           },
           "TerritoryId": 613,
           "InteractionType": "WalkTo",
-          "$": "Sui-no-Sato, NE outside"
+          "$": "Sui-no-Sato, NE outside",
+          "RestartNavigationIfCancelled": false
         },
         {
           "DataId": 1023280,
index fed711ae5d4156635cd6e3b9d3e11dfea1979a31..738d856d1c144ba415b4d03e7950481c170341e8 100644 (file)
@@ -91,6 +91,7 @@
           "TerritoryId": 613,
           "InteractionType": "WalkTo",
           "$": "Exile, outside",
+          "RestartNavigationIfCancelled": false,
           "Fly": true
         },
         {
           "TerritoryId": 613,
           "InteractionType": "WalkTo",
           "$": "Sui-no-Sato, SW outside",
+          "RestartNavigationIfCancelled": false,
           "Fly": true
         },
         {
index b3a2e566aaa6e90e3c5d3a9bbe3db92e470bf4f5..6664fb25e99142c6eaabc89d47ddbbe99dd486eb 100644 (file)
@@ -49,7 +49,8 @@
           },
           "TerritoryId": 613,
           "InteractionType": "WalkTo",
-          "$": "Sui-no-Sato, NE outside"
+          "$": "Sui-no-Sato, NE outside",
+          "RestartNavigationIfCancelled": false
         },
         {
           "DataId": 1019970,
index 9b97dfe0a385c6cdc622cf8e080e7f1a27b57c8d..933b8b9efd8b1ff2716b5bd9d48147ce22f499cb 100644 (file)
@@ -28,7 +28,8 @@
           },
           "TerritoryId": 613,
           "InteractionType": "WalkTo",
-          "$": "Sui-no-Sato, NE inside"
+          "$": "Sui-no-Sato, NE inside",
+          "RestartNavigationIfCancelled": false
         },
         {
           "DataId": 1019978,
index 93efd3c0212a7a7cb4629b585ea95c23ed3c19e1..09e470756b1fdb4f46a04a1f146f6f2eeac680fe 100644 (file)
           "type": "boolean",
           "description": "Most interactions with objects are checked for a Y (height) difference of 2 in-game units. If set to true, the game won't attempt to get any closer if the height difference is larger than this."
         },
+        "RestartNavigationIfCancelled": {
+          "type": "boolean",
+          "description": "For some specific loading screen transitions (e.g. when entering/leaving the water through the portals in the ruby sea), setting this to 'false' means it won't re-attempt to move to the portal after the loading animation"
+        },
         "TerritoryId": {
           "type": "integer",
           "description": "The territory id associated with the location",
index a09386bc1c6ad4aca8b3c7d49fddfa342f893d17..5a23e6e4714d8440f054268c84c4b40cbb188f7c 100644 (file)
@@ -36,6 +36,7 @@ public sealed class QuestStep
     public bool? Land { get; set; }
     public bool? Sprint { get; set; }
     public bool? IgnoreDistanceToObject { get; set; }
+    public bool? RestartNavigationIfCancelled { get; set; }
     public string? Comment { get; set; }
 
     /// <summary>
index 6809c9f1ecacb44d43e96222d113ca2e1cdac21d..676d51d06e32c3bcf81ebe004514f1d93df02677 100644 (file)
@@ -151,7 +151,7 @@ internal sealed class MovementController : IDisposable
 
         if (IsPathRunning && Destination != null)
         {
-            if (_gameFunctions.IsLoadingScreenVisible(false))
+            if (_gameFunctions.IsLoadingScreenVisible())
             {
                 _logger.LogInformation("Stopping movement, loading screen visible");
                 Stop();
index a24fb2f0964f889d6fdcb0579697364fa9af5cbe..331926743260ea389bb37bd87ab72f4ec76cafa0 100644 (file)
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using System.Numerics;
 using Dalamud.Game.ClientState.Conditions;
@@ -67,7 +68,7 @@ internal static class MoveTo
         public ITask Move(MoveParams moveParams)
         {
             return new MoveInternal(moveParams, movementController, gameFunctions,
-                loggerFactory.CreateLogger<MoveInternal>(), condition, dataManager);
+                loggerFactory.CreateLogger<MoveInternal>(), condition, clientState, dataManager);
         }
 
         public ITask Land()
@@ -163,20 +164,24 @@ internal static class MoveTo
         private readonly MovementController _movementController;
         private readonly ILogger<MoveInternal> _logger;
         private readonly ICondition _condition;
+        private readonly IClientState _clientState;
 
         private readonly Action _startAction;
         private readonly Vector3 _destination;
+        private readonly MoveParams _moveParams;
 
         public MoveInternal(MoveParams moveParams,
             MovementController movementController,
             GameFunctions gameFunctions,
             ILogger<MoveInternal> logger,
             ICondition condition,
+            IClientState clientState,
             IDataManager dataManager)
         {
             _movementController = movementController;
             _logger = logger;
             _condition = condition;
+            _clientState = clientState;
             _cannotExecuteAtThisTime = dataManager.GetString<LogMessage>(579, x => x.Text)!;
 
             _destination = moveParams.Destination;
@@ -206,6 +211,8 @@ internal static class MoveTo
                         ignoreDistanceToObject: moveParams.IgnoreDistanceToObject,
                         land: moveParams.Land);
             }
+
+            _moveParams = moveParams;
         }
 
         public bool Start()
@@ -224,6 +231,15 @@ internal static class MoveTo
             if (movementStartedAt == DateTime.MaxValue || movementStartedAt.AddSeconds(2) >= DateTime.Now)
                 return ETaskResult.StillRunning;
 
+            if (_moveParams.RestartNavigation &&
+                Vector3.Distance(_clientState.LocalPlayer!.Position, _destination) >
+                (_moveParams.StopDistance ?? QuestStep.DefaultStopDistance) + 5f)
+            {
+                _logger.LogInformation("Looks like movement was interrupted, re-attempting to move");
+                _startAction();
+                return ETaskResult.StillRunning;
+            }
+
             return ETaskResult.TaskComplete;
         }
 
@@ -248,7 +264,8 @@ internal static class MoveTo
         bool Sprint = true,
         bool Fly = false,
         bool Land = false,
-        bool IgnoreDistanceToObject = false)
+        bool IgnoreDistanceToObject = false,
+        bool RestartNavigation = true)
     {
         public MoveParams(QuestStep step, Vector3 destination)
             : this(step.TerritoryId,
@@ -259,7 +276,8 @@ internal static class MoveTo
                 step.Sprint != false,
                 step.Fly == true,
                 step.Land == true,
-                step.IgnoreDistanceToObject == true)
+                step.IgnoreDistanceToObject == true,
+                step.RestartNavigationIfCancelled != false)
         {
         }
     }
index 360e882d82cec03fe8278be74aaadb06826bcef2..517957055b2d22173d317569af813e2ee82ece86 100644 (file)
@@ -398,7 +398,7 @@ internal sealed unsafe class GameFunctions
         if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null)
             return true;
 
-        if (IsLoadingScreenVisible(true))
+        if (IsLoadingScreenVisible())
             return true;
 
         if (_condition[ConditionFlag.Crafting])
@@ -438,19 +438,16 @@ internal sealed unsafe class GameFunctions
                flags.Contains(ConditionFlag.OccupiedInQuestEvent);
     }
 
-    public bool IsLoadingScreenVisible(bool all)
+    public bool IsLoadingScreenVisible()
     {
         if (_gameGui.TryGetAddonByName("FadeMiddle", out AtkUnitBase* fade) && LAddon.IsAddonReady(fade) && fade->IsVisible)
             return true;
 
-        if (all)
-        {
-            if (_gameGui.TryGetAddonByName("FadeBack", out fade) && LAddon.IsAddonReady(fade) && fade->IsVisible)
-                return true;
+        if (_gameGui.TryGetAddonByName("FadeBack", out fade) && LAddon.IsAddonReady(fade) && fade->IsVisible)
+            return true;
 
-            if (_gameGui.TryGetAddonByName("NowLoading", out fade) && LAddon.IsAddonReady(fade) && fade->IsVisible)
-                return true;
-        }
+        if (_gameGui.TryGetAddonByName("NowLoading", out fade) && LAddon.IsAddonReady(fade) && fade->IsVisible)
+            return true;
 
         return false;
     }