muffin v7.38.8
This commit is contained in:
parent
5e2d8f648b
commit
3e10cbbbf2
51 changed files with 2585 additions and 1972 deletions
|
|
@ -0,0 +1,20 @@
|
|||
using Questionable.Functions;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class AbandonDutyCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly GameFunctions _gameFunctions;
|
||||
|
||||
public string CommandName => "abandon-duty";
|
||||
|
||||
public AbandonDutyCommandHandler(GameFunctions gameFunctions)
|
||||
{
|
||||
_gameFunctions = gameFunctions;
|
||||
}
|
||||
|
||||
public void Execute(string[] arguments)
|
||||
{
|
||||
_gameFunctions.AbandonDuty();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Questionable.Data;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model.Common;
|
||||
using Questionable.Model.Questing.Converter;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class AethernetCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly IDataManager _dataManager;
|
||||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly AetheryteFunctions _aetheryteFunctions;
|
||||
|
||||
private readonly IChatGui _chatGui;
|
||||
|
||||
public string CommandName => "aethernet";
|
||||
|
||||
public AethernetCommandHandler(IDataManager dataManager, IClientState clientState, AetheryteFunctions aetheryteFunctions, IChatGui chatGui)
|
||||
{
|
||||
_dataManager = dataManager;
|
||||
_clientState = clientState;
|
||||
_aetheryteFunctions = aetheryteFunctions;
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
|
||||
public void Execute(string[] arguments)
|
||||
{
|
||||
ushort territoryType = _clientState.TerritoryType;
|
||||
Dictionary<EAetheryteLocation, string> values = AethernetShardConverter.Values;
|
||||
AetheryteData aetheryteData = new AetheryteData(_dataManager);
|
||||
HashSet<string> hashSet = new HashSet<string>();
|
||||
Dictionary<string, List<(EAetheryteLocation, string, bool)>> dictionary = new Dictionary<string, List<(EAetheryteLocation, string, bool)>>();
|
||||
EAetheryteLocation key;
|
||||
string value;
|
||||
foreach (KeyValuePair<EAetheryteLocation, string> item3 in values)
|
||||
{
|
||||
item3.Deconstruct(out key, out value);
|
||||
EAetheryteLocation key2 = key;
|
||||
string text = value;
|
||||
if (aetheryteData.TerritoryIds.TryGetValue(key2, out var value2) && value2 == territoryType)
|
||||
{
|
||||
int num = text.IndexOf(']', StringComparison.Ordinal);
|
||||
if (num > 0)
|
||||
{
|
||||
string item = text.Substring(1, num - 1);
|
||||
hashSet.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hashSet.Count == 0)
|
||||
{
|
||||
_chatGui.Print("No aethernet shards found in current zone.", "Questionable", 576);
|
||||
return;
|
||||
}
|
||||
foreach (KeyValuePair<EAetheryteLocation, string> item4 in values)
|
||||
{
|
||||
item4.Deconstruct(out key, out value);
|
||||
EAetheryteLocation eAetheryteLocation = key;
|
||||
string text2 = value;
|
||||
int num2 = text2.IndexOf(']', StringComparison.Ordinal);
|
||||
if (num2 <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string text3 = text2.Substring(1, num2 - 1);
|
||||
if (hashSet.Contains(text3))
|
||||
{
|
||||
if (!dictionary.ContainsKey(text3))
|
||||
{
|
||||
dictionary[text3] = new List<(EAetheryteLocation, string, bool)>();
|
||||
}
|
||||
bool item2 = _aetheryteFunctions.IsAetheryteUnlocked(eAetheryteLocation);
|
||||
dictionary[text3].Add((eAetheryteLocation, text2, item2));
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<string, List<(EAetheryteLocation, string, bool)>> item5 in dictionary.OrderBy<KeyValuePair<string, List<(EAetheryteLocation, string, bool)>>, string>((KeyValuePair<string, List<(EAetheryteLocation Location, string Name, bool Unlocked)>> x) => x.Key))
|
||||
{
|
||||
item5.Deconstruct(out value, out var value3);
|
||||
string value4 = value;
|
||||
List<(EAetheryteLocation, string, bool)> list = value3;
|
||||
List<(EAetheryteLocation, string, bool)> list2 = list.Where<(EAetheryteLocation, string, bool)>(((EAetheryteLocation Location, string Name, bool Unlocked) x) => x.Unlocked).ToList();
|
||||
List<(EAetheryteLocation, string, bool)> list3 = list.Where<(EAetheryteLocation, string, bool)>(((EAetheryteLocation Location, string Name, bool Unlocked) x) => !x.Unlocked).ToList();
|
||||
_chatGui.Print($"Aethernet Shards in {value4} ({list.Count} total):", "Questionable", 576);
|
||||
_chatGui.Print($" Unlocked: {list2.Count}", "Questionable", 576);
|
||||
_chatGui.Print($" Missing: {list3.Count}", "Questionable", 576);
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
if (list3.Count > 0)
|
||||
{
|
||||
_chatGui.Print("Missing/Unattuned Aethernet Shards:", "Questionable", 576);
|
||||
foreach (var item6 in list3.OrderBy<(EAetheryteLocation, string, bool), string>(((EAetheryteLocation Location, string Name, bool Unlocked) x) => x.Name))
|
||||
{
|
||||
_chatGui.Print(" " + item6.Item2, "Questionable", 576);
|
||||
}
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
}
|
||||
if (list2.Count > 0)
|
||||
{
|
||||
_chatGui.Print("Unlocked Aethernet Shards:", "Questionable", 576);
|
||||
foreach (var item7 in list2.OrderBy<(EAetheryteLocation, string, bool), string>(((EAetheryteLocation Location, string Name, bool Unlocked) x) => x.Name))
|
||||
{
|
||||
_chatGui.Print(" " + item7.Item2, "Questionable", 576);
|
||||
}
|
||||
}
|
||||
if (dictionary.Count > 1)
|
||||
{
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class DebugCommandExecutor
|
||||
{
|
||||
private readonly Dictionary<string, IDebugCommandHandler> _handlers;
|
||||
|
||||
public DebugCommandExecutor(IEnumerable<IDebugCommandHandler> handlers)
|
||||
{
|
||||
_handlers = handlers.ToDictionary<IDebugCommandHandler, string>((IDebugCommandHandler h) => h.CommandName, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public bool TryExecute(string command, string[] arguments)
|
||||
{
|
||||
if (_handlers.TryGetValue(command, out IDebugCommandHandler value))
|
||||
{
|
||||
value.Execute(arguments);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
using Questionable.Windows;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class DebugOverlayCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly DebugOverlay _debugOverlay;
|
||||
|
||||
private readonly QuestRegistry _questRegistry;
|
||||
|
||||
private readonly IChatGui _chatGui;
|
||||
|
||||
public string CommandName => "do";
|
||||
|
||||
public DebugOverlayCommandHandler(DebugOverlay debugOverlay, QuestRegistry questRegistry, IChatGui chatGui)
|
||||
{
|
||||
_debugOverlay = debugOverlay;
|
||||
_questRegistry = questRegistry;
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
|
||||
public void Execute(string[] arguments)
|
||||
{
|
||||
ElementId elementId;
|
||||
if (!_debugOverlay.DrawConditions())
|
||||
{
|
||||
_chatGui.PrintError("You don't have the debug overlay enabled.", "Questionable", 576);
|
||||
}
|
||||
else if (arguments.Length >= 1 && ElementId.TryFromString(arguments[0], out elementId) && elementId != null)
|
||||
{
|
||||
if (_questRegistry.TryGetQuest(elementId, out Quest quest))
|
||||
{
|
||||
_debugOverlay.HighlightedQuest = quest.Id;
|
||||
_chatGui.Print($"Set highlighted quest to {elementId} ({quest.Info.Name}).", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.PrintError($"Unknown quest {elementId}.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_debugOverlay.HighlightedQuest = null;
|
||||
_chatGui.Print("Cleared highlighted quest.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
using System.Collections.Generic;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class FestivalsCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly IChatGui _chatGui;
|
||||
|
||||
public string CommandName => "festivals";
|
||||
|
||||
public FestivalsCommandHandler(IChatGui chatGui)
|
||||
{
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
|
||||
public unsafe void Execute(string[] arguments)
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
for (byte b = 0; b < 4; b++)
|
||||
{
|
||||
GameMain.Festival festival = GameMain.Instance()->ActiveFestivals[b];
|
||||
if (festival.Id == 0)
|
||||
{
|
||||
list.Add($"Slot {b}: None");
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add($"Slot {b}: {festival.Id}({festival.Phase})");
|
||||
}
|
||||
}
|
||||
_chatGui.Print("Festival slots:", "Questionable", 576);
|
||||
foreach (string item in list)
|
||||
{
|
||||
_chatGui.Print(" " + item, "Questionable", 576);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal interface IDebugCommandHandler
|
||||
{
|
||||
string CommandName { get; }
|
||||
|
||||
void Execute(string[] arguments);
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Functions;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class MountIdCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly GameFunctions _gameFunctions;
|
||||
|
||||
private readonly IDataManager _dataManager;
|
||||
|
||||
private readonly IChatGui _chatGui;
|
||||
|
||||
public string CommandName => "mountid";
|
||||
|
||||
public MountIdCommandHandler(GameFunctions gameFunctions, IDataManager dataManager, IChatGui chatGui)
|
||||
{
|
||||
_gameFunctions = gameFunctions;
|
||||
_dataManager = dataManager;
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
|
||||
public void Execute(string[] arguments)
|
||||
{
|
||||
ushort? mountId = _gameFunctions.GetMountId();
|
||||
if (mountId.HasValue)
|
||||
{
|
||||
Mount? rowOrDefault = _dataManager.GetExcelSheet<Mount>().GetRowOrDefault(mountId.Value);
|
||||
_chatGui.Print($"Mount ID: {mountId}, Name: {rowOrDefault?.Singular}, Obtainable: {((rowOrDefault?.Order == -1) ? "No" : "Yes")}", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.Print("You are not mounted.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class NextQuestCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly QuestController _questController;
|
||||
|
||||
private readonly QuestRegistry _questRegistry;
|
||||
|
||||
private readonly QuestFunctions _questFunctions;
|
||||
|
||||
private readonly IChatGui _chatGui;
|
||||
|
||||
public string CommandName => "next";
|
||||
|
||||
public NextQuestCommandHandler(QuestController questController, QuestRegistry questRegistry, QuestFunctions questFunctions, IChatGui chatGui)
|
||||
{
|
||||
_questController = questController;
|
||||
_questRegistry = questRegistry;
|
||||
_questFunctions = questFunctions;
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
|
||||
public void Execute(string[] arguments)
|
||||
{
|
||||
if (arguments.Length >= 1 && ElementId.TryFromString(arguments[0], out ElementId elementId) && elementId != null)
|
||||
{
|
||||
Quest quest;
|
||||
if (_questFunctions.IsQuestLocked(elementId))
|
||||
{
|
||||
_chatGui.PrintError($"Quest {elementId} is locked.", "Questionable", 576);
|
||||
}
|
||||
else if (_questRegistry.TryGetQuest(elementId, out quest))
|
||||
{
|
||||
_questController.SetNextQuest(quest);
|
||||
_chatGui.Print($"Set next quest to {elementId} ({quest.Info.Name}).", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.PrintError($"Unknown quest {elementId}.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_questController.SetNextQuest(null);
|
||||
_chatGui.Print("Cleared next quest.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class QuestKillsCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly QuestController _questController;
|
||||
|
||||
private readonly QuestFunctions _questFunctions;
|
||||
|
||||
private readonly IDataManager _dataManager;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly IChatGui _chatGui;
|
||||
|
||||
public string CommandName => "quest-kills";
|
||||
|
||||
public QuestKillsCommandHandler(QuestController questController, QuestFunctions questFunctions, IDataManager dataManager, IObjectTable objectTable, IChatGui chatGui)
|
||||
{
|
||||
_questController = questController;
|
||||
_questFunctions = questFunctions;
|
||||
_dataManager = dataManager;
|
||||
_objectTable = objectTable;
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
|
||||
public void Execute(string[] arguments)
|
||||
{
|
||||
(QuestController.QuestProgress, QuestController.ECurrentQuestType)? currentQuestDetails = _questController.CurrentQuestDetails;
|
||||
if (!currentQuestDetails.HasValue)
|
||||
{
|
||||
_chatGui.PrintError("No active quest.", "Questionable", 576);
|
||||
return;
|
||||
}
|
||||
QuestController.QuestProgress item = currentQuestDetails.Value.Item1;
|
||||
Questionable.Model.Quest quest = item.Quest;
|
||||
QuestProgressInfo questProgressInfo = null;
|
||||
if (quest.Id is QuestId elementId)
|
||||
{
|
||||
questProgressInfo = _questFunctions.GetQuestProgressInfo(elementId);
|
||||
}
|
||||
if (questProgressInfo == null)
|
||||
{
|
||||
_chatGui.PrintError("Unable to retrieve quest progress information.", "Questionable", 576);
|
||||
return;
|
||||
}
|
||||
QuestSequence questSequence = quest.FindSequence(item.Sequence);
|
||||
if (questSequence == null)
|
||||
{
|
||||
_chatGui.PrintError($"Sequence {item.Sequence} not found for quest {quest.Id}.", "Questionable", 576);
|
||||
return;
|
||||
}
|
||||
QuestStep questStep = ((item.Step < questSequence.Steps.Count) ? questSequence.Steps[item.Step] : null);
|
||||
if (questStep == null)
|
||||
{
|
||||
_chatGui.PrintError($"Step {item.Step} not found in sequence {item.Sequence}.", "Questionable", 576);
|
||||
return;
|
||||
}
|
||||
_chatGui.Print($"Quest: {quest.Info.Name} ({quest.Id})", "Questionable", 576);
|
||||
_chatGui.Print($"Sequence: {item.Sequence}, Step: {item.Step}", "Questionable", 576);
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
_chatGui.Print("Quest Variables: " + string.Join(", ", questProgressInfo.Variables.Select((byte v, int i) => $"[{i}]={v}")), "Questionable", 576);
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
ExcelSheet<BNpcName> bnpcNameSheet = _dataManager.GetExcelSheet<BNpcName>();
|
||||
HashSet<uint> hashSet = new HashSet<uint>(questStep.KillEnemyDataIds);
|
||||
foreach (ComplexCombatData complexCombatDatum in questStep.ComplexCombatData)
|
||||
{
|
||||
hashSet.Add(complexCombatDatum.DataId);
|
||||
}
|
||||
if (hashSet.Count > 0)
|
||||
{
|
||||
_chatGui.Print($"All Enemy DataIds Found: {hashSet.Count}", "Questionable", 576);
|
||||
foreach (uint item3 in hashSet.OrderBy((uint x) => x))
|
||||
{
|
||||
(string Name, bool Found) tuple = GetEnemyName(item3);
|
||||
var (value, _) = tuple;
|
||||
if (tuple.Found)
|
||||
{
|
||||
_chatGui.Print($" - {value} (DataId: {item3})", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.Print($" - DataId: {item3}", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
}
|
||||
if (questStep.ComplexCombatData.Count > 0)
|
||||
{
|
||||
_chatGui.Print($"Complex Combat Data Entries: {questStep.ComplexCombatData.Count}", "Questionable", 576);
|
||||
_chatGui.Print("Kill Progress:", "Questionable", 576);
|
||||
if (questStep.ComplexCombatData.Count == 1 && hashSet.Count > 1)
|
||||
{
|
||||
ComplexCombatData complexCombatData = questStep.ComplexCombatData[0];
|
||||
int num = -1;
|
||||
byte? b = null;
|
||||
for (int num2 = 0; num2 < complexCombatData.CompletionQuestVariablesFlags.Count; num2++)
|
||||
{
|
||||
QuestWorkValue questWorkValue = complexCombatData.CompletionQuestVariablesFlags[num2];
|
||||
if (questWorkValue != null && questWorkValue.Low.HasValue)
|
||||
{
|
||||
num = num2;
|
||||
b = questWorkValue.Low;
|
||||
break;
|
||||
}
|
||||
}
|
||||
byte b2 = (byte)(((num >= 0 && num < questProgressInfo.Variables.Count) ? questProgressInfo.Variables[num] : 0) & 0xF);
|
||||
string value2 = (b.HasValue ? $" {b2}/{b}" : "");
|
||||
string value3 = ((b.HasValue && b2 >= b) ? "✓" : "○");
|
||||
foreach (uint item4 in hashSet.OrderBy((uint x) => x))
|
||||
{
|
||||
(string Name, bool Found) tuple3 = GetEnemyName(item4);
|
||||
var (value4, _) = tuple3;
|
||||
if (tuple3.Found)
|
||||
{
|
||||
_chatGui.Print($" {value3} Slay {value4}.{value2} (DataId: {item4})", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.Print($" {value3} Slay enemy.{value2} (DataId: {item4})", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int num3 = 0; num3 < questStep.ComplexCombatData.Count; num3++)
|
||||
{
|
||||
ComplexCombatData complexCombatData2 = questStep.ComplexCombatData[num3];
|
||||
int num4 = -1;
|
||||
byte? b3 = null;
|
||||
bool flag = false;
|
||||
for (int num5 = 0; num5 < complexCombatData2.CompletionQuestVariablesFlags.Count; num5++)
|
||||
{
|
||||
QuestWorkValue questWorkValue2 = complexCombatData2.CompletionQuestVariablesFlags[num5];
|
||||
if (questWorkValue2 != null)
|
||||
{
|
||||
if (questWorkValue2.Low.HasValue)
|
||||
{
|
||||
num4 = num5;
|
||||
b3 = questWorkValue2.Low;
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
if (questWorkValue2.High.HasValue)
|
||||
{
|
||||
num4 = num5;
|
||||
b3 = questWorkValue2.High;
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
byte b4 = (byte)((num4 >= 0 && num4 < questProgressInfo.Variables.Count) ? questProgressInfo.Variables[num4] : 0);
|
||||
byte b5 = (flag ? ((byte)(b4 >> 4)) : ((byte)(b4 & 0xF)));
|
||||
string value5;
|
||||
if (complexCombatData2.NameId.HasValue)
|
||||
{
|
||||
BNpcName? bNpcName = bnpcNameSheet?.GetRowOrDefault(complexCombatData2.NameId.Value);
|
||||
value5 = ((!bNpcName.HasValue || string.IsNullOrEmpty(bNpcName.Value.Singular.ToString())) ? "enemy" : bNpcName.Value.Singular.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
(string Name, bool Found) tuple5 = GetEnemyName(complexCombatData2.DataId);
|
||||
string item2 = tuple5.Name;
|
||||
value5 = (tuple5.Found ? item2 : "enemy");
|
||||
}
|
||||
string value6 = (b3.HasValue ? $" {b5}/{b3}" : "");
|
||||
string value7 = ((b3.HasValue && b5 >= b3) ? "✓" : "○");
|
||||
string value8 = (complexCombatData2.NameId.HasValue ? $" (DataId: {complexCombatData2.DataId}, NameId: {complexCombatData2.NameId})" : $" (DataId: {complexCombatData2.DataId})");
|
||||
_chatGui.Print($" {value7} Slay {value5}.{value6}{value8}", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
}
|
||||
else if (questStep.KillEnemyDataIds.Count == 0)
|
||||
{
|
||||
_chatGui.Print("No kill enemy data for this step.", "Questionable", 576);
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
}
|
||||
if (questStep.CompletionQuestVariablesFlags.Count <= 0 || !questStep.CompletionQuestVariablesFlags.Any((QuestWorkValue x) => x != null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_chatGui.Print("Completion Flags (Debug):", "Questionable", 576);
|
||||
for (int num6 = 0; num6 < questStep.CompletionQuestVariablesFlags.Count; num6++)
|
||||
{
|
||||
QuestWorkValue questWorkValue3 = questStep.CompletionQuestVariablesFlags[num6];
|
||||
if (questWorkValue3 != null)
|
||||
{
|
||||
int num7 = ((num6 < questProgressInfo.Variables.Count) ? questProgressInfo.Variables[num6] : 0);
|
||||
byte b6 = (byte)(num7 >> 4);
|
||||
byte b7 = (byte)(num7 & 0xF);
|
||||
string value9 = (((!questWorkValue3.High.HasValue || questWorkValue3.High == b6) && (!questWorkValue3.Low.HasValue || questWorkValue3.Low == b7)) ? " ✓" : " ✗");
|
||||
_chatGui.Print($" [{num6}] Expected: H={questWorkValue3.High?.ToString(CultureInfo.InvariantCulture) ?? "any"} L={questWorkValue3.Low?.ToString(CultureInfo.InvariantCulture) ?? "any"} | Actual: H={b6.ToString(CultureInfo.InvariantCulture)} L={b7.ToString(CultureInfo.InvariantCulture)}{value9}", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
(string Name, bool Found) GetEnemyName(uint dataId)
|
||||
{
|
||||
if (_objectTable.FirstOrDefault((IGameObject x) => x is IBattleNpc battleNpc2 && battleNpc2.BaseId == dataId) is IBattleNpc { NameId: not 0u } battleNpc)
|
||||
{
|
||||
BNpcName? bNpcName2 = bnpcNameSheet?.GetRowOrDefault(battleNpc.NameId);
|
||||
if (bNpcName2.HasValue && !string.IsNullOrEmpty(bNpcName2.Value.Singular.ToString()))
|
||||
{
|
||||
return (Name: bNpcName2.Value.Singular.ToString(), Found: true);
|
||||
}
|
||||
}
|
||||
return (Name: string.Empty, Found: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using Questionable.Windows;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class SequencesCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly QuestSequenceWindow _questSequenceWindow;
|
||||
|
||||
public string CommandName => "seq";
|
||||
|
||||
public SequencesCommandHandler(QuestSequenceWindow questSequenceWindow)
|
||||
{
|
||||
_questSequenceWindow = questSequenceWindow;
|
||||
}
|
||||
|
||||
public void Execute(string[] arguments)
|
||||
{
|
||||
_questSequenceWindow.ToggleOrUncollapse();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using Questionable.Windows;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class SetupCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly OneTimeSetupWindow _oneTimeSetupWindow;
|
||||
|
||||
public string CommandName => "setup";
|
||||
|
||||
public SetupCommandHandler(OneTimeSetupWindow oneTimeSetupWindow)
|
||||
{
|
||||
_oneTimeSetupWindow = oneTimeSetupWindow;
|
||||
}
|
||||
|
||||
public void Execute(string[] arguments)
|
||||
{
|
||||
_oneTimeSetupWindow.IsOpenAndUncollapsed = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class SimulateQuestCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly QuestController _questController;
|
||||
|
||||
private readonly QuestRegistry _questRegistry;
|
||||
|
||||
private readonly IChatGui _chatGui;
|
||||
|
||||
public string CommandName => "sim";
|
||||
|
||||
public SimulateQuestCommandHandler(QuestController questController, QuestRegistry questRegistry, IChatGui chatGui)
|
||||
{
|
||||
_questController = questController;
|
||||
_questRegistry = questRegistry;
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
|
||||
public void Execute(string[] arguments)
|
||||
{
|
||||
if (arguments.Length >= 1 && ElementId.TryFromString(arguments[0], out ElementId elementId) && elementId != null)
|
||||
{
|
||||
if (_questRegistry.TryGetQuest(elementId, out Quest quest))
|
||||
{
|
||||
byte sequence = 0;
|
||||
int step = 0;
|
||||
if (arguments.Length >= 2 && byte.TryParse(arguments[1], out var result))
|
||||
{
|
||||
QuestSequence questSequence = quest.FindSequence(result);
|
||||
if (questSequence != null)
|
||||
{
|
||||
sequence = questSequence.Sequence;
|
||||
if (arguments.Length >= 3 && int.TryParse(arguments[2], out var result2) && questSequence.FindStep(result2) != null)
|
||||
{
|
||||
step = result2;
|
||||
}
|
||||
}
|
||||
}
|
||||
_questController.SimulateQuest(quest, sequence, step);
|
||||
_chatGui.Print($"Simulating quest {elementId} ({quest.Info.Name}).", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.PrintError($"Unknown quest {elementId}.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_questController.SimulateQuest(null, 0, 0);
|
||||
_chatGui.Print("Cleared simulated quest.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using System.Collections.Generic;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class TaxiCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly IDataManager _dataManager;
|
||||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly IChatGui _chatGui;
|
||||
|
||||
public string CommandName => "taxi";
|
||||
|
||||
public TaxiCommandHandler(IDataManager dataManager, IClientState clientState, IChatGui chatGui)
|
||||
{
|
||||
_dataManager = dataManager;
|
||||
_clientState = clientState;
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
|
||||
public unsafe void Execute(string[] arguments)
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
ExcelSheet<ChocoboTaxiStand> excelSheet = _dataManager.GetExcelSheet<ChocoboTaxiStand>();
|
||||
UIState* ptr = UIState.Instance();
|
||||
if (ptr == null)
|
||||
{
|
||||
_chatGui.PrintError("UIState is null", "Questionable", 576);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < 192; i++)
|
||||
{
|
||||
uint num = (uint)(i + 1179648);
|
||||
try
|
||||
{
|
||||
if (excelSheet.HasRow(num) && ptr->IsChocoboTaxiStandUnlocked(num))
|
||||
{
|
||||
string value = excelSheet.GetRow(num).PlaceName.ToString();
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
value = "Unknown";
|
||||
}
|
||||
list.Add($"{value} (ID: {i}, Row: 0x{num:X})");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
_chatGui.Print($"Unlocked taxi stands ({list.Count}):", "Questionable", 576);
|
||||
if (list.Count == 0)
|
||||
{
|
||||
_chatGui.Print(" (No unlocked taxi stands found)", "Questionable", 576);
|
||||
return;
|
||||
}
|
||||
foreach (string item in list)
|
||||
{
|
||||
_chatGui.Print(" - " + item, "Questionable", 576);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Questionable.Functions;
|
||||
|
||||
namespace Questionable.Controller.DebugCommands;
|
||||
|
||||
internal sealed class UnlockLinksCommandHandler : IDebugCommandHandler
|
||||
{
|
||||
private readonly GameFunctions _gameFunctions;
|
||||
|
||||
private readonly IChatGui _chatGui;
|
||||
|
||||
private IReadOnlyList<uint> _previouslyUnlockedUnlockLinks = Array.Empty<uint>();
|
||||
|
||||
public string CommandName => "unlock-links";
|
||||
|
||||
public UnlockLinksCommandHandler(GameFunctions gameFunctions, IChatGui chatGui)
|
||||
{
|
||||
_gameFunctions = gameFunctions;
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
|
||||
public void Execute(string[] arguments)
|
||||
{
|
||||
IReadOnlyList<uint> unlockLinks = _gameFunctions.GetUnlockLinks();
|
||||
if (unlockLinks.Count >= 0)
|
||||
{
|
||||
_chatGui.Print($"Saved {unlockLinks.Count} unlock links to log.", "Questionable", 576);
|
||||
List<uint> list = unlockLinks.Except(_previouslyUnlockedUnlockLinks).ToList();
|
||||
if (_previouslyUnlockedUnlockLinks.Count > 0 && list.Count > 0)
|
||||
{
|
||||
_chatGui.Print("New unlock links: " + string.Join(", ", list), "Questionable", 576);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.PrintError("Could not query unlock links.", "Questionable", 576);
|
||||
}
|
||||
_previouslyUnlockedUnlockLinks = unlockLinks;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_previouslyUnlockedUnlockLinks = Array.Empty<uint>();
|
||||
}
|
||||
}
|
||||
|
|
@ -58,6 +58,8 @@ internal sealed class InteractionUiController : IDisposable
|
|||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly ShopController _shopController;
|
||||
|
||||
private readonly BossModIpc _bossModIpc;
|
||||
|
|
@ -84,7 +86,7 @@ internal sealed class InteractionUiController : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public unsafe InteractionUiController(IAddonLifecycle addonLifecycle, IDataManager dataManager, QuestFunctions questFunctions, AetheryteFunctions aetheryteFunctions, ExcelFunctions excelFunctions, QuestController questController, GatheringPointRegistry gatheringPointRegistry, QuestRegistry questRegistry, QuestData questData, TerritoryData territoryData, IGameGui gameGui, ITargetManager targetManager, IPluginLog pluginLog, IClientState clientState, ShopController shopController, BossModIpc bossModIpc, Configuration configuration, ILogger<InteractionUiController> logger)
|
||||
public unsafe InteractionUiController(IAddonLifecycle addonLifecycle, IDataManager dataManager, QuestFunctions questFunctions, AetheryteFunctions aetheryteFunctions, ExcelFunctions excelFunctions, QuestController questController, GatheringPointRegistry gatheringPointRegistry, QuestRegistry questRegistry, QuestData questData, TerritoryData territoryData, IGameGui gameGui, ITargetManager targetManager, IPluginLog pluginLog, IClientState clientState, IObjectTable objectTable, ShopController shopController, BossModIpc bossModIpc, Configuration configuration, ILogger<InteractionUiController> logger)
|
||||
{
|
||||
_addonLifecycle = addonLifecycle;
|
||||
_dataManager = dataManager;
|
||||
|
|
@ -99,6 +101,7 @@ internal sealed class InteractionUiController : IDisposable
|
|||
_gameGui = gameGui;
|
||||
_targetManager = targetManager;
|
||||
_clientState = clientState;
|
||||
_objectTable = objectTable;
|
||||
_shopController = shopController;
|
||||
_bossModIpc = bossModIpc;
|
||||
_configuration = configuration;
|
||||
|
|
@ -857,14 +860,18 @@ internal sealed class InteractionUiController : IDisposable
|
|||
{
|
||||
_logger.LogTrace("FindTargetTerritoryFromQuestStep (current): {CurrentTerritory}, {TargetTerritory}", questStep.TerritoryId, questStep.TargetTerritoryId);
|
||||
}
|
||||
if (questStep != null && (questStep.TerritoryId != _clientState.TerritoryType || !questStep.TargetTerritoryId.HasValue) && questStep.InteractionType == EInteractionType.Gather && _gatheringPointRegistry.TryGetGatheringPointId(questStep.ItemsToGather[0].ItemId, ((EClassJob?)_clientState.LocalPlayer?.ClassJob.RowId).GetValueOrDefault(), out GatheringPointId gatheringPointId) && _gatheringPointRegistry.TryGetGatheringPoint(gatheringPointId, out GatheringRoot gatheringRoot))
|
||||
if (questStep != null && (questStep.TerritoryId != _clientState.TerritoryType || !questStep.TargetTerritoryId.HasValue) && questStep.InteractionType == EInteractionType.Gather)
|
||||
{
|
||||
foreach (QuestStep step in gatheringRoot.Steps)
|
||||
IGameObject gameObject = _objectTable[0];
|
||||
if (_gatheringPointRegistry.TryGetGatheringPointId(questStep.ItemsToGather[0].ItemId, ((EClassJob?)(gameObject as ICharacter)?.ClassJob.RowId).GetValueOrDefault(), out GatheringPointId gatheringPointId) && _gatheringPointRegistry.TryGetGatheringPoint(gatheringPointId, out GatheringRoot gatheringRoot))
|
||||
{
|
||||
if (step.TerritoryId == _clientState.TerritoryType && step.TargetTerritoryId.HasValue)
|
||||
foreach (QuestStep step in gatheringRoot.Steps)
|
||||
{
|
||||
_logger.LogTrace("FindTargetTerritoryFromQuestStep (gathering): {CurrentTerritory}, {TargetTerritory}", step.TerritoryId, step.TargetTerritoryId);
|
||||
return step.TargetTerritoryId;
|
||||
if (step.TerritoryId == _clientState.TerritoryType && step.TargetTerritoryId.HasValue)
|
||||
{
|
||||
_logger.LogTrace("FindTargetTerritoryFromQuestStep (gathering): {CurrentTerritory}, {TargetTerritory}", step.TerritoryId, step.TargetTerritoryId);
|
||||
return step.TargetTerritoryId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ internal static class Mount
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class MountEvaluator(GameFunctions gameFunctions, ICondition condition, TerritoryData territoryData, IClientState clientState, ILogger<MountEvaluator> logger)
|
||||
internal sealed class MountEvaluator(GameFunctions gameFunctions, ICondition condition, TerritoryData territoryData, IClientState clientState, IObjectTable objectTable, ILogger<MountEvaluator> logger)
|
||||
{
|
||||
public unsafe MountResult EvaluateMountState(MountTask task, bool dryRun, ref DateTime retryAt)
|
||||
{
|
||||
|
|
@ -71,7 +71,7 @@ internal static class Mount
|
|||
}
|
||||
if (task.MountIf == EMountIf.AwayFromPosition)
|
||||
{
|
||||
float num = System.Numerics.Vector3.Distance((FFXIVClientStructs.FFXIV.Common.Math.Vector3)(clientState.LocalPlayer?.Position ?? ((System.Numerics.Vector3)FFXIVClientStructs.FFXIV.Common.Math.Vector3.Zero)), task.Position.GetValueOrDefault());
|
||||
float num = System.Numerics.Vector3.Distance((FFXIVClientStructs.FFXIV.Common.Math.Vector3)(objectTable[0]?.Position ?? ((System.Numerics.Vector3)FFXIVClientStructs.FFXIV.Common.Math.Vector3.Zero)), task.Position.GetValueOrDefault());
|
||||
if (task.TerritoryId == clientState.TerritoryType && num < 30f && !Conditions.Instance()->Diving)
|
||||
{
|
||||
logger.Log(logLevel, "Not using mount, as we're close to the target");
|
||||
|
|
@ -159,7 +159,7 @@ internal static class Mount
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class UnmountExecutor(ICondition condition, ILogger<UnmountTask> logger, GameFunctions gameFunctions, IClientState clientState) : TaskExecutor<UnmountTask>()
|
||||
internal sealed class UnmountExecutor(ICondition condition, ILogger<UnmountTask> logger, GameFunctions gameFunctions, IObjectTable objectTable) : TaskExecutor<UnmountTask>()
|
||||
{
|
||||
private bool _unmountTriggered;
|
||||
|
||||
|
|
@ -221,10 +221,9 @@ internal static class Mount
|
|||
|
||||
private unsafe bool IsUnmounting()
|
||||
{
|
||||
IPlayerCharacter localPlayer = clientState.LocalPlayer;
|
||||
if (localPlayer != null)
|
||||
if (objectTable[0] is IPlayerCharacter playerCharacter)
|
||||
{
|
||||
BattleChara* address = (BattleChara*)localPlayer.Address;
|
||||
BattleChara* address = (BattleChara*)playerCharacter.Address;
|
||||
return (address->Mount.Flags & 1) == 1;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
|
|
@ -30,7 +31,7 @@ internal static class DoGather
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class GatherExecutor(GatheringController gatheringController, GameFunctions gameFunctions, IGameGui gameGui, IClientState clientState, ICondition condition, ILogger<GatherExecutor> logger) : TaskExecutor<Task>()
|
||||
internal sealed class GatherExecutor(GatheringController gatheringController, GameFunctions gameFunctions, IGameGui gameGui, IObjectTable objectTable, ICondition condition, ILogger<GatherExecutor> logger) : TaskExecutor<Task>()
|
||||
{
|
||||
private bool _wasGathering;
|
||||
|
||||
|
|
@ -268,7 +269,7 @@ internal static class DoGather
|
|||
|
||||
private EAction PickAction(EAction minerAction, EAction botanistAction)
|
||||
{
|
||||
if (clientState.LocalPlayer?.ClassJob.RowId == 16)
|
||||
if ((objectTable[0] as ICharacter)?.ClassJob.RowId == 16)
|
||||
{
|
||||
return minerAction;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
|
@ -27,7 +28,7 @@ internal static class DoGatherCollectable
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class GatherCollectableExecutor(GatheringController gatheringController, GameFunctions gameFunctions, IClientState clientState, IGameGui gameGui, ILogger<GatherCollectableExecutor> logger) : TaskExecutor<Task>()
|
||||
internal sealed class GatherCollectableExecutor(GatheringController gatheringController, GameFunctions gameFunctions, IObjectTable objectTable, IGameGui gameGui, ILogger<GatherCollectableExecutor> logger) : TaskExecutor<Task>()
|
||||
{
|
||||
private Queue<EAction>? _actionQueue;
|
||||
|
||||
|
|
@ -137,42 +138,42 @@ internal static class DoGatherCollectable
|
|||
|
||||
private Queue<EAction> GetNextActions(NodeCondition nodeCondition)
|
||||
{
|
||||
uint currentGp = clientState.LocalPlayer.CurrentGp;
|
||||
logger.LogTrace("Getting next actions (with {GP} GP, {MeticulousCollectability}~ meticulous, {ScourCollectability}~ scour)", currentGp, nodeCondition.CollectabilityFromMeticulous, nodeCondition.CollectabilityFromScour);
|
||||
uint num = (objectTable[0] as ICharacter)?.CurrentGp ?? 0;
|
||||
logger.LogTrace("Getting next actions (with {GP} GP, {MeticulousCollectability}~ meticulous, {ScourCollectability}~ scour)", num, nodeCondition.CollectabilityFromMeticulous, nodeCondition.CollectabilityFromScour);
|
||||
Queue<EAction> queue = new Queue<EAction>();
|
||||
uint num = nodeCondition.CollectabilityToGoal(base.Task.Request.Collectability);
|
||||
if (num <= nodeCondition.CollectabilityFromMeticulous)
|
||||
uint num2 = nodeCondition.CollectabilityToGoal(base.Task.Request.Collectability);
|
||||
if (num2 <= nodeCondition.CollectabilityFromMeticulous)
|
||||
{
|
||||
logger.LogTrace("Can get all needed {NeededCollectability} from {Collectability}~ meticulous", num, nodeCondition.CollectabilityFromMeticulous);
|
||||
logger.LogTrace("Can get all needed {NeededCollectability} from {Collectability}~ meticulous", num2, nodeCondition.CollectabilityFromMeticulous);
|
||||
queue.Enqueue(PickAction(EAction.MeticulousMiner, EAction.MeticulousBotanist));
|
||||
return queue;
|
||||
}
|
||||
if (num <= nodeCondition.CollectabilityFromScour)
|
||||
if (num2 <= nodeCondition.CollectabilityFromScour)
|
||||
{
|
||||
logger.LogTrace("Can get all needed {NeededCollectability} from {Collectability}~ scour", num, nodeCondition.CollectabilityFromScour);
|
||||
logger.LogTrace("Can get all needed {NeededCollectability} from {Collectability}~ scour", num2, nodeCondition.CollectabilityFromScour);
|
||||
queue.Enqueue(PickAction(EAction.ScourMiner, EAction.ScourBotanist));
|
||||
return queue;
|
||||
}
|
||||
if (!nodeCondition.ScrutinyActive && currentGp >= 200)
|
||||
if (!nodeCondition.ScrutinyActive && num >= 200)
|
||||
{
|
||||
logger.LogTrace("Still missing {NeededCollectability} collectability, scrutiny inactive", num);
|
||||
logger.LogTrace("Still missing {NeededCollectability} collectability, scrutiny inactive", num2);
|
||||
queue.Enqueue(PickAction(EAction.ScrutinyMiner, EAction.ScrutinyBotanist));
|
||||
return queue;
|
||||
}
|
||||
if (nodeCondition.ScrutinyActive)
|
||||
{
|
||||
logger.LogTrace("Scrutiny active, need {NeededCollectability} and we expect {Collectability}~ meticulous", num, nodeCondition.CollectabilityFromMeticulous);
|
||||
logger.LogTrace("Scrutiny active, need {NeededCollectability} and we expect {Collectability}~ meticulous", num2, nodeCondition.CollectabilityFromMeticulous);
|
||||
queue.Enqueue(PickAction(EAction.MeticulousMiner, EAction.MeticulousBotanist));
|
||||
return queue;
|
||||
}
|
||||
logger.LogTrace("Scrutiny active, need {NeededCollectability} and we expect {Collectability}~ scour", num, nodeCondition.CollectabilityFromScour);
|
||||
logger.LogTrace("Scrutiny active, need {NeededCollectability} and we expect {Collectability}~ scour", num2, nodeCondition.CollectabilityFromScour);
|
||||
queue.Enqueue(PickAction(EAction.ScourMiner, EAction.ScourBotanist));
|
||||
return queue;
|
||||
}
|
||||
|
||||
private EAction PickAction(EAction minerAction, EAction botanistAction)
|
||||
{
|
||||
if (clientState.LocalPlayer?.ClassJob.RowId == 16)
|
||||
if ((objectTable[0] as ICharacter)?.ClassJob.RowId == 16)
|
||||
{
|
||||
return minerAction;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||
|
|
@ -43,7 +44,7 @@ internal static class EquipRecommended
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class DoEquipRecommended(IClientState clientState, IChatGui chatGui, ICondition condition) : TaskExecutor<EquipTask>()
|
||||
internal sealed class DoEquipRecommended(IObjectTable objectTable, IChatGui chatGui, ICondition condition) : TaskExecutor<EquipTask>()
|
||||
{
|
||||
private bool _checkedOrTriggeredEquipmentUpdate;
|
||||
|
||||
|
|
@ -55,7 +56,11 @@ internal static class EquipRecommended
|
|||
{
|
||||
return false;
|
||||
}
|
||||
RecommendEquipModule.Instance()->SetupForClassJob((byte)clientState.LocalPlayer.ClassJob.RowId);
|
||||
if (!(objectTable[0] is ICharacter character))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
RecommendEquipModule.Instance()->SetupForClassJob((byte)character.ClassJob.RowId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -47,12 +48,17 @@ internal static class Jump
|
|||
}
|
||||
}
|
||||
|
||||
internal abstract class JumpBase<T>(MovementController movementController, IClientState clientState, IFramework framework) : TaskExecutor<T>() where T : class, IJumpTask
|
||||
internal abstract class JumpBase<T>(MovementController movementController, IObjectTable objectTable, IFramework framework) : TaskExecutor<T>() where T : class, IJumpTask
|
||||
{
|
||||
protected unsafe override bool Start()
|
||||
{
|
||||
IGameObject gameObject = _003CobjectTable_003EP[0];
|
||||
if (gameObject == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
float num = base.Task.JumpDestination.CalculateStopDistance();
|
||||
if ((_003CclientState_003EP.LocalPlayer.Position - base.Task.JumpDestination.Position).Length() <= num)
|
||||
if ((gameObject.Position - base.Task.JumpDestination.Position).Length() <= num)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -94,8 +100,8 @@ internal static class Jump
|
|||
|
||||
internal sealed class DoSingleJump : JumpBase<SingleJumpTask>
|
||||
{
|
||||
public DoSingleJump(MovementController movementController, IClientState clientState, IFramework framework)
|
||||
: base(movementController, clientState, framework)
|
||||
public DoSingleJump(MovementController movementController, IObjectTable objectTable, IFramework framework)
|
||||
: base(movementController, objectTable, framework)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -110,19 +116,19 @@ internal static class Jump
|
|||
|
||||
internal sealed class DoRepeatedJumps : JumpBase<RepeatedJumpTask>
|
||||
{
|
||||
private readonly IClientState _clientState;
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private DateTime _continueAt;
|
||||
|
||||
private int _attempts;
|
||||
|
||||
public DoRepeatedJumps(MovementController movementController, IClientState clientState, IFramework framework, ICondition condition, ILogger<DoRepeatedJumps> logger)
|
||||
public DoRepeatedJumps(MovementController movementController, IObjectTable objectTable, IFramework framework, ICondition condition, ILogger<DoRepeatedJumps> logger)
|
||||
{
|
||||
_003Ccondition_003EP = condition;
|
||||
_003Clogger_003EP = logger;
|
||||
_clientState = clientState;
|
||||
_objectTable = objectTable;
|
||||
_continueAt = DateTime.MinValue;
|
||||
base._002Ector(movementController, clientState, framework);
|
||||
base._002Ector(movementController, objectTable, framework);
|
||||
}
|
||||
|
||||
protected override bool Start()
|
||||
|
|
@ -137,12 +143,17 @@ internal static class Jump
|
|||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
float num = base.Task.JumpDestination.CalculateStopDistance();
|
||||
if ((_clientState.LocalPlayer.Position - base.Task.JumpDestination.Position).Length() <= num || _clientState.LocalPlayer.Position.Y >= base.Task.JumpDestination.Position.Y - 0.5f)
|
||||
IGameObject gameObject = _objectTable[0];
|
||||
if (gameObject == null)
|
||||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
_003Clogger_003EP.LogTrace("Y-Heights for jumps: player={A}, target={B}", _clientState.LocalPlayer.Position.Y, base.Task.JumpDestination.Position.Y - 0.5f);
|
||||
float num = base.Task.JumpDestination.CalculateStopDistance();
|
||||
if ((gameObject.Position - base.Task.JumpDestination.Position).Length() <= num || gameObject.Position.Y >= base.Task.JumpDestination.Position.Y - 0.5f)
|
||||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
_003Clogger_003EP.LogTrace("Y-Heights for jumps: player={A}, target={B}", gameObject.Position.Y, base.Task.JumpDestination.Position.Y - 0.5f);
|
||||
if (ActionManager.Instance()->UseAction(ActionType.GeneralAction, 2u, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null))
|
||||
{
|
||||
_attempts++;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ internal static class SinglePlayerDuty
|
|||
public const ushort Naadam = 688;
|
||||
}
|
||||
|
||||
internal sealed class Factory(BossModIpc bossModIpc, TerritoryData territoryData, ICondition condition, IClientState clientState) : ITaskFactory
|
||||
internal sealed class Factory(BossModIpc bossModIpc, TerritoryData territoryData, ICondition condition, IClientState clientState, IObjectTable objectTable) : ITaskFactory
|
||||
{
|
||||
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
{
|
||||
|
|
@ -70,7 +70,7 @@ internal static class SinglePlayerDuty
|
|||
{
|
||||
return true;
|
||||
}
|
||||
Vector3 vector = clientState.LocalPlayer?.Position ?? default(Vector3);
|
||||
Vector3 vector = objectTable[0]?.Position ?? default(Vector3);
|
||||
return (new Vector3(352.01f, -1.45f, 288.59f) - vector).Length() < 10f;
|
||||
}, "Wait(moving to Ovoo)");
|
||||
yield return new Mount.UnmountTask();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace Questionable.Controller.Steps.Movement;
|
||||
|
||||
internal sealed class LandExecutor(IClientState clientState, ICondition condition, ILogger<LandExecutor> logger) : TaskExecutor<LandTask>()
|
||||
internal sealed class LandExecutor(IObjectTable objectTable, ICondition condition, ILogger<LandExecutor> logger) : TaskExecutor<LandTask>()
|
||||
{
|
||||
private bool _landing;
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ internal sealed class LandExecutor(IClientState clientState, ICondition conditio
|
|||
|
||||
private unsafe bool AttemptLanding()
|
||||
{
|
||||
Character* ptr = (Character*)(clientState.LocalPlayer?.Address ?? 0);
|
||||
Character* ptr = (Character*)(objectTable[0]?.Address ?? 0);
|
||||
if (ptr != null && ActionManager.Instance()->GetActionStatus(ActionType.GeneralAction, 23u, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) == 0)
|
||||
{
|
||||
logger.LogInformation("Attempting to land");
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
using LLib;
|
||||
|
|
@ -28,6 +29,8 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly ICondition _condition;
|
||||
|
||||
private readonly Questionable.Controller.Steps.Common.Mount.MountEvaluator _mountEvaluator;
|
||||
|
|
@ -46,12 +49,13 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
|
||||
private (Questionable.Controller.Steps.Common.Mount.MountExecutor Executor, Questionable.Controller.Steps.Common.Mount.MountTask Task)? _mountDuringMovement;
|
||||
|
||||
public MoveExecutor(MovementController movementController, GameFunctions gameFunctions, ILogger<MoveExecutor> logger, IClientState clientState, ICondition condition, IDataManager dataManager, Questionable.Controller.Steps.Common.Mount.MountEvaluator mountEvaluator, IServiceProvider serviceProvider)
|
||||
public MoveExecutor(MovementController movementController, GameFunctions gameFunctions, ILogger<MoveExecutor> logger, IClientState clientState, IObjectTable objectTable, ICondition condition, IDataManager dataManager, Questionable.Controller.Steps.Common.Mount.MountEvaluator mountEvaluator, IServiceProvider serviceProvider)
|
||||
{
|
||||
_movementController = movementController;
|
||||
_gameFunctions = gameFunctions;
|
||||
_logger = logger;
|
||||
_clientState = clientState;
|
||||
_objectTable = objectTable;
|
||||
_condition = condition;
|
||||
_serviceProvider = serviceProvider;
|
||||
_mountEvaluator = mountEvaluator;
|
||||
|
|
@ -95,7 +99,7 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
_canRestart = base.Task.RestartNavigation;
|
||||
_destination = base.Task.Destination;
|
||||
float num = base.Task.StopDistance ?? 3f;
|
||||
Vector3? vector = _clientState.LocalPlayer?.Position;
|
||||
Vector3? vector = _objectTable[0]?.Position;
|
||||
float num2 = ((!vector.HasValue) ? float.MaxValue : Vector3.Distance(vector.Value, _destination));
|
||||
if (num2 > num)
|
||||
{
|
||||
|
|
@ -170,7 +174,8 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
if (_canRestart && Vector3.Distance(_clientState.LocalPlayer.Position, _destination) > (base.Task.StopDistance ?? 3f) + 5f)
|
||||
IGameObject gameObject = _objectTable[0];
|
||||
if (_canRestart && gameObject != null && Vector3.Distance(gameObject.Position, _destination) > (base.Task.StopDistance ?? 3f) + 5f)
|
||||
{
|
||||
_canRestart = false;
|
||||
if (_clientState.TerritoryType == base.Task.TerritoryId)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps.Common;
|
||||
|
|
@ -13,7 +14,7 @@ namespace Questionable.Controller.Steps.Movement;
|
|||
|
||||
internal static class MoveTo
|
||||
{
|
||||
internal sealed class Factory(IClientState clientState, AetheryteData aetheryteData, TerritoryData territoryData, ILogger<Factory> logger) : ITaskFactory
|
||||
internal sealed class Factory(IClientState clientState, IObjectTable objectTable, AetheryteData aetheryteData, TerritoryData territoryData, ILogger<Factory> logger) : ITaskFactory
|
||||
{
|
||||
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
{
|
||||
|
|
@ -62,7 +63,8 @@ internal static class MoveTo
|
|||
|
||||
private IEnumerable<ITask> CreateMoveTasks(QuestStep step, Vector3 destination)
|
||||
{
|
||||
if (step.InteractionType == EInteractionType.Jump && step.JumpDestination != null && (clientState.LocalPlayer.Position - step.JumpDestination.Position).Length() <= (step.JumpDestination.StopDistance ?? 1f))
|
||||
IGameObject gameObject = objectTable[0];
|
||||
if (step.InteractionType == EInteractionType.Jump && step.JumpDestination != null && gameObject != null && (gameObject.Position - step.JumpDestination.Position).Length() <= (step.JumpDestination.StopDistance ?? 1f))
|
||||
{
|
||||
logger.LogInformation("We're at the jump destination, skipping movement");
|
||||
yield break;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using Questionable.Functions;
|
|||
|
||||
namespace Questionable.Controller.Steps.Movement;
|
||||
|
||||
internal sealed class WaitForNearDataIdExecutor(GameFunctions gameFunctions, IClientState clientState) : TaskExecutor<WaitForNearDataId>()
|
||||
internal sealed class WaitForNearDataIdExecutor(GameFunctions gameFunctions, IObjectTable objectTable) : TaskExecutor<WaitForNearDataId>()
|
||||
{
|
||||
protected override bool Start()
|
||||
{
|
||||
|
|
@ -14,7 +14,8 @@ internal sealed class WaitForNearDataIdExecutor(GameFunctions gameFunctions, ICl
|
|||
public override ETaskResult Update()
|
||||
{
|
||||
IGameObject gameObject = gameFunctions.FindObjectByDataId(base.Task.DataId);
|
||||
if (gameObject == null || (gameObject.Position - clientState.LocalPlayer.Position).Length() > base.Task.StopDistance)
|
||||
IGameObject gameObject2 = objectTable[0];
|
||||
if (gameObject == null || gameObject2 == null || (gameObject.Position - gameObject2.Position).Length() > base.Task.StopDistance)
|
||||
{
|
||||
throw new TaskException("Object not found or too far away, no position so we can't move");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps.Common;
|
||||
|
|
@ -50,7 +51,7 @@ internal static class AethernetShortcut
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class UseAethernetShortcut(ILogger<UseAethernetShortcut> logger, AetheryteFunctions aetheryteFunctions, GameFunctions gameFunctions, QuestFunctions questFunctions, IClientState clientState, AetheryteData aetheryteData, TerritoryData territoryData, LifestreamIpc lifestreamIpc, MovementController movementController, ICondition condition) : TaskExecutor<Task>()
|
||||
internal sealed class UseAethernetShortcut(ILogger<UseAethernetShortcut> logger, AetheryteFunctions aetheryteFunctions, GameFunctions gameFunctions, QuestFunctions questFunctions, IClientState clientState, IObjectTable objectTable, AetheryteData aetheryteData, TerritoryData territoryData, LifestreamIpc lifestreamIpc, MovementController movementController, ICondition condition) : TaskExecutor<Task>()
|
||||
{
|
||||
private bool _moving;
|
||||
|
||||
|
|
@ -98,7 +99,12 @@ internal static class AethernetShortcut
|
|||
if (aetheryteFunctions.IsAetheryteUnlocked(base.Task.From) && aetheryteFunctions.IsAetheryteUnlocked(base.Task.To))
|
||||
{
|
||||
ushort territoryType = clientState.TerritoryType;
|
||||
Vector3 playerPosition = clientState.LocalPlayer.Position;
|
||||
IGameObject gameObject = objectTable[0];
|
||||
if (gameObject == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Vector3 playerPosition = gameObject.Position;
|
||||
if (aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) < aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.To))
|
||||
{
|
||||
if (aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) < (base.Task.From.IsFirmamentAetheryte() ? 11f : 4f))
|
||||
|
|
@ -202,7 +208,7 @@ internal static class AethernetShortcut
|
|||
DoTeleport();
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
Vector3? vector = clientState.LocalPlayer?.Position;
|
||||
Vector3? vector = objectTable[0]?.Position;
|
||||
if (!vector.HasValue)
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps.Common;
|
||||
|
|
@ -45,7 +46,7 @@ internal static class AetheryteShortcut
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class UseAetheryteShortcut(ILogger<UseAetheryteShortcut> logger, AetheryteFunctions aetheryteFunctions, QuestFunctions questFunctions, IClientState clientState, IChatGui chatGui, ICondition condition, AetheryteData aetheryteData, ExtraConditionUtils extraConditionUtils) : TaskExecutor<Task>()
|
||||
internal sealed class UseAetheryteShortcut(ILogger<UseAetheryteShortcut> logger, AetheryteFunctions aetheryteFunctions, QuestFunctions questFunctions, IClientState clientState, IObjectTable objectTable, IChatGui chatGui, ICondition condition, AetheryteData aetheryteData, ExtraConditionUtils extraConditionUtils) : TaskExecutor<Task>()
|
||||
{
|
||||
private bool _teleported;
|
||||
|
||||
|
|
@ -116,14 +117,15 @@ internal static class AetheryteShortcut
|
|||
return true;
|
||||
}
|
||||
}
|
||||
IGameObject gameObject = objectTable[0];
|
||||
NearPositionCondition nearPosition = skipAetheryteCondition.NearPosition;
|
||||
if (nearPosition != null && clientState.TerritoryType == nearPosition.TerritoryId && Vector3.Distance(nearPosition.Position, clientState.LocalPlayer.Position) <= nearPosition.MaximumDistance)
|
||||
if (nearPosition != null && clientState.TerritoryType == nearPosition.TerritoryId && gameObject != null && Vector3.Distance(nearPosition.Position, gameObject.Position) <= nearPosition.MaximumDistance)
|
||||
{
|
||||
logger.LogInformation("Skipping aetheryte shortcut, as we're near the position");
|
||||
return true;
|
||||
}
|
||||
NearPositionCondition notNearPosition = skipAetheryteCondition.NotNearPosition;
|
||||
if (notNearPosition != null && clientState.TerritoryType == notNearPosition.TerritoryId && notNearPosition.MaximumDistance <= Vector3.Distance(notNearPosition.Position, clientState.LocalPlayer.Position))
|
||||
if (notNearPosition != null && clientState.TerritoryType == notNearPosition.TerritoryId && gameObject != null && notNearPosition.MaximumDistance <= Vector3.Distance(notNearPosition.Position, gameObject.Position))
|
||||
{
|
||||
logger.LogInformation("Skipping aetheryte shortcut, as we're not near the position");
|
||||
return true;
|
||||
|
|
@ -134,23 +136,27 @@ internal static class AetheryteShortcut
|
|||
return true;
|
||||
}
|
||||
}
|
||||
if (base.Task.ExpectedTerritoryId == territoryType && !skipAetheryteCondition.Never)
|
||||
if (base.Task.ExpectedTerritoryId == territoryType)
|
||||
{
|
||||
if (skipAetheryteCondition != null && skipAetheryteCondition.InSameTerritory)
|
||||
IGameObject gameObject2 = objectTable[0];
|
||||
if (gameObject2 != null && !skipAetheryteCondition.Never)
|
||||
{
|
||||
logger.LogInformation("Skipping aetheryte teleport due to SkipCondition (InSameTerritory)");
|
||||
return true;
|
||||
}
|
||||
Vector3 position = clientState.LocalPlayer.Position;
|
||||
if (base.Task.Step.Position.HasValue && (position - base.Task.Step.Position.Value).Length() < base.Task.Step.CalculateActualStopDistance())
|
||||
{
|
||||
logger.LogInformation("Skipping aetheryte teleport, we're near the target");
|
||||
return true;
|
||||
}
|
||||
if (aetheryteData.CalculateDistance(position, territoryType, base.Task.TargetAetheryte) < 20f || (base.Task.Step.AethernetShortcut != null && (aetheryteData.CalculateDistance(position, territoryType, base.Task.Step.AethernetShortcut.From) < 20f || aetheryteData.CalculateDistance(position, territoryType, base.Task.Step.AethernetShortcut.To) < 20f)))
|
||||
{
|
||||
logger.LogInformation("Skipping aetheryte teleport");
|
||||
return true;
|
||||
if (skipAetheryteCondition != null && skipAetheryteCondition.InSameTerritory)
|
||||
{
|
||||
logger.LogInformation("Skipping aetheryte teleport due to SkipCondition (InSameTerritory)");
|
||||
return true;
|
||||
}
|
||||
Vector3 position = gameObject2.Position;
|
||||
if (base.Task.Step.Position.HasValue && (position - base.Task.Step.Position.Value).Length() < base.Task.Step.CalculateActualStopDistance())
|
||||
{
|
||||
logger.LogInformation("Skipping aetheryte teleport, we're near the target");
|
||||
return true;
|
||||
}
|
||||
if (aetheryteData.CalculateDistance(position, territoryType, base.Task.TargetAetheryte) < 20f || (base.Task.Step.AethernetShortcut != null && (aetheryteData.CalculateDistance(position, territoryType, base.Task.Step.AethernetShortcut.From) < 20f || aetheryteData.CalculateDistance(position, territoryType, base.Task.Step.AethernetShortcut.To) < 20f)))
|
||||
{
|
||||
logger.LogInformation("Skipping aetheryte teleport");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -208,7 +214,7 @@ internal static class AetheryteShortcut
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class MoveAwayFromAetheryteExecutor(MoveExecutor moveExecutor, AetheryteData aetheryteData, IClientState clientState) : TaskExecutor<MoveAwayFromAetheryte>()
|
||||
internal sealed class MoveAwayFromAetheryteExecutor(MoveExecutor moveExecutor, AetheryteData aetheryteData, IClientState clientState, IObjectTable objectTable) : TaskExecutor<MoveAwayFromAetheryte>()
|
||||
{
|
||||
private static readonly Dictionary<EAetheryteLocation, List<Vector3>> AetherytesToMoveFrom;
|
||||
|
||||
|
|
@ -219,7 +225,12 @@ internal static class AetheryteShortcut
|
|||
|
||||
protected override bool Start()
|
||||
{
|
||||
Vector3 playerPosition = clientState.LocalPlayer.Position;
|
||||
IGameObject gameObject = objectTable[0];
|
||||
if (gameObject == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Vector3 playerPosition = gameObject.Position;
|
||||
if (aetheryteData.CalculateDistance(playerPosition, clientState.TerritoryType, base.Task.TargetAetheryte) >= 20f)
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
|
|
@ -43,7 +44,7 @@ internal static class Craft
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class DoCraft(IDataManager dataManager, IClientState clientState, ArtisanIpc artisanIpc, ILogger<DoCraft> logger) : TaskExecutor<CraftTask>()
|
||||
internal sealed class DoCraft(IDataManager dataManager, IObjectTable objectTable, ArtisanIpc artisanIpc, ILogger<DoCraft> logger) : TaskExecutor<CraftTask>()
|
||||
{
|
||||
protected override bool Start()
|
||||
{
|
||||
|
|
@ -57,7 +58,7 @@ internal static class Craft
|
|||
{
|
||||
throw new TaskException($"Item {base.Task.ItemId} is not craftable");
|
||||
}
|
||||
uint num = (EClassJob)clientState.LocalPlayer.ClassJob.RowId switch
|
||||
uint num = (EClassJob?)(objectTable[0] as ICharacter)?.ClassJob.RowId switch
|
||||
{
|
||||
EClassJob.Carpenter => rowOrDefault.Value.CRP.RowId,
|
||||
EClassJob.Blacksmith => rowOrDefault.Value.BSM.RowId,
|
||||
|
|
|
|||
|
|
@ -9,14 +9,17 @@ internal sealed class ExtraConditionUtils
|
|||
{
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
public ExtraConditionUtils(IClientState clientState)
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
public ExtraConditionUtils(IClientState clientState, IObjectTable objectTable)
|
||||
{
|
||||
_clientState = clientState;
|
||||
_objectTable = objectTable;
|
||||
}
|
||||
|
||||
public bool MatchesExtraCondition(EExtraSkipCondition skipCondition)
|
||||
{
|
||||
Vector3? vector = _clientState.LocalPlayer?.Position;
|
||||
Vector3? vector = _objectTable[0]?.Position;
|
||||
if (vector.HasValue && _clientState.TerritoryType != 0)
|
||||
{
|
||||
return MatchesExtraCondition(skipCondition, vector.Value, _clientState.TerritoryType);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
|
@ -42,7 +43,7 @@ internal static class Gather
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class DelayedGatheringExecutor(GatheringPointRegistry gatheringPointRegistry, TerritoryData territoryData, IClientState clientState, IServiceProvider serviceProvider, ILogger<DelayedGatheringExecutor> logger) : TaskExecutor<DelayedGatheringTask>(), IExtraTaskCreator, ITaskExecutor
|
||||
internal sealed class DelayedGatheringExecutor(GatheringPointRegistry gatheringPointRegistry, TerritoryData territoryData, IClientState clientState, IObjectTable objectTable, IServiceProvider serviceProvider, ILogger<DelayedGatheringExecutor> logger) : TaskExecutor<DelayedGatheringTask>(), IExtraTaskCreator, ITaskExecutor
|
||||
{
|
||||
protected override bool Start()
|
||||
{
|
||||
|
|
@ -56,8 +57,8 @@ internal static class Gather
|
|||
|
||||
public IEnumerable<ITask> CreateExtraTasks()
|
||||
{
|
||||
EClassJob rowId = (EClassJob)clientState.LocalPlayer.ClassJob.RowId;
|
||||
if (!gatheringPointRegistry.TryGetGatheringPointId(base.Task.GatheredItem.ItemId, rowId, out GatheringPointId gatheringPointId))
|
||||
EClassJob valueOrDefault = ((EClassJob?)(objectTable[0] as ICharacter)?.ClassJob.RowId).GetValueOrDefault();
|
||||
if (!gatheringPointRegistry.TryGetGatheringPointId(base.Task.GatheredItem.ItemId, valueOrDefault, out GatheringPointId gatheringPointId))
|
||||
{
|
||||
throw new TaskException($"No gathering point found for item {base.Task.GatheredItem.ItemId}");
|
||||
}
|
||||
|
|
@ -69,7 +70,7 @@ internal static class Gather
|
|||
{
|
||||
yield break;
|
||||
}
|
||||
switch (rowId)
|
||||
switch (valueOrDefault)
|
||||
{
|
||||
case EClassJob.Miner:
|
||||
yield return new Questionable.Controller.Steps.Interactions.Action.TriggerStatusIfMissing(EStatus.Prospect, EAction.Prospect);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ internal static class SkipCondition
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class CheckSkip(ILogger<CheckSkip> logger, Configuration configuration, AetheryteFunctions aetheryteFunctions, GameFunctions gameFunctions, QuestFunctions questFunctions, IClientState clientState, ICondition condition, ExtraConditionUtils extraConditionUtils, ClassJobUtils classJobUtils) : TaskExecutor<SkipTask>()
|
||||
internal sealed class CheckSkip(ILogger<CheckSkip> logger, Configuration configuration, AetheryteFunctions aetheryteFunctions, GameFunctions gameFunctions, QuestFunctions questFunctions, IClientState clientState, IObjectTable objectTable, ICondition condition, ExtraConditionUtils extraConditionUtils, ClassJobUtils classJobUtils) : TaskExecutor<SkipTask>()
|
||||
{
|
||||
protected override bool Start()
|
||||
{
|
||||
|
|
@ -200,9 +200,10 @@ internal static class SkipCondition
|
|||
if (skipConditions.NotTargetable && step != null && step.DataId.HasValue)
|
||||
{
|
||||
IGameObject gameObject = gameFunctions.FindObjectByDataId(step.DataId.Value);
|
||||
IGameObject gameObject2 = objectTable[0];
|
||||
if (gameObject == null)
|
||||
{
|
||||
if ((step.Position.GetValueOrDefault() - clientState.LocalPlayer.Position).Length() < 100f)
|
||||
if (gameObject2 != null && (step.Position.GetValueOrDefault() - gameObject2.Position).Length() < 100f)
|
||||
{
|
||||
logger.LogInformation("Skipping step, object is not nearby (but we are)");
|
||||
return true;
|
||||
|
|
@ -340,9 +341,10 @@ internal static class SkipCondition
|
|||
|
||||
private bool CheckLevelCondition(SkipStepConditions skipConditions)
|
||||
{
|
||||
if (skipConditions.MinimumLevel.HasValue && clientState.LocalPlayer != null && clientState.LocalPlayer.Level >= skipConditions.MinimumLevel.Value)
|
||||
ICharacter character = objectTable[0] as ICharacter;
|
||||
if (skipConditions.MinimumLevel.HasValue && character != null && character.Level >= skipConditions.MinimumLevel.Value)
|
||||
{
|
||||
logger.LogInformation("Skipping step, as player level {CurrentLevel} >= minimum level {MinLevel}", clientState.LocalPlayer.Level, skipConditions.MinimumLevel.Value);
|
||||
logger.LogInformation("Skipping step, as player level {CurrentLevel} >= minimum level {MinLevel}", character.Level, skipConditions.MinimumLevel.Value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -407,9 +409,9 @@ internal static class SkipCondition
|
|||
if (requiredCurrentJob != null && requiredCurrentJob.Count > 0)
|
||||
{
|
||||
List<EClassJob> list = step.RequiredCurrentJob.SelectMany((EExtendedClassJob x) => classJobUtils.AsIndividualJobs(x, elementId)).ToList();
|
||||
EClassJob rowId = (EClassJob)clientState.LocalPlayer.ClassJob.RowId;
|
||||
logger.LogInformation("Checking current job {CurrentJob} against {ExpectedJobs}", rowId, string.Join(",", list));
|
||||
if (!list.Contains(rowId))
|
||||
EClassJob valueOrDefault = ((EClassJob?)(objectTable[0] as ICharacter)?.ClassJob.RowId).GetValueOrDefault();
|
||||
logger.LogInformation("Checking current job {CurrentJob} against {ExpectedJobs}", valueOrDefault, string.Join(",", list));
|
||||
if (!list.Contains(valueOrDefault))
|
||||
{
|
||||
logger.LogInformation("Skipping step, as step requires a different job");
|
||||
return true;
|
||||
|
|
@ -421,14 +423,15 @@ internal static class SkipCondition
|
|||
|
||||
private bool CheckPositionCondition(SkipStepConditions skipConditions)
|
||||
{
|
||||
IGameObject gameObject = objectTable[0];
|
||||
NearPositionCondition nearPosition = skipConditions.NearPosition;
|
||||
if (nearPosition != null && clientState.TerritoryType == nearPosition.TerritoryId && Vector3.Distance(nearPosition.Position, clientState.LocalPlayer.Position) <= nearPosition.MaximumDistance)
|
||||
if (nearPosition != null && clientState.TerritoryType == nearPosition.TerritoryId && gameObject != null && Vector3.Distance(nearPosition.Position, gameObject.Position) <= nearPosition.MaximumDistance)
|
||||
{
|
||||
logger.LogInformation("Skipping step, as we're near the position");
|
||||
return true;
|
||||
}
|
||||
NearPositionCondition notNearPosition = skipConditions.NotNearPosition;
|
||||
if (notNearPosition != null && clientState.TerritoryType == notNearPosition.TerritoryId && notNearPosition.MaximumDistance <= Vector3.Distance(notNearPosition.Position, clientState.LocalPlayer.Position))
|
||||
if (notNearPosition != null && clientState.TerritoryType == notNearPosition.TerritoryId && gameObject != null && notNearPosition.MaximumDistance <= Vector3.Distance(notNearPosition.Position, gameObject.Position))
|
||||
{
|
||||
logger.LogInformation("Skipping step, as we're not near the position");
|
||||
return true;
|
||||
|
|
@ -479,7 +482,7 @@ internal static class SkipCondition
|
|||
|
||||
private unsafe bool IsBetterOrEqualItemEquipped(uint itemId)
|
||||
{
|
||||
if (clientState.LocalPlayer == null)
|
||||
if (objectTable[0] == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||
using LLib.GameData;
|
||||
|
|
@ -31,11 +32,11 @@ internal static class SwitchClassJob
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed class SwitchClassJobExecutor(IClientState clientState) : AbstractDelayedTaskExecutor<Task>()
|
||||
internal sealed class SwitchClassJobExecutor(IObjectTable objectTable) : AbstractDelayedTaskExecutor<Task>()
|
||||
{
|
||||
protected unsafe override bool StartInternal()
|
||||
{
|
||||
if (clientState.LocalPlayer.ClassJob.RowId == (uint)base.Task.ClassJob)
|
||||
if ((objectTable[0] as ICharacter)?.ClassJob.RowId == (uint?)base.Task.ClassJob)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Questionable.Controller.Steps.Shared;
|
|||
|
||||
internal static class WaitAtEnd
|
||||
{
|
||||
internal sealed class Factory(IClientState clientState, ICondition condition, TerritoryData territoryData, AutoDutyIpc autoDutyIpc, BossModIpc bossModIpc) : ITaskFactory
|
||||
internal sealed class Factory(IClientState clientState, IObjectTable objectTable, ICondition condition, TerritoryData territoryData, AutoDutyIpc autoDutyIpc, BossModIpc bossModIpc) : ITaskFactory
|
||||
{
|
||||
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
{
|
||||
|
|
@ -129,10 +129,10 @@ internal static class WaitAtEnd
|
|||
}
|
||||
else
|
||||
{
|
||||
Vector3 lastPosition = step.Position ?? clientState.LocalPlayer?.Position ?? Vector3.Zero;
|
||||
Vector3 lastPosition = step.Position ?? objectTable[0]?.Position ?? Vector3.Zero;
|
||||
task = new WaitCondition.Task(delegate
|
||||
{
|
||||
Vector3? vector = clientState.LocalPlayer?.Position;
|
||||
Vector3? vector = objectTable[0]?.Position;
|
||||
return vector.HasValue && (lastPosition - vector.Value).Length() > 2f;
|
||||
}, "Wait(tp away from " + lastPosition.ToString("G", CultureInfo.InvariantCulture) + ")");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using System.Runtime.InteropServices;
|
|||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
|
|
@ -323,12 +322,13 @@ internal sealed class CombatController : IDisposable
|
|||
}
|
||||
}
|
||||
}
|
||||
IGameObject localPlayer = _objectTable[0];
|
||||
IGameObject gameObject = (from x in _objectTable
|
||||
select new
|
||||
{
|
||||
GameObject = x,
|
||||
Priority = GetKillPriority(x).Priority,
|
||||
Distance = Vector3.Distance(x.Position, _clientState.LocalPlayer.Position)
|
||||
Distance = Vector3.Distance(x.Position, localPlayer?.Position ?? Vector3.Zero)
|
||||
} into x
|
||||
where x.Priority > 0
|
||||
orderby x.Priority descending, x.Distance
|
||||
|
|
@ -355,7 +355,8 @@ internal sealed class CombatController : IDisposable
|
|||
}
|
||||
if (gameObject is IBattleNpc battleNpc && battleNpc.StatusFlags.HasFlag(StatusFlags.InCombat))
|
||||
{
|
||||
if (gameObject.TargetObjectId == _clientState.LocalPlayer?.GameObjectId)
|
||||
IGameObject? gameObject2 = _objectTable[0];
|
||||
if (gameObject.TargetObjectId == gameObject2?.GameObjectId)
|
||||
{
|
||||
return (Priority: num.Value + 150, Reason: text + "/Targeted");
|
||||
}
|
||||
|
|
@ -393,11 +394,12 @@ internal sealed class CombatController : IDisposable
|
|||
}
|
||||
List<ComplexCombatData> complexCombatDatas = _currentFight.Data.ComplexCombatDatas;
|
||||
GameObject* address = (GameObject*)gameObject.Address;
|
||||
if (address->FateId != 0 && _currentFight.Data.SpawnType != EEnemySpawnType.FateEnemies && gameObject.TargetObjectId != _clientState.LocalPlayer?.GameObjectId)
|
||||
IGameObject gameObject2 = _objectTable[0];
|
||||
if (address->FateId != 0 && _currentFight.Data.SpawnType != EEnemySpawnType.FateEnemies && gameObject.TargetObjectId != gameObject2?.GameObjectId)
|
||||
{
|
||||
return (Priority: null, Reason: "FATE mob");
|
||||
}
|
||||
Vector3 value = _clientState.LocalPlayer?.Position ?? Vector3.Zero;
|
||||
Vector3 value = gameObject2?.Position ?? Vector3.Zero;
|
||||
bool flag = _currentFight.Data.SpawnType != EEnemySpawnType.FinishCombatIfAny && (_currentFight.Data.SpawnType != EEnemySpawnType.OverworldEnemies || !(Vector3.Distance(value, battleNpc.Position) >= 50f)) && _currentFight.Data.SpawnType != EEnemySpawnType.FateEnemies;
|
||||
if (complexCombatDatas.Count > 0)
|
||||
{
|
||||
|
|
@ -430,6 +432,7 @@ internal sealed class CombatController : IDisposable
|
|||
|
||||
private void SetTarget(IGameObject? target)
|
||||
{
|
||||
IGameObject gameObject = _objectTable[0];
|
||||
if (target == null)
|
||||
{
|
||||
if (_targetManager.Target != null)
|
||||
|
|
@ -438,9 +441,9 @@ internal sealed class CombatController : IDisposable
|
|||
_targetManager.Target = null;
|
||||
}
|
||||
}
|
||||
else if (Vector3.Distance(_clientState.LocalPlayer.Position, target.Position) > 55f)
|
||||
else if (gameObject != null && Vector3.Distance(gameObject.Position, target.Position) > 55f)
|
||||
{
|
||||
_logger.LogInformation("Moving to target, distance: {Distance:N2}", Vector3.Distance(_clientState.LocalPlayer.Position, target.Position));
|
||||
_logger.LogInformation("Moving to target, distance: {Distance:N2}", Vector3.Distance(gameObject.Position, target.Position));
|
||||
MoveToTarget(target);
|
||||
}
|
||||
else
|
||||
|
|
@ -468,39 +471,45 @@ internal sealed class CombatController : IDisposable
|
|||
|
||||
private void MoveToTarget(IGameObject gameObject)
|
||||
{
|
||||
IPlayerCharacter localPlayer = _clientState.LocalPlayer;
|
||||
if (localPlayer == null)
|
||||
IGameObject gameObject2 = _objectTable[0];
|
||||
if (gameObject2 == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float num = localPlayer.HitboxRadius + gameObject.HitboxRadius;
|
||||
float num2 = Vector3.Distance(localPlayer.Position, gameObject.Position);
|
||||
byte? b = localPlayer.ClassJob.ValueNullable?.Role;
|
||||
bool flag;
|
||||
if (b.HasValue)
|
||||
float num = gameObject2.HitboxRadius + gameObject.HitboxRadius;
|
||||
float num2 = Vector3.Distance(gameObject2.Position, gameObject.Position);
|
||||
ICharacter character = gameObject2 as ICharacter;
|
||||
bool flag = character != null;
|
||||
bool flag2;
|
||||
if (flag)
|
||||
{
|
||||
byte valueOrDefault = b.GetValueOrDefault();
|
||||
if ((uint)(valueOrDefault - 3) <= 1u)
|
||||
byte? b = character.ClassJob.ValueNullable?.Role;
|
||||
if (b.HasValue)
|
||||
{
|
||||
flag = true;
|
||||
goto IL_008e;
|
||||
byte valueOrDefault = b.GetValueOrDefault();
|
||||
if ((uint)(valueOrDefault - 3) <= 1u)
|
||||
{
|
||||
flag2 = true;
|
||||
goto IL_00a3;
|
||||
}
|
||||
}
|
||||
flag2 = false;
|
||||
goto IL_00a3;
|
||||
}
|
||||
flag = false;
|
||||
goto IL_008e;
|
||||
IL_008e:
|
||||
goto IL_00a7;
|
||||
IL_00a7:
|
||||
float num3 = (flag ? 20f : 2.9f);
|
||||
bool flag2 = num2 - num >= num3;
|
||||
bool flag3 = IsInLineOfSight(gameObject);
|
||||
if (flag2 || !flag3)
|
||||
bool flag3 = num2 - num >= num3;
|
||||
bool flag4 = IsInLineOfSight(gameObject);
|
||||
if (flag3 || !flag4)
|
||||
{
|
||||
bool flag4 = num2 - num > 5f;
|
||||
if (!flag2 && !flag3)
|
||||
bool flag5 = num2 - num > 5f;
|
||||
if (!flag3 && !flag4)
|
||||
{
|
||||
num3 = Math.Min(num3, num2) / 2f;
|
||||
flag4 = true;
|
||||
flag5 = true;
|
||||
}
|
||||
if (!flag4)
|
||||
if (!flag5)
|
||||
{
|
||||
_logger.LogInformation("Moving to {TargetName} ({BaseId}) to attack", gameObject.Name, gameObject.BaseId);
|
||||
MovementController movementController = _movementController;
|
||||
|
|
@ -518,11 +527,20 @@ internal sealed class CombatController : IDisposable
|
|||
_movementController.NavigateTo(EMovementType.Combat, null, gameObject.Position, fly: false, sprint: false, num3 + num - 0.25f, float.MaxValue);
|
||||
}
|
||||
}
|
||||
return;
|
||||
IL_00a3:
|
||||
flag = flag2;
|
||||
goto IL_00a7;
|
||||
}
|
||||
|
||||
internal unsafe bool IsInLineOfSight(IGameObject target)
|
||||
{
|
||||
Vector3 position = _clientState.LocalPlayer.Position;
|
||||
IGameObject gameObject = _objectTable[0];
|
||||
if (gameObject == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Vector3 position = gameObject.Position;
|
||||
position.Y += 2f;
|
||||
Vector3 position2 = target.Position;
|
||||
position2.Y += 2f;
|
||||
|
|
|
|||
|
|
@ -1,20 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Data;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Common;
|
||||
using Questionable.Model.Questing;
|
||||
using Questionable.Model.Questing.Converter;
|
||||
using Questionable.Windows;
|
||||
|
||||
namespace Questionable.Controller;
|
||||
|
|
@ -33,12 +21,8 @@ internal sealed class CommandHandler : IDisposable
|
|||
|
||||
private readonly MovementController _movementController;
|
||||
|
||||
private readonly QuestRegistry _questRegistry;
|
||||
|
||||
private readonly ConfigWindow _configWindow;
|
||||
|
||||
private readonly DebugOverlay _debugOverlay;
|
||||
|
||||
private readonly OneTimeSetupWindow _oneTimeSetupWindow;
|
||||
|
||||
private readonly QuestWindow _questWindow;
|
||||
|
|
@ -53,33 +37,19 @@ internal sealed class CommandHandler : IDisposable
|
|||
|
||||
private readonly ITargetManager _targetManager;
|
||||
|
||||
private readonly QuestFunctions _questFunctions;
|
||||
|
||||
private readonly GameFunctions _gameFunctions;
|
||||
|
||||
private readonly AetheryteFunctions _aetheryteFunctions;
|
||||
|
||||
private readonly IDataManager _dataManager;
|
||||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly Configuration _configuration;
|
||||
|
||||
private readonly ChangelogWindow _changelogWindow;
|
||||
|
||||
private IReadOnlyList<uint> _previouslyUnlockedUnlockLinks = Array.Empty<uint>();
|
||||
|
||||
public CommandHandler(ICommandManager commandManager, IChatGui chatGui, QuestController questController, MovementController movementController, QuestRegistry questRegistry, ConfigWindow configWindow, DebugOverlay debugOverlay, OneTimeSetupWindow oneTimeSetupWindow, QuestWindow questWindow, QuestSelectionWindow questSelectionWindow, QuestSequenceWindow questSequenceWindow, JournalProgressWindow journalProgressWindow, PriorityWindow priorityWindow, ITargetManager targetManager, QuestFunctions questFunctions, GameFunctions gameFunctions, AetheryteFunctions aetheryteFunctions, IDataManager dataManager, IClientState clientState, IObjectTable objectTable, Configuration configuration, ChangelogWindow changelogWindow)
|
||||
{
|
||||
_commandManager = commandManager;
|
||||
_chatGui = chatGui;
|
||||
_questController = questController;
|
||||
_movementController = movementController;
|
||||
_questRegistry = questRegistry;
|
||||
_configWindow = configWindow;
|
||||
_debugOverlay = debugOverlay;
|
||||
_oneTimeSetupWindow = oneTimeSetupWindow;
|
||||
_questWindow = questWindow;
|
||||
_questSelectionWindow = questSelectionWindow;
|
||||
|
|
@ -87,12 +57,7 @@ internal sealed class CommandHandler : IDisposable
|
|||
_journalProgressWindow = journalProgressWindow;
|
||||
_priorityWindow = priorityWindow;
|
||||
_targetManager = targetManager;
|
||||
_questFunctions = questFunctions;
|
||||
_gameFunctions = gameFunctions;
|
||||
_aetheryteFunctions = aetheryteFunctions;
|
||||
_dataManager = dataManager;
|
||||
_clientState = clientState;
|
||||
_objectTable = objectTable;
|
||||
_configuration = configuration;
|
||||
_changelogWindow = changelogWindow;
|
||||
_clientState.Logout += OnLogout;
|
||||
|
|
@ -185,465 +150,8 @@ internal sealed class CommandHandler : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe void ProcessDebugCommand(string command, string arguments)
|
||||
private void ProcessDebugCommand(string command, string arguments)
|
||||
{
|
||||
if (OpenSetupIfNeeded(arguments))
|
||||
{
|
||||
return;
|
||||
}
|
||||
string[] array = arguments.Split(' ');
|
||||
string text = array[0];
|
||||
if (text == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch (text.Length)
|
||||
{
|
||||
case 4:
|
||||
switch (text[0])
|
||||
{
|
||||
case 'n':
|
||||
if (text == "next")
|
||||
{
|
||||
SetNextQuest(array.Skip(1).ToArray());
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
{
|
||||
if (!(text == "taxi"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
List<string> list5 = new List<string>();
|
||||
ExcelSheet<ChocoboTaxiStand> excelSheet = _dataManager.GetExcelSheet<ChocoboTaxiStand>();
|
||||
UIState* ptr = UIState.Instance();
|
||||
if (ptr == null)
|
||||
{
|
||||
_chatGui.PrintError("UIState is null", "Questionable", 576);
|
||||
break;
|
||||
}
|
||||
for (int num10 = 0; num10 < 192; num10++)
|
||||
{
|
||||
uint num11 = (uint)(num10 + 1179648);
|
||||
try
|
||||
{
|
||||
if (excelSheet.HasRow(num11) && ptr->IsChocoboTaxiStandUnlocked(num11))
|
||||
{
|
||||
string value14 = excelSheet.GetRow(num11).PlaceName.ToString();
|
||||
if (string.IsNullOrEmpty(value14))
|
||||
{
|
||||
value14 = "Unknown";
|
||||
}
|
||||
list5.Add($"{value14} (ID: {num10}, Row: 0x{num11:X})");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
_chatGui.Print($"Unlocked taxi stands ({list5.Count}):", "Questionable", 576);
|
||||
if (list5.Count == 0)
|
||||
{
|
||||
_chatGui.Print(" (No unlocked taxi stands found)", "Questionable", 576);
|
||||
break;
|
||||
}
|
||||
{
|
||||
foreach (string item5 in list5)
|
||||
{
|
||||
_chatGui.Print(" - " + item5, "Questionable", 576);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (text[1])
|
||||
{
|
||||
default:
|
||||
return;
|
||||
case 'i':
|
||||
if (text == "sim")
|
||||
{
|
||||
SetSimulatedQuest(array.Skip(1).ToArray());
|
||||
}
|
||||
return;
|
||||
case 'e':
|
||||
break;
|
||||
}
|
||||
if (!(text == "seq"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
goto IL_0209;
|
||||
case 12:
|
||||
switch (text[0])
|
||||
{
|
||||
case 'a':
|
||||
if (text == "abandon-duty")
|
||||
{
|
||||
_gameFunctions.AbandonDuty();
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
{
|
||||
if (!(text == "unlock-links"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
IReadOnlyList<uint> unlockLinks = _gameFunctions.GetUnlockLinks();
|
||||
if (unlockLinks.Count >= 0)
|
||||
{
|
||||
_chatGui.Print($"Saved {unlockLinks.Count} unlock links to log.", "Questionable", 576);
|
||||
List<uint> list6 = unlockLinks.Except(_previouslyUnlockedUnlockLinks).ToList();
|
||||
if (_previouslyUnlockedUnlockLinks.Count > 0 && list6.Count > 0)
|
||||
{
|
||||
_chatGui.Print("New unlock links: " + string.Join(", ", list6), "Questionable", 576);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.PrintError("Could not query unlock links.", "Questionable", 576);
|
||||
}
|
||||
_previouslyUnlockedUnlockLinks = unlockLinks;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
switch (text[0])
|
||||
{
|
||||
default:
|
||||
return;
|
||||
case 's':
|
||||
break;
|
||||
case 'f':
|
||||
{
|
||||
if (!(text == "festivals"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<string> list4 = new List<string>();
|
||||
for (byte b8 = 0; b8 < 4; b8++)
|
||||
{
|
||||
GameMain.Festival festival = GameMain.Instance()->ActiveFestivals[b8];
|
||||
if (festival.Id == 0)
|
||||
{
|
||||
list4.Add($"Slot {b8}: None");
|
||||
}
|
||||
else
|
||||
{
|
||||
list4.Add($"Slot {b8}: {festival.Id}({festival.Phase})");
|
||||
}
|
||||
}
|
||||
_chatGui.Print("Festival slots:", "Questionable", 576);
|
||||
{
|
||||
foreach (string item6 in list4)
|
||||
{
|
||||
_chatGui.Print(" " + item6, "Questionable", 576);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
case 'a':
|
||||
{
|
||||
if (!(text == "aethernet"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
ushort territoryType = _clientState.TerritoryType;
|
||||
Dictionary<EAetheryteLocation, string> values = AethernetShardConverter.Values;
|
||||
AetheryteData aetheryteData = new AetheryteData(_dataManager);
|
||||
HashSet<string> hashSet2 = new HashSet<string>();
|
||||
Dictionary<string, List<(EAetheryteLocation, string, bool)>> dictionary = new Dictionary<string, List<(EAetheryteLocation, string, bool)>>();
|
||||
EAetheryteLocation key;
|
||||
string value10;
|
||||
foreach (KeyValuePair<EAetheryteLocation, string> item7 in values)
|
||||
{
|
||||
item7.Deconstruct(out key, out value10);
|
||||
EAetheryteLocation key2 = key;
|
||||
string text2 = value10;
|
||||
if (aetheryteData.TerritoryIds.TryGetValue(key2, out var value11) && value11 == territoryType)
|
||||
{
|
||||
int num8 = text2.IndexOf(']', StringComparison.Ordinal);
|
||||
if (num8 > 0)
|
||||
{
|
||||
string item3 = text2.Substring(1, num8 - 1);
|
||||
hashSet2.Add(item3);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hashSet2.Count == 0)
|
||||
{
|
||||
_chatGui.Print("No aethernet shards found in current zone.", "Questionable", 576);
|
||||
return;
|
||||
}
|
||||
foreach (KeyValuePair<EAetheryteLocation, string> item8 in values)
|
||||
{
|
||||
item8.Deconstruct(out key, out value10);
|
||||
EAetheryteLocation eAetheryteLocation = key;
|
||||
string text3 = value10;
|
||||
int num9 = text3.IndexOf(']', StringComparison.Ordinal);
|
||||
if (num9 <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string text4 = text3.Substring(1, num9 - 1);
|
||||
if (hashSet2.Contains(text4))
|
||||
{
|
||||
if (!dictionary.ContainsKey(text4))
|
||||
{
|
||||
dictionary[text4] = new List<(EAetheryteLocation, string, bool)>();
|
||||
}
|
||||
bool item4 = _aetheryteFunctions.IsAetheryteUnlocked(eAetheryteLocation);
|
||||
dictionary[text4].Add((eAetheryteLocation, text3, item4));
|
||||
}
|
||||
}
|
||||
{
|
||||
foreach (KeyValuePair<string, List<(EAetheryteLocation, string, bool)>> item9 in dictionary.OrderBy<KeyValuePair<string, List<(EAetheryteLocation, string, bool)>>, string>((KeyValuePair<string, List<(EAetheryteLocation Location, string Name, bool Unlocked)>> x) => x.Key))
|
||||
{
|
||||
item9.Deconstruct(out value10, out var value12);
|
||||
string value13 = value10;
|
||||
List<(EAetheryteLocation, string, bool)> list = value12;
|
||||
List<(EAetheryteLocation, string, bool)> list2 = list.Where<(EAetheryteLocation, string, bool)>(((EAetheryteLocation Location, string Name, bool Unlocked) x) => x.Unlocked).ToList();
|
||||
List<(EAetheryteLocation, string, bool)> list3 = list.Where<(EAetheryteLocation, string, bool)>(((EAetheryteLocation Location, string Name, bool Unlocked) x) => !x.Unlocked).ToList();
|
||||
_chatGui.Print($"Aethernet Shards in {value13} ({list.Count} total):", "Questionable", 576);
|
||||
_chatGui.Print($" Unlocked: {list2.Count}", "Questionable", 576);
|
||||
_chatGui.Print($" Missing: {list3.Count}", "Questionable", 576);
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
if (list3.Count > 0)
|
||||
{
|
||||
_chatGui.Print("Missing/Unattuned Aethernet Shards:", "Questionable", 576);
|
||||
foreach (var item10 in list3.OrderBy<(EAetheryteLocation, string, bool), string>(((EAetheryteLocation Location, string Name, bool Unlocked) x) => x.Name))
|
||||
{
|
||||
_chatGui.Print(" " + item10.Item2, "Questionable", 576);
|
||||
}
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
}
|
||||
if (list2.Count > 0)
|
||||
{
|
||||
_chatGui.Print("Unlocked Aethernet Shards:", "Questionable", 576);
|
||||
foreach (var item11 in list2.OrderBy<(EAetheryteLocation, string, bool), string>(((EAetheryteLocation Location, string Name, bool Unlocked) x) => x.Name))
|
||||
{
|
||||
_chatGui.Print(" " + item11.Item2, "Questionable", 576);
|
||||
}
|
||||
}
|
||||
if (dictionary.Count > 1)
|
||||
{
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(text == "sequences"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
goto IL_0209;
|
||||
case 5:
|
||||
if (text == "setup")
|
||||
{
|
||||
_oneTimeSetupWindow.IsOpenAndUncollapsed = true;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (text == "do")
|
||||
{
|
||||
ConfigureDebugOverlay(array.Skip(1).ToArray());
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (text == "mountid")
|
||||
{
|
||||
PrintMountId();
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
{
|
||||
if (!(text == "quest-kills"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
(QuestController.QuestProgress, QuestController.ECurrentQuestType)? currentQuestDetails = _questController.CurrentQuestDetails;
|
||||
if (!currentQuestDetails.HasValue)
|
||||
{
|
||||
_chatGui.PrintError("No active quest.", "Questionable", 576);
|
||||
break;
|
||||
}
|
||||
QuestController.QuestProgress item = currentQuestDetails.Value.Item1;
|
||||
Questionable.Model.Quest quest = item.Quest;
|
||||
QuestProgressInfo questProgressInfo = null;
|
||||
if (quest.Id is QuestId elementId)
|
||||
{
|
||||
questProgressInfo = _questFunctions.GetQuestProgressInfo(elementId);
|
||||
}
|
||||
if (questProgressInfo == null)
|
||||
{
|
||||
_chatGui.PrintError("Unable to retrieve quest progress information.", "Questionable", 576);
|
||||
break;
|
||||
}
|
||||
QuestSequence questSequence = quest.FindSequence(item.Sequence);
|
||||
if (questSequence == null)
|
||||
{
|
||||
_chatGui.PrintError($"Sequence {item.Sequence} not found for quest {quest.Id}.", "Questionable", 576);
|
||||
break;
|
||||
}
|
||||
QuestStep questStep = ((item.Step < questSequence.Steps.Count) ? questSequence.Steps[item.Step] : null);
|
||||
if (questStep == null)
|
||||
{
|
||||
_chatGui.PrintError($"Step {item.Step} not found in sequence {item.Sequence}.", "Questionable", 576);
|
||||
break;
|
||||
}
|
||||
_chatGui.Print($"Quest: {quest.Info.Name} ({quest.Id})", "Questionable", 576);
|
||||
_chatGui.Print($"Sequence: {item.Sequence}, Step: {item.Step}", "Questionable", 576);
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
_chatGui.Print("Quest Variables: " + string.Join(", ", questProgressInfo.Variables.Select((byte v, int i) => $"[{i}]={v}")), "Questionable", 576);
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
ExcelSheet<BNpcName> bnpcNameSheet = _dataManager.GetExcelSheet<BNpcName>();
|
||||
HashSet<uint> hashSet = new HashSet<uint>(questStep.KillEnemyDataIds);
|
||||
foreach (ComplexCombatData complexCombatDatum in questStep.ComplexCombatData)
|
||||
{
|
||||
hashSet.Add(complexCombatDatum.DataId);
|
||||
}
|
||||
if (hashSet.Count > 0)
|
||||
{
|
||||
_chatGui.Print($"All Enemy DataIds Found: {hashSet.Count}", "Questionable", 576);
|
||||
foreach (uint item12 in hashSet.OrderBy((uint x) => x))
|
||||
{
|
||||
(string Name, bool Found) tuple = GetEnemyName(item12);
|
||||
var (value, _) = tuple;
|
||||
if (tuple.Found)
|
||||
{
|
||||
_chatGui.Print($" - {value} (DataId: {item12})", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.Print($" - DataId: {item12}", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
}
|
||||
if (questStep.ComplexCombatData.Count > 0)
|
||||
{
|
||||
_chatGui.Print($"Complex Combat Data Entries: {questStep.ComplexCombatData.Count}", "Questionable", 576);
|
||||
_chatGui.Print("Kill Progress:", "Questionable", 576);
|
||||
if (questStep.ComplexCombatData.Count == 1 && hashSet.Count > 1)
|
||||
{
|
||||
ComplexCombatData complexCombatData = questStep.ComplexCombatData[0];
|
||||
int num = -1;
|
||||
byte? b = null;
|
||||
for (int num2 = 0; num2 < complexCombatData.CompletionQuestVariablesFlags.Count; num2++)
|
||||
{
|
||||
QuestWorkValue questWorkValue = complexCombatData.CompletionQuestVariablesFlags[num2];
|
||||
if (questWorkValue != null && questWorkValue.Low.HasValue)
|
||||
{
|
||||
num = num2;
|
||||
b = questWorkValue.Low;
|
||||
break;
|
||||
}
|
||||
}
|
||||
byte b2 = (byte)(((num >= 0 && num < questProgressInfo.Variables.Count) ? questProgressInfo.Variables[num] : 0) & 0xF);
|
||||
string value2 = (b.HasValue ? $" {b2}/{b}" : "");
|
||||
string value3 = ((b.HasValue && b2 >= b) ? "✓" : "○");
|
||||
foreach (uint item13 in hashSet.OrderBy((uint x) => x))
|
||||
{
|
||||
(string Name, bool Found) tuple3 = GetEnemyName(item13);
|
||||
var (value4, _) = tuple3;
|
||||
if (tuple3.Found)
|
||||
{
|
||||
_chatGui.Print($" {value3} Slay {value4}.{value2} (DataId: {item13})", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.Print($" {value3} Slay enemy.{value2} (DataId: {item13})", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int num3 = 0; num3 < questStep.ComplexCombatData.Count; num3++)
|
||||
{
|
||||
ComplexCombatData complexCombatData2 = questStep.ComplexCombatData[num3];
|
||||
int num4 = -1;
|
||||
byte? b3 = null;
|
||||
bool flag = false;
|
||||
for (int num5 = 0; num5 < complexCombatData2.CompletionQuestVariablesFlags.Count; num5++)
|
||||
{
|
||||
QuestWorkValue questWorkValue2 = complexCombatData2.CompletionQuestVariablesFlags[num5];
|
||||
if (questWorkValue2 != null)
|
||||
{
|
||||
if (questWorkValue2.Low.HasValue)
|
||||
{
|
||||
num4 = num5;
|
||||
b3 = questWorkValue2.Low;
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
if (questWorkValue2.High.HasValue)
|
||||
{
|
||||
num4 = num5;
|
||||
b3 = questWorkValue2.High;
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
byte b4 = (byte)((num4 >= 0 && num4 < questProgressInfo.Variables.Count) ? questProgressInfo.Variables[num4] : 0);
|
||||
byte b5 = (flag ? ((byte)(b4 >> 4)) : ((byte)(b4 & 0xF)));
|
||||
string value5;
|
||||
if (complexCombatData2.NameId.HasValue)
|
||||
{
|
||||
BNpcName? bNpcName = bnpcNameSheet?.GetRowOrDefault(complexCombatData2.NameId.Value);
|
||||
value5 = ((!bNpcName.HasValue || string.IsNullOrEmpty(bNpcName.Value.Singular.ToString())) ? "enemy" : bNpcName.Value.Singular.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
(string Name, bool Found) tuple5 = GetEnemyName(complexCombatData2.DataId);
|
||||
string item2 = tuple5.Name;
|
||||
value5 = (tuple5.Found ? item2 : "enemy");
|
||||
}
|
||||
string value6 = (b3.HasValue ? $" {b5}/{b3}" : "");
|
||||
string value7 = ((b3.HasValue && b5 >= b3) ? "✓" : "○");
|
||||
string value8 = (complexCombatData2.NameId.HasValue ? $" (DataId: {complexCombatData2.DataId}, NameId: {complexCombatData2.NameId})" : $" (DataId: {complexCombatData2.DataId})");
|
||||
_chatGui.Print($" {value7} Slay {value5}.{value6}{value8}", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
}
|
||||
else if (questStep.KillEnemyDataIds.Count == 0)
|
||||
{
|
||||
_chatGui.Print("No kill enemy data for this step.", "Questionable", 576);
|
||||
_chatGui.Print("", "Questionable", 576);
|
||||
}
|
||||
if (questStep.CompletionQuestVariablesFlags.Count <= 0 || !questStep.CompletionQuestVariablesFlags.Any((QuestWorkValue x) => x != null))
|
||||
{
|
||||
break;
|
||||
}
|
||||
_chatGui.Print("Completion Flags (Debug):", "Questionable", 576);
|
||||
for (int num6 = 0; num6 < questStep.CompletionQuestVariablesFlags.Count; num6++)
|
||||
{
|
||||
QuestWorkValue questWorkValue3 = questStep.CompletionQuestVariablesFlags[num6];
|
||||
if (questWorkValue3 != null)
|
||||
{
|
||||
int num7 = ((num6 < questProgressInfo.Variables.Count) ? questProgressInfo.Variables[num6] : 0);
|
||||
byte b6 = (byte)(num7 >> 4);
|
||||
byte b7 = (byte)(num7 & 0xF);
|
||||
string value9 = (((!questWorkValue3.High.HasValue || questWorkValue3.High == b6) && (!questWorkValue3.Low.HasValue || questWorkValue3.Low == b7)) ? " ✓" : " ✗");
|
||||
_chatGui.Print($" [{num6}] Expected: H={questWorkValue3.High?.ToString(CultureInfo.InvariantCulture) ?? "any"} L={questWorkValue3.Low?.ToString(CultureInfo.InvariantCulture) ?? "any"} | Actual: H={b6.ToString(CultureInfo.InvariantCulture)} L={b7.ToString(CultureInfo.InvariantCulture)}{value9}", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
case 8:
|
||||
case 10:
|
||||
break;
|
||||
IL_0209:
|
||||
_questSequenceWindow.ToggleOrUncollapse();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool OpenSetupIfNeeded(string arguments)
|
||||
|
|
@ -663,110 +171,8 @@ internal sealed class CommandHandler : IDisposable
|
|||
return false;
|
||||
}
|
||||
|
||||
private void ConfigureDebugOverlay(string[] arguments)
|
||||
{
|
||||
ElementId elementId;
|
||||
if (!_debugOverlay.DrawConditions())
|
||||
{
|
||||
_chatGui.PrintError("You don't have the debug overlay enabled.", "Questionable", 576);
|
||||
}
|
||||
else if (arguments.Length >= 1 && ElementId.TryFromString(arguments[0], out elementId) && elementId != null)
|
||||
{
|
||||
if (_questRegistry.TryGetQuest(elementId, out Questionable.Model.Quest quest))
|
||||
{
|
||||
_debugOverlay.HighlightedQuest = quest.Id;
|
||||
_chatGui.Print($"Set highlighted quest to {elementId} ({quest.Info.Name}).", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.PrintError($"Unknown quest {elementId}.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_debugOverlay.HighlightedQuest = null;
|
||||
_chatGui.Print("Cleared highlighted quest.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetNextQuest(string[] arguments)
|
||||
{
|
||||
if (arguments.Length >= 1 && ElementId.TryFromString(arguments[0], out ElementId elementId) && elementId != null)
|
||||
{
|
||||
Questionable.Model.Quest quest;
|
||||
if (_questFunctions.IsQuestLocked(elementId))
|
||||
{
|
||||
_chatGui.PrintError($"Quest {elementId} is locked.", "Questionable", 576);
|
||||
}
|
||||
else if (_questRegistry.TryGetQuest(elementId, out quest))
|
||||
{
|
||||
_questController.SetNextQuest(quest);
|
||||
_chatGui.Print($"Set next quest to {elementId} ({quest.Info.Name}).", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.PrintError($"Unknown quest {elementId}.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_questController.SetNextQuest(null);
|
||||
_chatGui.Print("Cleared next quest.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSimulatedQuest(string[] arguments)
|
||||
{
|
||||
if (arguments.Length >= 1 && ElementId.TryFromString(arguments[0], out ElementId elementId) && elementId != null)
|
||||
{
|
||||
if (_questRegistry.TryGetQuest(elementId, out Questionable.Model.Quest quest))
|
||||
{
|
||||
byte sequence = 0;
|
||||
int step = 0;
|
||||
if (arguments.Length >= 2 && byte.TryParse(arguments[1], out var result))
|
||||
{
|
||||
QuestSequence questSequence = quest.FindSequence(result);
|
||||
if (questSequence != null)
|
||||
{
|
||||
sequence = questSequence.Sequence;
|
||||
if (arguments.Length >= 3 && int.TryParse(arguments[2], out var result2) && questSequence.FindStep(result2) != null)
|
||||
{
|
||||
step = result2;
|
||||
}
|
||||
}
|
||||
}
|
||||
_questController.SimulateQuest(quest, sequence, step);
|
||||
_chatGui.Print($"Simulating quest {elementId} ({quest.Info.Name}).", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.PrintError($"Unknown quest {elementId}.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_questController.SimulateQuest(null, 0, 0);
|
||||
_chatGui.Print("Cleared simulated quest.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintMountId()
|
||||
{
|
||||
ushort? mountId = _gameFunctions.GetMountId();
|
||||
if (mountId.HasValue)
|
||||
{
|
||||
Mount? rowOrDefault = _dataManager.GetExcelSheet<Mount>().GetRowOrDefault(mountId.Value);
|
||||
_chatGui.Print($"Mount ID: {mountId}, Name: {rowOrDefault?.Singular}, Obtainable: {((rowOrDefault?.Order == -1) ? "No" : "Yes")}", "Questionable", 576);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatGui.Print("You are not mounted.", "Questionable", 576);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLogout(int type, int code)
|
||||
{
|
||||
_previouslyUnlockedUnlockLinks = Array.Empty<uint>();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Gui.ContextMenu;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
|
@ -43,9 +44,11 @@ internal sealed class ContextMenuController : IDisposable
|
|||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly ILogger<ContextMenuController> _logger;
|
||||
|
||||
public ContextMenuController(IContextMenu contextMenu, QuestController questController, GatheringPointRegistry gatheringPointRegistry, GatheringData gatheringData, QuestRegistry questRegistry, QuestData questData, GameFunctions gameFunctions, QuestFunctions questFunctions, IGameGui gameGui, IChatGui chatGui, IClientState clientState, ILogger<ContextMenuController> logger)
|
||||
public ContextMenuController(IContextMenu contextMenu, QuestController questController, GatheringPointRegistry gatheringPointRegistry, GatheringData gatheringData, QuestRegistry questRegistry, QuestData questData, GameFunctions gameFunctions, QuestFunctions questFunctions, IGameGui gameGui, IChatGui chatGui, IClientState clientState, IObjectTable objectTable, ILogger<ContextMenuController> logger)
|
||||
{
|
||||
_contextMenu = contextMenu;
|
||||
_questController = questController;
|
||||
|
|
@ -58,6 +61,7 @@ internal sealed class ContextMenuController : IDisposable
|
|||
_gameGui = gameGui;
|
||||
_chatGui = chatGui;
|
||||
_clientState = clientState;
|
||||
_objectTable = objectTable;
|
||||
_logger = logger;
|
||||
_contextMenu.OnMenuOpened += MenuOpened;
|
||||
}
|
||||
|
|
@ -113,7 +117,11 @@ internal sealed class ContextMenuController : IDisposable
|
|||
|
||||
private unsafe void AddContextMenuEntry(IMenuOpenedArgs args, uint itemId, uint npcId, EClassJob classJob, string verb)
|
||||
{
|
||||
EClassJob rowId = (EClassJob)_clientState.LocalPlayer.ClassJob.RowId;
|
||||
if (!(_objectTable[0] is ICharacter { ClassJob: var classJob2 }))
|
||||
{
|
||||
return;
|
||||
}
|
||||
EClassJob rowId = (EClassJob)classJob2.RowId;
|
||||
bool flag = classJob != rowId;
|
||||
if (flag)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
|
|
@ -135,15 +136,18 @@ internal sealed class InterruptHandler : IDisposable
|
|||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly TerritoryData _territoryData;
|
||||
|
||||
private readonly ILogger<InterruptHandler> _logger;
|
||||
|
||||
public event EventHandler? Interrupted;
|
||||
|
||||
public unsafe InterruptHandler(IGameInteropProvider gameInteropProvider, IClientState clientState, TerritoryData territoryData, ILogger<InterruptHandler> logger)
|
||||
public unsafe InterruptHandler(IGameInteropProvider gameInteropProvider, IClientState clientState, IObjectTable objectTable, TerritoryData territoryData, ILogger<InterruptHandler> logger)
|
||||
{
|
||||
_clientState = clientState;
|
||||
_objectTable = objectTable;
|
||||
_territoryData = territoryData;
|
||||
_logger = logger;
|
||||
_processActionEffectHook = gameInteropProvider.HookFromSignature<ProcessActionEffect>("40 ?? 56 57 41 ?? 41 ?? 41 ?? 48 ?? ?? ?? ?? ?? ?? ?? 48", HandleProcessActionEffect);
|
||||
|
|
@ -158,11 +162,12 @@ internal sealed class InterruptHandler : IDisposable
|
|||
{
|
||||
return;
|
||||
}
|
||||
IGameObject gameObject = _objectTable[0];
|
||||
for (int i = 0; i < effectHeader->TargetCount; i++)
|
||||
{
|
||||
int num = (int)(effectTail[i] & 0xFFFFFFFFu);
|
||||
EffectEntry* ptr = effectArray + 8 * i;
|
||||
bool flag = (uint)num == _clientState.LocalPlayer?.GameObjectId;
|
||||
bool flag = (uint)num == gameObject?.GameObjectId;
|
||||
if (flag)
|
||||
{
|
||||
EActionEffectType type = ptr->Type;
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ internal sealed class MovementController : IDisposable
|
|||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly GameFunctions _gameFunctions;
|
||||
|
||||
private readonly ChatFunctions _chatFunctions;
|
||||
|
|
@ -89,6 +91,8 @@ internal sealed class MovementController : IDisposable
|
|||
|
||||
private Task<List<Vector3>>? _pathfindTask;
|
||||
|
||||
private long _pathfindStartTime;
|
||||
|
||||
public bool IsNavmeshReady
|
||||
{
|
||||
get
|
||||
|
|
@ -138,10 +142,15 @@ internal sealed class MovementController : IDisposable
|
|||
|
||||
public int BuiltNavmeshPercent => _navmeshIpc.GetBuildProgress();
|
||||
|
||||
public MovementController(NavmeshIpc navmeshIpc, IClientState clientState, GameFunctions gameFunctions, ChatFunctions chatFunctions, ICondition condition, MovementOverrideController movementOverrideController, AetheryteData aetheryteData, ILogger<MovementController> logger)
|
||||
public bool IsNavmeshPathfindInProgress => _navmeshIpc.IsPathfindInProgress;
|
||||
|
||||
public int NumQueuedPathfindRequests => _navmeshIpc.NumQueuedPathfindRequests;
|
||||
|
||||
public MovementController(NavmeshIpc navmeshIpc, IClientState clientState, IObjectTable objectTable, GameFunctions gameFunctions, ChatFunctions chatFunctions, ICondition condition, MovementOverrideController movementOverrideController, AetheryteData aetheryteData, ILogger<MovementController> logger)
|
||||
{
|
||||
_navmeshIpc = navmeshIpc;
|
||||
_clientState = clientState;
|
||||
_objectTable = objectTable;
|
||||
_gameFunctions = gameFunctions;
|
||||
_chatFunctions = chatFunctions;
|
||||
_condition = condition;
|
||||
|
|
@ -154,16 +163,51 @@ internal sealed class MovementController : IDisposable
|
|||
{
|
||||
if (_pathfindTask != null && Destination != null)
|
||||
{
|
||||
if (!_pathfindTask.IsCompleted && Environment.TickCount64 - _pathfindStartTime > 30000 && _navmeshIpc.NumQueuedPathfindRequests > 5)
|
||||
{
|
||||
_logger.LogWarning("Pathfinding appears stuck: {QueuedRequests} queued requests, task running for {Duration}ms", _navmeshIpc.NumQueuedPathfindRequests, Environment.TickCount64 - _pathfindStartTime);
|
||||
}
|
||||
if (_pathfindTask.IsCompletedSuccessfully)
|
||||
{
|
||||
_logger.LogInformation("Pathfinding complete, got {Count} points", _pathfindTask.Result.Count);
|
||||
if (_pathfindTask.Result.Count == 0)
|
||||
{
|
||||
if (Destination.NavmeshCalculations == 1)
|
||||
{
|
||||
_logger.LogWarning("Initial pathfinding returned 0 points, attempting to find accessible destination");
|
||||
Vector3? vector = TryFindAccessibleDestination(Destination.Position, Destination.IsFlying, Destination.Land);
|
||||
if (vector.HasValue && Vector3.Distance(Destination.Position, vector.Value) < 30f)
|
||||
{
|
||||
_logger.LogInformation("Retrying pathfinding with adjusted destination: {AdjustedDestination}", vector.Value.ToString("G", CultureInfo.InvariantCulture));
|
||||
Restart(Destination with
|
||||
{
|
||||
Position = vector.Value
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (Destination.IsFlying && Destination.Land)
|
||||
{
|
||||
_logger.LogWarning("Adjusted destination failed, trying tolerance-based pathfinding");
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(30L));
|
||||
Vector3 vector2 = _objectTable[0]?.Position ?? Vector3.Zero;
|
||||
if (Destination.IsFlying)
|
||||
{
|
||||
Vector3 vector3 = vector2;
|
||||
vector3.Y = vector2.Y + 0.2f;
|
||||
vector2 = vector3;
|
||||
}
|
||||
_pathfindStartTime = Environment.TickCount64;
|
||||
_pathfindTask = _navmeshIpc.PathfindWithTolerance(vector2, Destination.Position, Destination.IsFlying, 10f, _cancellationTokenSource.Token);
|
||||
Destination.NavmeshCalculations++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
ResetPathfinding();
|
||||
throw new PathfindingFailedException();
|
||||
}
|
||||
List<Vector3> list = _pathfindTask.Result.Skip(1).ToList();
|
||||
Vector3 p = _clientState.LocalPlayer?.Position ?? list[0];
|
||||
Vector3 p = _objectTable[0]?.Position ?? list[0];
|
||||
if (Destination.IsFlying && !_condition[ConditionFlag.InFlight] && _condition[ConditionFlag.Mounted] && (IsOnFlightPath(p) || list.Any(IsOnFlightPath)))
|
||||
{
|
||||
ActionManager.Instance()->UseAction(ActionType.GeneralAction, 2u, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null);
|
||||
|
|
@ -179,6 +223,7 @@ internal sealed class MovementController : IDisposable
|
|||
_logger.LogInformation("Running navmesh recalculation with fudged point ({From} to {To})", list.Last(), Destination.Position);
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(30L));
|
||||
_pathfindStartTime = Environment.TickCount64;
|
||||
_pathfindTask = _navmeshIpc.Pathfind(list.Last(), Destination.Position, Destination.IsFlying, _cancellationTokenSource.Token);
|
||||
return;
|
||||
}
|
||||
|
|
@ -220,7 +265,7 @@ internal sealed class MovementController : IDisposable
|
|||
Restart(Destination);
|
||||
return;
|
||||
}
|
||||
Vector3 vector = _clientState.LocalPlayer?.Position ?? Vector3.Zero;
|
||||
Vector3 vector4 = _objectTable[0]?.Position ?? Vector3.Zero;
|
||||
if (Destination.MovementType == EMovementType.Landing)
|
||||
{
|
||||
if (!_condition[ConditionFlag.InFlight])
|
||||
|
|
@ -228,9 +273,9 @@ internal sealed class MovementController : IDisposable
|
|||
Stop();
|
||||
}
|
||||
}
|
||||
else if ((vector - Destination.Position).Length() < Destination.StopDistance)
|
||||
else if ((vector4 - Destination.Position).Length() < Destination.StopDistance)
|
||||
{
|
||||
if (vector.Y - Destination.Position.Y <= Destination.VerticalStopDistance)
|
||||
if (vector4.Y - Destination.Position.Y <= Destination.VerticalStopDistance)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
|
@ -239,7 +284,7 @@ internal sealed class MovementController : IDisposable
|
|||
IGameObject gameObject = _gameFunctions.FindObjectByDataId(Destination.DataId.Value);
|
||||
if ((gameObject is ICharacter || gameObject is IEventObj) ? true : false)
|
||||
{
|
||||
if (Math.Abs(vector.Y - gameObject.Position.Y) < 1.95f)
|
||||
if (Math.Abs(vector4.Y - gameObject.Position.Y) < 1.95f)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
|
@ -250,7 +295,7 @@ internal sealed class MovementController : IDisposable
|
|||
{
|
||||
Stop();
|
||||
}
|
||||
else if (Math.Abs(vector.Y - gameObject.Position.Y) < 1.95f)
|
||||
else if (Math.Abs(vector4.Y - gameObject.Position.Y) < 1.95f)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
|
@ -268,10 +313,10 @@ internal sealed class MovementController : IDisposable
|
|||
else
|
||||
{
|
||||
List<Vector3> waypoints = _navmeshIpc.GetWaypoints();
|
||||
Vector3? vector2 = _clientState.LocalPlayer?.Position;
|
||||
if (vector2.HasValue && (!Destination.ShouldRecalculateNavmesh() || !RecalculateNavmesh(waypoints, vector2.Value)) && !Destination.IsFlying && !_condition[ConditionFlag.Mounted] && !_gameFunctions.HasStatusPreventingSprint() && Destination.CanSprint)
|
||||
Vector3? vector5 = _objectTable[0]?.Position;
|
||||
if (vector5.HasValue && (!Destination.ShouldRecalculateNavmesh() || !RecalculateNavmesh(waypoints, vector5.Value)) && !Destination.IsFlying && !_condition[ConditionFlag.Mounted] && !_gameFunctions.HasStatusPreventingSprint() && Destination.CanSprint)
|
||||
{
|
||||
TriggerSprintIfNeeded(waypoints, vector2.Value);
|
||||
TriggerSprintIfNeeded(waypoints, vector5.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -331,7 +376,7 @@ internal sealed class MovementController : IDisposable
|
|||
Destination.NavmeshCalculations++;
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(30L));
|
||||
Vector3 vector2 = _clientState.LocalPlayer.Position;
|
||||
Vector3 vector2 = _objectTable[0]?.Position ?? Vector3.Zero;
|
||||
if (fly && _aetheryteData.CalculateDistance(vector2, _clientState.TerritoryType, EAetheryteLocation.CoerthasCentralHighlandsCampDragonhead) < 11f)
|
||||
{
|
||||
Vector3 vector = vector2;
|
||||
|
|
@ -345,7 +390,16 @@ internal sealed class MovementController : IDisposable
|
|||
vector.Y = vector2.Y + 0.2f;
|
||||
vector2 = vector;
|
||||
}
|
||||
_pathfindTask = _navmeshIpc.Pathfind(vector2, to, fly, _cancellationTokenSource.Token);
|
||||
_pathfindStartTime = Environment.TickCount64;
|
||||
if (fly && land)
|
||||
{
|
||||
_logger.LogInformation("Using tolerance-based pathfinding for landing (tolerance: 5.0)");
|
||||
_pathfindTask = _navmeshIpc.PathfindWithTolerance(vector2, to, fly, 5f, _cancellationTokenSource.Token);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pathfindTask = _navmeshIpc.Pathfind(vector2, to, fly, _cancellationTokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
public void NavigateTo(EMovementType type, uint? dataId, List<Vector3> to, bool fly, bool sprint, float? stopDistance, float? verticalStopDistance = null, bool land = false)
|
||||
|
|
@ -380,6 +434,46 @@ internal sealed class MovementController : IDisposable
|
|||
_pathfindTask = null;
|
||||
}
|
||||
|
||||
private Vector3? TryFindAccessibleDestination(Vector3 target, bool flying, bool landing)
|
||||
{
|
||||
float[] array = ((!(flying && landing)) ? ((!flying) ? new float[3] { 1f, 3f, 5f } : new float[3] { 2f, 5f, 10f }) : new float[3] { 5f, 10f, 15f });
|
||||
float[] array2 = ((!flying) ? new float[3] { 1f, 2f, 3f } : new float[3] { 3f, 5f, 10f });
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
float num = array[i];
|
||||
float num2 = array2[Math.Min(i, array2.Length - 1)];
|
||||
Vector3? vector = _navmeshIpc.FindNearestMeshPoint(target, num, num2);
|
||||
if (vector.HasValue)
|
||||
{
|
||||
float num3 = Vector3.Distance(target, vector.Value);
|
||||
if (num3 <= num * 1.5f)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
_logger.LogInformation("Adjusted destination from {Original} to {Adjusted} (distance: {Distance:F2}, extent: {ExtentXZ}/{ExtentY})", target.ToString("G", CultureInfo.InvariantCulture), vector.Value.ToString("G", CultureInfo.InvariantCulture), num3, num, num2);
|
||||
}
|
||||
return vector.Value;
|
||||
}
|
||||
}
|
||||
Vector3? pointOnFloor = _navmeshIpc.GetPointOnFloor(target, flying, num);
|
||||
if (!pointOnFloor.HasValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
float num4 = Vector3.Distance(target, pointOnFloor.Value);
|
||||
if (num4 <= num * 1.5f)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
_logger.LogInformation("Adjusted destination via floor point from {Original} to {Adjusted} (distance: {Distance:F2}, extent: {ExtentXZ})", target.ToString("G", CultureInfo.InvariantCulture), pointOnFloor.Value.ToString("G", CultureInfo.InvariantCulture), num4, num);
|
||||
}
|
||||
return pointOnFloor.Value;
|
||||
}
|
||||
}
|
||||
_logger.LogWarning("Could not find accessible mesh point near {Target} within max extent {MaxExtent}", target.ToString("G", CultureInfo.InvariantCulture), array[^1]);
|
||||
return null;
|
||||
}
|
||||
|
||||
private unsafe bool RecalculateNavmesh(List<Vector3> navPoints, Vector3 start)
|
||||
{
|
||||
if (Destination == null)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Numerics;
|
|||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Keys;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Gui.Toast;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
|
@ -84,6 +85,8 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
|||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly GameFunctions _gameFunctions;
|
||||
|
||||
private readonly QuestFunctions _questFunctions;
|
||||
|
|
@ -231,10 +234,11 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
|||
|
||||
public event AutomationTypeChangedEventHandler? AutomationTypeChanged;
|
||||
|
||||
public QuestController(IClientState clientState, GameFunctions gameFunctions, QuestFunctions questFunctions, MovementController movementController, CombatController combatController, GatheringController gatheringController, ILogger<QuestController> logger, QuestRegistry questRegistry, IKeyState keyState, IChatGui chatGui, ICondition condition, IToastGui toastGui, Configuration configuration, TaskCreator taskCreator, IServiceProvider serviceProvider, InterruptHandler interruptHandler, IDataManager dataManager, SinglePlayerDutyConfigComponent singlePlayerDutyConfigComponent)
|
||||
public QuestController(IClientState clientState, IObjectTable objectTable, GameFunctions gameFunctions, QuestFunctions questFunctions, MovementController movementController, CombatController combatController, GatheringController gatheringController, ILogger<QuestController> logger, QuestRegistry questRegistry, IKeyState keyState, IChatGui chatGui, ICondition condition, IToastGui toastGui, Configuration configuration, TaskCreator taskCreator, IServiceProvider serviceProvider, InterruptHandler interruptHandler, IDataManager dataManager, SinglePlayerDutyConfigComponent singlePlayerDutyConfigComponent)
|
||||
: base(chatGui, condition, serviceProvider, interruptHandler, dataManager, logger)
|
||||
{
|
||||
_clientState = clientState;
|
||||
_objectTable = objectTable;
|
||||
_gameFunctions = gameFunctions;
|
||||
_questFunctions = questFunctions;
|
||||
_movementController = movementController;
|
||||
|
|
@ -425,12 +429,12 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
|||
_lastProgressUpdate = DateTime.Now;
|
||||
return;
|
||||
}
|
||||
IPlayerCharacter localPlayer = _clientState.LocalPlayer;
|
||||
if (localPlayer == null)
|
||||
IGameObject gameObject = _objectTable[0];
|
||||
if (gameObject == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Vector3 position = localPlayer.Position;
|
||||
Vector3 position = gameObject.Position;
|
||||
if (CurrentQuest == null)
|
||||
{
|
||||
return;
|
||||
|
|
@ -463,7 +467,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
|||
{
|
||||
if (_configuration.General.AutoStepRefreshEnabled && AutomationType == EAutomationType.Automatic && IsRunning && CurrentQuest != null && _clientState.IsLoggedIn)
|
||||
{
|
||||
return _clientState.LocalPlayer != null;
|
||||
return _objectTable[0] != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -651,9 +655,9 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
|||
{
|
||||
_logger.LogInformation("New quest: {QuestName}", quest.Info.Name);
|
||||
_startedQuest = new QuestProgress(quest, b);
|
||||
if (_clientState.LocalPlayer != null && _clientState.LocalPlayer.Level < quest.Info.Level)
|
||||
if (_objectTable[0] is IPlayerCharacter playerCharacter && playerCharacter.Level < quest.Info.Level)
|
||||
{
|
||||
_logger.LogInformation("Stopping automation, player level ({PlayerLevel}) < quest level ({QuestLevel}", _clientState.LocalPlayer.Level, quest.Info.Level);
|
||||
_logger.LogInformation("Stopping automation, player level ({PlayerLevel}) < quest level ({QuestLevel}", playerCharacter.Level, quest.Info.Level);
|
||||
Stop("Quest level too high");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
68
Questionable/Questionable.Data/HuntMobData.cs
Normal file
68
Questionable/Questionable.Data/HuntMobData.cs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
using System.Collections.Generic;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace Questionable.Data;
|
||||
|
||||
internal sealed class HuntMobData
|
||||
{
|
||||
private readonly HashSet<uint> _aRankDataIds = new HashSet<uint>();
|
||||
|
||||
private readonly HashSet<uint> _sRankDataIds = new HashSet<uint>();
|
||||
|
||||
private readonly HashSet<uint> _allHuntMobDataIds = new HashSet<uint>();
|
||||
|
||||
public const float SafeDistance = 15f;
|
||||
|
||||
public IReadOnlySet<uint> ARankDataIds => _aRankDataIds;
|
||||
|
||||
public IReadOnlySet<uint> SRankDataIds => _sRankDataIds;
|
||||
|
||||
public IReadOnlySet<uint> AllHuntMobDataIds => _allHuntMobDataIds;
|
||||
|
||||
public HuntMobData(IDataManager dataManager)
|
||||
{
|
||||
ExcelSheet<NotoriousMonster> excelSheet = dataManager.GetExcelSheet<NotoriousMonster>();
|
||||
if (excelSheet == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (NotoriousMonster item in excelSheet)
|
||||
{
|
||||
byte rank = item.Rank;
|
||||
if ((uint)(rank - 2) > 1u)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
uint rowId = item.BNpcBase.RowId;
|
||||
if (rowId != 0)
|
||||
{
|
||||
_allHuntMobDataIds.Add(rowId);
|
||||
if (item.Rank == 2)
|
||||
{
|
||||
_aRankDataIds.Add(rowId);
|
||||
}
|
||||
else if (item.Rank == 3)
|
||||
{
|
||||
_sRankDataIds.Add(rowId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsHuntMob(uint dataId)
|
||||
{
|
||||
return _allHuntMobDataIds.Contains(dataId);
|
||||
}
|
||||
|
||||
public bool IsARank(uint dataId)
|
||||
{
|
||||
return _aRankDataIds.Contains(dataId);
|
||||
}
|
||||
|
||||
public bool IsSRank(uint dataId)
|
||||
{
|
||||
return _sRankDataIds.Contains(dataId);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,12 +11,18 @@ namespace Questionable.External;
|
|||
|
||||
internal sealed class NavmeshIpc
|
||||
{
|
||||
private readonly IDalamudPluginInterface _pluginInterface;
|
||||
|
||||
private readonly ILogger<NavmeshIpc> _logger;
|
||||
|
||||
private readonly ICallGateSubscriber<bool> _isNavReady;
|
||||
|
||||
private readonly ICallGateSubscriber<Vector3, Vector3, bool, CancellationToken, Task<List<Vector3>>> _navPathfind;
|
||||
|
||||
private readonly ICallGateSubscriber<bool> _navPathfindInProgress;
|
||||
|
||||
private readonly ICallGateSubscriber<int> _navNumQueuedRequests;
|
||||
|
||||
private readonly ICallGateSubscriber<List<Vector3>, bool, object> _pathMoveTo;
|
||||
|
||||
private readonly ICallGateSubscriber<object> _pathStop;
|
||||
|
|
@ -29,6 +35,8 @@ internal sealed class NavmeshIpc
|
|||
|
||||
private readonly ICallGateSubscriber<Vector3, bool, float, Vector3?> _queryPointOnFloor;
|
||||
|
||||
private readonly ICallGateSubscriber<Vector3, float, float, Vector3?> _queryNearestPoint;
|
||||
|
||||
private readonly ICallGateSubscriber<float> _buildProgress;
|
||||
|
||||
public bool IsReady
|
||||
|
|
@ -61,17 +69,51 @@ internal sealed class NavmeshIpc
|
|||
}
|
||||
}
|
||||
|
||||
public bool IsPathfindInProgress
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return _navPathfindInProgress.InvokeFunc();
|
||||
}
|
||||
catch (IpcError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int NumQueuedPathfindRequests
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return _navNumQueuedRequests.InvokeFunc();
|
||||
}
|
||||
catch (IpcError)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public NavmeshIpc(IDalamudPluginInterface pluginInterface, ILogger<NavmeshIpc> logger)
|
||||
{
|
||||
_pluginInterface = pluginInterface;
|
||||
_logger = logger;
|
||||
_isNavReady = pluginInterface.GetIpcSubscriber<bool>("vnavmesh.Nav.IsReady");
|
||||
_navPathfind = pluginInterface.GetIpcSubscriber<Vector3, Vector3, bool, CancellationToken, Task<List<Vector3>>>("vnavmesh.Nav.PathfindCancelable");
|
||||
_navPathfindInProgress = pluginInterface.GetIpcSubscriber<bool>("vnavmesh.Nav.PathfindInProgress");
|
||||
_navNumQueuedRequests = pluginInterface.GetIpcSubscriber<int>("vnavmesh.Nav.PathfindNumQueued");
|
||||
_pathMoveTo = pluginInterface.GetIpcSubscriber<List<Vector3>, bool, object>("vnavmesh.Path.MoveTo");
|
||||
_pathStop = pluginInterface.GetIpcSubscriber<object>("vnavmesh.Path.Stop");
|
||||
_pathIsRunning = pluginInterface.GetIpcSubscriber<bool>("vnavmesh.Path.IsRunning");
|
||||
_pathListWaypoints = pluginInterface.GetIpcSubscriber<List<Vector3>>("vnavmesh.Path.ListWaypoints");
|
||||
_pathSetTolerance = pluginInterface.GetIpcSubscriber<float, object>("vnavmesh.Path.SetTolerance");
|
||||
_queryPointOnFloor = pluginInterface.GetIpcSubscriber<Vector3, bool, float, Vector3?>("vnavmesh.Query.Mesh.PointOnFloor");
|
||||
_queryNearestPoint = pluginInterface.GetIpcSubscriber<Vector3, float, float, Vector3?>("vnavmesh.Query.Mesh.NearestPoint");
|
||||
_buildProgress = pluginInterface.GetIpcSubscriber<float>("vnavmesh.Nav.BuildProgress");
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +143,20 @@ internal sealed class NavmeshIpc
|
|||
}
|
||||
}
|
||||
|
||||
public Task<List<Vector3>> PathfindWithTolerance(Vector3 localPlayerPosition, Vector3 targetPosition, bool fly, float tolerance, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_pathSetTolerance.InvokeAction(0.25f);
|
||||
return _pluginInterface.GetIpcSubscriber<Vector3, Vector3, bool, float, CancellationToken, Task<List<Vector3>>>("vnavmesh.Nav.PathfindWithTolerance").InvokeFunc(localPlayerPosition, targetPosition, fly, tolerance, cancellationToken);
|
||||
}
|
||||
catch (IpcError exception)
|
||||
{
|
||||
_logger.LogWarning(exception, "Could not pathfind with tolerance via navmesh");
|
||||
return Task.FromException<List<Vector3>>(exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveTo(List<Vector3> position, bool fly)
|
||||
{
|
||||
Stop();
|
||||
|
|
@ -126,6 +182,30 @@ internal sealed class NavmeshIpc
|
|||
}
|
||||
}
|
||||
|
||||
public Vector3? GetPointOnFloor(Vector3 position, bool unlandable, float halfExtentXZ)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _queryPointOnFloor.InvokeFunc(position, unlandable, halfExtentXZ);
|
||||
}
|
||||
catch (IpcError)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3? FindNearestMeshPoint(Vector3 position, float halfExtentXZ, float halfExtentY)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _queryNearestPoint.InvokeFunc(position, halfExtentXZ, halfExtentY);
|
||||
}
|
||||
catch (IpcError)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Vector3> GetWaypoints()
|
||||
{
|
||||
if (IsPathRunning)
|
||||
|
|
|
|||
|
|
@ -22,16 +22,16 @@ internal sealed class AetheryteFunctions
|
|||
|
||||
private readonly IDataManager _dataManager;
|
||||
|
||||
private readonly IClientState _clientState;
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
public DateTime ReturnRequestedAt { get; set; } = DateTime.MinValue;
|
||||
|
||||
public AetheryteFunctions(IServiceProvider serviceProvider, ILogger<AetheryteFunctions> logger, IDataManager dataManager, IClientState clientState)
|
||||
public AetheryteFunctions(IServiceProvider serviceProvider, ILogger<AetheryteFunctions> logger, IDataManager dataManager, IObjectTable objectTable)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
_dataManager = dataManager;
|
||||
_clientState = clientState;
|
||||
_objectTable = objectTable;
|
||||
}
|
||||
|
||||
public unsafe bool IsAetheryteUnlocked(uint aetheryteId, out byte subIndex)
|
||||
|
|
@ -114,7 +114,7 @@ internal sealed class AetheryteFunctions
|
|||
|
||||
public unsafe AetheryteRegistrationResult CanRegisterFreeOrFavoriteAetheryte(EAetheryteLocation aetheryteLocation)
|
||||
{
|
||||
if (_clientState.LocalPlayer == null)
|
||||
if (_objectTable[0] == null)
|
||||
{
|
||||
return AetheryteRegistrationResult.NotPossible;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ internal sealed class GameFunctions
|
|||
|
||||
public unsafe ushort? GetMountId()
|
||||
{
|
||||
BattleChara* ptr = (BattleChara*)(_clientState.LocalPlayer?.Address ?? 0);
|
||||
BattleChara* ptr = (BattleChara*)(_objectTable.LocalPlayer?.Address ?? 0);
|
||||
if (ptr != null && ptr->Mount.MountId != 0)
|
||||
{
|
||||
return ptr->Mount.MountId;
|
||||
|
|
@ -203,14 +203,14 @@ internal sealed class GameFunctions
|
|||
if (gameObject != null)
|
||||
{
|
||||
Vector3 position = gameObject.Position;
|
||||
return ActionManager.Instance()->UseActionLocation(ActionType.KeyItem, itemId, 3758096384uL, &position, 0u, 0);
|
||||
return ActionManager.Instance()->UseActionLocation(ActionType.EventItem, itemId, 3758096384uL, &position, 0u, 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public unsafe bool UseItemOnPosition(Vector3 position, uint itemId)
|
||||
{
|
||||
return ActionManager.Instance()->UseActionLocation(ActionType.KeyItem, itemId, 3758096384uL, &position, 0u, 0);
|
||||
return ActionManager.Instance()->UseActionLocation(ActionType.EventItem, itemId, 3758096384uL, &position, 0u, 0);
|
||||
}
|
||||
|
||||
public unsafe bool UseAction(EAction action)
|
||||
|
|
@ -287,7 +287,7 @@ internal sealed class GameFunctions
|
|||
{
|
||||
return true;
|
||||
}
|
||||
IPlayerCharacter localPlayer = _clientState.LocalPlayer;
|
||||
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
|
||||
if (localPlayer == null)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -308,7 +308,7 @@ internal sealed class GameFunctions
|
|||
|
||||
private unsafe bool HasCharacterStatusPreventingMountOrSprint()
|
||||
{
|
||||
IPlayerCharacter localPlayer = _clientState.LocalPlayer;
|
||||
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
|
||||
if (localPlayer == null)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -324,7 +324,7 @@ internal sealed class GameFunctions
|
|||
|
||||
public unsafe bool HasStatus(EStatus statusId)
|
||||
{
|
||||
IPlayerCharacter localPlayer = _clientState.LocalPlayer;
|
||||
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
|
||||
if (localPlayer == null)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -423,7 +423,7 @@ internal sealed class GameFunctions
|
|||
|
||||
public unsafe bool IsOccupied()
|
||||
{
|
||||
if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null)
|
||||
if (!_clientState.IsLoggedIn || _objectTable.LocalPlayer == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -547,7 +547,7 @@ internal sealed class GameFunctions
|
|||
|
||||
public unsafe bool SyncToFate(uint fateId)
|
||||
{
|
||||
IPlayerCharacter localPlayer = _clientState.LocalPlayer;
|
||||
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
|
||||
if (localPlayer == null)
|
||||
{
|
||||
_logger.LogWarning("Cannot sync to FATE: LocalPlayer is null");
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ internal sealed class QuestFunctions
|
|||
|
||||
private readonly IDataManager _dataManager;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly IGameGui _gameGui;
|
||||
|
|
@ -68,7 +70,7 @@ internal sealed class QuestFunctions
|
|||
|
||||
private ElementId? _lastLoggedAcceptedHiddenMsq;
|
||||
|
||||
public QuestFunctions(QuestRegistry questRegistry, QuestData questData, AetheryteFunctions aetheryteFunctions, AlliedSocietyQuestFunctions alliedSocietyQuestFunctions, AlliedSocietyData alliedSocietyData, AetheryteData aetheryteData, Configuration configuration, IDataManager dataManager, IClientState clientState, IGameGui gameGui, IAetheryteList aetheryteList, ILogger<QuestFunctions> logger)
|
||||
public QuestFunctions(QuestRegistry questRegistry, QuestData questData, AetheryteFunctions aetheryteFunctions, AlliedSocietyQuestFunctions alliedSocietyQuestFunctions, AlliedSocietyData alliedSocietyData, AetheryteData aetheryteData, Configuration configuration, IDataManager dataManager, IObjectTable objectTable, IClientState clientState, IGameGui gameGui, IAetheryteList aetheryteList, ILogger<QuestFunctions> logger)
|
||||
{
|
||||
_questRegistry = questRegistry;
|
||||
_questData = questData;
|
||||
|
|
@ -78,6 +80,7 @@ internal sealed class QuestFunctions
|
|||
_aetheryteData = aetheryteData;
|
||||
_configuration = configuration;
|
||||
_dataManager = dataManager;
|
||||
_objectTable = objectTable;
|
||||
_clientState = clientState;
|
||||
_gameGui = gameGui;
|
||||
_aetheryteList = aetheryteList;
|
||||
|
|
@ -163,14 +166,14 @@ internal sealed class QuestFunctions
|
|||
}
|
||||
questReference = QuestReference.NoQuest(questReference.State);
|
||||
}
|
||||
byte currentLevel = _clientState.LocalPlayer?.Level ?? 0;
|
||||
byte currentLevel = _objectTable.LocalPlayer?.Level ?? 0;
|
||||
if (questReference.CurrentQuest != null)
|
||||
{
|
||||
Questionable.Model.Quest quest;
|
||||
bool flag = _questRegistry.TryGetQuest(questReference.CurrentQuest, out quest);
|
||||
bool flag2 = IsQuestAccepted(questReference.CurrentQuest);
|
||||
_logger.LogTrace("MSQ check: QuestId={QuestId}, InRegistry={InRegistry}, Level={QuestLevel}, CurrentLevel={CurrentLevel}, IsAccepted={IsAccepted}", questReference.CurrentQuest, flag, ((int?)quest?.Info.Level) ?? (-1), currentLevel, flag2);
|
||||
EClassJob valueOrDefault = ((EClassJob?)_clientState.LocalPlayer?.ClassJob.RowId).GetValueOrDefault();
|
||||
EClassJob valueOrDefault = ((EClassJob?)_objectTable.LocalPlayer?.ClassJob.RowId).GetValueOrDefault();
|
||||
if (valueOrDefault != EClassJob.Adventurer)
|
||||
{
|
||||
QuestInfo questInfo = (from x in _questData.GetClassJobQuests(valueOrDefault)
|
||||
|
|
@ -467,7 +470,7 @@ internal sealed class QuestFunctions
|
|||
return (QuestReference.NoQuest(MainScenarioQuestState.Unavailable), $"Not readdy to accept quest {questId.Value}");
|
||||
}
|
||||
_lastLoggedNotReadyQuest = null;
|
||||
if (!(_clientState.LocalPlayer?.Level).HasValue)
|
||||
if (!(_objectTable.LocalPlayer?.Level).HasValue)
|
||||
{
|
||||
_logger.LogTrace("GetMainScenarioQuest: In loading screen");
|
||||
return (QuestReference.NoQuest(MainScenarioQuestState.LoadingScreen), "In loading screen");
|
||||
|
|
@ -492,7 +495,7 @@ internal sealed class QuestFunctions
|
|||
|
||||
private unsafe bool IsOnAlliedSocietyMount()
|
||||
{
|
||||
BattleChara* ptr = (BattleChara*)(_clientState.LocalPlayer?.Address ?? 0);
|
||||
BattleChara* ptr = (BattleChara*)(_objectTable.LocalPlayer?.Address ?? 0);
|
||||
if (ptr != null && ptr->Mount.MountId != 0)
|
||||
{
|
||||
return _alliedSocietyData.Mounts.ContainsKey(ptr->Mount.MountId);
|
||||
|
|
@ -639,7 +642,7 @@ internal sealed class QuestFunctions
|
|||
}
|
||||
if (!_configuration.Advanced.SkipClassJobQuests)
|
||||
{
|
||||
EClassJob valueOrDefault = ((EClassJob?)_clientState.LocalPlayer?.ClassJob.RowId).GetValueOrDefault();
|
||||
EClassJob valueOrDefault = ((EClassJob?)_objectTable.LocalPlayer?.ClassJob.RowId).GetValueOrDefault();
|
||||
uint[] shadowbringersRoleQuestChapters = QuestData.AllRoleQuestChapters.Select((IReadOnlyList<uint> x) => x[0]).ToArray();
|
||||
if (valueOrDefault != EClassJob.Adventurer)
|
||||
{
|
||||
|
|
@ -712,7 +715,7 @@ internal sealed class QuestFunctions
|
|||
}
|
||||
if (!ignoreLevel)
|
||||
{
|
||||
byte b = _clientState.LocalPlayer?.Level ?? 0;
|
||||
byte b = _objectTable.LocalPlayer?.Level ?? 0;
|
||||
if (b == 0)
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -31,11 +31,13 @@ internal sealed class StopConditionComponent : ConfigComponent
|
|||
|
||||
private readonly UiUtils _uiUtils;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly QuestController _questController;
|
||||
|
||||
public StopConditionComponent(IDalamudPluginInterface pluginInterface, QuestSelector questSelector, QuestFunctions questFunctions, QuestRegistry questRegistry, QuestTooltipComponent questTooltipComponent, UiUtils uiUtils, IClientState clientState, QuestController questController, Configuration configuration)
|
||||
public StopConditionComponent(IDalamudPluginInterface pluginInterface, QuestSelector questSelector, QuestFunctions questFunctions, QuestRegistry questRegistry, QuestTooltipComponent questTooltipComponent, UiUtils uiUtils, IObjectTable objectTable, IClientState clientState, QuestController questController, Configuration configuration)
|
||||
: base(pluginInterface, configuration)
|
||||
{
|
||||
StopConditionComponent stopConditionComponent = this;
|
||||
|
|
@ -45,6 +47,7 @@ internal sealed class StopConditionComponent : ConfigComponent
|
|||
_questFunctions = questFunctions;
|
||||
_questTooltipComponent = questTooltipComponent;
|
||||
_uiUtils = uiUtils;
|
||||
_objectTable = objectTable;
|
||||
_clientState = clientState;
|
||||
_questController = questController;
|
||||
_questSelector.SuggestionPredicate = (Quest quest) => configuration.Stop.QuestsToStopAfter.All((ElementId x) => x != quest.Id);
|
||||
|
|
@ -88,7 +91,7 @@ internal sealed class StopConditionComponent : ConfigComponent
|
|||
base.Configuration.Stop.TargetLevel = Math.Max(1, Math.Min(100, data));
|
||||
Save();
|
||||
}
|
||||
int num = _clientState.LocalPlayer?.Level ?? 0;
|
||||
int num = _objectTable.LocalPlayer?.Level ?? 0;
|
||||
if (num > 0)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ internal sealed class ActiveQuestComponent
|
|||
|
||||
private readonly UiUtils _uiUtils;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly IChatGui _chatGui;
|
||||
|
|
@ -58,7 +60,7 @@ internal sealed class ActiveQuestComponent
|
|||
return _003CRegexGenerator_g_003EFBB8301322196CF81C64F1652C2FA6E1D6BF3907141F781E9D97ABED51BF056C4__MultipleWhitespaceRegex_0.Instance;
|
||||
}
|
||||
|
||||
public ActiveQuestComponent(QuestController questController, MovementController movementController, CombatController combatController, GatheringController gatheringController, QuestFunctions questFunctions, ICommandManager commandManager, Configuration configuration, QuestRegistry questRegistry, PriorityWindow priorityWindow, UiUtils uiUtils, IClientState clientState, IChatGui chatGui, ILogger<ActiveQuestComponent> logger)
|
||||
public ActiveQuestComponent(QuestController questController, MovementController movementController, CombatController combatController, GatheringController gatheringController, QuestFunctions questFunctions, ICommandManager commandManager, Configuration configuration, QuestRegistry questRegistry, PriorityWindow priorityWindow, UiUtils uiUtils, IObjectTable objectTable, IClientState clientState, IChatGui chatGui, ILogger<ActiveQuestComponent> logger)
|
||||
{
|
||||
_questController = questController;
|
||||
_movementController = movementController;
|
||||
|
|
@ -70,6 +72,7 @@ internal sealed class ActiveQuestComponent
|
|||
_questRegistry = questRegistry;
|
||||
_priorityWindow = priorityWindow;
|
||||
_uiUtils = uiUtils;
|
||||
_objectTable = objectTable;
|
||||
_clientState = clientState;
|
||||
_chatGui = chatGui;
|
||||
_logger = logger;
|
||||
|
|
@ -243,7 +246,7 @@ internal sealed class ActiveQuestComponent
|
|||
Vector4 col = ImGuiColors.ParsedPurple;
|
||||
if (flag)
|
||||
{
|
||||
int num = _clientState.LocalPlayer?.Level ?? 0;
|
||||
int num = _objectTable.LocalPlayer?.Level ?? 0;
|
||||
if (num > 0 && num >= _configuration.Stop.TargetLevel)
|
||||
{
|
||||
col = ImGuiColors.ParsedGreen;
|
||||
|
|
@ -267,7 +270,7 @@ internal sealed class ActiveQuestComponent
|
|||
ImGui.Separator();
|
||||
if (flag)
|
||||
{
|
||||
int num2 = _clientState.LocalPlayer?.Level ?? 0;
|
||||
int num2 = _objectTable.LocalPlayer?.Level ?? 0;
|
||||
text = new ImU8String(14, 1);
|
||||
text.AppendLiteral("Stop at level ");
|
||||
text.AppendFormatted(_configuration.Stop.TargetLevel);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ internal sealed class CreationUtilsComponent
|
|||
|
||||
private readonly QuestSelectionWindow _questSelectionWindow;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly ITargetManager _targetManager;
|
||||
|
|
@ -49,7 +51,7 @@ internal sealed class CreationUtilsComponent
|
|||
|
||||
private readonly ILogger<CreationUtilsComponent> _logger;
|
||||
|
||||
public CreationUtilsComponent(MovementController movementController, GameFunctions gameFunctions, QuestFunctions questFunctions, TerritoryData territoryData, QuestData questData, QuestSelectionWindow questSelectionWindow, IClientState clientState, ITargetManager targetManager, ICondition condition, IGameGui gameGui, Configuration configuration, ILogger<CreationUtilsComponent> logger)
|
||||
public CreationUtilsComponent(MovementController movementController, GameFunctions gameFunctions, QuestFunctions questFunctions, TerritoryData territoryData, QuestData questData, QuestSelectionWindow questSelectionWindow, IObjectTable objectTable, IClientState clientState, ITargetManager targetManager, ICondition condition, IGameGui gameGui, Configuration configuration, ILogger<CreationUtilsComponent> logger)
|
||||
{
|
||||
_movementController = movementController;
|
||||
_gameFunctions = gameFunctions;
|
||||
|
|
@ -57,6 +59,7 @@ internal sealed class CreationUtilsComponent
|
|||
_territoryData = territoryData;
|
||||
_questData = questData;
|
||||
_questSelectionWindow = questSelectionWindow;
|
||||
_objectTable = objectTable;
|
||||
_clientState = clientState;
|
||||
_targetManager = targetManager;
|
||||
_condition = condition;
|
||||
|
|
@ -129,16 +132,16 @@ internal sealed class CreationUtilsComponent
|
|||
handler.AppendFormatted(value);
|
||||
handler.AppendLiteral(")");
|
||||
ImGui.Text(string.Create(provider, ref handler));
|
||||
if (_clientState.LocalPlayer != null)
|
||||
if (_objectTable.LocalPlayer != null)
|
||||
{
|
||||
invariantCulture = CultureInfo.InvariantCulture;
|
||||
IFormatProvider provider2 = invariantCulture;
|
||||
handler = new DefaultInterpolatedStringHandler(10, 1, invariantCulture);
|
||||
handler.AppendLiteral("Distance: ");
|
||||
handler.AppendFormatted((target.Position - _clientState.LocalPlayer.Position).Length(), "F2");
|
||||
handler.AppendFormatted((target.Position - _objectTable.LocalPlayer.Position).Length(), "F2");
|
||||
ImGui.Text(string.Create(provider2, ref handler));
|
||||
ImGui.SameLine();
|
||||
float value2 = target.Position.Y - _clientState.LocalPlayer.Position.Y;
|
||||
float value2 = target.Position.Y - _objectTable.LocalPlayer.Position.Y;
|
||||
invariantCulture = CultureInfo.InvariantCulture;
|
||||
IFormatProvider provider3 = invariantCulture;
|
||||
handler = new DefaultInterpolatedStringHandler(3, 1, invariantCulture);
|
||||
|
|
@ -317,7 +320,7 @@ internal sealed class CreationUtilsComponent
|
|||
|
||||
private void DrawCopyButton()
|
||||
{
|
||||
if (_clientState.LocalPlayer != null)
|
||||
if (_objectTable.LocalPlayer != null)
|
||||
{
|
||||
bool num = ImGuiComponents.IconButton(FontAwesomeIcon.Copy);
|
||||
if (ImGui.IsItemHovered())
|
||||
|
|
@ -328,11 +331,11 @@ internal sealed class CreationUtilsComponent
|
|||
{
|
||||
ImU8String clipboardText = new ImU8String(87, 4);
|
||||
clipboardText.AppendLiteral("\"Position\": {\n \"X\": ");
|
||||
clipboardText.AppendFormatted(_clientState.LocalPlayer.Position.X.ToString(CultureInfo.InvariantCulture));
|
||||
clipboardText.AppendFormatted(_objectTable.LocalPlayer.Position.X.ToString(CultureInfo.InvariantCulture));
|
||||
clipboardText.AppendLiteral(",\n \"Y\": ");
|
||||
clipboardText.AppendFormatted(_clientState.LocalPlayer.Position.Y.ToString(CultureInfo.InvariantCulture));
|
||||
clipboardText.AppendFormatted(_objectTable.LocalPlayer.Position.Y.ToString(CultureInfo.InvariantCulture));
|
||||
clipboardText.AppendLiteral(",\n \"Z\": ");
|
||||
clipboardText.AppendFormatted(_clientState.LocalPlayer.Position.Z.ToString(CultureInfo.InvariantCulture));
|
||||
clipboardText.AppendFormatted(_objectTable.LocalPlayer.Position.Z.ToString(CultureInfo.InvariantCulture));
|
||||
clipboardText.AppendLiteral("\n},\n\"TerritoryId\": ");
|
||||
clipboardText.AppendFormatted(_clientState.TerritoryType);
|
||||
clipboardText.AppendLiteral(",\n\"InteractionType\": \"\"");
|
||||
|
|
@ -340,7 +343,7 @@ internal sealed class CreationUtilsComponent
|
|||
}
|
||||
else if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
Vector3 position = _clientState.LocalPlayer.Position;
|
||||
Vector3 position = _objectTable.LocalPlayer.Position;
|
||||
IFormatProvider invariantCulture = CultureInfo.InvariantCulture;
|
||||
DefaultInterpolatedStringHandler handler = new DefaultInterpolatedStringHandler(12, 3, invariantCulture);
|
||||
handler.AppendLiteral("new(");
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ internal sealed class DebugOverlay : Window
|
|||
return;
|
||||
}
|
||||
IClientState clientState = _clientState;
|
||||
if (clientState != null && clientState.IsLoggedIn && clientState.LocalPlayer != null && !clientState.IsPvPExcludingDen && _questController.IsQuestWindowOpen)
|
||||
if (clientState != null && clientState.IsLoggedIn && !clientState.IsPvPExcludingDen && _objectTable.LocalPlayer != null && _questController.IsQuestWindowOpen)
|
||||
{
|
||||
DrawCurrentQuest();
|
||||
DrawHighlightedQuest();
|
||||
|
|
@ -103,7 +103,7 @@ internal sealed class DebugOverlay : Window
|
|||
QuestStep questStep = questSequence.FindStep(i);
|
||||
if (questStep != null && TryGetPosition(questStep, out var position))
|
||||
{
|
||||
DrawStep(i.ToString(CultureInfo.InvariantCulture), questStep, position.Value, (Vector3.Distance(_clientState.LocalPlayer.Position, position.Value) < questStep.CalculateActualStopDistance()) ? 4278255360u : 4278190335u);
|
||||
DrawStep(i.ToString(CultureInfo.InvariantCulture), questStep, position.Value, (Vector3.Distance(_objectTable.LocalPlayer.Position, position.Value) < questStep.CalculateActualStopDistance()) ? 4278255360u : 4278190335u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -141,7 +141,7 @@ internal sealed class DebugOverlay : Window
|
|||
text.AppendLiteral("\n");
|
||||
text.AppendFormatted(position.ToString("G", CultureInfo.InvariantCulture));
|
||||
text.AppendLiteral(" [");
|
||||
text.AppendFormatted((position - _clientState.LocalPlayer.Position).Length(), "N2");
|
||||
text.AppendFormatted((position - _objectTable.LocalPlayer.Position).Length(), "N2");
|
||||
text.AppendLiteral("]\n");
|
||||
text.AppendFormatted(step.Comment);
|
||||
windowDrawList.AddText(pos, color, text);
|
||||
|
|
@ -175,7 +175,7 @@ internal sealed class DebugOverlay : Window
|
|||
text.AppendLiteral(" - ");
|
||||
text.AppendFormatted(item2);
|
||||
text.AppendLiteral(", ");
|
||||
text.AppendFormatted(Vector3.Distance(item3.Position, _clientState.LocalPlayer.Position), "N2");
|
||||
text.AppendFormatted(Vector3.Distance(item3.Position, _objectTable.LocalPlayer.Position), "N2");
|
||||
text.AppendLiteral(", ");
|
||||
text.AppendFormatted(item3.IsTargetable);
|
||||
windowDrawList.AddText(pos, (uint)col, text);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
|
|||
|
||||
private readonly QuestController _questController;
|
||||
|
||||
private readonly IObjectTable _objectTable;
|
||||
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly Configuration _configuration;
|
||||
|
|
@ -50,12 +52,13 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
|
|||
|
||||
public bool IsMinimized { get; set; }
|
||||
|
||||
public QuestWindow(IDalamudPluginInterface pluginInterface, QuestController questController, IClientState clientState, Configuration configuration, TerritoryData territoryData, ActiveQuestComponent activeQuestComponent, ARealmRebornComponent aRealmRebornComponent, EventInfoComponent eventInfoComponent, CreationUtilsComponent creationUtilsComponent, QuickAccessButtonsComponent quickAccessButtonsComponent, RemainingTasksComponent remainingTasksComponent, IFramework framework, InteractionUiController interactionUiController, ConfigWindow configWindow)
|
||||
public QuestWindow(IDalamudPluginInterface pluginInterface, QuestController questController, IObjectTable objectTable, IClientState clientState, Configuration configuration, TerritoryData territoryData, ActiveQuestComponent activeQuestComponent, ARealmRebornComponent aRealmRebornComponent, EventInfoComponent eventInfoComponent, CreationUtilsComponent creationUtilsComponent, QuickAccessButtonsComponent quickAccessButtonsComponent, RemainingTasksComponent remainingTasksComponent, IFramework framework, InteractionUiController interactionUiController, ConfigWindow configWindow)
|
||||
: base("Questionable v" + PluginVersion.ToString(3) + "###Questionable", ImGuiWindowFlags.AlwaysAutoResize)
|
||||
{
|
||||
QuestWindow questWindow = this;
|
||||
_pluginInterface = pluginInterface;
|
||||
_questController = questController;
|
||||
_objectTable = objectTable;
|
||||
_clientState = clientState;
|
||||
_configuration = configuration;
|
||||
_territoryData = territoryData;
|
||||
|
|
@ -134,7 +137,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null || _clientState.IsPvPExcludingDen)
|
||||
if (!_clientState.IsLoggedIn || _objectTable.LocalPlayer == null || _clientState.IsPvPExcludingDen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue