// // NostaleLocalClient.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 Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NosSmooth.Core.Client; using NosSmooth.Core.Commands; using NosSmooth.Core.Extensions; using NosSmooth.Core.Packets; using NosSmoothCore; using Remora.Results; namespace NosSmooth.LocalClient; /// /// The local nostale client. /// /// /// Client used for living in the same process as NostaleClientX.exe. /// It hooks the send and receive packet methods. /// public class NostaleLocalClient : BaseNostaleClient { private readonly PacketSerializerProvider _packetSerializerProvider; private readonly IPacketHandler _packetHandler; private readonly ILogger _logger; private readonly IServiceProvider _provider; private readonly NosClient _client; private readonly LocalClientOptions _options; private IPacketInterceptor? _interceptor; /// /// Initializes a new instance of the class. /// /// The command processor. /// The packet serializer. /// The packet serializer provider. /// The packet handler. /// The logger. /// The options for the client. /// The dependency injection provider. /// The nostale managed client. public NostaleLocalClient ( CommandProcessor commandProcessor, IPacketSerializer packetSerializer, PacketSerializerProvider packetSerializerProvider, IPacketHandler packetHandler, ILogger logger, IOptions options, IServiceProvider provider, NosClient client ) : base(commandProcessor, packetSerializer) { _options = options.Value; _packetSerializerProvider = packetSerializerProvider; _packetHandler = packetHandler; _logger = logger; _provider = provider; _client = client; } /// public override async Task RunAsync(CancellationToken stopRequested = default) { _logger.LogInformation("Starting local client"); NetworkCallback receiveCallback = ReceiveCallback; NetworkCallback sendCallback = SendCallback; _client.GetNetwork().SetReceiveCallback(receiveCallback); _client.GetNetwork().SetSendCallback(sendCallback); _logger.LogInformation("Packet methods hooked successfully"); try { await Task.Delay(-1, stopRequested); } catch { } _client.ResetHooks(); return Result.FromSuccess(); } /// public override Task ReceivePacketAsync(string packetString, CancellationToken ct = default) { ReceivePacket(packetString); return Task.FromResult(Result.FromSuccess()); } /// public override Task SendPacketAsync(string packetString, CancellationToken ct = default) { SendPacket(packetString); return Task.FromResult(Result.FromSuccess()); } private bool ReceiveCallback(string packet) { if (_options.AllowIntercept) { if (_interceptor is null) { _interceptor = _provider.GetRequiredService(); } return _interceptor.InterceptReceive(ref packet); } Task.Run(async () => await ProcessPacketAsync(PacketType.Received, packet)); return true; } private bool SendCallback(string packet) { if (_options.AllowIntercept) { if (_interceptor is null) { _interceptor = _provider.GetRequiredService(); } return _interceptor.InterceptSend(ref packet); } Task.Run(async () => await ProcessPacketAsync(PacketType.Sent, packet)); return true; } private void SendPacket(string packetString) { _client.GetNetwork().SendPacket(packetString); _logger.LogDebug($"Sending client packet {packetString}"); } private void ReceivePacket(string packetString) { _client.GetNetwork().ReceivePacket(packetString); _logger.LogDebug($"Receiving client packet {packetString}"); } private async Task ProcessPacketAsync(PacketType type, string packetString) { IPacketSerializer serializer; if (type == PacketType.Received) { serializer = _packetSerializerProvider.ServerSerializer; } else { serializer = _packetSerializerProvider.ClientSerializer; } var packet = serializer.Deserialize(packetString); if (!packet.IsSuccess) { _logger.LogWarning($"Could not parse {packetString}. Reason: {packet.Error.Message}"); return; } Result result; if (type == PacketType.Received) { result = await _packetHandler.HandleReceivedPacketAsync(packet.Entity, packetString); } else { result = await _packetHandler.HandleSentPacketAsync(packet.Entity, packetString); } if (!result.IsSuccess) { _logger.LogError("There was an error whilst handling packet"); _logger.LogResultError(result); } } }