forked from aly/qstbak
qstcompanion v1.0.6
This commit is contained in:
parent
5e1e1decc5
commit
ada27cf05b
30 changed files with 3403 additions and 426 deletions
|
|
@ -0,0 +1,393 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
|
||||
namespace QuestionableCompanion.Services;
|
||||
|
||||
public class ARRTrialAutomationService : IDisposable
|
||||
{
|
||||
private readonly IPluginLog log;
|
||||
|
||||
private readonly IFramework framework;
|
||||
|
||||
private readonly ICommandManager commandManager;
|
||||
|
||||
private readonly IChatGui chatGui;
|
||||
|
||||
private readonly Configuration config;
|
||||
|
||||
private readonly QuestionableIPC questionableIPC;
|
||||
|
||||
private readonly SubmarineManager submarineManager;
|
||||
|
||||
private readonly HelperManager helperManager;
|
||||
|
||||
private readonly IPartyList partyList;
|
||||
|
||||
private readonly ICondition condition;
|
||||
|
||||
private readonly MemoryHelper memoryHelper;
|
||||
|
||||
private bool isInDuty;
|
||||
|
||||
private static readonly (uint QuestId, uint TrialId, string ADCommand, string Name)[] Trials = new(uint, uint, string, string)[3]
|
||||
{
|
||||
(1048u, 20004u, "/ad run trial 292 1", "Ifrit HM"),
|
||||
(1157u, 20006u, "/ad run trial 294 1", "Garuda HM"),
|
||||
(1158u, 20005u, "/ad run trial 293 1", "Titan HM")
|
||||
};
|
||||
|
||||
private const uint TRIGGER_QUEST = 89u;
|
||||
|
||||
private const uint TARGET_QUEST = 363u;
|
||||
|
||||
private bool isProcessing;
|
||||
|
||||
private int currentTrialIndex = -1;
|
||||
|
||||
private bool waitingForQuest;
|
||||
|
||||
private bool waitingForParty;
|
||||
|
||||
private bool waitingForTrial;
|
||||
|
||||
private DateTime lastCheckTime = DateTime.MinValue;
|
||||
|
||||
public ARRTrialAutomationService(IPluginLog log, IFramework framework, ICommandManager commandManager, IChatGui chatGui, Configuration config, QuestionableIPC questionableIPC, SubmarineManager submarineManager, HelperManager helperManager, IPartyList partyList, ICondition condition, MemoryHelper memoryHelper)
|
||||
{
|
||||
this.log = log;
|
||||
this.framework = framework;
|
||||
this.commandManager = commandManager;
|
||||
this.chatGui = chatGui;
|
||||
this.config = config;
|
||||
this.questionableIPC = questionableIPC;
|
||||
this.submarineManager = submarineManager;
|
||||
this.helperManager = helperManager;
|
||||
this.partyList = partyList;
|
||||
this.condition = condition;
|
||||
this.memoryHelper = memoryHelper;
|
||||
framework.Update += OnFrameworkUpdate;
|
||||
condition.ConditionChange += OnConditionChanged;
|
||||
log.Information("[ARRTrials] Service initialized");
|
||||
}
|
||||
|
||||
private void OnFrameworkUpdate(IFramework framework)
|
||||
{
|
||||
if (!isProcessing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (waitingForParty && partyList != null && partyList.Length > 1)
|
||||
{
|
||||
if (!((DateTime.Now - lastCheckTime).TotalSeconds < 1.0))
|
||||
{
|
||||
lastCheckTime = DateTime.Now;
|
||||
log.Information($"[ARRTrials] Party join detected (Size: {partyList.Length}) - Triggering trial...");
|
||||
waitingForParty = false;
|
||||
TriggerCurrentTrial();
|
||||
}
|
||||
}
|
||||
else if (waitingForQuest && currentTrialIndex >= 0 && currentTrialIndex < Trials.Length && !((DateTime.Now - lastCheckTime).TotalSeconds < 2.0))
|
||||
{
|
||||
lastCheckTime = DateTime.Now;
|
||||
(uint QuestId, uint TrialId, string ADCommand, string Name) tuple = Trials[currentTrialIndex];
|
||||
uint trialId = tuple.TrialId;
|
||||
string name = tuple.Name;
|
||||
bool unlocked = IsTrialUnlocked(trialId);
|
||||
log.Debug($"[ARRTrials] Polling {name} ({trialId}) Unlocked: {unlocked}");
|
||||
if (unlocked)
|
||||
{
|
||||
log.Information("[ARRTrials] Polling detected " + name + " unlocked - Proceeding...");
|
||||
waitingForQuest = false;
|
||||
helperManager.InviteHelpers();
|
||||
waitingForParty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsTrialComplete(uint instanceId)
|
||||
{
|
||||
return UIState.IsInstanceContentCompleted(instanceId);
|
||||
}
|
||||
|
||||
public bool IsTrialUnlocked(uint instanceId)
|
||||
{
|
||||
return UIState.IsInstanceContentUnlocked(instanceId);
|
||||
}
|
||||
|
||||
public bool IsTargetQuestAvailableOrComplete()
|
||||
{
|
||||
if (QuestManager.IsQuestComplete(363u))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (questionableIPC.IsReadyToAcceptQuest(363u.ToString()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnTriggerQuestComplete()
|
||||
{
|
||||
if (!config.EnableARRPrimalCheck)
|
||||
{
|
||||
log.Debug("[ARRTrials] Feature disabled, skipping check");
|
||||
return;
|
||||
}
|
||||
log.Information("[ARRTrials] Quest 89 complete, starting ARR Primal check...");
|
||||
StartTrialChain();
|
||||
}
|
||||
|
||||
public void StartTrialChain()
|
||||
{
|
||||
if (isProcessing)
|
||||
{
|
||||
log.Debug("[ARRTrials] Already processing trial chain");
|
||||
return;
|
||||
}
|
||||
isProcessing = true;
|
||||
submarineManager.SetExternalPause(paused: true);
|
||||
int startIndex = -1;
|
||||
for (int i = Trials.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (!IsTrialComplete(Trials[i].TrialId))
|
||||
{
|
||||
for (int j = 0; j <= i; j++)
|
||||
{
|
||||
if (!IsTrialComplete(Trials[j].TrialId))
|
||||
{
|
||||
startIndex = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (startIndex == -1)
|
||||
{
|
||||
log.Information("[ARRTrials] All trials already complete!");
|
||||
isProcessing = false;
|
||||
submarineManager.SetExternalPause(paused: false);
|
||||
return;
|
||||
}
|
||||
currentTrialIndex = startIndex;
|
||||
log.Information($"[ARRTrials] Starting from trial index {startIndex}: {Trials[startIndex].Name}");
|
||||
ProcessCurrentTrial();
|
||||
}
|
||||
|
||||
private void ProcessCurrentTrial()
|
||||
{
|
||||
if (currentTrialIndex < 0 || currentTrialIndex >= Trials.Length)
|
||||
{
|
||||
log.Information("[ARRTrials] Trial chain complete!");
|
||||
isProcessing = false;
|
||||
submarineManager.SetExternalPause(paused: false);
|
||||
return;
|
||||
}
|
||||
var (questId, trialId, _, name) = Trials[currentTrialIndex];
|
||||
if (IsTrialComplete(trialId))
|
||||
{
|
||||
log.Information("[ARRTrials] " + name + " already complete, moving to next");
|
||||
currentTrialIndex++;
|
||||
ProcessCurrentTrial();
|
||||
}
|
||||
else if (!QuestManager.IsQuestComplete(questId))
|
||||
{
|
||||
log.Information($"[ARRTrials] Queueing unlock quest {questId} for {name}");
|
||||
questionableIPC.AddQuestPriority(questId.ToString());
|
||||
framework.RunOnFrameworkThread(delegate
|
||||
{
|
||||
commandManager.ProcessCommand("/qst start");
|
||||
});
|
||||
waitingForQuest = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Information("[ARRTrials] " + name + " unlocked, inviting helper and triggering trial...");
|
||||
helperManager.InviteHelpers();
|
||||
waitingForParty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnQuestComplete(uint questId)
|
||||
{
|
||||
if (!isProcessing || !waitingForQuest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = currentTrialIndex; i < Trials.Length; i++)
|
||||
{
|
||||
if (Trials[i].QuestId == questId)
|
||||
{
|
||||
log.Information($"[ARRTrials] Unlock quest {questId} completed, triggering trial");
|
||||
waitingForQuest = false;
|
||||
helperManager.InviteHelpers();
|
||||
waitingForParty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPartyReady()
|
||||
{
|
||||
if (isProcessing && waitingForParty)
|
||||
{
|
||||
waitingForParty = false;
|
||||
TriggerCurrentTrial();
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerCurrentTrial()
|
||||
{
|
||||
if (currentTrialIndex >= 0 && currentTrialIndex < Trials.Length)
|
||||
{
|
||||
(uint, uint, string, string) tuple = Trials[currentTrialIndex];
|
||||
string adCommand = tuple.Item3;
|
||||
string name = tuple.Item4;
|
||||
log.Information("[ARRTrials] Triggering " + name + " via AD command");
|
||||
framework.RunOnFrameworkThread(delegate
|
||||
{
|
||||
chatGui.Print(new XivChatEntry
|
||||
{
|
||||
Message = "[QSTCompanion] Triggering " + name + "...",
|
||||
Type = XivChatType.Echo
|
||||
});
|
||||
commandManager.ProcessCommand("/ad cfg Unsynced true");
|
||||
commandManager.ProcessCommand(adCommand);
|
||||
});
|
||||
waitingForTrial = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDutyComplete()
|
||||
{
|
||||
if (!isProcessing || !waitingForTrial)
|
||||
{
|
||||
return;
|
||||
}
|
||||
(uint QuestId, uint TrialId, string ADCommand, string Name) tuple = Trials[currentTrialIndex];
|
||||
uint trialId = tuple.TrialId;
|
||||
string name = tuple.Name;
|
||||
if (IsTrialComplete(trialId))
|
||||
{
|
||||
log.Information("[ARRTrials] " + name + " completed successfully!");
|
||||
waitingForTrial = false;
|
||||
currentTrialIndex++;
|
||||
framework.RunOnFrameworkThread(delegate
|
||||
{
|
||||
ProcessCurrentTrial();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Warning("[ARRTrials] " + name + " NOT complete after verification. Retrying current step...");
|
||||
waitingForTrial = false;
|
||||
framework.RunOnFrameworkThread(delegate
|
||||
{
|
||||
ProcessCurrentTrial();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public string GetStatus()
|
||||
{
|
||||
if (!isProcessing)
|
||||
{
|
||||
return "Idle";
|
||||
}
|
||||
if (currentTrialIndex >= 0 && currentTrialIndex < Trials.Length)
|
||||
{
|
||||
string name = Trials[currentTrialIndex].Name;
|
||||
if (waitingForQuest)
|
||||
{
|
||||
return "Waiting for " + name + " unlock quest";
|
||||
}
|
||||
if (waitingForParty)
|
||||
{
|
||||
return "Waiting for party (" + name + ")";
|
||||
}
|
||||
if (waitingForTrial)
|
||||
{
|
||||
return "In " + name;
|
||||
}
|
||||
return "Processing " + name;
|
||||
}
|
||||
return "Processing...";
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
isProcessing = false;
|
||||
currentTrialIndex = -1;
|
||||
waitingForQuest = false;
|
||||
waitingForParty = false;
|
||||
waitingForTrial = false;
|
||||
submarineManager.SetExternalPause(paused: false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
framework.Update -= OnFrameworkUpdate;
|
||||
condition.ConditionChange -= OnConditionChanged;
|
||||
log.Information("[ARRTrials] Service disposed");
|
||||
}
|
||||
|
||||
private void OnConditionChanged(ConditionFlag flag, bool value)
|
||||
{
|
||||
if (flag == ConditionFlag.BoundByDuty)
|
||||
{
|
||||
if (value && !isInDuty)
|
||||
{
|
||||
isInDuty = true;
|
||||
log.Debug("[ARRTrials] Entered duty");
|
||||
}
|
||||
else if (!value && isInDuty)
|
||||
{
|
||||
isInDuty = false;
|
||||
OnDutyExited();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDutyExited()
|
||||
{
|
||||
if (!isProcessing || !waitingForTrial)
|
||||
{
|
||||
return;
|
||||
}
|
||||
log.Information("[ARRTrials] Exited duty - stopping AD and disbanding...");
|
||||
framework.RunOnFrameworkThread(delegate
|
||||
{
|
||||
commandManager.ProcessCommand("/ad stop");
|
||||
});
|
||||
Task.Run(async delegate
|
||||
{
|
||||
await Task.Delay(2000);
|
||||
framework.RunOnFrameworkThread(delegate
|
||||
{
|
||||
memoryHelper.SendChatMessage("/leave");
|
||||
commandManager.ProcessCommand("/ad stop");
|
||||
log.Information("[ARRTrials] /leave and safety /ad stop sent");
|
||||
});
|
||||
log.Information("[ARRTrials] Waiting for completion state check...");
|
||||
await Task.Delay(1000);
|
||||
(uint, uint, string, string) tuple = Trials[currentTrialIndex];
|
||||
uint trialId = tuple.Item2;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
if (IsTrialComplete(trialId))
|
||||
{
|
||||
log.Information($"[ARRTrials] Completion verified on attempt {i + 1}");
|
||||
break;
|
||||
}
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
OnDutyComplete();
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue