new Task(step.InteractionType, step.Comment),
EInteractionType.Duty when !autoDutyIpc.IsConfiguredToRunContent(step.ContentFinderConditionId, step.AutoDutyEnabled) =>
new Task(step.InteractionType, step.ContentFinderConditionId.HasValue
- ? territoryData.GetContentFinderConditionName(step.ContentFinderConditionId.Value)
+ ? territoryData.GetContentFinderCondition(step.ContentFinderConditionId.Value)?.Name
: step.Comment),
EInteractionType.SinglePlayerDuty => new Task(step.InteractionType, quest.Info.Name),
_ => null,
using System.Collections.Generic;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
+using FFXIVClientStructs.FFXIV.Client.Game;
+using LLib.Gear;
+using Questionable.Controller.Steps.Common;
using Questionable.Controller.Steps.Shared;
using Questionable.Data;
using Questionable.External;
}
internal sealed class StartAutoDutyExecutor(
+ GearStatsCalculator gearStatsCalculator,
AutoDutyIpc autoDutyIpc,
TerritoryData territoryData,
- IClientState clientState) : TaskExecutor<StartAutoDutyTask>
+ IClientState clientState,
+ IChatGui chatGui,
+ SendNotification.Executor sendNotificationExecutor) : TaskExecutor<StartAutoDutyTask>
{
protected override bool Start()
{
+ if (!territoryData.TryGetContentFinderCondition(Task.ContentFinderConditionId,
+ out var cfcData))
+ throw new TaskException("Failed to get territory ID for content finder condition");
+
+ unsafe
+ {
+ InventoryManager* inventoryManager = InventoryManager.Instance();
+ if (inventoryManager == null)
+ throw new TaskException("Inventory unavailable");
+
+ var equippedItems = inventoryManager->GetInventoryContainer(InventoryType.EquippedItems);
+ if (equippedItems == null)
+ throw new TaskException("Equipped items unavailable");
+
+ var currentItemLevel = gearStatsCalculator.CalculateAverageItemLevel(equippedItems);
+ if (cfcData.RequiredItemLevel > currentItemLevel)
+ {
+ string errorText =
+ $"Could not use AutoDuty to queue for {cfcData.Name}, required item level: {cfcData.RequiredItemLevel}, current item level: {currentItemLevel}.";
+ if (!sendNotificationExecutor.Start(new SendNotification.Task(EInteractionType.Duty, errorText)))
+ chatGui.PrintError(errorText, CommandHandler.MessageTag, CommandHandler.TagColor);
+
+ return false;
+ }
+ }
+
autoDutyIpc.StartInstance(Task.ContentFinderConditionId);
return true;
}
public override ETaskResult Update()
{
- if (!territoryData.TryGetTerritoryIdForContentFinderCondition(Task.ContentFinderConditionId,
- out uint territoryId))
+ if (!territoryData.TryGetContentFinderCondition(Task.ContentFinderConditionId,
+ out var cfcData))
throw new TaskException("Failed to get territory ID for content finder condition");
- return clientState.TerritoryType == territoryId ? ETaskResult.TaskComplete : ETaskResult.StillRunning;
+ return clientState.TerritoryType == cfcData.TerritoryId
+ ? ETaskResult.TaskComplete
+ : ETaskResult.StillRunning;
}
}
public override ETaskResult Update()
{
- if (!territoryData.TryGetTerritoryIdForContentFinderCondition(Task.ContentFinderConditionId,
- out uint territoryId))
+ if (!territoryData.TryGetContentFinderCondition(Task.ContentFinderConditionId,
+ out var cfcData))
throw new TaskException("Failed to get territory ID for content finder condition");
- return clientState.TerritoryType != territoryId && autoDutyIpc.IsStopped()
+ return clientState.TerritoryType != cfcData.TerritoryId && autoDutyIpc.IsStopped()
? ETaskResult.TaskComplete
: ETaskResult.StillRunning;
}
using System;
-using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using Dalamud.Game;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
-using FFXIVClientStructs.FFXIV.Client.Game.Character;
using Lumina.Excel.Sheets;
namespace Questionable.Data;
private readonly ImmutableHashSet<ushort> _territoriesWithMount;
private readonly ImmutableDictionary<ushort, uint> _dutyTerritories;
private readonly ImmutableDictionary<uint, string> _instanceNames;
- private readonly ImmutableDictionary<uint, string> _contentFinderConditionNames;
- private readonly ImmutableDictionary<uint, uint> _contentFinderConditionIds;
+ private readonly ImmutableDictionary<uint, ContentFinderConditionData> _contentFinderConditions;
public TerritoryData(IDataManager dataManager)
{
.Where(x => x.RowId > 0 && x.Content.RowId != 0 && x.ContentLinkType == 1 && x.ContentType.RowId != 6)
.ToImmutableDictionary(x => x.Content.RowId, x => x.Name.ToDalamudString().ToString());
- _contentFinderConditionNames = dataManager.GetExcelSheet<ContentFinderCondition>()
+ _contentFinderConditions = dataManager.GetExcelSheet<ContentFinderCondition>()
.Where(x => x.RowId > 0 && x.Content.RowId != 0 && x.ContentLinkType == 1 && x.ContentType.RowId != 6)
- .ToImmutableDictionary(x => x.RowId, x => FixName(x.Name.ToDalamudString().ToString(), dataManager.Language));
- _contentFinderConditionIds = dataManager.GetExcelSheet<ContentFinderCondition>()
- .Where(x => x.RowId > 0 && x.Content.RowId != 0 && x.ContentLinkType == 1 && x.ContentType.RowId != 6)
- .ToImmutableDictionary(x => x.RowId, x => x.TerritoryType.RowId);
+ .Select(x => new ContentFinderConditionData(x, dataManager.Language))
+ .ToImmutableDictionary(x => x.ContentFinderConditionId, x => x);
}
public string? GetName(ushort territoryId) => _territoryNames.GetValueOrDefault(territoryId);
public string? GetInstanceName(ushort instanceId) => _instanceNames.GetValueOrDefault(instanceId);
- public string? GetContentFinderConditionName(uint cfcId) => _contentFinderConditionNames.GetValueOrDefault(cfcId);
+ public ContentFinderConditionData? GetContentFinderCondition(uint cfcId) =>
+ _contentFinderConditions.GetValueOrDefault(cfcId);
- public bool TryGetTerritoryIdForContentFinderCondition(uint cfcId, out uint territoryId) =>
- _contentFinderConditionIds.TryGetValue(cfcId, out territoryId);
+ public bool TryGetContentFinderCondition(uint cfcId,
+ [NotNullWhen(true)] out ContentFinderConditionData? contentFinderConditionData) =>
+ _contentFinderConditions.TryGetValue(cfcId, out contentFinderConditionData);
private static string FixName(string name, ClientLanguage language)
{
return string.Concat(name[0].ToString().ToUpper(CultureInfo.InvariantCulture), name.AsSpan(1));
}
+
+ public sealed record ContentFinderConditionData(
+ uint ContentFinderConditionId,
+ string Name,
+ uint TerritoryId,
+ ushort RequiredItemLevel)
+ {
+ public ContentFinderConditionData(ContentFinderCondition condition, ClientLanguage clientLanguage)
+ : this(condition.RowId, FixName(condition.Name.ToDalamudString().ToString(), clientLanguage),
+ condition.TerritoryType.RowId, condition.ItemLevelRequired)
+ {
+ }
+ }
}
return false;
if (_configuration.Duties.WhitelistedDutyCfcIds.Contains(cfcId.Value) &&
- _territoryData.TryGetTerritoryIdForContentFinderCondition(cfcId.Value, out _))
+ _territoryData.TryGetContentFinderCondition(cfcId.Value, out _))
return true;
return autoDutyEnabled && HasPath(cfcId.Value);
public bool HasPath(uint cfcId)
{
- if (!_territoryData.TryGetTerritoryIdForContentFinderCondition(cfcId, out uint territoryType))
+ if (!_territoryData.TryGetContentFinderCondition(cfcId, out var cfcData))
return false;
try
{
- return _contentHasPath.InvokeFunc(territoryType);
+ return _contentHasPath.InvokeFunc(cfcData.TerritoryId);
}
catch (IpcError e)
{
- _logger.LogWarning("Unable to query AutoDuty for path in territory {TerritoryType}: {Message}", territoryType, e.Message);
+ _logger.LogWarning("Unable to query AutoDuty for path in territory {TerritoryType}: {Message}", cfcData.TerritoryId, e.Message);
return false;
}
}
public void StartInstance(uint cfcId)
{
- if (!_territoryData.TryGetTerritoryIdForContentFinderCondition(cfcId, out uint territoryType))
+ if (!_territoryData.TryGetContentFinderCondition(cfcId, out var cfcData))
throw new TaskException($"Unknown ContentFinderConditionId {cfcId}");
try
{
- _run.InvokeAction(territoryType, 0, true);
+ _run.InvokeAction(cfcData.TerritoryId, 0, true);
}
catch (IpcError e)
{
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using LLib;
+using LLib.Gear;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Questionable.Controller;
serviceCollection.AddSingleton<NotificationMasterIpc>();
serviceCollection.AddSingleton<AutomatonIpc>();
serviceCollection.AddSingleton<AutoDutyIpc>();
+
+ serviceCollection.AddSingleton<GearStatsCalculator>();
}
private static void AddTaskFactories(ServiceCollection serviceCollection)
{
Expansion = (EExpansionVersion)x.TerritoryType.Value.ExVersion.RowId,
CfcId = x.RowId,
- Name = territoryData.GetContentFinderConditionName(x.RowId) ?? "?",
+ Name = territoryData.GetContentFinderCondition(x.RowId)?.Name ?? "?",
TerritoryId = x.TerritoryType.RowId,
ContentType = x.ContentType.RowId,
Level = x.ClassJobLevelRequired,