//
// 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.MapResult(func => func((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.MapResult(func => func((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;*/
}
}