qstbak/Questionable/Questionable.Controller.Steps.Interactions/Dive.cs
2025-10-09 07:47:19 +10:00

168 lines
4.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
using FFXIVClientStructs.FFXIV.Client.System.Input;
using FFXIVClientStructs.FFXIV.Client.System.String;
using FFXIVClientStructs.FFXIV.Client.UI;
using Microsoft.Extensions.Logging;
using Questionable.Controller.Steps.Common;
using Questionable.Model;
using Questionable.Model.Questing;
namespace Questionable.Controller.Steps.Interactions;
internal static class Dive
{
internal sealed class Factory : SimpleTaskFactory
{
public override ITask? CreateTask(Quest quest, QuestSequence sequence, QuestStep step)
{
if (step.InteractionType != EInteractionType.Dive)
{
return null;
}
return new Task();
}
}
internal sealed class Task : ITask
{
public override string ToString()
{
return "Dive";
}
}
internal sealed class DoDive(ICondition condition, ILogger<DoDive> logger) : AbstractDelayedTaskExecutor<Task>(TimeSpan.FromSeconds(5L))
{
private readonly Queue<(uint Type, nint Key)> _keysToPress = new Queue<(uint, nint)>();
private int _attempts;
protected override bool StartInternal()
{
if (condition[ConditionFlag.Diving])
{
return false;
}
if (condition[ConditionFlag.Mounted] || condition[ConditionFlag.Swimming])
{
Descend();
return true;
}
throw new TaskException("You aren't swimming, so we can't dive.");
}
public unsafe override ETaskResult Update()
{
if (_keysToPress.TryDequeue(out (uint, nint) result))
{
if (result.Item1 == 0)
{
return ETaskResult.StillRunning;
}
logger.LogDebug("{Action} key {KeyCode:X2}", (result.Item1 == 256) ? "Pressing" : "Releasing", result.Item2);
NativeMethods.SendMessage((nint)Device.Instance()->hWnd, result.Item1, result.Item2, IntPtr.Zero);
return ETaskResult.StillRunning;
}
return base.Update();
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
protected override ETaskResult UpdateInternal()
{
if (condition[ConditionFlag.Diving])
{
return ETaskResult.TaskComplete;
}
if (_attempts >= 3)
{
throw new TaskException("Please dive manually.");
}
Descend();
_attempts++;
return ETaskResult.StillRunning;
}
private unsafe void Descend()
{
UIInputData.Keybind keybind = default(UIInputData.Keybind);
Utf8String* name = Utf8String.FromString("MOVE_DESCENT");
UIInputData.Instance()->GetKeybindByName(name, (Keybind*)(&keybind));
logger.LogInformation("Dive keybind: {Key1} + {Modifier1}, {Key2} + {Modifier2}", keybind.Key, keybind.Modifier, keybind.AltKey, keybind.AltModifier);
int num = 2;
List<List<nint>> list = new List<List<nint>>(num);
CollectionsMarshal.SetCount(list, num);
Span<List<nint>> span = CollectionsMarshal.AsSpan(list);
int num2 = 0;
span[num2] = GetKeysToPress(keybind.Key, keybind.Modifier);
num2++;
span[num2] = GetKeysToPress(keybind.AltKey, keybind.AltModifier);
List<nint> list2 = (from x in list
where x != null
select (x)).MinBy((List<nint> x) => x.Count);
if (list2 == null || list2.Count == 0)
{
throw new TaskException("No useable keybind found for diving");
}
foreach (nint item in list2)
{
_keysToPress.Enqueue((256u, item));
_keysToPress.Enqueue((0u, 0));
_keysToPress.Enqueue((0u, 0));
}
for (int num3 = 0; num3 < 5; num3++)
{
_keysToPress.Enqueue((0u, 0));
}
list2.Reverse();
foreach (nint item2 in list2)
{
_keysToPress.Enqueue((257u, item2));
}
}
}
private static class NativeMethods
{
public const uint WM_KEYUP = 257u;
public const uint WM_KEYDOWN = 256u;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
public static extern nint SendMessage(nint hWnd, uint Msg, nint wParam, nint lParam);
}
private static List<nint>? GetKeysToPress(SeVirtualKey key, ModifierFlag modifier)
{
List<nint> list = new List<nint>();
if (modifier.HasFlag(ModifierFlag.Ctrl))
{
list.Add(17);
}
if (modifier.HasFlag(ModifierFlag.Shift))
{
list.Add(16);
}
if (modifier.HasFlag(ModifierFlag.Alt))
{
list.Add(18);
}
nint num = (nint)key;
if (num == 0)
{
return null;
}
list.Add(num);
return list;
}
}