Files
GoakeFlax/Source/Game/GameMode/NetworkManager_Server.cs

223 lines
7.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using FlaxEngine;
using FlaxEngine.Networking;
using Console = Game.Console;
using Object = FlaxEngine.Object;
namespace Game;
public static partial class NetworkManager
{
private static List<NetworkConnection> ConnectedClients;
private static List<Type> NetworkedTypes;
public static INetworkDriver ServerNetworkDriver { get; set; }
//public static WorldStateManager serverWorldStateManager = null;
public static bool StartServer(bool listenServer = true)
{
Time.Synchronize();
Cleanup();
ConnectedClients = new List<NetworkConnection>(MaximumClients);
INetworkDriver driver = Object.New<ENetDriver>();
//NetworkLagDriver driver = Object.New<NetworkLagDriver>();
if (driver is NetworkLagDriver networkLagDriver)
networkLagDriver.Lag = 50.0f;//200f;
ServerNetworkDriver = driver;
server = NetworkPeer.CreatePeer(new NetworkConfig
{
NetworkDriver = (Object)driver,
ConnectionsLimit = MaximumClients,
MessagePoolSize = 2048,
MessageSize = MTU,
Address = "any",
Port = ServerPort
});
if (!server.Listen())
{
Console.PrintError("Failed to start the server.");
return false;
}
Scripting.Update += OnServerNetworkUpdate;
Scripting.Exit += Cleanup;
Level.ActorSpawned += OnServerActorSpawned;
NetworkedTypes = new List<Type>();
#if false
var assemblies = Utils.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 == "Snippets" ||
assemblyName == "netstandard" ||
assemblyName == "Anonymously Hosted DynamicMethods Assembly" ||
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);
#endif
//serverWorldStateManager = new WorldStateManager(isServer: true);
//WorldStateManager.Init();
World.InitServer();
if (listenServer)
return ConnectServer(listenServer: true);
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, NetworkChannelType channelType = NetworkChannelType.Reliable)
{
server.EndSendMessage(channelType, message, connection);
}
public static void ServerEndSendMessage(ref NetworkMessage message, NetworkConnection[] connections, NetworkChannelType channelType = NetworkChannelType.Reliable)
{
server.EndSendMessage(channelType, message, connections);
}
public static NetworkMessage ClientBeginSendMessage()
{
NetworkMessage message = client.BeginSendMessage();
message.WriteByte((byte)NetworkMessageType.Message);
return message;
}
public static void ClientEndSendMessage(ref NetworkMessage message, NetworkChannelType channelType = NetworkChannelType.Reliable)
{
client.EndSendMessage(channelType, message);
}
private static void OnServerNetworkUpdate()
{
using var _ = Utilities.ProfileScope("NetworkManager_OnServerNetworkUpdate");
while (server.PopEvent(out NetworkEvent networkEvent))
OnServerReadMessage(ref networkEvent);
}
private static void OnServerReadMessage(ref NetworkEvent networkEvent)
{
using var _ = Utilities.ProfileScope("NetworkManager_OnServerReadMessage");
switch (networkEvent.EventType)
{
case NetworkEventType.Connected:
{
Console.Print($"Client({networkEvent.Sender.ConnectionId}) is trying to connect");
try
{
//IsServer = true;
bool handled = false;
foreach (var func in OnServerConnectingDelegates)
{
handled = func(networkEvent.Sender);
if (handled)
break;
}
if (handled)
{
ConnectedClients.Add(networkEvent.Sender);
Console.Print(
$"Client({networkEvent.Sender.ConnectionId}) connected. Total clients: {ConnectedClients.Count}");
foreach (var func in OnServerConnectedDelegates)
func(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, CollectionsMarshal.AsSpan(OnServerMessageDelegates));
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();
}
}
private static void OnServerActorSpawned(Actor actor)
{
//Console.Print($"actor spawned: {actor.Name} ({actor.TypeName})");
}
}