1
0
forked from liza/Questionable

Various fixes

This commit is contained in:
Liza 2024-06-10 19:56:13 +02:00
parent 73fef2677e
commit 564f1adc01
Signed by: liza
GPG Key ID: 7199F8D727D55F67
13 changed files with 195 additions and 46 deletions

View File

@ -77,7 +77,7 @@
"Z": 365.7129
},
"TerritoryId": 958,
"InteractionType": "WaitForManualProgress",
"InteractionType": "SinglePlayerDuty",
"Comment": "Follow Alphinaud and Alisaie",
"DialogueChoices": [
{

View File

@ -76,7 +76,7 @@
null,
null,
null,
128
-128
]
},
{

View File

@ -52,7 +52,15 @@
"Z": -503.2578
},
"TerritoryId": 958,
"InteractionType": "Interact"
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
},
{
"DataId": 2012094,
@ -64,7 +72,15 @@
"TerritoryId": 958,
"InteractionType": "Interact",
"Comment": "Map",
"Mount": true
"Mount": true,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 2012005,
@ -86,7 +102,15 @@
},
"TerritoryId": 958,
"InteractionType": "Interact",
"Comment": "Warmachine Wreckage"
"Comment": "Warmachine Wreckage",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 2012096,
@ -97,7 +121,15 @@
},
"TerritoryId": 958,
"InteractionType": "Interact",
"Comment": "Children's Slide"
"Comment": "Children's Slide",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
16
]
}
]
},

View File

@ -21,6 +21,16 @@
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -148.48793,
"Y": -10.30035,
"Z": -247.25652
},
"TerritoryId": 956,
"InteractionType": "WalkTo",
"Comment": "Avoids Combat"
},
{
"DataId": 2011987,
"Position": {
@ -43,6 +53,16 @@
"Mount": true,
"DisableNavmesh": true
},
{
"Position": {
"X": -480.30975,
"Y": -22.946651,
"Z": -145.08534
},
"TerritoryId": 956,
"InteractionType": "WalkTo",
"Comment": "Avoids Combat (typically)"
},
{
"DataId": 2011988,
"Position": {

View File

@ -71,7 +71,8 @@ internal sealed class QuestController
if (_keyState[VirtualKey.ESCAPE])
{
Stop();
if (_currentTask != null || _taskQueue.Count > 0)
Stop("ESC pressed");
_movementController.Stop();
}
@ -92,7 +93,7 @@ internal sealed class QuestController
{
_logger.LogInformation("No current quest, resetting data");
CurrentQuest = null;
Stop();
Stop("Resetting current quest");
}
}
else if (CurrentQuest == null || CurrentQuest.Quest.QuestId != currentQuestId)
@ -101,14 +102,15 @@ internal sealed class QuestController
{
_logger.LogInformation("New quest: {QuestName}", quest.Name);
CurrentQuest = new QuestProgress(quest, currentSequence, 0);
Stop("Different Quest");
}
else if (CurrentQuest != null)
{
_logger.LogInformation("No active quest anymore? Not sure what happened...");
CurrentQuest = null;
Stop("No active Quest");
}
Stop();
return;
}
@ -116,7 +118,7 @@ internal sealed class QuestController
{
DebugState = "No quest active";
Comment = null;
Stop();
Stop("No quest active");
return;
}
@ -140,11 +142,7 @@ internal sealed class QuestController
if (CurrentQuest.Sequence != currentSequence)
{
CurrentQuest = CurrentQuest with { Sequence = currentSequence, Step = 0 };
bool automatic = _automatic;
Stop();
if (automatic)
ExecuteNextStep(true);
Stop("New sequence", continueIfAutomatic: true);
}
var q = CurrentQuest.Quest;
@ -153,7 +151,7 @@ internal sealed class QuestController
{
DebugState = "Sequence not found";
Comment = null;
Stop();
Stop("Unknown sequence");
return;
}
@ -161,7 +159,8 @@ internal sealed class QuestController
{
DebugState = "Step completed";
Comment = null;
Stop();
if (_currentTask != null || _taskQueue.Count > 0)
Stop("Step complete", continueIfAutomatic: true);
return;
}
@ -169,7 +168,7 @@ internal sealed class QuestController
{
DebugState = "Step not found";
Comment = null;
Stop();
Stop("Unknown step");
return;
}
@ -249,16 +248,32 @@ internal sealed class QuestController
*/
}
public void Stop()
private void ClearTasksInternal()
{
_currentTask = null;
if (_taskQueue.Count > 0)
_taskQueue.Clear();
}
public void Stop(string label, bool continueIfAutomatic = false)
{
using var scope = _logger.BeginScope(label);
ClearTasksInternal();
// reset task queue
if (continueIfAutomatic && _automatic)
{
if (CurrentQuest?.Step is >= 0 and < 255)
ExecuteNextStep(true);
}
else
{
_logger.LogInformation("Stopping automatic questing");
_automatic = false;
}
}
private void UpdateCurrentTask()
{
@ -286,7 +301,7 @@ internal sealed class QuestController
catch (Exception e)
{
_logger.LogError(e, "Failed to start task {TaskName}", upcomingTask.ToString());
Stop();
Stop("Task failed to start");
return;
}
}
@ -302,7 +317,7 @@ internal sealed class QuestController
catch (Exception e)
{
_logger.LogError(e, "Failed to update task {TaskName}", _currentTask.ToString());
Stop();
Stop("Task failed to update");
return;
}
@ -312,7 +327,8 @@ internal sealed class QuestController
return;
case ETaskResult.SkipRemainingTasksForStep:
_logger.LogInformation("Result: {Result}, skipping remaining tasks for step", result);
_logger.LogInformation("{Task} → {Result}, skipping remaining tasks for step",
_currentTask, result);
_currentTask = null;
while (_taskQueue.TryDequeue(out ITask? nextTask))
@ -327,28 +343,28 @@ internal sealed class QuestController
return;
case ETaskResult.TaskComplete:
_logger.LogInformation("Result: {Result}, remaining tasks: {RemainingTaskCount}", result,
_taskQueue.Count);
_logger.LogInformation("{Task} → {Result}, remaining tasks: {RemainingTaskCount}",
_currentTask, result, _taskQueue.Count);
_currentTask = null;
// handled in next update
return;
case ETaskResult.NextStep:
_logger.LogInformation("Result: {Result}", result);
_logger.LogInformation("{Task} → {Result}", _currentTask, result);
IncreaseStepCount(true);
return;
case ETaskResult.End:
_logger.LogInformation("Result: {Result}", result);
Stop();
_logger.LogInformation("{Task} → {Result}", _currentTask, result);
Stop("Task end");
return;
}
}
public void ExecuteNextStep(bool automatic)
{
Stop();
ClearTasksInternal();
_automatic = automatic;
(QuestSequence? seq, QuestStep? step) = GetNextStep();
@ -382,6 +398,9 @@ internal sealed class QuestController
return;
}
_logger.LogInformation("Tasks for {QuestId}, {Sequence}, {Step}: {Tasks}",
CurrentQuest.Quest.QuestId, seq.Sequence, seq.Steps.IndexOf(step),
string.Join(", ", newTasks.Select(x => x.ToString())));
foreach (var task in newTasks)
_taskQueue.Enqueue(task);
}
@ -394,6 +413,9 @@ internal sealed class QuestController
return _currentTask == null ? $"- (+{_taskQueue.Count})" : $"{_currentTask} (+{_taskQueue.Count})";
}
public bool HasCurrentTaskMatching<T>() =>
_currentTask is T;
public sealed record QuestProgress(
Quest Quest,
byte Sequence,

View File

@ -14,10 +14,10 @@ internal static class SkipCondition
{
public ITask? CreateTask(Quest quest, QuestSequence sequence, QuestStep step)
{
if (step.SkipIf.Count == 0)
if (step.SkipIf.Contains(ESkipCondition.Never))
return null;
if (step.SkipIf.Contains(ESkipCondition.Never))
if (step.SkipIf.Count == 0 && step.CompletionQuestVariablesFlags.Count == 0)
return null;
return serviceProvider.GetRequiredService<CheckTask>()

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Numerics;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
using Microsoft.Extensions.DependencyInjection;
using Questionable.Controller.Steps.BaseTasks;
@ -13,7 +14,7 @@ namespace Questionable.Controller.Steps.BaseFactory;
internal static class WaitAtEnd
{
internal sealed class Factory(IServiceProvider serviceProvider) : ITaskFactory
internal sealed class Factory(IServiceProvider serviceProvider, IClientState clientState) : ITaskFactory
{
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
{
@ -54,6 +55,36 @@ internal static class WaitAtEnd
new NextStep()
];
case EInteractionType.Interact when step.TargetTerritoryId != null:
ITask waitInteraction;
if (step.TerritoryId != step.TargetTerritoryId)
{
// interaction moves to a different territory
waitInteraction = new WaitConditionTask(() => clientState.TerritoryType == step.TerritoryId,
$"Wait(tp to territory: {step.TerritoryId})");
}
else
{
Vector3 lastPosition = step.Position ?? clientState.LocalPlayer?.Position ?? Vector3.Zero;
waitInteraction = new WaitConditionTask(() =>
{
Vector3? currentPosition = clientState.LocalPlayer?.Position;
if (currentPosition == null)
return false;
// interaction moved to elsewhere in the zone
return (lastPosition - currentPosition.Value).Length() > 20;
}, $"Wait(tp away from {lastPosition.ToString("G", CultureInfo.InvariantCulture)})");
}
return
[
waitInteraction,
serviceProvider.GetRequiredService<WaitDelay>(),
new NextStep()
];
case EInteractionType.Interact:
default:
return [serviceProvider.GetRequiredService<WaitDelay>(), new NextStep()];
}
@ -136,7 +167,7 @@ internal static class WaitAtEnd
public ETaskResult Update() => ETaskResult.NextStep;
public override string ToString() => "Next Step";
public override string ToString() => "NextStep";
}
internal sealed class EndAutomation : ILastTask
@ -145,6 +176,6 @@ internal static class WaitAtEnd
public ETaskResult Update() => ETaskResult.End;
public override string ToString() => "End automation";
public override string ToString() => "EndAutomation";
}
}

View File

@ -32,7 +32,10 @@ internal sealed class MountTask(
}
if (gameFunctions.HasStatusPreventingSprintOrMount())
{
logger.LogInformation("Can't mount due to status preventing sprint or mount");
return false;
}
logger.LogInformation("Step wants a mount, trying to mount in territory {Id}...", _territoryId);
if (!condition[ConditionFlag.InCombat])
@ -48,6 +51,12 @@ internal sealed class MountTask(
{
if (!_mountTriggered)
{
if (gameFunctions.HasStatusPreventingSprintOrMount())
{
logger.LogInformation("Can't mount due to status preventing sprint or mount");
return ETaskResult.TaskComplete;
}
_mountTriggered = gameFunctions.Mount();
return ETaskResult.StillRunning;
}

View File

@ -24,7 +24,7 @@ internal static class Combat
ArgumentNullException.ThrowIfNull(step.DataId);
var task = serviceProvider.GetRequiredService<Interact.DoInteract>()
.With(step.DataId.Value);
.With(step.DataId.Value, true);
return [unmount, task];
}
else if (step.EnemySpawnType == EEnemySpawnType.AfterItemUse)

View File

@ -21,21 +21,25 @@ internal static class Interact
ArgumentNullException.ThrowIfNull(step.DataId);
return serviceProvider.GetRequiredService<DoInteract>().With(step.DataId.Value);
return serviceProvider.GetRequiredService<DoInteract>()
.With(step.DataId.Value, step.TargetTerritoryId != null);
}
}
internal sealed class DoInteract(GameFunctions gameFunctions, ICondition condition, ILogger<DoInteract> logger)
: ITask
{
private bool _needsUnmount;
private bool _interacted;
private DateTime _continueAt = DateTime.MinValue;
private uint DataId { get; set; }
private bool SkipMarkerCheck { get; set; }
public ITask With(uint dataId)
public ITask With(uint dataId, bool skipMarkerCheck)
{
DataId = dataId;
SkipMarkerCheck = skipMarkerCheck;
return this;
}
@ -51,6 +55,7 @@ internal static class Interact
// this is only relevant for followers on quests
if (!gameObject.IsTargetable && condition[ConditionFlag.Mounted])
{
_needsUnmount = true;
gameFunctions.Unmount();
_continueAt = DateTime.Now.AddSeconds(0.5);
return true;
@ -71,6 +76,18 @@ internal static class Interact
if (DateTime.Now <= _continueAt)
return ETaskResult.StillRunning;
if (_needsUnmount)
{
if (condition[ConditionFlag.Mounted])
{
gameFunctions.Unmount();
_continueAt = DateTime.Now.AddSeconds(0.5);
return ETaskResult.StillRunning;
}
else
_needsUnmount = false;
}
if (!_interacted)
{
GameObject? gameObject = gameFunctions.FindObjectByDataId(DataId);
@ -87,7 +104,7 @@ internal static class Interact
private unsafe bool HasAnyMarker(GameObject gameObject)
{
if (gameObject.ObjectKind != ObjectKind.EventNpc)
if (SkipMarkerCheck || gameObject.ObjectKind != ObjectKind.EventNpc)
return true;
var gameObjectStruct = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)gameObject.Address;

View File

@ -54,7 +54,7 @@ internal sealed class DalamudInitializer : IDisposable
}
catch (MovementController.PathfindingFailedException)
{
_questController.Stop();
_questController.Stop("Pathfinding failed");
}
}

View File

@ -470,17 +470,18 @@ internal sealed unsafe class GameFunctions
public bool Unmount()
{
if (!_condition[ConditionFlag.Mounted])
return false;
return true;
if (ActionManager.Instance()->GetActionStatus(ActionType.GeneralAction, 23) == 0)
{
_logger.LogInformation("Unmounting...");
ActionManager.Instance()->UseAction(ActionType.GeneralAction, 23);
return ActionManager.Instance()->UseAction(ActionType.GeneralAction, 23);
}
else
{
_logger.LogWarning("Can't unmount right now?");
return true;
return false;
}
}
public void OpenDutyFinder(uint contentFinderConditionId)

View File

@ -4,6 +4,7 @@ using System.Globalization;
using System.Numerics;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
@ -16,6 +17,7 @@ using ImGuiNET;
using LLib.ImGui;
using Microsoft.Extensions.Logging;
using Questionable.Controller;
using Questionable.Controller.Steps.BaseFactory;
using Questionable.Model;
using Questionable.Model.V1;
@ -85,6 +87,7 @@ internal sealed class DebugWindow : LWindow, IPersistableWindowConfig, IDisposab
ImGui.Separator();
DrawQuickAccessButtons();
DrawRemainingTasks();
}
private unsafe void DrawQuest()
@ -141,14 +144,25 @@ internal sealed class DebugWindow : LWindow, IPersistableWindowConfig, IDisposab
if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
{
_movementController.Stop();
_questController.Stop();
_questController.Stop("Manual");
}
QuestStep? currentStep = currentQuest.Quest
.FindSequence(currentQuest.Sequence)
?.FindStep(currentQuest.Step);
bool colored = currentStep != null && currentStep.InteractionType == EInteractionType.Instruction
&& _questController.HasCurrentTaskMatching<WaitAtEnd.WaitNextStepOrSequence>();
if (colored)
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen);
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.ArrowCircleRight, "Skip"))
{
_questController.Stop();
_movementController.Stop();
_questController.Stop("Manual");
_questController.IncreaseStepCount();
}
if (colored)
ImGui.PopStyleColor();
}
else
ImGui.Text("No active quest");
@ -278,7 +292,7 @@ internal sealed class DebugWindow : LWindow, IPersistableWindowConfig, IDisposab
if (ImGui.Button("Stop Nav"))
{
_movementController.Stop();
_questController.Stop();
_questController.Stop("Manual");
}
ImGui.EndDisabled();
@ -289,7 +303,10 @@ internal sealed class DebugWindow : LWindow, IPersistableWindowConfig, IDisposab
_framework.RunOnTick(() => _gameUiController.HandleCurrentDialogueChoices(),
TimeSpan.FromMilliseconds(200));
}
}
private void DrawRemainingTasks()
{
var remainingTasks = _questController.GetRemainingTaskNames();
if (remainingTasks.Count > 0)
{