Add experimental navmesh path replay (mostly for finding stuck places)

This commit is contained in:
Liza 2024-07-10 17:58:11 +02:00
parent 069833a8f8
commit 0bd15c03f5
Signed by: liza
GPG Key ID: 7199F8D727D55F67
4 changed files with 174 additions and 6 deletions

View File

@ -263,6 +263,16 @@
{ {
"Sequence": 5, "Sequence": 5,
"Steps": [ "Steps": [
{
"Position": {
"X": -136.90475,
"Y": -215.01514,
"Z": 330.17505
},
"TerritoryId": 1189,
"InteractionType": "WalkTo",
"Mount": true
},
{ {
"DataId": 1047669, "DataId": 1047669,
"Position": { "Position": {

View File

@ -53,6 +53,7 @@ internal sealed class QuestController
public QuestProgress? CurrentQuest { get; set; } public QuestProgress? CurrentQuest { get; set; }
public SimulationProgress? SimulatedQuest { get; set; }
public string? DebugState { get; private set; } public string? DebugState { get; private set; }
public string? Comment { get; private set; } public string? Comment { get; private set; }
@ -110,7 +111,16 @@ internal sealed class QuestController
{ {
DebugState = null; DebugState = null;
(ushort currentQuestId, byte currentSequence) = _gameFunctions.GetCurrentQuest(); ushort currentQuestId;
byte currentSequence;
if (SimulatedQuest != null)
{
currentQuestId = SimulatedQuest.Quest.QuestId;
currentSequence = SimulatedQuest.Sequence;
}
else
(currentQuestId, currentSequence) = _gameFunctions.GetCurrentQuest();
if (currentQuestId == 0) if (currentQuestId == 0)
{ {
if (CurrentQuest != null) if (CurrentQuest != null)
@ -302,6 +312,14 @@ internal sealed class QuestController
} }
} }
public void SimulateQuest(Quest? quest)
{
if (quest != null)
SimulatedQuest = new SimulationProgress(quest, 0);
else
SimulatedQuest = null;
}
private void UpdateCurrentTask() private void UpdateCurrentTask()
{ {
if (_gameFunctions.IsOccupied()) if (_gameFunctions.IsOccupied())
@ -464,6 +482,8 @@ internal sealed class QuestController
} }
} }
public sealed record SimulationProgress(Quest Quest, byte Sequence);
public void Skip(ushort questQuestId, byte currentQuestSequence) public void Skip(ushort questQuestId, byte currentQuestSequence)
{ {
lock (_lock) lock (_lock)

View File

@ -6,6 +6,7 @@ using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Questionable.Controller; using Questionable.Controller;
using Questionable.Data; using Questionable.Data;
using Questionable.Model;
using Questionable.Windows; using Questionable.Windows;
namespace Questionable; namespace Questionable;
@ -18,15 +19,18 @@ internal sealed class DalamudInitializer : IDisposable
private readonly QuestController _questController; private readonly QuestController _questController;
private readonly MovementController _movementController; private readonly MovementController _movementController;
private readonly NavigationShortcutController _navigationShortcutController; private readonly NavigationShortcutController _navigationShortcutController;
private readonly IChatGui _chatGui;
private readonly WindowSystem _windowSystem; private readonly WindowSystem _windowSystem;
private readonly QuestWindow _questWindow; private readonly QuestWindow _questWindow;
private readonly ConfigWindow _configWindow;
private readonly DebugOverlay _debugOverlay; private readonly DebugOverlay _debugOverlay;
private readonly ConfigWindow _configWindow;
private readonly QuestRegistry _questRegistry;
public DalamudInitializer(IDalamudPluginInterface pluginInterface, IFramework framework, public DalamudInitializer(IDalamudPluginInterface pluginInterface, IFramework framework,
ICommandManager commandManager, QuestController questController, MovementController movementController, ICommandManager commandManager, QuestController questController, MovementController movementController,
GameUiController gameUiController, NavigationShortcutController navigationShortcutController, GameUiController gameUiController, NavigationShortcutController navigationShortcutController, IChatGui chatGui,
WindowSystem windowSystem, QuestWindow questWindow, DebugOverlay debugOverlay, ConfigWindow configWindow) WindowSystem windowSystem, QuestWindow questWindow, DebugOverlay debugOverlay, ConfigWindow configWindow,
QuestRegistry questRegistry)
{ {
_pluginInterface = pluginInterface; _pluginInterface = pluginInterface;
_framework = framework; _framework = framework;
@ -34,10 +38,12 @@ internal sealed class DalamudInitializer : IDisposable
_questController = questController; _questController = questController;
_movementController = movementController; _movementController = movementController;
_navigationShortcutController = navigationShortcutController; _navigationShortcutController = navigationShortcutController;
_chatGui = chatGui;
_windowSystem = windowSystem; _windowSystem = windowSystem;
_questWindow = questWindow; _questWindow = questWindow;
_configWindow = configWindow;
_debugOverlay = debugOverlay; _debugOverlay = debugOverlay;
_configWindow = configWindow;
_questRegistry = questRegistry;
_windowSystem.AddWindow(questWindow); _windowSystem.AddWindow(questWindow);
_windowSystem.AddWindow(configWindow); _windowSystem.AddWindow(configWindow);
@ -83,10 +89,46 @@ internal sealed class DalamudInitializer : IDisposable
} }
else if (arguments.StartsWith("do", StringComparison.Ordinal)) else if (arguments.StartsWith("do", StringComparison.Ordinal))
{ {
if (!_debugOverlay.DrawConditions())
{
_chatGui.PrintError("[Questionable] You don't have the debug overlay enabled.");
return;
}
if (arguments.Length >= 4 && ushort.TryParse(arguments.AsSpan(3), out ushort questId)) if (arguments.Length >= 4 && ushort.TryParse(arguments.AsSpan(3), out ushort questId))
{
if (_questRegistry.IsKnownQuest(questId))
{
_debugOverlay.HighlightedQuest = questId; _debugOverlay.HighlightedQuest = questId;
_chatGui.Print($"[Questionable] Set highlighted quest to {questId}.");
}
else else
_chatGui.PrintError($"[Questionable] Unknown quest {questId}.");
}
else
{
_debugOverlay.HighlightedQuest = null; _debugOverlay.HighlightedQuest = null;
_chatGui.Print("[Questionable] Cleared highlighted quest.");
}
}
else if (arguments.StartsWith("sim", StringComparison.InvariantCulture))
{
string[] parts = arguments.Split(' ');
if (parts.Length == 2 && ushort.TryParse(parts[1], out ushort questId))
{
if (_questRegistry.TryGetQuest(questId, out Quest? quest))
{
_questController.SimulateQuest(quest);
_chatGui.Print($"[Questionable] Simulating quest {questId}.");
}
else
_chatGui.PrintError($"[Questionable] Unknown quest {questId}.");
}
else
{
_questController.SimulateQuest(null);
_chatGui.Print("[Questionable] Cleared simulated quest.");
}
} }
else if (string.IsNullOrEmpty(arguments)) else if (string.IsNullOrEmpty(arguments))
_questWindow.Toggle(); _questWindow.Toggle();

View File

@ -8,6 +8,7 @@ using Dalamud.Game.Text;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
@ -202,6 +203,101 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
_configuration.General.AutoAcceptNextQuest = autoAcceptNextQuest; _configuration.General.AutoAcceptNextQuest = autoAcceptNextQuest;
_pluginInterface.SavePluginConfig(_configuration); _pluginInterface.SavePluginConfig(_configuration);
} }
if (_questController.SimulatedQuest != null)
{
ImGui.Separator();
ImGui.TextColored(ImGuiColors.DalamudRed, "Quest sim active (experimental)");
ImGui.Text($"Sequence: {_questController.SimulatedQuest.Sequence}");
ImGui.BeginDisabled(_questController.SimulatedQuest.Sequence == 0);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Minus))
{
_movementController.Stop();
_questController.Stop("Sim-");
byte oldSequence = _questController.SimulatedQuest.Sequence;
byte newSequence = _questController.SimulatedQuest.Quest.Data.QuestSequence
.Select(x => (byte)x.Sequence)
.LastOrDefault(x => x < oldSequence, byte.MinValue);
_questController.SimulatedQuest = _questController.SimulatedQuest with
{
Sequence = newSequence,
};
}
ImGui.EndDisabled();
ImGui.SameLine();
ImGui.BeginDisabled(_questController.SimulatedQuest.Sequence >= 255);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
{
_movementController.Stop();
_questController.Stop("Sim+");
byte oldSequence = _questController.SimulatedQuest.Sequence;
byte newSequence = _questController.SimulatedQuest.Quest.Data.QuestSequence
.Select(x => (byte)x.Sequence)
.FirstOrDefault(x => x > oldSequence, byte.MaxValue);
_questController.SimulatedQuest = _questController.SimulatedQuest with
{
Sequence = newSequence,
};
}
ImGui.EndDisabled();
var simulatedSequence =
_questController.SimulatedQuest.Quest.FindSequence(_questController.SimulatedQuest.Sequence);
if (simulatedSequence != null)
{
using var _ = ImRaii.PushId("SimulatedStep");
ImGui.Text($"Step: {currentQuest.Step} / {simulatedSequence.Steps.Count - 1}");
ImGui.BeginDisabled(currentQuest.Step == 0);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Minus))
{
_movementController.Stop();
_questController.Stop("SimStep-");
_questController.CurrentQuest = currentQuest with
{
Step = Math.Min(currentQuest.Step - 1, simulatedSequence.Steps.Count - 1),
};
}
ImGui.EndDisabled();
ImGui.SameLine();
ImGui.BeginDisabled(currentQuest.Step >= simulatedSequence.Steps.Count);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
{
_movementController.Stop();
_questController.Stop("SimStep+");
_questController.CurrentQuest = currentQuest with
{
Step = currentQuest.Step == simulatedSequence.Steps.Count - 1
? 255
: (currentQuest.Step + 1),
};
}
ImGui.EndDisabled();
if (ImGui.Button("Clear sim"))
{
_questController.SimulateQuest(null);
_movementController.Stop();
_questController.Stop("ClearSim");
}
}
}
} }
else else
ImGui.Text("No active quest"); ImGui.Text("No active quest");