quantum-space-buddies/QuantumUNET/QNetworkServer.cs
Mister_Nebula db1888bb19 Revert "aaaaa"
This reverts commit 51e240a2a2.
2021-11-26 17:36:27 +00:00

1384 lines
36 KiB
C#

using QuantumUNET.Components;
using QuantumUNET.Logging;
using QuantumUNET.Messages;
using QuantumUNET.Transport;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
namespace QuantumUNET
{
public class QNetworkServer
{
private QNetworkServer()
{
NetworkTransport.Init();
m_RemoveList = new HashSet<NetworkInstanceId>();
m_ExternalConnections = new HashSet<int>();
m_NetworkScene = new QNetworkScene();
m_SimpleServerSimple = new ServerSimpleWrapper(this);
}
public static List<QNetworkConnection> localConnections => instance.m_LocalConnectionsFakeList;
public static int listenPort => instance.m_SimpleServerSimple.listenPort;
public static int serverHostId => instance.m_SimpleServerSimple.serverHostId;
public static ReadOnlyCollection<QNetworkConnection> connections => instance.m_SimpleServerSimple.connections;
public static Dictionary<short, QNetworkMessageDelegate> handlers => instance.m_SimpleServerSimple.handlers;
public static HostTopology hostTopology => instance.m_SimpleServerSimple.hostTopology;
public static Dictionary<NetworkInstanceId, QNetworkIdentity> objects => instance.m_NetworkScene.localObjects;
public static bool dontListen { get; set; }
public static QNetworkServer instance
{
get
{
if (s_Instance == null)
{
var obj = s_Sync;
lock (obj)
{
if (s_Instance == null)
{
s_Instance = new QNetworkServer();
}
}
}
return s_Instance;
}
}
public static bool active { get; private set; }
public static bool localClientActive => instance.m_LocalClientActive;
public static int numChannels => instance.m_SimpleServerSimple.hostTopology.DefaultConfig.ChannelCount;
public static Type networkConnectionClass => instance.m_SimpleServerSimple.networkConnectionClass;
public static void SetNetworkConnectionClass<T>() where T : QNetworkConnection => instance.m_SimpleServerSimple.SetNetworkConnectionClass<T>();
public static bool Configure(ConnectionConfig config, int maxConnections) => instance.m_SimpleServerSimple.Configure(config, maxConnections);
public static bool Configure(HostTopology topology) => instance.m_SimpleServerSimple.Configure(topology);
public static void Reset()
{
NetworkTransport.Shutdown();
NetworkTransport.Init();
s_Instance = null;
active = false;
}
public static void Shutdown()
{
if (s_Instance != null)
{
s_Instance.InternalDisconnectAll();
if (!dontListen)
{
s_Instance.m_SimpleServerSimple.Stop();
}
s_Instance = null;
}
dontListen = false;
active = false;
}
internal void RegisterMessageHandlers()
{
m_SimpleServerSimple.RegisterHandlerSafe(QMsgType.ClientUpdateVars, OnUpdateVarsMessage);
m_SimpleServerSimple.RegisterHandlerSafe(QMsgType.Ready, OnClientReadyMessage);
m_SimpleServerSimple.RegisterHandlerSafe(QMsgType.Command, OnCommandMessage);
m_SimpleServerSimple.RegisterHandlerSafe(QMsgType.LocalPlayerTransform, QNetworkTransform.HandleTransform);
m_SimpleServerSimple.RegisterHandlerSafe(QMsgType.LocalChildTransform, QNetworkTransformChild.HandleChildTransform);
m_SimpleServerSimple.RegisterHandlerSafe(QMsgType.RemovePlayer, OnRemovePlayerMessage);
m_SimpleServerSimple.RegisterHandlerSafe(QMsgType.Animation, QNetworkAnimator.OnAnimationServerMessage);
m_SimpleServerSimple.RegisterHandlerSafe(QMsgType.AnimationParameters, QNetworkAnimator.OnAnimationParametersServerMessage);
m_SimpleServerSimple.RegisterHandlerSafe(QMsgType.AnimationTrigger, QNetworkAnimator.OnAnimationTriggerServerMessage);
maxPacketSize = hostTopology.DefaultConfig.PacketSize;
}
private static void OnUpdateVarsMessage(QNetworkMessage netMsg)
{
var networkInstanceId = netMsg.Reader.ReadNetworkId();
var typeName = netMsg.Reader.ReadString();
if (instance.m_NetworkScene.GetNetworkIdentity(networkInstanceId, out var networkIdentity))
{
var allBehaviours = networkIdentity.GetNetworkBehaviours();
var target = allBehaviours.First(x => x.GetType().Name == typeName);
target.OnDeserialize(netMsg.Reader, false);
}
else
{
Debug.LogError($"Did not find target for sync message for {networkInstanceId}");
}
}
public static bool Listen(int serverPort) => instance.InternalListen(null, serverPort);
public static bool Listen(string ipAddress, int serverPort) => instance.InternalListen(ipAddress, serverPort);
internal bool InternalListen(string ipAddress, int serverPort)
{
if (dontListen)
{
m_SimpleServerSimple.Initialize();
}
else if (!m_SimpleServerSimple.Listen(ipAddress, serverPort))
{
return false;
}
maxPacketSize = hostTopology.DefaultConfig.PacketSize;
active = true;
RegisterMessageHandlers();
return true;
}
internal int AddLocalClient(QLocalClient localClient)
{
int result;
if (m_LocalConnectionsFakeList.Count != 0)
{
QLog.Error("Local Connection already exists");
result = -1;
}
else
{
m_LocalConnection = new QULocalConnectionToClient(localClient)
{
connectionId = 0
};
m_SimpleServerSimple.SetConnectionAtIndex(m_LocalConnection);
m_LocalConnectionsFakeList.Add(m_LocalConnection);
m_LocalConnection.InvokeHandlerNoData(32);
result = 0;
}
return result;
}
internal void RemoveLocalClient(QNetworkConnection localClientConnection)
{
for (var i = 0; i < m_LocalConnectionsFakeList.Count; i++)
{
if (m_LocalConnectionsFakeList[i].connectionId == localClientConnection.connectionId)
{
m_LocalConnectionsFakeList.RemoveAt(i);
break;
}
}
if (m_LocalConnection != null)
{
m_LocalConnection.Disconnect();
m_LocalConnection.Dispose();
m_LocalConnection = null;
}
m_LocalClientActive = false;
m_SimpleServerSimple.RemoveConnectionAtIndex(0);
}
internal void SetLocalObjectOnServer(NetworkInstanceId netId, GameObject obj)
{
QLog.Debug($"SetLocalObjectOnServer {netId} {obj}");
m_NetworkScene.SetLocalObject(netId, obj, false, true);
}
internal void ActivateLocalClientScene()
{
if (!m_LocalClientActive)
{
m_LocalClientActive = true;
foreach (var networkIdentity in objects.Values)
{
if (!networkIdentity.IsClient)
{
QLog.Log($"ActivateClientScene {networkIdentity.NetId} {networkIdentity.gameObject}");
QClientScene.SetLocalObject(networkIdentity.NetId, networkIdentity.gameObject);
networkIdentity.OnStartClient();
}
}
}
}
public static bool SendToAll(short msgType, QMessageBase msg)
{
QLog.Debug($"Server.SendToAll msgType:{msgType}");
var flag = true;
foreach (var networkConnection in connections)
{
if (networkConnection != null)
{
flag &= networkConnection.Send(msgType, msg);
}
}
return flag;
}
private static bool SendToObservers(GameObject contextObj, short msgType, QMessageBase msg)
{
QLog.Debug($"Server.SendToObservers id:{msgType}");
var flag = true;
var component = contextObj.GetComponent<QNetworkIdentity>();
bool result;
if (component == null || component.Observers == null)
{
result = false;
}
else
{
var count = component.Observers.Count;
for (var i = 0; i < count; i++)
{
var networkConnection = component.Observers[i];
flag &= networkConnection.Send(msgType, msg);
}
result = flag;
}
return result;
}
public static bool SendToReady(GameObject contextObj, short msgType, QMessageBase msg)
{
QLog.Debug($"Server.SendToReady id:{msgType}");
bool result;
if (contextObj == null)
{
foreach (var networkConnection in connections)
{
if (networkConnection != null && networkConnection.isReady)
{
networkConnection.Send(msgType, msg);
}
}
result = true;
}
else
{
var flag = true;
var component = contextObj.GetComponent<QNetworkIdentity>();
if (component == null || component.Observers == null)
{
result = false;
}
else
{
var count = component.Observers.Count;
for (var j = 0; j < count; j++)
{
var networkConnection2 = component.Observers[j];
if (networkConnection2.isReady)
{
flag &= networkConnection2.Send(msgType, msg);
}
}
result = flag;
}
}
return result;
}
public static void SendWriterToReady(GameObject contextObj, QNetworkWriter writer, int channelId)
{
var arraySegment = writer.AsArraySegment();
if (arraySegment.Count > 32767)
{
throw new UnityException("NetworkWriter used buffer is too big!");
}
SendBytesToReady(contextObj, arraySegment.Array, arraySegment.Count, channelId);
}
public static void SendBytesToReady(GameObject contextObj, byte[] buffer, int numBytes, int channelId)
{
if (contextObj == null)
{
var flag = true;
foreach (var networkConnection in connections)
{
if (networkConnection != null && networkConnection.isReady)
{
if (!networkConnection.SendBytes(buffer, numBytes, channelId))
{
flag = false;
}
}
}
if (!flag)
{
QLog.Error("SendBytesToReady failed");
}
}
else
{
var component = contextObj.GetComponent<QNetworkIdentity>();
try
{
var flag2 = true;
var count = component.Observers.Count;
for (var j = 0; j < count; j++)
{
var networkConnection2 = component.Observers[j];
if (networkConnection2.isReady)
{
if (!networkConnection2.SendBytes(buffer, numBytes, channelId))
{
flag2 = false;
}
}
}
if (!flag2)
{
QLog.Error($"SendBytesToReady failed for {contextObj}");
}
}
catch (NullReferenceException)
{
QLog.Error($"SendBytesToReady object {contextObj} has not been spawned");
}
}
}
public static void SendBytesToPlayer(GameObject player, byte[] buffer, int numBytes, int channelId)
{
foreach (var networkConnection in connections)
{
if (networkConnection != null)
{
foreach (var controller in networkConnection.PlayerControllers)
{
if (controller.IsValid && controller.Gameobject == player)
{
networkConnection.SendBytes(buffer, numBytes, channelId);
break;
}
}
}
}
}
public static bool SendUnreliableToAll(short msgType, QMessageBase msg)
{
QLog.Log($"Server.SendUnreliableToAll msgType:{msgType}");
var flag = true;
foreach (var networkConnection in connections)
{
if (networkConnection != null)
{
flag &= networkConnection.SendUnreliable(msgType, msg);
}
}
return flag;
}
public static bool SendUnreliableToReady(GameObject contextObj, short msgType, QMessageBase msg)
{
QLog.Log($"Server.SendUnreliableToReady id:{msgType}");
bool result;
if (contextObj == null)
{
foreach (var networkConnection in connections)
{
if (networkConnection != null && networkConnection.isReady)
{
networkConnection.SendUnreliable(msgType, msg);
}
}
result = true;
}
else
{
var flag = true;
var component = contextObj.GetComponent<QNetworkIdentity>();
var count = component.Observers.Count;
for (var j = 0; j < count; j++)
{
var networkConnection2 = component.Observers[j];
if (networkConnection2.isReady)
{
flag &= networkConnection2.SendUnreliable(msgType, msg);
}
}
result = flag;
}
return result;
}
public static bool SendByChannelToAll(short msgType, QMessageBase msg, int channelId)
{
QLog.Log($"Server.SendByChannelToAll id:{msgType}");
var flag = true;
foreach (var networkConnection in connections)
{
if (networkConnection != null)
{
flag &= networkConnection.SendByChannel(msgType, msg, channelId);
}
}
return flag;
}
public static bool SendByChannelToReady(GameObject contextObj, short msgType, QMessageBase msg, int channelId)
{
QLog.Log($"Server.SendByChannelToReady msgType:{msgType}");
bool result;
if (contextObj == null)
{
foreach (var networkConnection in connections)
{
if (networkConnection != null && networkConnection.isReady)
{
networkConnection.SendByChannel(msgType, msg, channelId);
}
}
result = true;
}
else
{
var flag = true;
var component = contextObj.GetComponent<QNetworkIdentity>();
var count = component.Observers.Count;
for (var j = 0; j < count; j++)
{
var networkConnection2 = component.Observers[j];
if (networkConnection2.isReady)
{
flag &= networkConnection2.SendByChannel(msgType, msg, channelId);
}
}
result = flag;
}
return result;
}
public static void DisconnectAll() => instance.InternalDisconnectAll();
internal void InternalDisconnectAll()
{
m_SimpleServerSimple.DisconnectAllConnections();
if (m_LocalConnection != null)
{
m_LocalConnection.Disconnect();
m_LocalConnection.Dispose();
m_LocalConnection = null;
}
m_LocalClientActive = false;
}
internal static void Update() => s_Instance?.InternalUpdate();
private void UpdateServerObjects()
{
foreach (var networkIdentity in objects.Values)
{
try
{
networkIdentity.UNetUpdate();
}
catch (NullReferenceException)
{
}
catch (MissingReferenceException)
{
}
}
if (m_RemoveListCount++ % 100 == 0)
{
CheckForNullObjects();
}
}
private void CheckForNullObjects()
{
foreach (var networkInstanceId in objects.Keys)
{
var networkIdentity = objects[networkInstanceId];
if (networkIdentity == null || networkIdentity.gameObject == null)
{
m_RemoveList.Add(networkInstanceId);
}
}
if (m_RemoveList.Count > 0)
{
foreach (var key in m_RemoveList)
{
objects.Remove(key);
}
m_RemoveList.Clear();
}
}
internal void InternalUpdate()
{
m_SimpleServerSimple.Update();
if (dontListen)
{
m_SimpleServerSimple.UpdateConnections();
}
UpdateServerObjects();
}
private void OnConnected(QNetworkConnection conn)
{
QLog.Log($"Server accepted client:{conn.connectionId}");
conn.SetMaxDelay(m_MaxDelay);
conn.InvokeHandlerNoData(32);
SendCrc(conn);
}
private void OnDisconnected(QNetworkConnection conn)
{
conn.InvokeHandlerNoData(33);
foreach (var controller in conn.PlayerControllers)
{
if (controller.Gameobject != null)
{
QLog.Warning("Player not destroyed when connection disconnected.");
}
}
QLog.Log($"Server lost client:{conn.connectionId}");
conn.RemoveObservers();
conn.Dispose();
}
private void OnData(QNetworkConnection conn, int receivedSize, int channelId) => conn.TransportReceive(m_SimpleServerSimple.messageBuffer, receivedSize, channelId);
private void GenerateConnectError(int error)
{
QLog.Error($"UNet Server Connect Error: {error}");
GenerateError(null, error);
}
private void GenerateDataError(QNetworkConnection conn, int error)
{
QLog.Error($"UNet Server Data Error: {(NetworkError)error}");
GenerateError(conn, error);
}
private void GenerateDisconnectError(QNetworkConnection conn, int error)
{
QLog.Error($"UNet Server Disconnect Error: {(NetworkError)error} conn:[{conn}]:{conn.connectionId}");
GenerateError(conn, error);
}
private void GenerateError(QNetworkConnection conn, int error)
{
if (handlers.ContainsKey(34))
{
var errorMessage = new QErrorMessage
{
errorCode = error
};
var writer = new QNetworkWriter();
errorMessage.Serialize(writer);
var reader = new QNetworkReader(writer);
conn.InvokeHandler(34, reader, 0);
}
}
public static void RegisterHandler(short msgType, QNetworkMessageDelegate handler) => instance.m_SimpleServerSimple.RegisterHandler(msgType, handler);
public static void UnregisterHandler(short msgType) => instance.m_SimpleServerSimple.UnregisterHandler(msgType);
public static void ClearHandlers() => instance.m_SimpleServerSimple.ClearHandlers();
public static void ClearSpawners() => QNetworkScene.ClearSpawners();
public static void SendToClientOfPlayer(GameObject player, short msgType, QMessageBase msg)
{
foreach (var networkConnection in connections)
{
if (networkConnection != null)
{
foreach (var controller in networkConnection.PlayerControllers)
{
if (controller.IsValid && controller.Gameobject == player)
{
networkConnection.Send(msgType, msg);
return;
}
}
}
}
QLog.Error($"Failed to send message to player object '{player.name}, not found in connection list");
}
public static void SendToClient(int connectionId, short msgType, QMessageBase msg)
{
if (connectionId < connections.Count)
{
var networkConnection = connections[connectionId];
if (networkConnection != null)
{
networkConnection.Send(msgType, msg);
return;
}
}
QLog.Error($"Failed to send message to connection ID '{connectionId}, not found in connection list");
}
public static bool AddPlayerForConnection(QNetworkConnection conn, GameObject player, short playerControllerId) => instance.InternalAddPlayerForConnection(conn, player, playerControllerId);
internal bool InternalAddPlayerForConnection(QNetworkConnection conn, GameObject playerGameObject, short playerControllerId)
{
bool result;
if (!GetNetworkIdentity(playerGameObject, out var networkIdentity))
{
QLog.Log(
$"AddPlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to {playerGameObject}");
result = false;
}
else
{
networkIdentity.Reset();
if (!CheckPlayerControllerIdForConnection(conn, playerControllerId))
{
result = false;
}
else
{
GameObject x = null;
if (conn.GetPlayerController(playerControllerId, out var playerController))
{
x = playerController.Gameobject;
}
if (x != null)
{
QLog.Log(
$"AddPlayer: player object already exists for playerControllerId of {playerControllerId}");
result = false;
}
else
{
var playerController2 = new QPlayerController(playerGameObject, playerControllerId);
conn.SetPlayerController(playerController2);
networkIdentity.SetConnectionToClient(conn, playerController2.PlayerControllerId);
SetClientReady(conn);
if (SetupLocalPlayerForConnection(conn, networkIdentity, playerController2))
{
result = true;
}
else
{
QLog.Log(
$"Adding new playerGameObject object netId: {playerGameObject.GetComponent<QNetworkIdentity>().NetId} asset ID {playerGameObject.GetComponent<QNetworkIdentity>().AssetId}");
FinishPlayerForConnection(conn, networkIdentity, playerGameObject);
if (networkIdentity.LocalPlayerAuthority)
{
networkIdentity.SetClientOwner(conn);
}
result = true;
}
}
}
}
return result;
}
private static bool CheckPlayerControllerIdForConnection(QNetworkConnection conn, short playerControllerId)
{
bool result;
if (playerControllerId < 0)
{
QLog.Error($"AddPlayer: playerControllerId of {playerControllerId} is negative");
result = false;
}
else if (playerControllerId > 32)
{
QLog.Log($"AddPlayer: playerControllerId of {playerControllerId} is too high. max is {32}");
result = false;
}
else
{
if (playerControllerId > 16)
{
QLog.Warning($"AddPlayer: playerControllerId of {playerControllerId} is unusually high");
}
result = true;
}
return result;
}
private bool SetupLocalPlayerForConnection(QNetworkConnection conn, QNetworkIdentity uv, QPlayerController newPlayerController)
{
QLog.Log($"NetworkServer SetupLocalPlayerForConnection netID:{uv.NetId}");
bool result;
if (conn is QULocalConnectionToClient ulocalConnectionToClient)
{
QLog.Log("NetworkServer AddPlayer handling ULocalConnectionToClient");
if (uv.NetId.IsEmpty())
{
uv.OnStartServer(true);
}
uv.RebuildObservers(true);
SendSpawnMessage(uv, null);
ulocalConnectionToClient.LocalClient.AddLocalPlayer(newPlayerController);
uv.SetClientOwner(conn);
uv.ForceAuthority(true);
uv.SetLocalPlayer(newPlayerController.PlayerControllerId);
result = true;
}
else
{
result = false;
}
return result;
}
private static void FinishPlayerForConnection(QNetworkConnection conn, QNetworkIdentity uv, GameObject playerGameObject)
{
if (uv.NetId.IsEmpty())
{
Spawn(playerGameObject);
}
conn.Send(4, new QOwnerMessage
{
NetId = uv.NetId,
PlayerControllerId = uv.PlayerControllerId
});
}
private static bool GetNetworkIdentity(GameObject go, out QNetworkIdentity view)
{
view = go.GetComponent<QNetworkIdentity>();
bool result;
if (view == null)
{
QLog.Error("UNET failure. GameObject doesn't have NetworkIdentity.");
result = false;
}
else
{
result = true;
}
return result;
}
public static void SetClientReady(QNetworkConnection conn) => instance.SetClientReadyInternal(conn);
internal void SetClientReadyInternal(QNetworkConnection conn)
{
QLog.Log($"SetClientReadyInternal for conn:{conn.connectionId}");
if (conn.isReady)
{
QLog.Log($"SetClientReady conn {conn.connectionId} already ready");
}
else
{
if (conn.PlayerControllers.Count == 0)
{
QLog.Warning("Ready with no player object");
}
conn.isReady = true;
if (conn is QULocalConnectionToClient)
{
QLog.Log("NetworkServer Ready handling ULocalConnectionToClient");
foreach (var networkIdentity in objects.Values)
{
if (networkIdentity != null && networkIdentity.gameObject != null)
{
var flag = networkIdentity.OnCheckObserver(conn);
if (flag)
{
networkIdentity.AddObserver(conn);
}
if (!networkIdentity.IsClient)
{
QLog.Log("LocalClient.SetSpawnObject calling OnStartClient");
networkIdentity.OnStartClient();
}
}
}
}
else
{
QLog.Log($"Spawning {objects.Count} objects for conn {conn.connectionId}");
var objectSpawnFinishedMessage = new QObjectSpawnFinishedMessage
{
State = 0U
};
conn.Send(12, objectSpawnFinishedMessage);
foreach (var networkIdentity2 in objects.Values)
{
if (networkIdentity2 == null)
{
QLog.Warning("Invalid object found in server local object list (null NetworkIdentity).");
}
else if (networkIdentity2.gameObject.activeSelf)
{
QLog.Debug(
$"Sending spawn message for current server objects name='{networkIdentity2.gameObject.name}' netId={networkIdentity2.NetId}");
var flag2 = networkIdentity2.OnCheckObserver(conn);
if (flag2)
{
networkIdentity2.AddObserver(conn);
}
}
}
objectSpawnFinishedMessage.State = 1U;
conn.Send(12, objectSpawnFinishedMessage);
}
}
}
internal static void ShowForConnection(QNetworkIdentity uv, QNetworkConnection conn)
{
if (conn.isReady)
{
instance.SendSpawnMessage(uv, conn);
}
}
internal static void HideForConnection(QNetworkIdentity uv, QNetworkConnection conn) => conn.Send(13, new QObjectDestroyMessage
{
NetId = uv.NetId
});
public static void SetAllClientsNotReady()
{
foreach (var networkConnection in connections)
{
if (networkConnection != null)
{
SetClientNotReady(networkConnection);
}
}
}
public static void SetClientNotReady(QNetworkConnection conn) => instance.InternalSetClientNotReady(conn);
internal void InternalSetClientNotReady(QNetworkConnection conn)
{
if (conn.isReady)
{
QLog.Log($"PlayerNotReady {conn}");
conn.isReady = false;
conn.RemoveObservers();
var msg = new QNotReadyMessage();
conn.Send(36, msg);
}
}
private static void OnClientReadyMessage(QNetworkMessage netMsg)
{
QLog.Log($"Default handler for ready message from {netMsg.Connection}");
SetClientReady(netMsg.Connection);
}
private static void OnRemovePlayerMessage(QNetworkMessage netMsg)
{
netMsg.ReadMessage(s_RemovePlayerMessage);
netMsg.Connection.GetPlayerController(s_RemovePlayerMessage.PlayerControllerId, out var playerController);
if (playerController != null)
{
netMsg.Connection.RemovePlayerController(s_RemovePlayerMessage.PlayerControllerId);
Destroy(playerController.Gameobject);
}
else
{
QLog.Error(
$"Received remove player message but could not find the player ID: {s_RemovePlayerMessage.PlayerControllerId}");
}
}
private static void OnCommandMessage(QNetworkMessage netMsg)
{
var cmdHash = (int)netMsg.Reader.ReadPackedUInt32();
var networkInstanceId = netMsg.Reader.ReadNetworkId();
var gameObject = FindLocalObject(networkInstanceId);
if (gameObject == null)
{
QLog.Warning($"Instance not found when handling Command message [netId={networkInstanceId}]");
}
else
{
var component = gameObject.GetComponent<QNetworkIdentity>();
if (component == null)
{
QLog.Warning(
$"NetworkIdentity deleted when handling Command message [netId={networkInstanceId}]");
}
else
{
var flag = false;
foreach (var playerController in netMsg.Connection.PlayerControllers)
{
if (playerController.Gameobject != null && playerController.Gameobject.GetComponent<QNetworkIdentity>().NetId == component.NetId)
{
flag = true;
break;
}
}
if (!flag)
{
if (component.ClientAuthorityOwner != netMsg.Connection)
{
QLog.Warning($"Command for object without authority [netId={networkInstanceId}]");
return;
}
}
QLog.Log($"OnCommandMessage for netId={networkInstanceId} conn={netMsg.Connection}");
component.HandleCommand(cmdHash, netMsg.Reader);
}
}
}
internal void SpawnObject(GameObject obj)
{
if (!active)
{
QLog.Error(
$"SpawnObject for {obj}, NetworkServer is not active. Cannot spawn objects without an active server.");
}
else if (!GetNetworkIdentity(obj, out var networkIdentity))
{
QLog.Error($"SpawnObject {obj} has no QSBNetworkIdentity. Please add a NetworkIdentity to {obj}");
}
else
{
networkIdentity.Reset();
networkIdentity.OnStartServer(false);
networkIdentity.RebuildObservers(true);
}
}
internal void SendSpawnMessage(QNetworkIdentity uv, QNetworkConnection conn)
{
if (!uv.ServerOnly)
{
if (uv.SceneId.IsEmpty())
{
var objectSpawnMessage = new QObjectSpawnMessage
{
NetId = uv.NetId,
assetId = uv.AssetId,
Position = uv.transform.position,
Rotation = uv.transform.rotation
};
var networkWriter = new QNetworkWriter();
uv.UNetSerializeAllVars(networkWriter);
if (networkWriter.Position > 0)
{
objectSpawnMessage.Payload = networkWriter.ToArray();
}
if (conn != null)
{
conn.Send(QMsgType.ObjectSpawn, objectSpawnMessage);
}
else
{
SendToReady(uv.gameObject, 3, objectSpawnMessage);
}
}
else
{
var objectSpawnSceneMessage = new QObjectSpawnSceneMessage
{
NetId = uv.NetId,
SceneId = uv.SceneId,
Position = uv.transform.position
};
var networkWriter2 = new QNetworkWriter();
uv.UNetSerializeAllVars(networkWriter2);
if (networkWriter2.Position > 0)
{
objectSpawnSceneMessage.Payload = networkWriter2.ToArray();
}
if (conn != null)
{
conn.Send(10, objectSpawnSceneMessage);
}
else
{
SendToReady(uv.gameObject, 3, objectSpawnSceneMessage);
}
}
}
}
public static void DestroyPlayersForConnection(QNetworkConnection conn)
{
if (conn.PlayerControllers.Count == 0)
{
QLog.Warning("Empty player list given to NetworkServer.Destroy(), nothing to do.");
}
else
{
if (conn.ClientOwnedObjects != null)
{
var hashSet = new HashSet<NetworkInstanceId>(conn.ClientOwnedObjects);
foreach (var gameObject in hashSet.Select(FindLocalObject).Where(gameObject => gameObject != null))
{
DestroyObject(gameObject);
}
}
foreach (var playerController in conn.PlayerControllers)
{
if (playerController.IsValid)
{
if (!(playerController.UnetView == null))
{
DestroyObject(playerController.UnetView, true);
}
playerController.Gameobject = null;
}
}
conn.PlayerControllers.Clear();
}
}
private static void UnSpawnObject(GameObject obj)
{
if (obj == null)
{
QLog.Log("NetworkServer UnspawnObject is null");
}
else if (GetNetworkIdentity(obj, out var uv))
{
UnSpawnObject(uv);
}
}
private static void UnSpawnObject(QNetworkIdentity uv) => DestroyObject(uv, false);
private static void DestroyObject(GameObject obj)
{
if (obj == null)
{
QLog.Log("NetworkServer DestroyObject is null");
}
else if (GetNetworkIdentity(obj, out var uv))
{
DestroyObject(uv, true);
}
}
private static void DestroyObject(QNetworkIdentity uv, bool destroyServerObject)
{
QLog.Log($"DestroyObject instance:{uv.NetId}");
if (objects.ContainsKey(uv.NetId))
{
objects.Remove(uv.NetId);
}
uv.ClientAuthorityOwner?.RemoveOwnedObject(uv);
var objectDestroyMessage = new QObjectDestroyMessage
{
NetId = uv.NetId
};
SendToObservers(uv.gameObject, 1, objectDestroyMessage);
uv.ClearObservers();
if (QNetworkClient.active && instance.m_LocalClientActive)
{
uv.OnNetworkDestroy();
QClientScene.SetLocalObject(objectDestroyMessage.NetId, null);
}
if (destroyServerObject)
{
UnityEngine.Object.Destroy(uv.gameObject);
}
uv.MarkForReset();
}
public static void ClearLocalObjects() => objects.Clear();
public static void Spawn(GameObject obj)
{
if (VerifyCanSpawn(obj))
{
instance.SpawnObject(obj);
}
}
private static bool CheckForPrefab(GameObject obj) => false;
private static bool VerifyCanSpawn(GameObject obj)
{
bool result;
if (CheckForPrefab(obj))
{
QLog.Error($"GameObject {obj.name} is a prefab, it can't be spawned. This will cause errors in builds.");
result = false;
}
else
{
result = true;
}
return result;
}
public static bool SpawnWithClientAuthority(GameObject obj, GameObject player)
{
var component = player.GetComponent<QNetworkIdentity>();
bool result;
if (component == null)
{
QLog.Error("SpawnWithClientAuthority player object has no NetworkIdentity");
result = false;
}
else if (component.ConnectionToClient == null)
{
QLog.Error("SpawnWithClientAuthority player object is not a player.");
result = false;
}
else
{
result = SpawnWithClientAuthority(obj, component.ConnectionToClient);
}
return result;
}
public static bool SpawnWithClientAuthority(GameObject obj, QNetworkConnection conn)
{
bool result;
if (!conn.isReady)
{
QLog.Error("SpawnWithClientAuthority NetworkConnection is not ready!");
result = false;
}
else
{
Spawn(obj);
var component = obj.GetComponent<QNetworkIdentity>();
result = !(component == null) && component.IsServer && component.AssignClientAuthority(conn);
}
return result;
}
public static bool SpawnWithClientAuthority(GameObject obj, int assetId, QNetworkConnection conn)
{
Spawn(obj, assetId);
var component = obj.GetComponent<QNetworkIdentity>();
return !(component == null) && component.IsServer && component.AssignClientAuthority(conn);
}
public static void Spawn(GameObject obj, int assetId)
{
if (VerifyCanSpawn(obj))
{
if (GetNetworkIdentity(obj, out var networkIdentity))
{
networkIdentity.SetDynamicAssetId(assetId);
}
instance.SpawnObject(obj);
}
}
public static void Destroy(GameObject obj) => DestroyObject(obj);
public static void UnSpawn(GameObject obj) => UnSpawnObject(obj);
internal bool InvokeBytes(QULocalConnectionToServer conn, byte[] buffer, int numBytes, int channelId)
{
var networkReader = new QNetworkReader(buffer);
networkReader.ReadInt16();
var num = networkReader.ReadInt16();
bool result;
if (handlers.ContainsKey(num) && m_LocalConnection != null)
{
m_LocalConnection.InvokeHandler(num, networkReader, channelId);
result = true;
}
else
{
result = false;
}
return result;
}
internal bool InvokeHandlerOnServer(QULocalConnectionToServer conn, short msgType, QMessageBase msg, int channelId)
{
bool result;
if (handlers.ContainsKey(msgType) && m_LocalConnection != null)
{
var writer = new QNetworkWriter();
msg.Serialize(writer);
var reader = new QNetworkReader(writer);
m_LocalConnection.InvokeHandler(msgType, reader, channelId);
result = true;
}
else
{
QLog.Error($"Local invoke: Failed to find local connection to invoke handler on [connectionId={conn.connectionId}] for MsgId:{msgType}");
result = false;
}
return result;
}
public static GameObject FindLocalObject(NetworkInstanceId netId) => instance.m_NetworkScene.FindLocalObject(netId);
private static bool ValidateSceneObject(QNetworkIdentity netId) => netId.gameObject.hideFlags != HideFlags.NotEditable && netId.gameObject.hideFlags != HideFlags.HideAndDontSave && !netId.SceneId.IsEmpty();
public static bool SpawnObjects()
{
bool result;
if (!active)
{
result = true;
}
else
{
var objectsOfTypeAll = Resources.FindObjectsOfTypeAll<QNetworkIdentity>();
foreach (var networkIdentity in objectsOfTypeAll)
{
if (ValidateSceneObject(networkIdentity))
{
Debug.Log(
$"SpawnObjects sceneId:{networkIdentity.SceneId} name:{networkIdentity.gameObject.name}");
networkIdentity.Reset();
networkIdentity.gameObject.SetActive(true);
}
}
foreach (var networkIdentity2 in objectsOfTypeAll)
{
if (ValidateSceneObject(networkIdentity2))
{
Spawn(networkIdentity2.gameObject);
networkIdentity2.ForceAuthority(true);
}
}
result = true;
}
return result;
}
private static void SendCrc(QNetworkConnection targetConnection)
{
if (QNetworkCRC.singleton != null)
{
if (QNetworkCRC.scriptCRCCheck)
{
var crcmessage = new QCRCMessage();
var list = new List<QCRCMessageEntry>();
foreach (var text in QNetworkCRC.singleton.scripts.Keys)
{
list.Add(new QCRCMessageEntry
{
name = text,
channel = (byte)QNetworkCRC.singleton.scripts[text]
});
}
crcmessage.scripts = list.ToArray();
targetConnection.Send(14, crcmessage);
}
}
}
private static volatile QNetworkServer s_Instance;
private static readonly object s_Sync = new UnityEngine.Object();
private bool m_LocalClientActive;
private readonly List<QNetworkConnection> m_LocalConnectionsFakeList = new();
private QULocalConnectionToClient m_LocalConnection;
private readonly QNetworkScene m_NetworkScene;
private readonly HashSet<int> m_ExternalConnections;
public readonly ServerSimpleWrapper m_SimpleServerSimple;
private float m_MaxDelay = 0.1f;
private readonly HashSet<NetworkInstanceId> m_RemoveList;
private int m_RemoveListCount;
private const int k_RemoveListInterval = 100;
internal static ushort maxPacketSize;
private static readonly QRemovePlayerMessage s_RemovePlayerMessage = new();
public class ServerSimpleWrapper : QNetworkServerSimple
{
public ServerSimpleWrapper(QNetworkServer server) => m_Server = server;
public override void OnConnectError(int connectionId, byte error) => m_Server.GenerateConnectError(error);
public override void OnDataError(QNetworkConnection conn, byte error) => m_Server.GenerateDataError(conn, error);
public override void OnDisconnectError(QNetworkConnection conn, byte error) => m_Server.GenerateDisconnectError(conn, error);
public override void OnConnected(QNetworkConnection conn) => m_Server.OnConnected(conn);
public override void OnDisconnected(QNetworkConnection conn) => m_Server.OnDisconnected(conn);
public override void OnData(QNetworkConnection conn, int receivedSize, int channelId) => m_Server.OnData(conn, receivedSize, channelId);
private readonly QNetworkServer m_Server;
}
}
}