using System; using System.Collections.Generic; using System.Linq; using FlaxEditor; using FlaxEngine; using FlaxEngine.Assertions; using FlaxEngine.Networking; using Console = Game.Console; namespace Game; [AttributeUsage(AttributeTargets.Class)] public class NetworkPredictedAttribute : Attribute { } // TODO: insert code to update variables with this attribute? // rename to NetworkReplicatedAttribute? [AttributeUsage(AttributeTargets.Class)] public class NetworkedAttribute : Attribute { } // NetworkMulticastAttribute: calls methods marked with this in all clients public enum NetworkMessageType : byte { Handshake = 1, Message } public static partial class NetworkManager { public delegate bool OnMessageDecl(ref NetworkEvent networkEvent); private static bool initialized; public static NetworkPeer server; public static NetworkPeer client; private static readonly ushort ServerPort = 59183; private static string ServerAddress; private static readonly ushort MTU = 1500; private static readonly ushort MaximumClients = 32; private static List OnClientMessageDelegates = new(3); private static List OnServerMessageDelegates = new(3); public static void RegisterClientMessageCallback(OnMessageDecl deleg) { Assert.IsTrue(!OnClientMessageDelegates.Contains(deleg)); OnClientMessageDelegates.Add(deleg); } public static void UnregisterClientMessageCallback(OnMessageDecl deleg) { Assert.IsTrue(OnClientMessageDelegates.Contains(deleg)); OnClientMessageDelegates.Remove(deleg); } public static void RegisterServerMessageCallback(OnMessageDecl deleg) { Assert.IsTrue(!OnServerMessageDelegates.Contains(deleg)); OnServerMessageDelegates.Add(deleg); } public static void UnregisterServerMessageCallback(OnMessageDecl deleg) { Assert.IsTrue(OnServerMessageDelegates.Contains(deleg)); OnServerMessageDelegates.Remove(deleg); } public static string DebugLastHandledMessage = ""; //public static bool IsServer = false; //public static bool IsClient = false; // static bool IsLocalClient = false; // Context dependant, true when message is handled by local client public static void Init() { if (initialized) return; /*if (Engine.CommandLine.Contains("-server")) { StartServer(); ServerAddress = "localhost"; ConnectServer(); } else if (Engine.CommandLine.Contains("-client")) { ServerAddress = "localhost"; ConnectServer(); } //#if FLAX_EDITOR else { StartServer(); ServerAddress = "localhost"; ConnectServer(); }*/ //#endif initialized = true; #if FLAX_EDITOR Editor.Instance.PlayModeEnd += Cleanup; #endif //WorldStateManager.Init(); // FIXME } public static void Cleanup() { Scripting.Exit -= Cleanup; Scripting.FixedUpdate -= OnDemoUpdate; Scripting.FixedUpdate -= OnServerNetworkUpdate; Level.ActorSpawned -= OnServerActorSpawned; Scripting.FixedUpdate -= OnClientNetworkUpdate; Level.ActorSpawned -= OnClientActorSpawned; if (server != null) { NetworkPeer.ShutdownPeer(server); server = null; } if (client != null) { NetworkPeer.ShutdownPeer(client); client = null; } LocalPlayerClientId = 0; #if FLAX_EDITOR Editor.Instance.PlayModeEnd -= Cleanup; //GameModeManager.Cleanup(); // FIXME #endif if (clientWorldStateManager != null) { clientWorldStateManager.Cleanup(); clientWorldStateManager = null; } if (serverWorldStateManager != null) { serverWorldStateManager.Cleanup(); serverWorldStateManager = null; } StopRecording(); initialized = false; } private static void OnNetworkMessage(ref NetworkEvent networkEvent, Span funcs) { byte messageTypeByte = networkEvent.Message.ReadByte(); if (!Enum.IsDefined(typeof(NetworkMessageType), messageTypeByte)) { Console.PrintError($"Unsupported message type received from client: {messageTypeByte}"); return; } NetworkMessageType messageType = (NetworkMessageType)messageTypeByte; switch (messageType) { case NetworkMessageType.Handshake: { string message = networkEvent.Message.ReadString(); Console.Print($"Received handshake from {networkEvent.Sender.ConnectionId}, msg: " + message); break; } case NetworkMessageType.Message: { var messageStartPosition = networkEvent.Message.Position; foreach (var func in funcs) { networkEvent.Message.Position = messageStartPosition; bool handled = func(ref networkEvent); if (handled) break; } //if (OnMessage != null) /*{ // GetInvocationList() allocates, use allocation-free but unsafe way to iterate // //foreach (OnMessageDecl func in OnMessage.GetInvocationList() // .Cast().ToArray()) foreach (OnMessageDecl func in OnMessageDelegates) { bool ret = func.Invoke(ref networkEvent); if (ret) break; } }*/ break; } default: Console.PrintError($"Unsupported message type received from client: {messageTypeByte}"); break; } } }