168 lines
4.3 KiB
C#
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;
|
|
}
|
|
}
|