1
0
Fork 0
forked from aly/qstbak

muffin v7.5.12

This commit is contained in:
alydev 2026-08-19 13:19:57 +10:00
parent 3102923ce2
commit 911ed68baa
65 changed files with 2356 additions and 1539 deletions

View file

@ -32,6 +32,7 @@ internal static class AethernetRide
private enum EAethernetPhase
{
None,
WaitingForPlayer,
Mounting,
Moving,
Unmounting,
@ -72,6 +73,12 @@ internal static class AethernetRide
return Environment.TickCount64 - _phaseStartedAt > (long)(timeoutSeconds * 1000f);
}
public override void ResetTimeout()
{
base.ResetTimeout();
_phaseStartedAt = Environment.TickCount64;
}
protected override bool Start()
{
SetPhase(EAethernetPhase.None);
@ -79,56 +86,60 @@ internal static class AethernetRide
aethernetTeleportService.Reset();
if (aetheryteFunctions.IsAetheryteUnlocked(base.Task.From) && aetheryteFunctions.IsAetheryteUnlocked(base.Task.To))
{
uint territoryType = clientState.TerritoryType;
IPlayerCharacter localPlayer = objectTable.LocalPlayer;
if (localPlayer == null)
{
return false;
}
Vector3 playerPosition = localPlayer.Position;
if (aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) < aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.To))
{
float num = (base.Task.From.IsFirmamentAetheryte() ? 11f : (AetheryteConverter.IsLargeAetheryte(base.Task.From) ? 11f : 4f));
if (aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) < num)
{
BeginTeleport();
return true;
}
if (base.Task.From == EAetheryteLocation.SolutionNine)
{
logger.LogDebug("Moving to S9 aetheryte");
int num2 = 4;
List<Vector3> list = new List<Vector3>(num2);
CollectionsMarshal.SetCount(list, num2);
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
span[0] = new Vector3(0f, 8.442986f, 9f);
span[1] = new Vector3(9f, 8.442986f, 0f);
span[2] = new Vector3(-9f, 8.442986f, 0f);
span[3] = new Vector3(0f, 8.442986f, -9f);
Vector3 to = list.MinBy((Vector3 x) => Vector3.Distance(playerPosition, x));
SetPhase(EAethernetPhase.Moving);
movementController.NavigateTo(EMovementType.Quest, (uint)base.Task.From, to, fly: false, sprint: true, 0.25f);
return true;
}
if (territoryData.CanUseMount(territoryType) && aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) > 30f && !gameFunctions.HasStatusPreventingMount() && gameFunctions.Mount())
{
SetPhase(EAethernetPhase.Mounting);
_continueAt = Environment.TickCount64 + 500;
return true;
}
StartMoving();
SetPhase(EAethernetPhase.WaitingForPlayer);
return true;
}
Vector3 position = localPlayer.Position;
if (HasArrived(position))
{
return false;
}
StartFromCurrentPosition(position);
return true;
}
if (clientState.TerritoryType == aetheryteData.TerritoryIds[base.Task.To])
{
logger.LogWarning("Aethernet ride not unlocked (from: {FromAetheryte}, to: {ToAetheryte}), skipping as we are already in the destination territory", base.Task.From, base.Task.To);
return false;
}
throw new TaskException($"Aethernet ride not unlocked (from: {base.Task.From}, to: {base.Task.To})");
}
private void StartFromCurrentPosition(Vector3 playerPosition)
{
uint territoryType = clientState.TerritoryType;
float num = (base.Task.From.IsFirmamentAetheryte() ? 11f : (AetheryteConverter.IsLargeAetheryte(base.Task.From) ? 11f : 4f));
if (aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) < num)
{
BeginTeleport();
}
else if (base.Task.From == EAetheryteLocation.SolutionNine)
{
logger.LogDebug("Moving to S9 aetheryte");
int num2 = 4;
List<Vector3> list = new List<Vector3>(num2);
CollectionsMarshal.SetCount(list, num2);
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
span[0] = new Vector3(0f, 8.442986f, 9f);
span[1] = new Vector3(9f, 8.442986f, 0f);
span[2] = new Vector3(-9f, 8.442986f, 0f);
span[3] = new Vector3(0f, 8.442986f, -9f);
Vector3 to = list.MinBy((Vector3 x) => Vector3.Distance(playerPosition, x));
SetPhase(EAethernetPhase.Moving);
movementController.NavigateTo(EMovementType.Quest, (uint)base.Task.From, to, fly: false, sprint: true, 0.25f);
}
else if (territoryData.CanUseMount(territoryType) && aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) > 30f && !gameFunctions.HasStatusPreventingMount() && gameFunctions.Mount())
{
SetPhase(EAethernetPhase.Mounting);
_continueAt = Environment.TickCount64 + 500;
}
else
{
if (clientState.TerritoryType != aetheryteData.TerritoryIds[base.Task.To])
{
throw new TaskException($"Aethernet ride not unlocked (from: {base.Task.From}, to: {base.Task.To})");
}
logger.LogWarning("Aethernet ride not unlocked (from: {FromAetheryte}, to: {ToAetheryte}), skipping as we are already in the destination territory", base.Task.From, base.Task.To);
StartMoving();
}
return false;
}
private void StartMoving()
@ -178,6 +189,20 @@ internal static class AethernetRide
}
switch (_phase)
{
case EAethernetPhase.WaitingForPlayer:
{
Vector3? vector2 = objectTable.LocalPlayer?.Position;
if (!vector2.HasValue)
{
return ETaskResult.StillRunning;
}
if (HasArrived(vector2.Value))
{
return ETaskResult.TaskComplete;
}
StartFromCurrentPosition(vector2.Value);
return ETaskResult.StillRunning;
}
case EAethernetPhase.Mounting:
if (condition[ConditionFlag.Mounted])
{
@ -228,21 +253,7 @@ internal static class AethernetRide
{
return ETaskResult.StillRunning;
}
if (aetheryteData.IsAirshipLanding(base.Task.To))
{
if (aetheryteData.CalculateAirshipLandingDistance(vector.Value, clientState.TerritoryType, base.Task.To) > 5f)
{
return ETaskResult.StillRunning;
}
}
else if (aetheryteData.IsCityAetheryte(base.Task.To) || aetheryteData.IsGoldSaucerAetheryte(base.Task.To))
{
if (aetheryteData.CalculateDistance(vector.Value, clientState.TerritoryType, base.Task.To) > 20f)
{
return ETaskResult.StillRunning;
}
}
else if (clientState.TerritoryType != aetheryteData.TerritoryIds[base.Task.To])
if (!HasArrived(vector.Value))
{
return ETaskResult.StillRunning;
}
@ -254,6 +265,15 @@ internal static class AethernetRide
}
}
private bool HasArrived(Vector3 position)
{
if (!aetheryteData.IsAirshipLanding(base.Task.To))
{
return aetheryteData.CalculateDistance(position, clientState.TerritoryType, base.Task.To) <= 20f;
}
return aetheryteData.CalculateAirshipLandingDistance(position, clientState.TerritoryType, base.Task.To) <= 5f;
}
public override bool ShouldInterruptOnDamage()
{
return true;

View file

@ -16,33 +16,85 @@ namespace Questionable.Controller.Steps.Shared;
internal static class RedeemRewardItems
{
internal sealed class Factory(QuestData questData, Configuration configuration) : ITaskFactory
internal sealed class Factory(QuestData questData, Configuration configuration, ILogger<Factory> logger) : ITaskFactory
{
public unsafe IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
{
if (step.InteractionType != EInteractionType.AcceptQuest)
{
return Array.Empty<ITask>();
}
List<ITask> list = new List<ITask>();
InventoryManager* ptr = InventoryManager.Instance();
if (ptr == null)
return CreateTasks(questData, configuration, logger);
}
}
internal sealed class CompletionFactory : ITaskFactory
{
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
{
if (step.InteractionType != EInteractionType.CompleteQuest)
{
return list;
return Array.Empty<ITask>();
}
bool hasFreeInventorySlot = InventoryHelper.HasFreeInventorySlot();
foreach (ItemReward redeemableItem in questData.RedeemableItems)
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new ScanAfterQuestCompletion(step.TurnInQuestId ?? quest.Id));
}
}
internal sealed record ScanAfterQuestCompletion(ElementId ElementId) : ITask
{
public override string ToString()
{
return $"ScanRewardsAfterQuestCompletion({ElementId})";
}
}
internal sealed class ScanAfterQuestCompletionExecutor(QuestFunctions questFunctions, QuestData questData, Configuration configuration, ILogger<ScanAfterQuestCompletionExecutor> logger) : TaskExecutor<ScanAfterQuestCompletion>(), IExtraTaskCreator, ITaskExecutor
{
private const long InventorySettleDelayMs = 1000L;
private long? _scanAt;
private List<ITask> _tasks = new List<ITask>();
protected override bool Start()
{
_scanAt = null;
_tasks = new List<ITask>();
return true;
}
public override ETaskResult Update()
{
if (!questFunctions.IsQuestComplete(base.Task.ElementId))
{
if (ptr->GetInventoryItemCount(redeemableItem.ItemId, isHq: false, checkEquipped: true, checkArmory: true, 0) != 0 && !redeemableItem.IsUnlocked() && PassesRedemptionFilters(redeemableItem.Type, redeemableItem.IsUntradable, configuration.General, hasFreeInventorySlot))
{
list.Add(new Task(redeemableItem));
}
return ETaskResult.StillRunning;
}
if (list.Count > 0)
long tickCount = Environment.TickCount64;
if (!_scanAt.HasValue)
{
list.Insert(0, new Mount.UnmountTask());
_scanAt = tickCount + 1000;
return ETaskResult.StillRunning;
}
return list;
if (tickCount < _scanAt)
{
return ETaskResult.StillRunning;
}
_tasks = CreateTasks(questData, configuration, logger);
if (_tasks.Count <= 0)
{
return ETaskResult.TaskComplete;
}
return ETaskResult.CreateNewTasks;
}
public IEnumerable<ITask> CreateExtraTasks()
{
return _tasks;
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
}
@ -182,6 +234,36 @@ internal static class RedeemRewardItems
}
}
private unsafe static List<ITask> CreateTasks(QuestData questData, Configuration configuration, ILogger logger)
{
List<ITask> list = new List<ITask>();
InventoryManager* ptr = InventoryManager.Instance();
if (ptr == null)
{
return list;
}
bool flag = InventoryHelper.HasFreeInventorySlot();
foreach (ItemReward redeemableItem in questData.RedeemableItems)
{
if (ptr->GetInventoryItemCount(redeemableItem.ItemId, isHq: false, checkEquipped: true, checkArmory: true, 0) != 0 && !redeemableItem.IsUnlocked())
{
if (!PassesRedemptionFilters(redeemableItem.Type, redeemableItem.IsUntradable, configuration.General, flag))
{
logger.LogDebug("Skipping quest reward {ItemName}: type={RewardType}, untradable={IsUntradable}, freeInventorySlot={HasFreeInventorySlot}", redeemableItem.Name, redeemableItem.Type, redeemableItem.IsUntradable, flag);
}
else
{
list.Add(new Task(redeemableItem));
}
}
}
if (list.Count > 0)
{
list.Insert(0, new Mount.UnmountTask());
}
return list;
}
internal static bool PassesRedemptionFilters(EItemRewardType type, bool isUntradable, Configuration.GeneralConfiguration general, bool hasFreeInventorySlot)
{
if (general.DisabledRewardTypes.Contains(type))

View file

@ -5,6 +5,7 @@ using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
using LLib.GameData;
using Questionable.Controller.Steps.Common;
using Questionable.Controller.Utils;
using Questionable.Data;
@ -61,19 +62,19 @@ internal static class WaitAtEnd
{
break;
}
goto IL_01bf;
goto IL_01ad;
case EInteractionType.SinglePlayerDuty:
if (bossModIpc.IsConfiguredToRunSoloInstance(quest.Id, step.SinglePlayerDutyOptions))
{
break;
}
goto IL_01bf;
goto IL_01ad;
case EInteractionType.Fish:
if (autoHookIpc.IsAvailable())
if (!autoHookIpc.IsAvailable())
{
break;
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new EndAutomation());
}
goto IL_01bf;
break;
case EInteractionType.WalkTo:
case EInteractionType.Jump:
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(Next(quest, sequence));
@ -91,13 +92,13 @@ internal static class WaitAtEnd
{
break;
}
goto IL_02a6;
goto IL_02ca;
case EInteractionType.UseItem:
if (!step.TargetTerritoryId.HasValue)
{
break;
}
goto IL_02a6;
goto IL_02ca;
case EInteractionType.AcceptQuest:
{
WaitQuestAccepted waitQuestAccepted = new WaitQuestAccepted(step.PickUpQuestId ?? quest.Id);
@ -128,9 +129,14 @@ internal static class WaitAtEnd
}
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[2] { waitQuestCompleted, waitDelay2 });
}
IL_01bf:
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new EndAutomation());
IL_02a6:
IL_01ad:
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[3]
{
new WaitManualDuty(),
new WaitDelay(),
Next(quest, sequence)
});
IL_02ca:
if (step.TerritoryId != step.TargetTerritoryId)
{
task2 = new WaitCondition.Task(() => clientState.TerritoryType == step.TargetTerritoryId, "Wait(tp to territory: " + territoryData.GetNameAndId(step.TargetTerritoryId.Value) + ")");
@ -369,6 +375,58 @@ internal static class WaitAtEnd
}
}
internal sealed record WaitManualDuty : IDutyTask, ITask
{
public override string ToString()
{
return "Wait(manual duty)";
}
}
internal sealed class WaitManualDutyExecutor(IClientState clientState, ICondition condition, TerritoryData territoryData) : TaskExecutor<WaitManualDuty>(), IDebugStateProvider, ITaskExecutor
{
private bool _enteredDuty;
protected override bool Start()
{
_enteredDuty = false;
return true;
}
public override ETaskResult Update()
{
uint territoryType = clientState.TerritoryType;
bool flag = territoryData.IsDutyInstance(territoryType) && !territoryData.IsFieldOperation(territoryType);
if (!_enteredDuty)
{
if (flag)
{
_enteredDuty = true;
}
return ETaskResult.StillRunning;
}
if (flag || ConditionHelper.IsBetweenAreas(condition))
{
return ETaskResult.StillRunning;
}
return ETaskResult.TaskComplete;
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
public string? GetDebugState()
{
if (!_enteredDuty)
{
return "Waiting for you to enter the duty";
}
return "Waiting for the duty to finish";
}
}
internal sealed record NextStep(ElementId ElementId, int Sequence) : ILastTask, ITask
{
public override string ToString()