using System; using System.Linq; using System.Runtime.InteropServices; using FlaxEngine; using FlaxEngine.Networking; using Console = Game.Console; using Object = FlaxEngine.Object; namespace Game; public static partial class NetworkManager { public static uint LocalPlayerClientId { get; /*private*/ set; } public static INetworkDriver ClientNetworkDriver { get; set; } //public static WorldStateManager clientWorldStateManager = null; public static bool ConnectServer(string serverAddress = "localhost", bool listenServer = false) { if (!listenServer) Cleanup(); ServerAddress = serverAddress; //var driver = Object.New(typeof(ENetDriver)); //ClientNetworkDriver = null; NetworkLagDriver driver = Object.New(); driver.Lag = 0f; ClientNetworkDriver = driver; client = NetworkPeer.CreatePeer(new NetworkConfig { NetworkDriver = driver, ConnectionsLimit = MaximumClients, MessagePoolSize = 2048, MessageSize = MTU, Address = ServerAddress == "localhost" ? "127.0.0.1" : ServerAddress, Port = ServerPort }); if (client == null) { Console.Print("Failed to create NetworkPeer."); return false; } if (!client.Connect()) { Console.Print("Failed to connect to the server."); return false; } Debug.Log("Connected..."); /*if (!listenServer) { //WorldStateManager.Init(); clientWorldStateManager = new WorldStateManager(isClient: true); } else { clientWorldStateManager = new WorldStateManager(isLocalClient: true); }*/ World.InitClient(); Scripting.Update += OnClientNetworkUpdate; if (!listenServer) { Scripting.Exit += Cleanup; //Level.ActorSpawned += OnClientActorSpawned; } string demoPath = System.IO.Path.Combine(AssetManager.DemoPath, $"{DateTimeOffset.Now.UtcTicks}_v2.gdem"); RecordDemo(demoPath); return true; } private static void OnClientNetworkUpdate() { using var _ = Utilities.ProfileScope("NetworkManager_OnClientNetworkUpdate"); while (client.PopEvent(out NetworkEvent networkEvent)) { RecordMessage(ref networkEvent); try { //IsLocalClient = server != null; //IsClient = true; OnClientReadMessage(ref networkEvent); } finally { //IsLocalClient = false; //IsClient = false; if (networkEvent.EventType == NetworkEventType.Message) client.RecycleMessage(networkEvent.Message); } } } private static void OnClientReadMessage(ref NetworkEvent networkEvent) { using var _ = Utilities.ProfileScope("NetworkManager_OnClientReadMessage"); switch (networkEvent.EventType) { case NetworkEventType.Connected: { foreach (var func in OnClientConnectedDelegates) func(networkEvent.Sender); break; } case NetworkEventType.Disconnected: { Console.Print("Disconnected from server, timeout."); //LocalPlayerClientId = 0; break; } case NetworkEventType.Timeout: { Console.Print("Disconnected from server, connection closed."); //LocalPlayerClientId = 0; break; } case NetworkEventType.Message: { OnNetworkMessage(ref networkEvent, CollectionsMarshal.AsSpan(OnClientMessageDelegates)); if (networkEvent.Message.Position > 0 && networkEvent.Message.Position < networkEvent.Message.Length) { string err = $"Network message was not fully read: {networkEvent.Message.Position} / {networkEvent.Message.Length}.\n"; networkEvent.Message.Position = 0; byte[] messageBytes = new byte[networkEvent.Message.Length]; unsafe { fixed (byte* messageBytePtr = &messageBytes[0]) networkEvent.Message.ReadBytes(messageBytePtr, (int)networkEvent.Message.Length); } //string messageBytesStr = string.Join(", ", messageBytes.Select(x => "0x" + ((int)x).ToString("X2"))); string messageBytesStr = string.Join("", messageBytes.Select(x => ((int)x).ToString("X2"))); Console.PrintError(err + $"Message dump: {messageBytesStr}"); } break; } default: throw new ArgumentOutOfRangeException(); } DebugLastHandledMessage = ""; } private static void OnClientActorSpawned(Actor actor) { } }