using System; using Dalamud.Hooking; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game.Event; using FFXIVClientStructs.FFXIV.Common.Lua; using Microsoft.Extensions.Logging; namespace Questionable.Controller.GameUi; internal sealed class AutoSnipeHandler : IDisposable { private unsafe delegate ulong EnqueueSnipeTaskDelegate(EventSceneModuleImplBase* scene, lua_State* state); private readonly QuestController _questController; private readonly Configuration _configuration; private readonly ILogger _logger; private readonly Hook? _enqueueSnipeTaskHook; public unsafe AutoSnipeHandler(QuestController questController, Configuration configuration, IGameInteropProvider gameInteropProvider, ILogger logger) { _questController = questController; _configuration = configuration; _logger = logger; try { _enqueueSnipeTaskHook = gameInteropProvider.HookFromSignature("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 50 48 8B F9 48 8D 4C 24 ??", EnqueueSnipeTask); _enqueueSnipeTaskHook.Enable(); _logger.LogInformation("AutoSnipeHandler enabled"); } catch (Exception exception) { _logger.LogError(exception, "Failed to initialize AutoSnipeHandler"); _enqueueSnipeTaskHook = null; } } private unsafe ulong EnqueueSnipeTask(EventSceneModuleImplBase* scene, lua_State* state) { if (_configuration.General.AutoSnipe && _questController.IsRunning) { _logger.LogDebug("Auto-completing snipe task"); TValue* top = state->top; top->tt = 3; top->value.n = 1.0; state->top++; return 1uL; } return _enqueueSnipeTaskHook.Original(scene, state); } public void Dispose() { if (_enqueueSnipeTaskHook != null) { _enqueueSnipeTaskHook.Disable(); _enqueueSnipeTaskHook.Dispose(); _logger.LogInformation("AutoSnipeHandler disabled"); } } }