using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Numerics; using System.Runtime.InteropServices; using Dalamud.Plugin; using Dalamud.Plugin.Ipc; using FFXIVClientStructs.FFXIV.Client.Game; using Microsoft.Extensions.DependencyInjection; using Questionable.Controller; using Questionable.Controller.Steps; using Questionable.Data; using Questionable.Functions; using Questionable.Model; using Questionable.Model.Questing; using Questionable.Windows; using Questionable.Windows.JournalComponents; using Questionable.Windows.QuestComponents; namespace Questionable.External; internal sealed class QuestionableIpc : IDisposable { public sealed class StepData { public required string QuestId { get; init; } public required byte Sequence { get; init; } public required int Step { get; init; } public required string InteractionType { get; init; } public required Vector3? Position { get; init; } public required ushort TerritoryId { get; init; } } public sealed class TaskData { public required string TaskName { get; init; } public required int RemainingTaskCount { get; init; } } public sealed class StopConditionData { public required bool Enabled { get; init; } public required int TargetValue { get; init; } } private const string IpcIsRunning = "Questionable.IsRunning"; private const string IpcGetCurrentQuestId = "Questionable.GetCurrentQuestId"; private const string IpcGetCurrentStepData = "Questionable.GetCurrentStepData"; private const string IpcGetCurrentTask = "Questionable.GetCurrentTask"; private const string IpcGetCurrentlyActiveEventQuests = "Questionable.GetCurrentlyActiveEventQuests"; private const string IpcStartQuest = "Questionable.StartQuest"; private const string IpcStartSingleQuest = "Questionable.StartSingleQuest"; private const string IpcIsQuestLocked = "Questionable.IsQuestLocked"; private const string IpcIsQuestComplete = "Questionable.IsQuestComplete"; private const string IpcIsReadyToAcceptQuest = "Questionable.IsReadyToAcceptQuest"; private const string IpcIsQuestAccepted = "Questionable.IsQuestAccepted"; private const string IpcIsQuestUnobtainable = "Questionable.IsQuestUnobtainable"; private const string IpcGetDefaultDutyMode = "Questionable.GetDefaultDutyMode"; private const string IpcSetDefaultDutyMode = "Questionable.SetDefaultDutyMode"; private const string IpcGetDutyModeOverride = "Questionable.GetDutyModeOverride"; private const string IpcSetDutyModeOverride = "Questionable.SetDutyModeOverride"; private const string IpcClearDutyModeOverride = "Questionable.ClearDutyModeOverride"; private const string IpcClearAllDutyModeOverrides = "Questionable.ClearAllDutyModeOverrides"; private const string IpcImportQuestPriority = "Questionable.ImportQuestPriority"; private const string IpcClearQuestPriority = "Questionable.ClearQuestPriority"; private const string IpcAddQuestPriority = "Questionable.AddQuestPriority"; private const string IpcInsertQuestPriority = "Questionable.InsertQuestPriority"; private const string IpcExportQuestPriority = "Questionable.ExportQuestPriority"; private const string IpcGetPriorityQuests = "Questionable.GetPriorityQuests"; private const string IpcRemovePriorityQuest = "Questionable.RemovePriorityQuest"; private const string IpcReorderPriorityQuest = "Questionable.ReorderPriorityQuest"; private const string IpcGetAvailablePresets = "Questionable.GetAvailablePresets"; private const string IpcGetPresetQuests = "Questionable.GetPresetQuests"; private const string IpcAddPresetToPriority = "Questionable.AddPresetToPriority"; private const string IpcIsPresetAvailable = "Questionable.IsPresetAvailable"; private const string IpcIsQuestInPriority = "Questionable.IsQuestInPriority"; private const string IpcGetQuestPriorityIndex = "Questionable.GetQuestPriorityIndex"; private const string IpcHasAvailablePriorityQuests = "Questionable.HasAvailablePriorityQuests"; private const string IpcGetStopConditionsEnabled = "Questionable.GetStopConditionsEnabled"; private const string IpcSetStopConditionsEnabled = "Questionable.SetStopConditionsEnabled"; private const string IpcGetStopQuestList = "Questionable.GetStopQuestList"; private const string IpcAddStopQuest = "Questionable.AddStopQuest"; private const string IpcRemoveStopQuest = "Questionable.RemoveStopQuest"; private const string IpcClearStopQuests = "Questionable.ClearStopQuests"; private const string IpcGetLevelStopCondition = "Questionable.GetLevelStopCondition"; private const string IpcSetLevelStopCondition = "Questionable.SetLevelStopCondition"; private const string IpcGetSequenceStopCondition = "Questionable.GetSequenceStopCondition"; private const string IpcSetSequenceStopCondition = "Questionable.SetSequenceStopCondition"; private const string IpcGetQuestSequenceStopCondition = "Questionable.GetQuestSequenceStopCondition"; private const string IpcSetQuestSequenceStopCondition = "Questionable.SetQuestSequenceStopCondition"; private const string IpcRemoveQuestSequenceStopCondition = "Questionable.RemoveQuestSequenceStopCondition"; private const string IpcGetAllQuestSequenceStopConditions = "Questionable.GetAllQuestSequenceStopConditions"; private const string IpcGetAlliedSocietyRemainingAllowances = "Questionable.AlliedSociety.GetRemainingAllowances"; private const string IpcGetAlliedSocietyTimeUntilReset = "Questionable.AlliedSociety.GetTimeUntilReset"; private const string IpcGetAlliedSocietyAvailableQuestIds = "Questionable.AlliedSociety.GetAvailableQuestIds"; private const string IpcGetAlliedSocietyAllAvailableQuestCounts = "Questionable.AlliedSociety.GetAllAvailableQuestCounts"; private const string IpcGetAlliedSocietyIsMaxRank = "Questionable.AlliedSociety.IsMaxRank"; private const string IpcGetAlliedSocietyCurrentRank = "Questionable.AlliedSociety.GetCurrentRank"; private const string IpcGetAlliedSocietiesWithAvailableQuests = "Questionable.AlliedSociety.GetSocietiesWithAvailableQuests"; private const string IpcAddAlliedSocietyOptimalQuests = "Questionable.AlliedSociety.AddOptimalQuests"; private const string IpcGetAlliedSocietyOptimalQuests = "Questionable.AlliedSociety.GetOptimalQuests"; private readonly QuestController _questController; private readonly QuestRegistry _questRegistry; private readonly QuestFunctions _questFunctions; private readonly QuestData _questData; private readonly ManualPriorityComponent _manualPriorityComponent; private readonly PresetBuilderComponent _presetBuilderComponent; private readonly Configuration _configuration; private readonly IDalamudPluginInterface _pluginInterface; private readonly IServiceProvider _serviceProvider; private readonly ICallGateProvider _isRunning; private readonly ICallGateProvider _getCurrentQuestId; private readonly ICallGateProvider _getCurrentStepData; private readonly ICallGateProvider _getCurrentTask; private readonly ICallGateProvider> _getCurrentlyActiveEventQuests; private readonly ICallGateProvider _startQuest; private readonly ICallGateProvider _startSingleQuest; private readonly ICallGateProvider _isQuestLocked; private readonly ICallGateProvider _IsQuestComplete; private readonly ICallGateProvider _IsReadyToAcceptQuest; private readonly ICallGateProvider _isQuestAccepted; private readonly ICallGateProvider _isQuestUnobtainable; private readonly ICallGateProvider _getDefaultDutyMode; private readonly ICallGateProvider _setDefaultDutyMode; private readonly ICallGateProvider _getDutyModeOverride; private readonly ICallGateProvider _setDutyModeOverride; private readonly ICallGateProvider _clearDutyModeOverride; private readonly ICallGateProvider _clearAllDutyModeOverrides; private readonly ICallGateProvider _importQuestPriority; private readonly ICallGateProvider _addQuestPriority; private readonly ICallGateProvider _clearQuestPriority; private readonly ICallGateProvider _insertQuestPriority; private readonly ICallGateProvider _exportQuestPriority; private readonly ICallGateProvider> _getPriorityQuests; private readonly ICallGateProvider _removePriorityQuest; private readonly ICallGateProvider _reorderPriorityQuest; private readonly ICallGateProvider> _getAvailablePresets; private readonly ICallGateProvider> _getPresetQuests; private readonly ICallGateProvider _addPresetToPriority; private readonly ICallGateProvider _isPresetAvailable; private readonly ICallGateProvider _isQuestInPriority; private readonly ICallGateProvider _getQuestPriorityIndex; private readonly ICallGateProvider _hasAvailablePriorityQuests; private readonly ICallGateProvider _getStopConditionsEnabled; private readonly ICallGateProvider _setStopConditionsEnabled; private readonly ICallGateProvider> _getStopQuestList; private readonly ICallGateProvider _addStopQuest; private readonly ICallGateProvider _removeStopQuest; private readonly ICallGateProvider _clearStopQuests; private readonly ICallGateProvider _getLevelStopCondition; private readonly ICallGateProvider _setLevelStopCondition; private readonly ICallGateProvider _getSequenceStopCondition; private readonly ICallGateProvider _setSequenceStopCondition; private readonly ICallGateProvider _getQuestSequenceStopCondition; private readonly ICallGateProvider _setQuestSequenceStopCondition; private readonly ICallGateProvider _removeQuestSequenceStopCondition; private readonly ICallGateProvider> _getAllQuestSequenceStopConditions; private readonly ICallGateProvider _getAlliedSocietyRemainingAllowances; private readonly ICallGateProvider _getAlliedSocietyTimeUntilReset; private readonly ICallGateProvider> _getAlliedSocietyAvailableQuestIds; private readonly ICallGateProvider> _getAlliedSocietyAllAvailableQuestCounts; private readonly ICallGateProvider _getAlliedSocietyIsMaxRank; private readonly ICallGateProvider _getAlliedSocietyCurrentRank; private readonly ICallGateProvider> _getAlliedSocietiesWithAvailableQuests; private readonly ICallGateProvider _addAlliedSocietyOptimalQuests; private readonly ICallGateProvider> _getAlliedSocietyOptimalQuests; public QuestionableIpc(QuestController questController, EventInfoComponent eventInfoComponent, QuestRegistry questRegistry, QuestFunctions questFunctions, QuestData questData, ManualPriorityComponent manualPriorityComponent, PresetBuilderComponent presetBuilderComponent, Configuration configuration, IDalamudPluginInterface pluginInterface, IServiceProvider serviceProvider) { QuestionableIpc questionableIpc = this; _questController = questController; _questRegistry = questRegistry; _questFunctions = questFunctions; _questData = questData; _manualPriorityComponent = manualPriorityComponent; _presetBuilderComponent = presetBuilderComponent; _configuration = configuration; _pluginInterface = pluginInterface; _serviceProvider = serviceProvider; _isRunning = pluginInterface.GetIpcProvider("Questionable.IsRunning"); _isRunning.RegisterFunc(() => questController.AutomationType != QuestController.EAutomationType.Manual || questController.IsRunning); _getCurrentQuestId = pluginInterface.GetIpcProvider("Questionable.GetCurrentQuestId"); _getCurrentQuestId.RegisterFunc(() => questController.CurrentQuest?.Quest.Id.ToString()); _getCurrentStepData = pluginInterface.GetIpcProvider("Questionable.GetCurrentStepData"); _getCurrentStepData.RegisterFunc(GetStepData); _getCurrentTask = pluginInterface.GetIpcProvider("Questionable.GetCurrentTask"); _getCurrentTask.RegisterFunc(GetCurrentTask); _getCurrentlyActiveEventQuests = pluginInterface.GetIpcProvider>("Questionable.GetCurrentlyActiveEventQuests"); _getCurrentlyActiveEventQuests.RegisterFunc(() => (from q in eventInfoComponent.GetCurrentlyActiveEventQuests() select q.ToString()).ToList()); _startQuest = pluginInterface.GetIpcProvider("Questionable.StartQuest"); _startQuest.RegisterFunc((string questId) => questionableIpc.StartQuest(questId, single: false)); _startSingleQuest = pluginInterface.GetIpcProvider("Questionable.StartSingleQuest"); _startSingleQuest.RegisterFunc((string questId) => questionableIpc.StartQuest(questId, single: true)); _isQuestLocked = pluginInterface.GetIpcProvider("Questionable.IsQuestLocked"); _isQuestLocked.RegisterFunc(IsQuestLocked); _IsQuestComplete = pluginInterface.GetIpcProvider("Questionable.IsQuestComplete"); _IsQuestComplete.RegisterFunc(IsQuestComplete); _IsReadyToAcceptQuest = pluginInterface.GetIpcProvider("Questionable.IsReadyToAcceptQuest"); _IsReadyToAcceptQuest.RegisterFunc(IsReadyToAcceptQuest); _isQuestAccepted = pluginInterface.GetIpcProvider("Questionable.IsQuestAccepted"); _isQuestAccepted.RegisterFunc(IsQuestAccepted); _isQuestUnobtainable = pluginInterface.GetIpcProvider("Questionable.IsQuestUnobtainable"); _isQuestUnobtainable.RegisterFunc(IsQuestUnobtainable); _getDefaultDutyMode = pluginInterface.GetIpcProvider("Questionable.GetDefaultDutyMode"); _getDefaultDutyMode.RegisterFunc(GetDefaultDutyMode); _setDefaultDutyMode = pluginInterface.GetIpcProvider("Questionable.SetDefaultDutyMode"); _setDefaultDutyMode.RegisterFunc(SetDefaultDutyMode); _getDutyModeOverride = pluginInterface.GetIpcProvider("Questionable.GetDutyModeOverride"); _getDutyModeOverride.RegisterFunc(GetDutyModeOverride); _setDutyModeOverride = pluginInterface.GetIpcProvider("Questionable.SetDutyModeOverride"); _setDutyModeOverride.RegisterFunc(SetDutyModeOverride); _clearDutyModeOverride = pluginInterface.GetIpcProvider("Questionable.ClearDutyModeOverride"); _clearDutyModeOverride.RegisterFunc(ClearDutyModeOverride); _clearAllDutyModeOverrides = pluginInterface.GetIpcProvider("Questionable.ClearAllDutyModeOverrides"); _clearAllDutyModeOverrides.RegisterFunc(ClearAllDutyModeOverrides); _importQuestPriority = pluginInterface.GetIpcProvider("Questionable.ImportQuestPriority"); _importQuestPriority.RegisterFunc(ImportQuestPriority); _addQuestPriority = pluginInterface.GetIpcProvider("Questionable.AddQuestPriority"); _addQuestPriority.RegisterFunc(AddQuestPriority); _clearQuestPriority = pluginInterface.GetIpcProvider("Questionable.ClearQuestPriority"); _clearQuestPriority.RegisterFunc(ClearQuestPriority); _insertQuestPriority = pluginInterface.GetIpcProvider("Questionable.InsertQuestPriority"); _insertQuestPriority.RegisterFunc(InsertQuestPriority); _exportQuestPriority = pluginInterface.GetIpcProvider("Questionable.ExportQuestPriority"); _exportQuestPriority.RegisterFunc(_manualPriorityComponent.EncodeQuestPriority); _getPriorityQuests = pluginInterface.GetIpcProvider>("Questionable.GetPriorityQuests"); _getPriorityQuests.RegisterFunc(GetPriorityQuests); _removePriorityQuest = pluginInterface.GetIpcProvider("Questionable.RemovePriorityQuest"); _removePriorityQuest.RegisterFunc(RemovePriorityQuest); _reorderPriorityQuest = pluginInterface.GetIpcProvider("Questionable.ReorderPriorityQuest"); _reorderPriorityQuest.RegisterFunc(ReorderPriorityQuest); _getAvailablePresets = pluginInterface.GetIpcProvider>("Questionable.GetAvailablePresets"); _getAvailablePresets.RegisterFunc(GetAvailablePresets); _getPresetQuests = pluginInterface.GetIpcProvider>("Questionable.GetPresetQuests"); _getPresetQuests.RegisterFunc(GetPresetQuests); _addPresetToPriority = pluginInterface.GetIpcProvider("Questionable.AddPresetToPriority"); _addPresetToPriority.RegisterFunc(AddPresetToPriority); _isPresetAvailable = pluginInterface.GetIpcProvider("Questionable.IsPresetAvailable"); _isPresetAvailable.RegisterFunc(IsPresetAvailable); _isQuestInPriority = pluginInterface.GetIpcProvider("Questionable.IsQuestInPriority"); _isQuestInPriority.RegisterFunc(IsQuestInPriority); _getQuestPriorityIndex = pluginInterface.GetIpcProvider("Questionable.GetQuestPriorityIndex"); _getQuestPriorityIndex.RegisterFunc(GetQuestPriorityIndex); _hasAvailablePriorityQuests = pluginInterface.GetIpcProvider("Questionable.HasAvailablePriorityQuests"); _hasAvailablePriorityQuests.RegisterFunc(HasAvailablePriorityQuests); _getStopConditionsEnabled = pluginInterface.GetIpcProvider("Questionable.GetStopConditionsEnabled"); _getStopConditionsEnabled.RegisterFunc(GetStopConditionsEnabled); _setStopConditionsEnabled = pluginInterface.GetIpcProvider("Questionable.SetStopConditionsEnabled"); _setStopConditionsEnabled.RegisterFunc(SetStopConditionsEnabled); _getStopQuestList = pluginInterface.GetIpcProvider>("Questionable.GetStopQuestList"); _getStopQuestList.RegisterFunc(GetStopQuestList); _addStopQuest = pluginInterface.GetIpcProvider("Questionable.AddStopQuest"); _addStopQuest.RegisterFunc(AddStopQuest); _removeStopQuest = pluginInterface.GetIpcProvider("Questionable.RemoveStopQuest"); _removeStopQuest.RegisterFunc(RemoveStopQuest); _clearStopQuests = pluginInterface.GetIpcProvider("Questionable.ClearStopQuests"); _clearStopQuests.RegisterFunc(ClearStopQuests); _getLevelStopCondition = pluginInterface.GetIpcProvider("Questionable.GetLevelStopCondition"); _getLevelStopCondition.RegisterFunc(GetLevelStopCondition); _setLevelStopCondition = pluginInterface.GetIpcProvider("Questionable.SetLevelStopCondition"); _setLevelStopCondition.RegisterFunc(SetLevelStopCondition); _getSequenceStopCondition = pluginInterface.GetIpcProvider("Questionable.GetSequenceStopCondition"); _getSequenceStopCondition.RegisterFunc(GetSequenceStopCondition); _setSequenceStopCondition = pluginInterface.GetIpcProvider("Questionable.SetSequenceStopCondition"); _setSequenceStopCondition.RegisterFunc(SetSequenceStopCondition); _getQuestSequenceStopCondition = pluginInterface.GetIpcProvider("Questionable.GetQuestSequenceStopCondition"); _getQuestSequenceStopCondition.RegisterFunc(GetQuestSequenceStopCondition); _setQuestSequenceStopCondition = pluginInterface.GetIpcProvider("Questionable.SetQuestSequenceStopCondition"); _setQuestSequenceStopCondition.RegisterFunc(SetQuestSequenceStopCondition); _removeQuestSequenceStopCondition = pluginInterface.GetIpcProvider("Questionable.RemoveQuestSequenceStopCondition"); _removeQuestSequenceStopCondition.RegisterFunc(RemoveQuestSequenceStopCondition); _getAllQuestSequenceStopConditions = pluginInterface.GetIpcProvider>("Questionable.GetAllQuestSequenceStopConditions"); _getAllQuestSequenceStopConditions.RegisterFunc(GetAllQuestSequenceStopConditions); _getAlliedSocietyRemainingAllowances = pluginInterface.GetIpcProvider("Questionable.AlliedSociety.GetRemainingAllowances"); _getAlliedSocietyRemainingAllowances.RegisterFunc(GetAlliedSocietyRemainingAllowances); _getAlliedSocietyTimeUntilReset = pluginInterface.GetIpcProvider("Questionable.AlliedSociety.GetTimeUntilReset"); _getAlliedSocietyTimeUntilReset.RegisterFunc(GetAlliedSocietyTimeUntilReset); _getAlliedSocietyAvailableQuestIds = pluginInterface.GetIpcProvider>("Questionable.AlliedSociety.GetAvailableQuestIds"); _getAlliedSocietyAvailableQuestIds.RegisterFunc(GetAlliedSocietyAvailableQuestIds); _getAlliedSocietyAllAvailableQuestCounts = pluginInterface.GetIpcProvider>("Questionable.AlliedSociety.GetAllAvailableQuestCounts"); _getAlliedSocietyAllAvailableQuestCounts.RegisterFunc(GetAlliedSocietyAllAvailableQuestCounts); _getAlliedSocietyIsMaxRank = pluginInterface.GetIpcProvider("Questionable.AlliedSociety.IsMaxRank"); _getAlliedSocietyIsMaxRank.RegisterFunc(GetAlliedSocietyIsMaxRank); _getAlliedSocietyCurrentRank = pluginInterface.GetIpcProvider("Questionable.AlliedSociety.GetCurrentRank"); _getAlliedSocietyCurrentRank.RegisterFunc(GetAlliedSocietyCurrentRank); _getAlliedSocietiesWithAvailableQuests = pluginInterface.GetIpcProvider>("Questionable.AlliedSociety.GetSocietiesWithAvailableQuests"); _getAlliedSocietiesWithAvailableQuests.RegisterFunc(GetAlliedSocietiesWithAvailableQuests); _addAlliedSocietyOptimalQuests = pluginInterface.GetIpcProvider("Questionable.AlliedSociety.AddOptimalQuests"); _addAlliedSocietyOptimalQuests.RegisterFunc(AddAlliedSocietyOptimalQuests); _getAlliedSocietyOptimalQuests = pluginInterface.GetIpcProvider>("Questionable.AlliedSociety.GetOptimalQuests"); _getAlliedSocietyOptimalQuests.RegisterFunc(GetAlliedSocietyOptimalQuests); } private bool StartQuest(string questId, bool single) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.TryGetQuest(elementId, out Quest quest)) { _questController.SetNextQuest(quest); if (single) { _questController.StartSingleQuest("IPCQuestSelection"); } else { _questController.Start("IPCQuestSelection"); } return true; } return false; } private StepData? GetStepData() { QuestController.QuestProgress currentQuest = _questController.CurrentQuest; if (currentQuest == null) { return null; } string text = currentQuest.Quest.Id.ToString(); if (string.IsNullOrEmpty(text)) { return null; } QuestStep questStep = currentQuest.Quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step); if (questStep == null) { return null; } return new StepData { QuestId = text, Sequence = currentQuest.Sequence, Step = currentQuest.Step, InteractionType = questStep.InteractionType.ToString(), Position = questStep.Position, TerritoryId = questStep.TerritoryId }; } private TaskData? GetCurrentTask() { ITask task = _questController.TaskQueue.CurrentTaskExecutor?.CurrentTask; if (task == null) { return null; } int remainingTaskCount = _questController.TaskQueue.RemainingTasks.Count(); string taskName = task.ToString() ?? "Unknown"; return new TaskData { TaskName = taskName, RemainingTaskCount = remainingTaskCount }; } private bool IsQuestLocked(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.TryGetQuest(elementId, out Quest _)) { return _questFunctions.IsQuestLocked(elementId); } return true; } private bool IsQuestComplete(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questFunctions.IsQuestComplete(elementId); } return false; } private bool IsReadyToAcceptQuest(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questFunctions.IsReadyToAcceptQuest(elementId); } return false; } private bool IsQuestAccepted(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questFunctions.IsQuestAccepted(elementId); } return false; } private bool IsQuestUnobtainable(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questFunctions.IsQuestUnobtainable(elementId); } return false; } private int GetDefaultDutyMode() { return (int)_configuration.Duties.DefaultDutyMode; } private bool SetDefaultDutyMode(int dutyMode) { if (!Enum.IsDefined(typeof(EDutyMode), dutyMode)) { return false; } _configuration.Duties.DefaultDutyMode = (EDutyMode)dutyMode; _pluginInterface.SavePluginConfig(_configuration); return true; } private int GetDutyModeOverride(uint contentFinderConditionId) { if (_configuration.Duties.DutyModeOverrides.TryGetValue(contentFinderConditionId, out var value)) { return (int)value; } return -1; } private bool SetDutyModeOverride(uint contentFinderConditionId, int dutyMode) { if (!Enum.IsDefined(typeof(EDutyMode), dutyMode)) { return false; } _configuration.Duties.DutyModeOverrides[contentFinderConditionId] = (EDutyMode)dutyMode; _pluginInterface.SavePluginConfig(_configuration); return true; } private bool ClearDutyModeOverride(uint contentFinderConditionId) { bool num = _configuration.Duties.DutyModeOverrides.Remove(contentFinderConditionId); if (num) { _pluginInterface.SavePluginConfig(_configuration); } return num; } private bool ClearAllDutyModeOverrides() { _configuration.Duties.DutyModeOverrides.Clear(); _pluginInterface.SavePluginConfig(_configuration); return true; } private bool ImportQuestPriority(string encodedQuestPriority) { List questElements = PriorityWindow.DecodeQuestPriority(encodedQuestPriority); _questController.ImportQuestPriority(questElements); return true; } private bool ClearQuestPriority() { _questController.ClearQuestPriority(); return true; } private bool AddQuestPriority(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.IsKnownQuest(elementId)) { return _questController.AddQuestPriority(elementId); } return false; } private bool InsertQuestPriority(int index, string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.IsKnownQuest(elementId)) { return _questController.InsertQuestPriority(index, elementId); } return false; } private List GetPriorityQuests() { return _questController.ManualPriorityQuests.Select((Quest q) => q.Id.ToString()).ToList(); } private bool RemovePriorityQuest(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { Quest quest = _questController.ManualPriorityQuests.FirstOrDefault((Quest q) => q.Id.Equals(elementId)); if (quest != null) { _questController.ManualPriorityQuests.Remove(quest); return true; } } return false; } private bool ReorderPriorityQuest(string questId, int newIndex) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { Quest quest = _questController.ManualPriorityQuests.FirstOrDefault((Quest q) => q.Id.Equals(elementId)); if (quest != null && newIndex >= 0 && newIndex < _questController.ManualPriorityQuests.Count) { _questController.ManualPriorityQuests.Remove(quest); _questController.ManualPriorityQuests.Insert(newIndex, quest); return true; } } return false; } private List GetAvailablePresets() { return new List { "aether_currents_hw", "aether_currents_sb", "aether_currents_shb", "aether_currents_ew", "aether_currents_dt", "aethernet_limsa", "aethernet_gridania", "aethernet_uldah", "aethernet_goldsaucer", "aethernet_ishgard", "aethernet_idyllshire", "aethernet_rhalgrs_reach", "aethernet_kugane", "aethernet_doman_enclave", "aethernet_the_crystarium", "aethernet_eulmore", "aethernet_old_sharlayan", "aethernet_radz_at_han", "aethernet_tuliyollal", "aethernet_solution_nine", "crystal_tower", "hard_primals" }; } private List GetPresetQuests(string presetName) { List source; switch (presetName) { case "aether_currents_hw": source = GetAetherCurrentQuestsByExpansion(EExpansionVersion.Heavensward); break; case "aether_currents_sb": source = GetAetherCurrentQuestsByExpansion(EExpansionVersion.Stormblood); break; case "aether_currents_shb": source = GetAetherCurrentQuestsByExpansion(EExpansionVersion.Shadowbringers); break; case "aether_currents_ew": source = GetAetherCurrentQuestsByExpansion(EExpansionVersion.Endwalker); break; case "aether_currents_dt": source = GetAetherCurrentQuestsByExpansion(EExpansionVersion.Dawntrail); break; case "aethernet_limsa": { int num = 1; List list15 = new List(num); CollectionsMarshal.SetCount(list15, num); Span span = CollectionsMarshal.AsSpan(list15); int index = 0; span[index] = new AethernetId(1); source = list15; break; } case "aethernet_gridania": { int index = 1; List list14 = new List(index); CollectionsMarshal.SetCount(list14, index); Span span = CollectionsMarshal.AsSpan(list14); int num = 0; span[num] = new AethernetId(2); source = list14; break; } case "aethernet_uldah": { int num = 1; List list13 = new List(num); CollectionsMarshal.SetCount(list13, num); Span span = CollectionsMarshal.AsSpan(list13); int index = 0; span[index] = new AethernetId(3); source = list13; break; } case "aethernet_goldsaucer": { int index = 1; List list12 = new List(index); CollectionsMarshal.SetCount(list12, index); Span span = CollectionsMarshal.AsSpan(list12); int num = 0; span[num] = new AethernetId(4); source = list12; break; } case "aethernet_ishgard": { int num = 1; List list11 = new List(num); CollectionsMarshal.SetCount(list11, num); Span span = CollectionsMarshal.AsSpan(list11); int index = 0; span[index] = new AethernetId(5); source = list11; break; } case "aethernet_idyllshire": { int index = 1; List list10 = new List(index); CollectionsMarshal.SetCount(list10, index); Span span = CollectionsMarshal.AsSpan(list10); int num = 0; span[num] = new AethernetId(6); source = list10; break; } case "aethernet_rhalgrs_reach": { int num = 1; List list9 = new List(num); CollectionsMarshal.SetCount(list9, num); Span span = CollectionsMarshal.AsSpan(list9); int index = 0; span[index] = new AethernetId(7); source = list9; break; } case "aethernet_kugane": { int index = 1; List list8 = new List(index); CollectionsMarshal.SetCount(list8, index); Span span = CollectionsMarshal.AsSpan(list8); int num = 0; span[num] = new AethernetId(8); source = list8; break; } case "aethernet_doman_enclave": { int num = 1; List list7 = new List(num); CollectionsMarshal.SetCount(list7, num); Span span = CollectionsMarshal.AsSpan(list7); int index = 0; span[index] = new AethernetId(9); source = list7; break; } case "aethernet_the_crystarium": { int index = 1; List list6 = new List(index); CollectionsMarshal.SetCount(list6, index); Span span = CollectionsMarshal.AsSpan(list6); int num = 0; span[num] = new AethernetId(10); source = list6; break; } case "aethernet_eulmore": { int num = 1; List list5 = new List(num); CollectionsMarshal.SetCount(list5, num); Span span = CollectionsMarshal.AsSpan(list5); int index = 0; span[index] = new AethernetId(11); source = list5; break; } case "aethernet_old_sharlayan": { int index = 1; List list4 = new List(index); CollectionsMarshal.SetCount(list4, index); Span span = CollectionsMarshal.AsSpan(list4); int num = 0; span[num] = new AethernetId(12); source = list4; break; } case "aethernet_radz_at_han": { int num = 1; List list3 = new List(num); CollectionsMarshal.SetCount(list3, num); Span span = CollectionsMarshal.AsSpan(list3); int index = 0; span[index] = new AethernetId(13); source = list3; break; } case "aethernet_tuliyollal": { int index = 1; List list2 = new List(index); CollectionsMarshal.SetCount(list2, index); Span span = CollectionsMarshal.AsSpan(list2); int num = 0; span[num] = new AethernetId(14); source = list2; break; } case "aethernet_solution_nine": { int num = 1; List list = new List(num); CollectionsMarshal.SetCount(list, num); Span span = CollectionsMarshal.AsSpan(list); int index = 0; span[index] = new AethernetId(15); source = list; break; } case "crystal_tower": source = QuestData.CrystalTowerQuests.Cast().ToList(); break; case "hard_primals": source = QuestData.HardModePrimals.Cast().ToList(); break; default: source = new List(); break; } return source.Select((ElementId q) => q.ToString()).ToList(); } private int AddPresetToPriority(string presetName) { List presetQuests = GetPresetQuests(presetName); int num = 0; foreach (string item in presetQuests) { if (ElementId.TryFromString(item, out ElementId elementId) && elementId != null && (_questFunctions.IsReadyToAcceptQuest(elementId) || _questFunctions.IsQuestAccepted(elementId)) && !_questController.ManualPriorityQuests.Any((Quest q) => q.Id.Equals(elementId)) && _questRegistry.IsKnownQuest(elementId) && _questController.AddQuestPriority(elementId)) { num++; } } return num; } private static List GetAetherCurrentQuestsByExpansion(EExpansionVersion expansion) { uint[] territoryRanges = expansion switch { EExpansionVersion.Heavensward => new uint[5] { 397u, 398u, 399u, 400u, 401u }, EExpansionVersion.Stormblood => new uint[6] { 612u, 613u, 614u, 620u, 621u, 622u }, EExpansionVersion.Shadowbringers => new uint[6] { 813u, 814u, 815u, 816u, 817u, 818u }, EExpansionVersion.Endwalker => new uint[6] { 956u, 957u, 958u, 959u, 960u, 961u }, EExpansionVersion.Dawntrail => new uint[6] { 1187u, 1188u, 1189u, 1190u, 1191u, 1192u }, _ => Array.Empty(), }; return QuestData.AetherCurrentQuestsByTerritory.Where>>((KeyValuePair> kvp) => territoryRanges.Contains(kvp.Key)).SelectMany((KeyValuePair> kvp) => kvp.Value).Cast() .ToList(); } private bool IsPresetAvailable(string presetName) { return GetAvailablePresets().Contains(presetName); } private bool IsQuestInPriority(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questController.ManualPriorityQuests.Any((Quest q) => q.Id.Equals(elementId)); } return false; } private int GetQuestPriorityIndex(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { Quest quest = _questController.ManualPriorityQuests.FirstOrDefault((Quest q) => q.Id.Equals(elementId)); if (quest != null) { return _questController.ManualPriorityQuests.IndexOf(quest); } } return -1; } private bool HasAvailablePriorityQuests() { return _questFunctions.GetNextPriorityQuestsThatCanBeAccepted().Any((PriorityQuestInfo x) => x.IsAvailable); } private bool GetStopConditionsEnabled() { return _configuration.Stop.Enabled; } private bool SetStopConditionsEnabled(bool enabled) { _configuration.Stop.Enabled = enabled; _pluginInterface.SavePluginConfig(_configuration); return true; } private List GetStopQuestList() { return _configuration.Stop.QuestsToStopAfter.Select((ElementId q) => q.ToString()).ToList(); } private bool AddStopQuest(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.IsKnownQuest(elementId) && !_configuration.Stop.QuestsToStopAfter.Contains(elementId)) { _configuration.Stop.QuestsToStopAfter.Add(elementId); _pluginInterface.SavePluginConfig(_configuration); return true; } return false; } private bool RemoveStopQuest(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { bool num = _configuration.Stop.QuestsToStopAfter.Remove(elementId); if (num) { _configuration.Stop.QuestSequences.Remove(questId); _pluginInterface.SavePluginConfig(_configuration); } return num; } return false; } private bool ClearStopQuests() { _configuration.Stop.QuestsToStopAfter.Clear(); _configuration.Stop.QuestSequences.Clear(); _pluginInterface.SavePluginConfig(_configuration); return true; } private StopConditionData GetLevelStopCondition() { return new StopConditionData { Enabled = _configuration.Stop.LevelToStopAfter, TargetValue = _configuration.Stop.TargetLevel }; } private bool SetLevelStopCondition(bool enabled, int targetLevel) { if (targetLevel < 1 || targetLevel > 100) { return false; } _configuration.Stop.LevelToStopAfter = enabled; _configuration.Stop.TargetLevel = targetLevel; _pluginInterface.SavePluginConfig(_configuration); return true; } private StopConditionData GetSequenceStopCondition() { return new StopConditionData { Enabled = _configuration.Stop.SequenceToStopAfter, TargetValue = _configuration.Stop.TargetSequence }; } private bool SetSequenceStopCondition(bool enabled, int targetSequence) { if (targetSequence < 0 || targetSequence > 255) { return false; } _configuration.Stop.SequenceToStopAfter = enabled; _configuration.Stop.TargetSequence = targetSequence; _pluginInterface.SavePluginConfig(_configuration); return true; } private int GetQuestSequenceStopCondition(string questId) { if (_configuration.Stop.QuestSequences.TryGetValue(questId, out var value) && value.HasValue) { return value.Value; } return -1; } private bool SetQuestSequenceStopCondition(string questId, int targetSequence) { if (targetSequence < 0 || targetSequence > 255) { return false; } if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.IsKnownQuest(elementId)) { if (!_configuration.Stop.QuestsToStopAfter.Contains(elementId)) { _configuration.Stop.QuestsToStopAfter.Add(elementId); } _configuration.Stop.QuestSequences[questId] = targetSequence; _pluginInterface.SavePluginConfig(_configuration); return true; } return false; } private bool RemoveQuestSequenceStopCondition(string questId) { bool num = _configuration.Stop.QuestSequences.Remove(questId); if (num) { _pluginInterface.SavePluginConfig(_configuration); } return num; } private Dictionary GetAllQuestSequenceStopConditions() { return _configuration.Stop.QuestSequences.Where>((KeyValuePair kvp) => kvp.Value.HasValue).ToDictionary((KeyValuePair kvp) => kvp.Key, (KeyValuePair kvp) => kvp.Value.Value); } private unsafe int GetAlliedSocietyRemainingAllowances() { QuestManager* ptr = QuestManager.Instance(); if (ptr == null) { return 12; } return (int)ptr->GetBeastTribeAllowance(); } private long GetAlliedSocietyTimeUntilReset() { TimeSpan item = AlliedSocietyJournalComponent.CalculateTimeUntilReset().TimeUntilReset; return item.Ticks; } private List GetAlliedSocietyAvailableQuestIds(byte alliedSocietyId) { if (!Enum.IsDefined(typeof(EAlliedSociety), alliedSocietyId)) { return new List(); } EAlliedSociety alliedSociety = (EAlliedSociety)alliedSocietyId; return (from q in _serviceProvider.GetRequiredService().GetAvailableAlliedSocietyQuests(alliedSociety) select q.ToString()).ToList(); } private Dictionary GetAlliedSocietyAllAvailableQuestCounts() { Dictionary dictionary = new Dictionary(); AlliedSocietyQuestFunctions requiredService = _serviceProvider.GetRequiredService(); EAlliedSociety[] values = Enum.GetValues(); foreach (EAlliedSociety eAlliedSociety in values) { if (eAlliedSociety != EAlliedSociety.None) { int count = requiredService.GetAvailableAlliedSocietyQuests(eAlliedSociety).Count; if (count > 0) { dictionary[(byte)eAlliedSociety] = count; } } } return dictionary; } private unsafe bool GetAlliedSocietyIsMaxRank(byte alliedSocietyId) { if (!Enum.IsDefined(typeof(EAlliedSociety), alliedSocietyId) || alliedSocietyId == 0) { return false; } QuestManager* ptr = QuestManager.Instance(); if (ptr == null) { return false; } byte b = (byte)(ptr->BeastReputation[alliedSocietyId - 1].Rank & 0x7F); return b >= (EAlliedSociety)alliedSocietyId switch { EAlliedSociety.Amaljaa => 3, EAlliedSociety.Sylphs => 3, EAlliedSociety.Kobolds => 3, EAlliedSociety.Sahagin => 3, EAlliedSociety.Ixal => 7, _ => 8, }; } private unsafe int GetAlliedSocietyCurrentRank(byte alliedSocietyId) { if (!Enum.IsDefined(typeof(EAlliedSociety), alliedSocietyId) || alliedSocietyId == 0) { return -1; } QuestManager* ptr = QuestManager.Instance(); if (ptr == null) { return -1; } return (byte)(ptr->BeastReputation[alliedSocietyId - 1].Rank & 0x7F); } private List GetAlliedSocietiesWithAvailableQuests() { List list = new List(); AlliedSocietyQuestFunctions requiredService = _serviceProvider.GetRequiredService(); EAlliedSociety[] values = Enum.GetValues(); foreach (EAlliedSociety eAlliedSociety in values) { if (eAlliedSociety != EAlliedSociety.None && requiredService.GetAvailableAlliedSocietyQuests(eAlliedSociety).Count > 0) { list.Add((byte)eAlliedSociety); } } return list; } private int AddAlliedSocietyOptimalQuests(byte alliedSocietyId) { if (!Enum.IsDefined(typeof(EAlliedSociety), alliedSocietyId) || alliedSocietyId == 0) { return 0; } EAlliedSociety eAlliedSociety = (EAlliedSociety)alliedSocietyId; List availableAlliedSocietyQuests = _serviceProvider.GetRequiredService().GetAvailableAlliedSocietyQuests(eAlliedSociety); if (availableAlliedSocietyQuests.Count == 0) { return 0; } Quest quest; List list = (from QuestInfo questInfo in availableAlliedSocietyQuests.Select((QuestId questId) => _questData.GetQuestInfo(questId)) where _questRegistry.TryGetQuest(questInfo.QuestId, out quest) && !quest.Root.Disabled where !_questController.ManualPriorityQuests.Any((Quest pq) => pq.Id.Equals(questInfo.QuestId)) orderby questInfo.AlliedSocietyRank descending select questInfo).ToList(); if (list.Count == 0) { return 0; } int val = (((int)eAlliedSociety <= 5) ? 12 : 3); int alliedSocietyRemainingAllowances = GetAlliedSocietyRemainingAllowances(); int count = Math.Min(Math.Min(val, alliedSocietyRemainingAllowances), list.Count); int num = 0; foreach (QuestInfo item in list.Take(count)) { if (_questController.AddQuestPriority(item.QuestId)) { num++; } } return num; } private List GetAlliedSocietyOptimalQuests(byte alliedSocietyId) { if (!Enum.IsDefined(typeof(EAlliedSociety), alliedSocietyId) || alliedSocietyId == 0) { return new List(); } EAlliedSociety eAlliedSociety = (EAlliedSociety)alliedSocietyId; List availableAlliedSocietyQuests = _serviceProvider.GetRequiredService().GetAvailableAlliedSocietyQuests(eAlliedSociety); if (availableAlliedSocietyQuests.Count == 0) { return new List(); } Quest quest; List list = (from QuestInfo questInfo in availableAlliedSocietyQuests.Select((QuestId questId) => _questData.GetQuestInfo(questId)) where _questRegistry.TryGetQuest(questInfo.QuestId, out quest) && !quest.Root.Disabled where !_questController.ManualPriorityQuests.Any((Quest pq) => pq.Id.Equals(questInfo.QuestId)) orderby questInfo.AlliedSocietyRank descending select questInfo).ToList(); if (list.Count == 0) { return new List(); } int val = (((int)eAlliedSociety <= 5) ? 12 : 3); int alliedSocietyRemainingAllowances = GetAlliedSocietyRemainingAllowances(); int count = Math.Min(Math.Min(val, alliedSocietyRemainingAllowances), list.Count); return (from q in list.Take(count) select q.QuestId.ToString()).ToList(); } public void Dispose() { _exportQuestPriority.UnregisterFunc(); _insertQuestPriority.UnregisterFunc(); _clearQuestPriority.UnregisterFunc(); _addQuestPriority.UnregisterFunc(); _importQuestPriority.UnregisterFunc(); _isQuestUnobtainable.UnregisterFunc(); _isQuestAccepted.UnregisterFunc(); _IsReadyToAcceptQuest.UnregisterFunc(); _IsQuestComplete.UnregisterFunc(); _isQuestLocked.UnregisterFunc(); _startSingleQuest.UnregisterFunc(); _startQuest.UnregisterFunc(); _getCurrentlyActiveEventQuests.UnregisterFunc(); _getCurrentTask.UnregisterFunc(); _getCurrentStepData.UnregisterFunc(); _getCurrentQuestId.UnregisterFunc(); _isRunning.UnregisterFunc(); _clearAllDutyModeOverrides.UnregisterFunc(); _clearDutyModeOverride.UnregisterFunc(); _setDutyModeOverride.UnregisterFunc(); _getDutyModeOverride.UnregisterFunc(); _setDefaultDutyMode.UnregisterFunc(); _getDefaultDutyMode.UnregisterFunc(); _hasAvailablePriorityQuests.UnregisterFunc(); _getQuestPriorityIndex.UnregisterFunc(); _isQuestInPriority.UnregisterFunc(); _isPresetAvailable.UnregisterFunc(); _addPresetToPriority.UnregisterFunc(); _getPresetQuests.UnregisterFunc(); _getAvailablePresets.UnregisterFunc(); _reorderPriorityQuest.UnregisterFunc(); _removePriorityQuest.UnregisterFunc(); _getPriorityQuests.UnregisterFunc(); _getAllQuestSequenceStopConditions.UnregisterFunc(); _removeQuestSequenceStopCondition.UnregisterFunc(); _setQuestSequenceStopCondition.UnregisterFunc(); _getQuestSequenceStopCondition.UnregisterFunc(); _setSequenceStopCondition.UnregisterFunc(); _getSequenceStopCondition.UnregisterFunc(); _setLevelStopCondition.UnregisterFunc(); _getLevelStopCondition.UnregisterFunc(); _clearStopQuests.UnregisterFunc(); _removeStopQuest.UnregisterFunc(); _addStopQuest.UnregisterFunc(); _getStopQuestList.UnregisterFunc(); _setStopConditionsEnabled.UnregisterFunc(); _getStopConditionsEnabled.UnregisterFunc(); _getAlliedSocietiesWithAvailableQuests.UnregisterFunc(); _getAlliedSocietyCurrentRank.UnregisterFunc(); _getAlliedSocietyIsMaxRank.UnregisterFunc(); _getAlliedSocietyAllAvailableQuestCounts.UnregisterFunc(); _getAlliedSocietyAvailableQuestIds.UnregisterFunc(); _getAlliedSocietyTimeUntilReset.UnregisterFunc(); _getAlliedSocietyRemainingAllowances.UnregisterFunc(); _addAlliedSocietyOptimalQuests.UnregisterFunc(); _getAlliedSocietyOptimalQuests.UnregisterFunc(); } }