using System.Threading; using System.Threading.Tasks; using LiteNetLib; using LiteNetLib.Utils; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Debug; namespace Syntriax.Engine.Network; public class LiteNetLibClient : LiteNetLibCommunicatorBase, INetworkCommunicatorClient { private readonly NetDataWriter netDataWriter = new(); private CancellationTokenSource? cancellationTokenSource = null; protected override IConnection GetConnection(NetPeer peer) => new LiteNetLibServerConnection(peer); public INetworkCommunicatorClient Connect(string address, int port, string? password = null) { if (!UniverseObject.IsInUniverse) throw new($"{nameof(LiteNetLibClient)} must be in an universe to connect"); password ??= string.Empty; logger?.Log(this, $"Connecting to server at '{address}:{port}' with password '{password}'"); Manager.Start(); Manager.Connect(address, port, password); return this; } public INetworkCommunicatorClient SendToServer(T packet, PacketDelivery packetDelivery) where T : class, new() { netDataWriter.Reset(); netPacketProcessor.Write(netDataWriter, packet); switch (packetDelivery) { case PacketDelivery.ReliableInOrder: Manager.FirstPeer.Send(netDataWriter, DeliveryMethod.ReliableOrdered); break; case PacketDelivery.UnreliableInOrder: Manager.FirstPeer.Send(netDataWriter, DeliveryMethod.Sequenced); break; case PacketDelivery.ReliableOutOfOrder: Manager.FirstPeer.Send(netDataWriter, DeliveryMethod.ReliableUnordered); break; case PacketDelivery.UnreliableOutOfOrder: Manager.FirstPeer.Send(netDataWriter, DeliveryMethod.Unreliable); break; default: Manager.FirstPeer.Send(netDataWriter, DeliveryMethod.ReliableOrdered); break; } return this; } protected override void OnEnteredUniverse(IUniverse universe) { base.OnEnteredUniverse(universe); cancellationTokenSource = new CancellationTokenSource(); PollEvents(cancellationTokenSource.Token); } protected override void OnExitedUniverse(IUniverse universe) { base.OnExitedUniverse(universe); cancellationTokenSource?.Cancel(); } /// /// Client needs to send everything as soon as possible so /// the events are polled a separate thread running constantly /// private async void PollEvents(CancellationToken cancellationToken) => await Task.Run(() => { while (true) { Manager.PollEvents(); Thread.Sleep(1); } }, cancellationToken); }