~ruther/NosSmooth

45f8bc92fd853ae7008cf52c153aa71368f11f32 — František Boháček 3 years ago f8a901c
feat: use nostale bindings instead of nossmooth core
M Core/NosSmooth.Core/Commands/WalkCommand.cs => Core/NosSmooth.Core/Commands/WalkCommand.cs +1 -1
@@ 13,4 13,4 @@ namespace NosSmooth.Core.Commands;
/// <param name="TargetX">The x coordinate of the target position to move to.</param>
/// <param name="TargetY">The y coordinate of the target position to move to.</param>
/// <param name="CancelOnUserMove">Whether to cancel the walk when the user clicks to move somewhere.</param>
public record WalkCommand(int TargetX, int TargetY, bool CancelOnUserMove = true) : ICommand;
\ No newline at end of file
public record WalkCommand(ushort TargetX, ushort TargetY, bool CancelOnUserMove = true) : ICommand;
\ No newline at end of file

M Local/NosSmooth.LocalClient/CommandHandlers/Walk/WalkCommandHandler.cs => Local/NosSmooth.LocalClient/CommandHandlers/Walk/WalkCommandHandler.cs +8 -11
@@ 6,8 6,8 @@

using Microsoft.Extensions.Options;
using NosSmooth.Core.Commands;
using NosSmooth.LocalBinding.Objects;
using NosSmooth.LocalClient.CommandHandlers.Walk.Errors;
using NosSmoothCore;
using Remora.Results;

namespace NosSmooth.LocalClient.CommandHandlers.Walk;


@@ 17,20 17,20 @@ namespace NosSmooth.LocalClient.CommandHandlers.Walk;
/// </summary>
public class WalkCommandHandler : ICommandHandler<WalkCommand>
{
    private readonly NosClient _nosClient;
    private readonly CharacterBinding _characterBinding;
    private readonly WalkStatus _walkStatus;
    private readonly WalkCommandHandlerOptions _options;

    /// <summary>
    /// Initializes a new instance of the <see cref="WalkCommandHandler"/> class.
    /// </summary>
    /// <param name="nosClient">The local client.</param>
    /// <param name="characterBinding">The character object binding.</param>
    /// <param name="walkStatus">The walk status.</param>
    /// <param name="options">The options.</param>
    public WalkCommandHandler(NosClient nosClient, WalkStatus walkStatus, IOptions<WalkCommandHandlerOptions> options)
    public WalkCommandHandler(CharacterBinding characterBinding, WalkStatus walkStatus, IOptions<WalkCommandHandlerOptions> options)
    {
        _options = options.Value;
        _nosClient = nosClient;
        _characterBinding = characterBinding;
        _walkStatus = walkStatus;
    }



@@ 46,11 46,8 @@ public class WalkCommandHandler : ICommandHandler<WalkCommand>
        await _walkStatus.SetWalking(linked, command.TargetX, command.TargetY, command.CancelOnUserMove);
        while (!ct.IsCancellationRequested)
        {
            try
            {
                _nosClient.GetCharacter().Walk(command.TargetX, command.TargetY);
            }
            catch (Exception e)
            var walkResult = _characterBinding.Walk(command.TargetX, command.TargetY);
            if (!walkResult.IsSuccess)
            {
                try
                {


@@ 61,7 58,7 @@ public class WalkCommandHandler : ICommandHandler<WalkCommand>
                    // ignored, just for cancellation
                }

                return e;
                return walkResult;
            }

            try

M Local/NosSmooth.LocalClient/CommandHandlers/Walk/WalkCommandHandlerOptions.cs => Local/NosSmooth.LocalClient/CommandHandlers/Walk/WalkCommandHandlerOptions.cs +0 -6
@@ 4,12 4,6 @@
//  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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NosSmooth.LocalClient.CommandHandlers.Walk
{
    /// <summary>

M Local/NosSmooth.LocalClient/CommandHandlers/Walk/WalkStatus.cs => Local/NosSmooth.LocalClient/CommandHandlers/Walk/WalkStatus.cs +7 -7
@@ 4,7 4,7 @@
//  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 NosSmooth.LocalClient.Hooks;
using NosSmooth.LocalBinding.Objects;

namespace NosSmooth.LocalClient.CommandHandlers.Walk;



@@ 13,7 13,7 @@ namespace NosSmooth.LocalClient.CommandHandlers.Walk;
/// </summary>
public class WalkStatus
{
    private readonly NostaleHookManager _hookManager;
    private readonly CharacterBinding _characterBinding;
    private readonly SemaphoreSlim _semaphore;
    private CancellationTokenSource? _walkingCancellation;
    private bool _userCanCancel;


@@ 22,10 22,10 @@ public class WalkStatus
    /// <summary>
    /// Initializes a new instance of the <see cref="WalkStatus"/> class.
    /// </summary>
    /// <param name="hookManager">The hooking manager.</param>
    public WalkStatus(NostaleHookManager hookManager)
    /// <param name="characterBinding">The character binding.</param>
    public WalkStatus(CharacterBinding characterBinding)
    {
        _hookManager = hookManager;
        _characterBinding = characterBinding;
        _semaphore = new SemaphoreSlim(1, 1);
    }



@@ 110,7 110,7 @@ public class WalkStatus

        if (!_walkHooked)
        {
            _hookManager.ClientWalked += OnCharacterWalked;
            _characterBinding.WalkCall += OnCharacterWalked;
            _walkHooked = true;
        }



@@ 159,7 159,7 @@ public class WalkStatus
        await CancelWalkingAsync(ct: ct);
    }

    private bool OnCharacterWalked(WalkEventArgs walkEventArgs)
    private bool OnCharacterWalked(ushort x, ushort y)
    {
        if (IsWalking)
        {

M Local/NosSmooth.LocalClient/Extensions/ServiceCollectionExtensions.cs => Local/NosSmooth.LocalClient/Extensions/ServiceCollectionExtensions.cs +2 -5
@@ 8,10 8,8 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NosSmooth.Core.Client;
using NosSmooth.Core.Extensions;
using NosSmooth.LocalClient.CommandHandlers;
using NosSmooth.LocalBinding.Extensions;
using NosSmooth.LocalClient.CommandHandlers.Walk;
using NosSmooth.LocalClient.Hooks;
using NosSmoothCore;

namespace NosSmooth.LocalClient.Extensions;



@@ 28,13 26,12 @@ public static class ServiceCollectionExtensions
    public static IServiceCollection AddLocalClient(this IServiceCollection serviceCollection)
    {
        serviceCollection.AddNostaleCore();
        serviceCollection.AddNostaleBindings();
        serviceCollection
            .AddCommandHandler<WalkCommandHandler>()
            .AddPacketResponder<WalkPacketResponder>()
            .AddSingleton<WalkStatus>();
        serviceCollection.TryAddSingleton<NostaleLocalClient>();
        serviceCollection.TryAddSingleton<NostaleHookManager>();
        serviceCollection.TryAddSingleton<NosClient>();
        serviceCollection.TryAddSingleton<INostaleClient>(p => p.GetRequiredService<NostaleLocalClient>());

        return serviceCollection;

D Local/NosSmooth.LocalClient/Hooks/NostaleHookManager.cs => Local/NosSmooth.LocalClient/Hooks/NostaleHookManager.cs +0 -74
@@ 1,74 0,0 @@
//
//  NostaleHookManager.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.ComponentModel;
using NosSmoothCore;
using Remora.Results;

namespace NosSmooth.LocalClient.Hooks;

/// <summary>
/// The manager for hooking functions.
/// </summary>
public class NostaleHookManager
{
    private readonly NosClient _nosClient;

    /// <summary>
    /// Initializes a new instance of the <see cref="NostaleHookManager"/> class.
    /// </summary>
    /// <param name="nosClient">The nostale client.</param>
    public NostaleHookManager(NosClient nosClient)
    {
        _nosClient = nosClient;
    }

    /// <summary>
    /// Event for the character walk function.
    /// </summary>
    public event Func<WalkEventArgs, bool>? ClientWalked;

    /// <summary>
    /// Hook the Character.Walk function.
    /// </summary>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Result HookCharacterWalk()
    {
        try
        {
            _nosClient.GetCharacter().SetWalkCallback(Walk);
        }
        catch (Exception e)
        {
            return e;
        }

        return Result.FromSuccess();
    }

    /// <summary>
    /// Reset the registered hooks.
    /// </summary>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Result ResetHooks()
    {
        try
        {
            _nosClient.ResetHooks();
        }
        catch (Exception e)
        {
            return e;
        }

        return Result.FromSuccess();
    }

    private bool Walk(int position)
    {
        return ClientWalked?.Invoke(new WalkEventArgs(position & 0xFFFF, (int)((position & 0xFFFF0000) >> 16))) ?? true;
    }
}
\ No newline at end of file

D Local/NosSmooth.LocalClient/Hooks/WalkEventArgs.cs => Local/NosSmooth.LocalClient/Hooks/WalkEventArgs.cs +0 -34
@@ 1,34 0,0 @@
//
//  WalkEventArgs.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.

namespace NosSmooth.LocalClient.Hooks;

/// <summary>
/// The event args for event in <see cref="NostaleHookManager"/>.
/// </summary>
public class WalkEventArgs
{
    /// <summary>
    /// Initializes a new instance of the <see cref="WalkEventArgs"/> class.
    /// </summary>
    /// <param name="targetX">The target x coordinate.</param>
    /// <param name="targetY">The target y coordinate.</param>
    public WalkEventArgs(int targetX, int targetY)
    {
        TargetX = targetX;
        TargetY = targetY;
    }

    /// <summary>
    /// Gets the target x coordinate.
    /// </summary>
    public int TargetX { get; }

    /// <summary>
    /// Gets the target y coordinate.
    /// </summary>
    public int TargetY { get; }
}
\ No newline at end of file

M Local/NosSmooth.LocalClient/LocalClientOptions.cs => Local/NosSmooth.LocalClient/LocalClientOptions.cs +0 -26
@@ 4,8 4,6 @@
//  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 NosSmooth.Core.Commands;

namespace NosSmooth.LocalClient;

/// <summary>


@@ 17,28 15,4 @@ public class LocalClientOptions
    /// Gets or sets whether the interception of packets should be allowed.
    /// </summary>
    public bool AllowIntercept { get; set; }

    /// <summary>
    /// Hook the packet sent method.
    /// </summary>
    /// <remarks>
    /// Packet handlers and interceptors won't be called for sent packets.
    /// </remarks>
    public bool HookPacketSend { get; set; } = true;

    /// <summary>
    /// Hook the packet received method.
    /// </summary>
    /// <remarks>
    /// Packet handlers and interceptors won't be called for received packets.
    /// </remarks>
    public bool HookPacketReceive { get; set; } = true;

    /// <summary>
    /// Whether to hook Character.Walk method. True by default.
    /// </summary>
    /// <remarks>
    /// If set to false, <see cref="WalkCommand.CancelOnUserMove"/> won't take any effect.
    /// </remarks>
    public bool HookCharacterWalk { get; set; } = true;
}
\ No newline at end of file

M Local/NosSmooth.LocalClient/NosSmooth.LocalClient.csproj => Local/NosSmooth.LocalClient/NosSmooth.LocalClient.csproj +8 -1
@@ 5,15 5,22 @@
        <Nullable>enable</Nullable>
        <LangVersion>10</LangVersion>
        <TargetFramework>net48</TargetFramework>
        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    </PropertyGroup>

    <ItemGroup>
      <ProjectReference Include="..\..\Core\NosSmooth.Core\NosSmooth.Core.csproj" />
      <ProjectReference Include="..\NosSmooth.LocalCore\NosSmooth.LocalCore.vcxproj" />
      <ProjectReference Include="..\NosSmooth.LocalBinding\NosSmooth.LocalBinding.csproj" />
    </ItemGroup>

    <ItemGroup>
      <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
      <PackageReference Include="Reloaded.Hooks" Version="3.5.0" />
      <PackageReference Include="Reloaded.Memory.Sigscan" Version="1.2.1" />
    </ItemGroup>

    <ItemGroup>
      <Folder Include="Bindings" />
    </ItemGroup>

</Project>

M Local/NosSmooth.LocalClient/NostaleLocalClient.cs => Local/NosSmooth.LocalClient/NostaleLocalClient.cs +12 -33
@@ 11,11 11,10 @@ using NosSmooth.Core.Client;
using NosSmooth.Core.Commands;
using NosSmooth.Core.Extensions;
using NosSmooth.Core.Packets;
using NosSmooth.LocalClient.Hooks;
using NosSmooth.LocalBinding.Objects;
using NosSmooth.Packets;
using NosSmooth.Packets.Attributes;
using NosSmooth.Packets.Errors;
using NosSmoothCore;
using Remora.Results;

namespace NosSmooth.LocalClient;


@@ 29,12 28,11 @@ namespace NosSmooth.LocalClient;
/// </remarks>
public class NostaleLocalClient : BaseNostaleClient
{
    private readonly NetworkBinding _networkBinding;
    private readonly IPacketSerializer _packetSerializer;
    private readonly NostaleHookManager _hookManager;
    private readonly IPacketHandler _packetHandler;
    private readonly ILogger _logger;
    private readonly IServiceProvider _provider;
    private readonly NosClient _client;
    private readonly LocalClientOptions _options;
    private CancellationToken? _stopRequested;
    private IPacketInterceptor? _interceptor;


@@ 42,34 40,31 @@ public class NostaleLocalClient : BaseNostaleClient
    /// <summary>
    /// Initializes a new instance of the <see cref="NostaleLocalClient"/> class.
    /// </summary>
    /// <param name="networkBinding">The network binding.</param>
    /// <param name="commandProcessor">The command processor.</param>
    /// <param name="packetSerializer">The packet serializer.</param>
    /// <param name="hookManager">The hooking manager.</param>
    /// <param name="packetHandler">The packet handler.</param>
    /// <param name="logger">The logger.</param>
    /// <param name="options">The options for the client.</param>
    /// <param name="provider">The dependency injection provider.</param>
    /// <param name="client">The nostale managed client.</param>
    public NostaleLocalClient
    (
        NetworkBinding networkBinding,
        CommandProcessor commandProcessor,
        IPacketSerializer packetSerializer,
        NostaleHookManager hookManager,
        IPacketHandler packetHandler,
        ILogger<NostaleLocalClient> logger,
        IOptions<LocalClientOptions> options,
        IServiceProvider provider,
        NosClient client
        IServiceProvider provider
    )
        : base(commandProcessor, packetSerializer)
    {
        _options = options.Value;
        _networkBinding = networkBinding;
        _packetSerializer = packetSerializer;
        _hookManager = hookManager;
        _packetHandler = packetHandler;
        _logger = logger;
        _provider = provider;
        _client = client;
    }

    /// <inheritdoc />


@@ 77,25 72,8 @@ public class NostaleLocalClient : BaseNostaleClient
    {
        _stopRequested = stopRequested;
        _logger.LogInformation("Starting local client");
        NetworkCallback receiveCallback = ReceiveCallback;
        NetworkCallback sendCallback = SendCallback;

        if (_options.HookPacketReceive)
        {
            _client.GetNetwork().SetReceiveCallback(receiveCallback);
        }

        if (_options.HookPacketSend)
        {
            _client.GetNetwork().SetSendCallback(sendCallback);
        }

        if (_options.HookCharacterWalk)
        {
            _hookManager.HookCharacterWalk();
        }

        _logger.LogInformation("Packet methods hooked successfully");
        _networkBinding.PacketSend += SendCallback;
        _networkBinding.PacketReceive += ReceiveCallback;

        try
        {


@@ 106,7 84,8 @@ public class NostaleLocalClient : BaseNostaleClient
            // ignored
        }

        _client.ResetHooks();
        _networkBinding.PacketSend -= SendCallback;
        _networkBinding.PacketReceive -= ReceiveCallback;

        return Result.FromSuccess();
    }


@@ 163,13 142,13 @@ public class NostaleLocalClient : BaseNostaleClient

    private void SendPacket(string packetString)
    {
        _client.GetNetwork().SendPacket(packetString);
        _networkBinding.SendPacket(packetString);
        _logger.LogDebug($"Sending client packet {packetString}");
    }

    private void ReceivePacket(string packetString)
    {
        _client.GetNetwork().ReceivePacket(packetString);
        _networkBinding.ReceivePacket(packetString);
        _logger.LogDebug($"Receiving client packet {packetString}");
    }


M Samples/WalkCommands/Commands/WalkCommands.cs => Samples/WalkCommands/Commands/WalkCommands.cs +2 -2
@@ 39,8 39,8 @@ public class WalkCommands
    /// <returns>A result that may or may not have succeeded.</returns>
    public async Task<Result> HandleWalkToAsync
    (
        int x,
        int y,
        ushort x,
        ushort y,
        bool isCancellable = true,
        CancellationToken ct = default
    )