// // UserActionDetector.cs // // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Data.SqlTypes; using NosSmooth.LocalBinding.Hooks; using NosSmooth.LocalBinding.Objects; using NosSmooth.LocalBinding.Structs; using Remora.Results; namespace NosSmooth.LocalClient; /// /// Tries to determine whether NosTale function calls /// were made by user. /// public class UserActionDetector { private readonly SemaphoreSlim _semaphore; private bool _handlingDisabled; private (ushort X, ushort Y) _lastWalkPosition; /// /// Initializes a new instance of the class. /// public UserActionDetector() { _semaphore = new SemaphoreSlim(1, 1); } /// /// Execute an action that makes sure walk won't be treated as a user action. /// /// The action to execute. /// The cancellation token for cancelling the operation. /// The return type. /// Return value of the action. public async Task NotUserActionAsync(Func action, CancellationToken ct = default) { await _semaphore.WaitAsync(ct); _handlingDisabled = true; var result = action(); _handlingDisabled = false; _semaphore.Release(); return result; } /// /// Execute an action that makes sure walk won't be treated as a user action. /// /// The action to execute. /// The cancellation token for cancelling the operation. /// Return value of the action. public async Task NotUserActionAsync(Action action, CancellationToken ct = default) { await _semaphore.WaitAsync(ct); _handlingDisabled = true; action(); _handlingDisabled = false; _semaphore.Release(); } /// /// Execute an action that makes sure walk won't be treated as a user action. /// /// The action to execute. /// A result that may or may not have succeeded. public Result NotUserAction(Func action) { _semaphore.Wait(); _handlingDisabled = true; var result = action(); _handlingDisabled = false; _semaphore.Release(); return result; } /// /// Execute an action that makes sure walk won't be treated as a user action. /// /// The action to execute. /// The return type. /// Return value of the action. public T NotUserAction(Func action) { _semaphore.Wait(); _handlingDisabled = true; var result = action(); _handlingDisabled = false; _semaphore.Release(); return result; } /// /// Execute walk action and make sure walk won't be treated as a user action. /// /// The walk hook. /// The x coordinate. /// The y coordinate. /// The result of the walk. public Result NotUserWalk(IPlayerWalkHook walkHook, short x, short y) => NotUserAction ( () => { _lastWalkPosition = ((ushort)x, (ushort)y); return walkHook.WrapperFunction((ushort)x, (ushort)y); } ); /// /// Execute walk action and make sure walk won't be treated as a user action. /// /// The walk hook. /// The x coordinate. /// The y coordinate. /// The cancellation token used for cancelling the operation. /// The result of the walk. public async Task> NotUserWalkAsync(IPlayerWalkHook walkHook, short x, short y, CancellationToken ct = default) => await NotUserActionAsync ( () => { _lastWalkPosition = ((ushort)x, (ushort)y); return walkHook.WrapperFunction((ushort)x, (ushort)y); }, ct ); /// /// Checks whether the given Walk call /// is a user action or not (either bot or NosTale action). /// /// The x coordinate of Walk call. /// The y coordinate of Walk call. /// Whether the action is a user action. public bool IsWalkUserAction(ushort x, ushort y) { if (_handlingDisabled) { _lastWalkPosition = (x, y); return false; } if (_lastWalkPosition.X == x && _lastWalkPosition.Y == y) { return false; } return true; } /// /// Checks whether the given PetWalk call /// is a user action or not (either bot or NosTale action). /// /// The pet manager. /// The x coordinate of PetWalk call. /// The y coordinate of PetWalk call. /// Whether the action is a user action. public bool IsPetWalkUserOperation(PetManager petManager, ushort x, ushort y) { return false; // TODO: implement user action detection for petwalk /*if (_handlingDisabled) { return false; } return true;*/ } }