using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using FlaxEngine; using FlaxEngine.Networking; using Console = Game.Console; using Object = FlaxEngine.Object; namespace Game { public static partial class NetworkManager { private static List ConnectedClients; private static List NetworkedTypes; public static bool StartServer() { ConnectedClients = new List(MaximumClients); server = NetworkPeer.CreatePeer(new NetworkConfig { NetworkDriver = Object.New(typeof(ENetDriver)), ConnectionsLimit = MaximumClients, MessagePoolSize = 2048, MessageSize = MTU, Address = "any", Port = ServerPort }); if (!server.Listen()) { Console.PrintError("Failed to start the server."); return false; } Scripting.FixedUpdate += OnServerUpdate; Scripting.Exit += Cleanup; Level.ActorSpawned += OnServerActorSpawned; NetworkedTypes = new List(); AppDomain currentDomain = AppDomain.CurrentDomain; var assemblies = currentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { // Skip common assemblies string assemblyName = assembly.GetName().Name; if (assemblyName == "System" || assemblyName.StartsWith("System.") || assemblyName.StartsWith("Mono.") || assemblyName == "mscorlib" || assemblyName == "Newtonsoft.Json" || assemblyName.StartsWith("FlaxEngine.") || assemblyName.StartsWith("JetBrains.") || assemblyName.StartsWith("Microsoft.") || assemblyName.StartsWith("nunit.")) continue; foreach (Type type in assembly.GetTypes()) if (type.GetCustomAttributes().Any(x => x is NetworkedAttribute)) NetworkedTypes.Add(type); } foreach (Type type in NetworkedTypes) Console.Print("tracking networked type: " + type.Name); return true; } public static NetworkMessage ServerBeginSendMessage() { NetworkMessage message = server.BeginSendMessage(); message.WriteByte((byte)NetworkMessageType.Message); return message; } public static void ServerEndSendMessage(ref NetworkMessage message, NetworkConnection connection) { server.EndSendMessage(NetworkChannelType.Reliable, message, connection); } public static NetworkMessage ClientBeginSendMessage() { NetworkMessage message = client.BeginSendMessage(); message.WriteByte((byte)NetworkMessageType.Message); return message; } public static void ClientEndSendMessage(ref NetworkMessage message) { client.EndSendMessage(NetworkChannelType.Reliable, message); } private static void OnServerUpdate() { /*using*/ Utilities.ScopeProfiler _ = Utilities.ProfileScope("NetworkManager_OnServerUpdate"); while (server.PopEvent(out NetworkEvent networkEvent)) switch (networkEvent.EventType) { case NetworkEventType.Connected: { Console.Print($"Client({networkEvent.Sender.ConnectionId}) is trying to connect"); try { IsServer = true; if (GameModeManager.OnClientConnecting(networkEvent.Sender)) { ConnectedClients.Add(networkEvent.Sender); Console.Print( $"Client({networkEvent.Sender.ConnectionId}) connected. Total clients: {ConnectedClients.Count}"); GameModeManager.OnClientConnected(networkEvent.Sender); } else Console.Print($"Client({networkEvent.Sender.ConnectionId}) connection refused"); } finally { IsServer = false; } break; } case NetworkEventType.Disconnected: case NetworkEventType.Timeout: { Console.Print($"Client({networkEvent.Sender.ConnectionId}) disconnected!"); ConnectedClients.Remove(networkEvent.Sender); Console.Print("Connected clients: " + ConnectedClients.Count); break; } case NetworkEventType.Message: { try { IsServer = true; OnNetworkMessage(ref networkEvent); 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}."; 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"))); Console.PrintError(err + $"Message dump: {messageBytesStr}"); } } finally { IsServer = false; server.RecycleMessage(networkEvent.Message); } break; } default: throw new ArgumentOutOfRangeException(); } _.Dispose(); } private static void OnServerActorSpawned(Actor actor) { //Console.Print($"actor spawned: {actor.Name} ({actor.TypeName})"); } } }