forked from aly/qstbak
qstcompanion v1.0.1
This commit is contained in:
parent
3e10cbbbf2
commit
44c67ab71b
79 changed files with 21148 additions and 0 deletions
|
|
@ -0,0 +1,454 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Ipc;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace QuestionableCompanion.Services;
|
||||
|
||||
public class ARPostProcessEventQuestService : IDisposable
|
||||
{
|
||||
private readonly IDalamudPluginInterface pluginInterface;
|
||||
|
||||
private readonly QuestionableIPC questionableIPC;
|
||||
|
||||
private readonly EventQuestResolver eventQuestResolver;
|
||||
|
||||
private readonly Configuration configuration;
|
||||
|
||||
private readonly IPluginLog log;
|
||||
|
||||
private readonly IFramework framework;
|
||||
|
||||
private readonly ICommandManager commandManager;
|
||||
|
||||
private readonly LifestreamIPC lifestreamIPC;
|
||||
|
||||
private ICallGateSubscriber<object>? characterAdditionalTaskSubscriber;
|
||||
|
||||
private ICallGateSubscriber<string, object>? characterPostProcessSubscriber;
|
||||
|
||||
private Action? characterAdditionalTaskHandler;
|
||||
|
||||
private Action<string>? characterPostProcessHandler;
|
||||
|
||||
private bool isProcessingEventQuests;
|
||||
|
||||
private DateTime postProcessStartTime;
|
||||
|
||||
private List<string> currentQuestHierarchy = new List<string>();
|
||||
|
||||
private string currentPluginName = string.Empty;
|
||||
|
||||
private string lastTerritoryWaitDetected = string.Empty;
|
||||
|
||||
private DateTime lastTerritoryTeleportTime = DateTime.MinValue;
|
||||
|
||||
private const string PLUGIN_NAME = "QuestionableCompanion";
|
||||
|
||||
private const string AR_CHARACTER_ADDITIONAL_TASK = "AutoRetainer.OnCharacterAdditionalTask";
|
||||
|
||||
private const string AR_CHARACTER_POST_PROCESS_EVENT = "AutoRetainer.OnCharacterReadyForPostprocess";
|
||||
|
||||
private const string AR_FINISH_CHARACTER_POST_PROCESS = "AutoRetainer.FinishCharacterPostprocessRequest";
|
||||
|
||||
private const string AR_REQUEST_CHARACTER_POST_PROCESS = "AutoRetainer.RequestCharacterPostprocess";
|
||||
|
||||
public ARPostProcessEventQuestService(IDalamudPluginInterface pluginInterface, QuestionableIPC questionableIPC, EventQuestResolver eventQuestResolver, Configuration configuration, IPluginLog log, IFramework framework, ICommandManager commandManager, LifestreamIPC lifestreamIPC)
|
||||
{
|
||||
this.pluginInterface = pluginInterface;
|
||||
this.questionableIPC = questionableIPC;
|
||||
this.eventQuestResolver = eventQuestResolver;
|
||||
this.configuration = configuration;
|
||||
this.log = log;
|
||||
this.framework = framework;
|
||||
this.commandManager = commandManager;
|
||||
this.lifestreamIPC = lifestreamIPC;
|
||||
InitializeIPC();
|
||||
}
|
||||
|
||||
private void InitializeIPC()
|
||||
{
|
||||
try
|
||||
{
|
||||
characterAdditionalTaskSubscriber = pluginInterface.GetIpcSubscriber<object>("AutoRetainer.OnCharacterAdditionalTask");
|
||||
if (characterAdditionalTaskSubscriber == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
characterAdditionalTaskHandler = delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
RegisterWithAutoRetainer();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
};
|
||||
characterAdditionalTaskSubscriber.Subscribe(characterAdditionalTaskHandler);
|
||||
characterPostProcessSubscriber = pluginInterface.GetIpcSubscriber<string, object>("AutoRetainer.OnCharacterReadyForPostprocess");
|
||||
if (characterPostProcessSubscriber == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
characterPostProcessHandler = delegate(string pluginName)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnARCharacterPostProcessStarted(pluginName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
};
|
||||
characterPostProcessSubscriber.Subscribe(characterPostProcessHandler);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterWithAutoRetainer()
|
||||
{
|
||||
try
|
||||
{
|
||||
pluginInterface.GetIpcSubscriber<string, object>("AutoRetainer.RequestCharacterPostprocess").InvokeAction("QuestionableCompanion");
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void OnARCharacterPostProcessStarted(string pluginName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pluginName != "QuestionableCompanion")
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!configuration.RunEventQuestsOnARPostProcess)
|
||||
{
|
||||
FinishPostProcess();
|
||||
return;
|
||||
}
|
||||
currentPluginName = pluginName;
|
||||
postProcessStartTime = DateTime.Now;
|
||||
framework.RunOnFrameworkThread(async delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
await ProcessEventQuestsAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
FinishPostProcess();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
FinishPostProcess();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcessEventQuestsAsync()
|
||||
{
|
||||
if (isProcessingEventQuests)
|
||||
{
|
||||
return;
|
||||
}
|
||||
isProcessingEventQuests = true;
|
||||
bool shouldFinishPostProcess = false;
|
||||
try
|
||||
{
|
||||
_ = 1;
|
||||
try
|
||||
{
|
||||
List<string> detectedEventQuests = DetectActiveEventQuests();
|
||||
if (detectedEventQuests.Count == 0)
|
||||
{
|
||||
shouldFinishPostProcess = true;
|
||||
return;
|
||||
}
|
||||
currentQuestHierarchy = new List<string>(detectedEventQuests);
|
||||
await ImportEventQuestsForPostProcess(detectedEventQuests);
|
||||
await WaitForEventQuestsCompletion(detectedEventQuests);
|
||||
shouldFinishPostProcess = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
shouldFinishPostProcess = true;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (shouldFinishPostProcess)
|
||||
{
|
||||
await ClearPriorityQuests();
|
||||
FinishPostProcess();
|
||||
}
|
||||
isProcessingEventQuests = false;
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> DetectActiveEventQuests()
|
||||
{
|
||||
try
|
||||
{
|
||||
return questionableIPC.GetCurrentlyActiveEventQuests() ?? new List<string>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ImportEventQuestsForPostProcess(List<string> detectedEventQuests)
|
||||
{
|
||||
List<string> allQuestsToImport = new List<string>();
|
||||
try
|
||||
{
|
||||
foreach (string questId in detectedEventQuests)
|
||||
{
|
||||
foreach (string quest in await GetQuestHierarchy(questId))
|
||||
{
|
||||
if (!allQuestsToImport.Contains(quest))
|
||||
{
|
||||
allQuestsToImport.Add(quest);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!questionableIPC.IsAvailable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
questionableIPC.ClearQuestPriority();
|
||||
await Task.Delay(500);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
foreach (string questId2 in allQuestsToImport)
|
||||
{
|
||||
try
|
||||
{
|
||||
questionableIPC.AddQuestPriority(questId2);
|
||||
await Task.Delay(100);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
await Task.Delay(500);
|
||||
try
|
||||
{
|
||||
await framework.RunOnFrameworkThread(delegate
|
||||
{
|
||||
commandManager.ProcessCommand("/qst start");
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<string>> GetQuestHierarchy(string questId)
|
||||
{
|
||||
List<string> hierarchy = new List<string>();
|
||||
HashSet<string> visited = new HashSet<string>();
|
||||
await CollectPrerequisitesRecursive(questId, hierarchy, visited);
|
||||
return hierarchy;
|
||||
}
|
||||
|
||||
private async Task CollectPrerequisitesRecursive(string questId, List<string> hierarchy, HashSet<string> visited)
|
||||
{
|
||||
if (visited.Contains(questId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
visited.Add(questId);
|
||||
try
|
||||
{
|
||||
List<string> prerequisites = eventQuestResolver.ResolveEventQuestDependencies(questId);
|
||||
if (prerequisites.Count > 0)
|
||||
{
|
||||
foreach (string prereq in prerequisites)
|
||||
{
|
||||
await CollectPrerequisitesRecursive(prereq, hierarchy, visited);
|
||||
}
|
||||
}
|
||||
hierarchy.Add(questId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
hierarchy.Add(questId);
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task WaitForEventQuestsCompletion(List<string> originalEventQuests)
|
||||
{
|
||||
TimeSpan maxWaitTime = TimeSpan.FromMinutes(configuration.EventQuestPostProcessTimeoutMinutes);
|
||||
DateTime startTime = DateTime.Now;
|
||||
TimeSpan checkInterval = TimeSpan.FromSeconds(2L);
|
||||
while (DateTime.Now - startTime < maxWaitTime)
|
||||
{
|
||||
try
|
||||
{
|
||||
CheckForTerritoryWait();
|
||||
if (!questionableIPC.IsAvailable)
|
||||
{
|
||||
await Task.Delay(checkInterval);
|
||||
continue;
|
||||
}
|
||||
bool isRunning = questionableIPC.IsRunning();
|
||||
List<string> currentEventQuests = DetectActiveEventQuests();
|
||||
if (originalEventQuests.Where((string q) => currentEventQuests.Contains(q)).ToList().Count == 0)
|
||||
{
|
||||
if (!isRunning)
|
||||
{
|
||||
break;
|
||||
}
|
||||
try
|
||||
{
|
||||
await framework.RunOnFrameworkThread(delegate
|
||||
{
|
||||
commandManager.ProcessCommand("/qst stop");
|
||||
});
|
||||
await Task.Delay(500);
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
await Task.Delay(checkInterval);
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckForTerritoryWait()
|
||||
{
|
||||
if (!questionableIPC.IsRunning())
|
||||
{
|
||||
return;
|
||||
}
|
||||
object task = questionableIPC.GetCurrentTask();
|
||||
if (task == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!(task is JObject jObject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
JToken taskNameToken = jObject["TaskName"];
|
||||
if (taskNameToken == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
string taskName = taskNameToken.ToString();
|
||||
if (string.IsNullOrEmpty(taskName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Match waitTerritoryMatch = new Regex("Wait\\(territory:\\s*(.+?)\\s*\\((\\d+)\\)\\)").Match(taskName);
|
||||
if (!waitTerritoryMatch.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
string territoryName = waitTerritoryMatch.Groups[1].Value.Trim();
|
||||
uint territoryId = uint.Parse(waitTerritoryMatch.Groups[2].Value);
|
||||
string territoryKey = $"{territoryName}_{territoryId}";
|
||||
double timeSinceLastTeleport = (DateTime.Now - lastTerritoryTeleportTime).TotalSeconds;
|
||||
if (lastTerritoryWaitDetected == territoryKey && timeSinceLastTeleport < 60.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lastTerritoryWaitDetected = territoryKey;
|
||||
lastTerritoryTeleportTime = DateTime.Now;
|
||||
framework.RunOnFrameworkThread(delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
commandManager.ProcessCommand("/li " + territoryName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ClearPriorityQuests()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (questionableIPC.IsAvailable)
|
||||
{
|
||||
questionableIPC.ClearQuestPriority();
|
||||
await Task.Delay(500);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void FinishPostProcess()
|
||||
{
|
||||
try
|
||||
{
|
||||
pluginInterface.GetIpcSubscriber<object>("AutoRetainer.FinishCharacterPostprocessRequest").InvokeAction();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (characterAdditionalTaskHandler != null && characterAdditionalTaskSubscriber != null)
|
||||
{
|
||||
characterAdditionalTaskSubscriber.Unsubscribe(characterAdditionalTaskHandler);
|
||||
}
|
||||
if (characterPostProcessHandler != null && characterPostProcessSubscriber != null)
|
||||
{
|
||||
characterPostProcessSubscriber.Unsubscribe(characterPostProcessHandler);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue