222 lines
7.8 KiB
C#
222 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)
|
|
{
|
|
Cleanup();
|
|
ConnectedClients = new List<NetworkConnection>(MaximumClients);
|
|
|
|
|
|
//INetworkDriver driver = Object.New<ENetDriver>();
|
|
NetworkLagDriver driver = Object.New<NetworkLagDriver>();
|
|
if (driver is NetworkLagDriver networkLagDriver)
|
|
networkLagDriver.Lag = 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})");
|
|
}
|
|
} |