mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
update clientstructs
- fix broken gamepad sig by delegating to CS
This commit is contained in:
parent
445fe09181
commit
919ca87bbe
5 changed files with 48 additions and 134 deletions
|
|
@ -24,12 +24,6 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
|
|||
/// </summary>
|
||||
public IntPtr ProcessPacketPlayerSetup { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the method which polls the gamepads for data.
|
||||
/// Called every frame, even when `Enable Gamepad` is off in the settings.
|
||||
/// </summary>
|
||||
public IntPtr GamepadPoll { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scan for and setup any configured address pointers.
|
||||
/// </summary>
|
||||
|
|
@ -43,7 +37,5 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
|
|||
// movzx edx, byte ptr [rbx+rsi+1D5E0E0h] KeyboardStateIndexArray
|
||||
this.KeyboardState = sig.ScanText("48 8D 0C 85 ?? ?? ?? ?? 8B 04 31 85 C2 0F 85") + 0x4;
|
||||
this.KeyboardStateIndexArray = sig.ScanText("0F B6 94 33 ?? ?? ?? ?? 84 D2") + 0x4;
|
||||
|
||||
this.GamepadPoll = sig.ScanText("40 55 53 57 41 54 41 57 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 44 0F 29 B4 24"); // unnamed in cs
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Dalamud.Game.ClientState.GamePad;
|
||||
|
||||
/// <summary>
|
||||
/// Struct which gets populated by polling the gamepads.
|
||||
///
|
||||
/// Has an array of gamepads, among many other things (here not mapped).
|
||||
/// All we really care about is the final data which the game uses to determine input.
|
||||
///
|
||||
/// The size is definitely bigger than only the following fields but I do not know how big.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct GamepadInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Left analogue stick's horizontal value, -99 for left, 99 for right.
|
||||
/// </summary>
|
||||
[FieldOffset(0x78)]
|
||||
public int LeftStickX;
|
||||
|
||||
/// <summary>
|
||||
/// Left analogue stick's vertical value, -99 for down, 99 for up.
|
||||
/// </summary>
|
||||
[FieldOffset(0x7C)]
|
||||
public int LeftStickY;
|
||||
|
||||
/// <summary>
|
||||
/// Right analogue stick's horizontal value, -99 for left, 99 for right.
|
||||
/// </summary>
|
||||
[FieldOffset(0x80)]
|
||||
public int RightStickX;
|
||||
|
||||
/// <summary>
|
||||
/// Right analogue stick's vertical value, -99 for down, 99 for up.
|
||||
/// </summary>
|
||||
[FieldOffset(0x84)]
|
||||
public int RightStickY;
|
||||
|
||||
/// <summary>
|
||||
/// Raw input, set the whole time while a button is held. See <see cref="GamepadButtons"/> for the mapping.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a bitfield.
|
||||
/// </remarks>
|
||||
[FieldOffset(0x88)]
|
||||
public ushort ButtonsRaw;
|
||||
|
||||
/// <summary>
|
||||
/// Button pressed, set once when the button is pressed. See <see cref="GamepadButtons"/> for the mapping.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a bitfield.
|
||||
/// </remarks>
|
||||
[FieldOffset(0x8C)]
|
||||
public ushort ButtonsPressed;
|
||||
|
||||
/// <summary>
|
||||
/// Button released input, set once right after the button is not hold anymore. See <see cref="GamepadButtons"/> for the mapping.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a bitfield.
|
||||
/// </remarks>
|
||||
[FieldOffset(0x90)]
|
||||
public ushort ButtonsReleased;
|
||||
|
||||
/// <summary>
|
||||
/// Repeatedly emits the held button input in fixed intervals. See <see cref="GamepadButtons"/> for the mapping.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a bitfield.
|
||||
/// </remarks>
|
||||
[FieldOffset(0x94)]
|
||||
public ushort ButtonsRepeat;
|
||||
}
|
||||
|
|
@ -4,7 +4,8 @@ using Dalamud.Hooking;
|
|||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Input;
|
||||
|
||||
using ImGuiNET;
|
||||
using Serilog;
|
||||
|
|
@ -23,7 +24,7 @@ namespace Dalamud.Game.ClientState.GamePad;
|
|||
#pragma warning restore SA1015
|
||||
internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
||||
{
|
||||
private readonly Hook<ControllerPoll>? gamepadPoll;
|
||||
private readonly Hook<PadDevice.Delegates.Poll>? gamepadPoll;
|
||||
|
||||
private bool isDisposed;
|
||||
|
||||
|
|
@ -35,25 +36,21 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
|||
[ServiceManager.ServiceConstructor]
|
||||
private GamepadState(ClientState clientState)
|
||||
{
|
||||
var resolver = clientState.AddressResolver;
|
||||
Log.Verbose($"GamepadPoll address {Util.DescribeAddress(resolver.GamepadPoll)}");
|
||||
this.gamepadPoll = Hook<ControllerPoll>.FromAddress(resolver.GamepadPoll, this.GamepadPollDetour);
|
||||
this.gamepadPoll = Hook<PadDevice.Delegates.Poll>.FromAddress((nint)PadDevice.StaticVirtualTablePointer->Poll, this.GamepadPollDetour);
|
||||
this.gamepadPoll?.Enable();
|
||||
}
|
||||
|
||||
private delegate int ControllerPoll(IntPtr controllerInput);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pointer to the current instance of the GamepadInput struct.
|
||||
/// </summary>
|
||||
public IntPtr GamepadInputAddress { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Vector2 LeftStick =>
|
||||
public Vector2 LeftStick =>
|
||||
new(this.leftStickX, this.leftStickY);
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Vector2 RightStick =>
|
||||
public Vector2 RightStick =>
|
||||
new(this.rightStickX, this.rightStickY);
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -61,28 +58,28 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
|||
///
|
||||
/// Exposed internally for Debug Data window.
|
||||
/// </summary>
|
||||
internal ushort ButtonsPressed { get; private set; }
|
||||
internal GamepadButtons ButtonsPressed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets raw button bitmask, set the whole time while a button is held. See <see cref="GamepadButtons"/> for the mapping.
|
||||
///
|
||||
/// Exposed internally for Debug Data window.
|
||||
/// </summary>
|
||||
internal ushort ButtonsRaw { get; private set; }
|
||||
internal GamepadButtons ButtonsRaw { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets button released bitmask, set once right after the button is not hold anymore. See <see cref="GamepadButtons"/> for the mapping.
|
||||
///
|
||||
/// Exposed internally for Debug Data window.
|
||||
/// </summary>
|
||||
internal ushort ButtonsReleased { get; private set; }
|
||||
internal GamepadButtons ButtonsReleased { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets button repeat bitmask, emits the held button input in fixed intervals. See <see cref="GamepadButtons"/> for the mapping.
|
||||
///
|
||||
/// Exposed internally for Debug Data window.
|
||||
/// </summary>
|
||||
internal ushort ButtonsRepeat { get; private set; }
|
||||
internal GamepadButtons ButtonsRepeat { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether detour should block gamepad input for game.
|
||||
|
|
@ -95,16 +92,16 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
|||
internal bool NavEnableGamepad { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Pressed(GamepadButtons button) => (this.ButtonsPressed & (ushort)button) > 0 ? 1 : 0;
|
||||
public float Pressed(GamepadButtons button) => (this.ButtonsPressed & button) > 0 ? 1 : 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Repeat(GamepadButtons button) => (this.ButtonsRepeat & (ushort)button) > 0 ? 1 : 0;
|
||||
public float Repeat(GamepadButtons button) => (this.ButtonsRepeat & button) > 0 ? 1 : 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Released(GamepadButtons button) => (this.ButtonsReleased & (ushort)button) > 0 ? 1 : 0;
|
||||
public float Released(GamepadButtons button) => (this.ButtonsReleased & button) > 0 ? 1 : 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Raw(GamepadButtons button) => (this.ButtonsRaw & (ushort)button) > 0 ? 1 : 0;
|
||||
public float Raw(GamepadButtons button) => (this.ButtonsRaw & button) > 0 ? 1 : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this instance, alongside its hooks.
|
||||
|
|
@ -115,28 +112,28 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
|||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private int GamepadPollDetour(IntPtr gamepadInput)
|
||||
private nint GamepadPollDetour(PadDevice* gamepadInput)
|
||||
{
|
||||
var original = this.gamepadPoll!.Original(gamepadInput);
|
||||
try
|
||||
{
|
||||
this.GamepadInputAddress = gamepadInput;
|
||||
var input = (GamepadInput*)gamepadInput;
|
||||
this.leftStickX = input->LeftStickX;
|
||||
this.leftStickY = input->LeftStickY;
|
||||
this.rightStickX = input->RightStickX;
|
||||
this.rightStickY = input->RightStickY;
|
||||
this.ButtonsRaw = input->ButtonsRaw;
|
||||
this.ButtonsPressed = input->ButtonsPressed;
|
||||
this.ButtonsReleased = input->ButtonsReleased;
|
||||
this.ButtonsRepeat = input->ButtonsRepeat;
|
||||
this.GamepadInputAddress = (nint)gamepadInput;
|
||||
|
||||
this.leftStickX = gamepadInput->GamepadInputData.LeftStickX;
|
||||
this.leftStickY = gamepadInput->GamepadInputData.LeftStickY;
|
||||
this.rightStickX = gamepadInput->GamepadInputData.RightStickX;
|
||||
this.rightStickY = gamepadInput->GamepadInputData.RightStickY;
|
||||
this.ButtonsRaw = (GamepadButtons)gamepadInput->GamepadInputData.Buttons;
|
||||
this.ButtonsPressed = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsPressed;
|
||||
this.ButtonsReleased = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsReleased;
|
||||
this.ButtonsRepeat = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsRepeat;
|
||||
|
||||
if (this.NavEnableGamepad)
|
||||
{
|
||||
input->LeftStickX = 0;
|
||||
input->LeftStickY = 0;
|
||||
input->RightStickX = 0;
|
||||
input->RightStickY = 0;
|
||||
gamepadInput->GamepadInputData.LeftStickX = 0;
|
||||
gamepadInput->GamepadInputData.LeftStickY = 0;
|
||||
gamepadInput->GamepadInputData.RightStickX = 0;
|
||||
gamepadInput->GamepadInputData.RightStickY = 0;
|
||||
|
||||
// NOTE (Chiv) Zeroing `ButtonsRaw` destroys `ButtonPressed`, `ButtonReleased`
|
||||
// and `ButtonRepeat` as the game uses the RAW input to determine those (apparently).
|
||||
|
|
@ -153,16 +150,16 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
|||
// `ButtonPressed` while ImGuiConfigFlags.NavEnableGamepad is set.
|
||||
// This is debatable.
|
||||
// ImGui itself does not care either way as it uses the Raw values and does its own state handling.
|
||||
const ushort deletionMask = (ushort)(~GamepadButtons.L2
|
||||
& ~GamepadButtons.R2
|
||||
& ~GamepadButtons.DpadDown
|
||||
& ~GamepadButtons.DpadLeft
|
||||
& ~GamepadButtons.DpadUp
|
||||
& ~GamepadButtons.DpadRight);
|
||||
input->ButtonsRaw &= deletionMask;
|
||||
input->ButtonsPressed = 0;
|
||||
input->ButtonsReleased = 0;
|
||||
input->ButtonsRepeat = 0;
|
||||
const GamepadButtonsFlags deletionMask = ~GamepadButtonsFlags.L2
|
||||
& ~GamepadButtonsFlags.R2
|
||||
& ~GamepadButtonsFlags.DPadDown
|
||||
& ~GamepadButtonsFlags.DPadLeft
|
||||
& ~GamepadButtonsFlags.DPadUp
|
||||
& ~GamepadButtonsFlags.DPadRight;
|
||||
gamepadInput->GamepadInputData.Buttons &= deletionMask;
|
||||
gamepadInput->GamepadInputData.ButtonsPressed = 0;
|
||||
gamepadInput->GamepadInputData.ButtonsReleased = 0;
|
||||
gamepadInput->GamepadInputData.ButtonsRepeat = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ internal class GamepadWidget : IDataWindowWidget
|
|||
{
|
||||
/// <inheritdoc/>
|
||||
public string[]? CommandShortcuts { get; init; } = { "gamepad", "controller" };
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string DisplayName { get; init; } = "Gamepad";
|
||||
public string DisplayName { get; init; } = "Gamepad";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Ready { get; set; }
|
||||
|
|
@ -42,24 +42,24 @@ internal class GamepadWidget : IDataWindowWidget
|
|||
|
||||
this.DrawHelper(
|
||||
"Buttons Raw",
|
||||
gamepadState.ButtonsRaw,
|
||||
(uint)gamepadState.ButtonsRaw,
|
||||
gamepadState.Raw);
|
||||
this.DrawHelper(
|
||||
"Buttons Pressed",
|
||||
gamepadState.ButtonsPressed,
|
||||
(uint)gamepadState.ButtonsPressed,
|
||||
gamepadState.Pressed);
|
||||
this.DrawHelper(
|
||||
"Buttons Repeat",
|
||||
gamepadState.ButtonsRepeat,
|
||||
(uint)gamepadState.ButtonsRepeat,
|
||||
gamepadState.Repeat);
|
||||
this.DrawHelper(
|
||||
"Buttons Released",
|
||||
gamepadState.ButtonsReleased,
|
||||
(uint)gamepadState.ButtonsReleased,
|
||||
gamepadState.Released);
|
||||
ImGui.Text($"LeftStick {gamepadState.LeftStick}");
|
||||
ImGui.Text($"RightStick {gamepadState.RightStick}");
|
||||
}
|
||||
|
||||
|
||||
private void DrawHelper(string text, uint mask, Func<GamepadButtons, float> resolve)
|
||||
{
|
||||
ImGui.Text($"{text} {mask:X4}");
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 3c99b4f8f7f56ee4defd3ee75809c73312359f9e
|
||||
Subproject commit 48076a4ce750c8f008f3bedd04d0bced03147f56
|
||||
Loading…
Add table
Add a link
Reference in a new issue