using System; using System.Collections.Generic; using System.Linq; using Dalamud.Plugin; using Dalamud.Plugin.Ipc; using Dalamud.Plugin.Ipc.Exceptions; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps; using Questionable.Data; using Questionable.Model.Questing; namespace Questionable.External; internal sealed class AutoDutyIpc { public enum DutyMode { Support = 1, UnsyncRegular } private readonly IDalamudPluginInterface _pluginInterface; private readonly Configuration _configuration; private readonly TerritoryData _territoryData; private readonly ILogger _logger; private readonly ICallGateSubscriber _contentHasPath; private readonly ICallGateSubscriber _getConfig; private readonly ICallGateSubscriber _setConfig; private readonly ICallGateSubscriber _run; private readonly ICallGateSubscriber _start; private readonly ICallGateSubscriber _isStopped; private readonly ICallGateSubscriber _stop; private bool _loggedContentHasPathQueryWarning; private bool _loggedLevelingModeWarning; public const int MinimumLevelForLevelingMode = 15; public AutoDutyIpc(IDalamudPluginInterface pluginInterface, Configuration configuration, TerritoryData territoryData, ILogger logger) { _pluginInterface = pluginInterface; _configuration = configuration; _territoryData = territoryData; _logger = logger; _contentHasPath = pluginInterface.GetIpcSubscriber("AutoDuty.ContentHasPath"); _getConfig = pluginInterface.GetIpcSubscriber("AutoDuty.GetConfig"); _setConfig = pluginInterface.GetIpcSubscriber("AutoDuty.SetConfig"); _run = pluginInterface.GetIpcSubscriber("AutoDuty.Run"); _start = pluginInterface.GetIpcSubscriber("AutoDuty.Start"); _isStopped = pluginInterface.GetIpcSubscriber("AutoDuty.IsStopped"); _stop = pluginInterface.GetIpcSubscriber("AutoDuty.Stop"); _loggedContentHasPathQueryWarning = false; _loggedLevelingModeWarning = false; } public bool ManagesRotationPluginState() { try { return string.Equals(_getConfig.InvokeFunc("AutoManageRotationPluginState"), "True", StringComparison.OrdinalIgnoreCase); } catch (IpcError) { return false; } } public bool ManagesBossModAiSettings() { try { return string.Equals(_getConfig.InvokeFunc("AutoManageBossModAISettings"), "True", StringComparison.OrdinalIgnoreCase); } catch (IpcError) { return false; } } public bool IsConfiguredToRunContent(DutyOptions? dutyOptions) { if (dutyOptions == null || dutyOptions.ContentFinderConditionId == 0) { return false; } if (!_configuration.Duties.RunInstancedContentWithAutoDuty) { return false; } uint contentFinderConditionId = dutyOptions.ContentFinderConditionId; if (_configuration.Duties.BlacklistedDutyCfcIds.Contains(contentFinderConditionId)) { return false; } if (_configuration.Duties.WhitelistedDutyCfcIds.Contains(contentFinderConditionId) && _territoryData.TryGetContentFinderCondition(contentFinderConditionId, out TerritoryData.ContentFinderConditionData _)) { return true; } if (DutyRegistry.Duties.TryGetValue(contentFinderConditionId, out DutyEntry value) && value.Enabled) { return HasPath(contentFinderConditionId); } return false; } public bool IsConfiguredToRunLevelingMode() { return _configuration.Duties.RunLevelingModeWhenUnderleveled; } public bool IsConfiguredToRunLevelingMode(int currentPlayerLevel) { if (!_configuration.Duties.RunLevelingModeWhenUnderleveled) { return false; } if (currentPlayerLevel < 15) { _logger.LogDebug("Leveling mode is enabled but player level {CurrentLevel} is below minimum required level {MinLevel}", currentPlayerLevel, 15); return false; } return true; } public bool HasPath(uint cfcId) { if (!_territoryData.TryGetContentFinderCondition(cfcId, out TerritoryData.ContentFinderConditionData contentFinderConditionData)) { return false; } try { return _contentHasPath.InvokeFunc(contentFinderConditionData.TerritoryId); } catch (IpcError ipcError) { if (!_loggedContentHasPathQueryWarning) { _logger.LogWarning("Unable to query AutoDuty for path in territory {TerritoryType}: {Message}", contentFinderConditionData.TerritoryId, ipcError.Message); _loggedContentHasPathQueryWarning = true; } return false; } } public void StartInstance(uint cfcId, DutyMode dutyMode) { if (!_territoryData.TryGetContentFinderCondition(cfcId, out TerritoryData.ContentFinderConditionData contentFinderConditionData)) { throw new TaskException($"Unknown ContentFinderConditionId {cfcId}"); } try { _logger.LogDebug("Disabling AutoDuty leveling mode before starting specific duty {CfcId}", cfcId); _setConfig.InvokeAction("leveling", "None"); _setConfig.InvokeAction("Unsynced", $"{dutyMode == DutyMode.UnsyncRegular}"); ICallGateSubscriber setConfig = _setConfig; setConfig.InvokeAction("dutyModeEnum", dutyMode switch { DutyMode.Support => "Support", DutyMode.UnsyncRegular => "Regular", _ => throw new ArgumentOutOfRangeException("dutyMode", dutyMode, null), }); _run.InvokeAction(contentFinderConditionData.TerritoryId, 1, !_configuration.Advanced.DisableAutoDutyBareMode); } catch (IpcError ipcError) { throw new TaskException("Unable to run content with AutoDuty: " + ipcError.Message, ipcError); } } public bool StartLevelingMode() { try { if (!IsStopped()) { _logger.LogDebug("AutoDuty is already running, not starting leveling mode again"); return true; } _logger.LogDebug("Starting AutoDuty Leveling mode (Support) - AutoDuty will select the best dungeon"); _setConfig.InvokeAction("leveling", "Support"); _setConfig.InvokeAction("AutoDutyModeEnum", "Looping"); _start.InvokeAction(arg1: true); return true; } catch (IpcError ipcError) { if (!_loggedLevelingModeWarning) { _logger.LogWarning("Unable to start AutoDuty Leveling mode: {Message}", ipcError.Message); _loggedLevelingModeWarning = true; } return false; } catch (Exception exception) { if (!_loggedLevelingModeWarning) { _logger.LogWarning(exception, "Unable to start AutoDuty Leveling mode"); _loggedLevelingModeWarning = true; } return false; } } public string DescribeInstallation() { List list = (from p in _pluginInterface.InstalledPlugins where p.InternalName.Contains("AutoDuty", StringComparison.OrdinalIgnoreCase) || p.Name.Contains("AutoDuty", StringComparison.OrdinalIgnoreCase) select $"{p.InternalName} {p.Version} from '{p.Manifest.InstalledFromUrl}' (loaded: {p.IsLoaded}, dev: {p.IsDev})").ToList(); string value = ((list.Count > 0) ? string.Join("; ", list) : "no AutoDuty plugin installed"); string value2 = "IPC Run: " + (_run.HasAction ? "registered" : "missing") + ", IsStopped: " + (_isStopped.HasFunction ? "registered" : "missing"); string value3 = $"GetConfig probe: {ProbeConfig("Questionable.Probe")}, dutyModeEnum: {ProbeConfig("dutyModeEnum")}, LoopTimes: {ProbeConfig("LoopTimes")}, IsStopped: {ProbeIsStopped()}"; return $"{value}; {value2}; {value3}"; } private string ProbeConfig(string key) { try { return "'" + _getConfig.InvokeFunc(key) + "'"; } catch (IpcError ipcError) { return $"<{ipcError.GetType().Name}: {ipcError.Message}>"; } } private string ProbeIsStopped() { try { return _isStopped.InvokeFunc().ToString(); } catch (IpcError ipcError) { return $"<{ipcError.GetType().Name}: {ipcError.Message}>"; } } public bool IsStopped() { try { return _isStopped.InvokeFunc(); } catch (IpcError) { return true; } } public bool Stop() { try { _logger.LogDebug("Calling AutoDuty.Stop"); try { _setConfig.InvokeAction("leveling", "None"); } catch (IpcError) { } _stop.InvokeAction(); return true; } catch (IpcError ipcError2) { _logger.LogWarning("Unable to stop AutoDuty: {Message}", ipcError2.Message); return false; } } }