diff --git a/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity b/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity index bf8b4a229..4e2c68ef0 100644 --- a/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity +++ b/Assets/Mirror/Examples/Benchmark/Scenes/Scene.unity @@ -293,6 +293,8 @@ MonoBehaviour: autoStartServerBuild: 1 showDebugMessages: 0 serverTickRate: 30 + serverBatching: 1 + serverBatchInterval: 0 offlineScene: onlineScene: transport: {fileID: 1282001521} diff --git a/Assets/Mirror/Runtime/LocalConnections.cs b/Assets/Mirror/Runtime/LocalConnections.cs index 6d4afcf75..839a36cb7 100644 --- a/Assets/Mirror/Runtime/LocalConnections.cs +++ b/Assets/Mirror/Runtime/LocalConnections.cs @@ -9,7 +9,7 @@ class ULocalConnectionToClient : NetworkConnectionToClient { internal ULocalConnectionToServer connectionToServer; - public ULocalConnectionToClient() : base(LocalConnectionId) { } + public ULocalConnectionToClient() : base(LocalConnectionId, false, 0) { } public override string address => "localhost"; diff --git a/Assets/Mirror/Runtime/NetworkConnection.cs b/Assets/Mirror/Runtime/NetworkConnection.cs index d0bb76a55..258be309e 100644 --- a/Assets/Mirror/Runtime/NetworkConnection.cs +++ b/Assets/Mirror/Runtime/NetworkConnection.cs @@ -222,7 +222,7 @@ public bool InvokeHandler(T msg, int channelId) } // helper function - protected void UnpackAndInvoke(NetworkReader reader, int channelId) + protected bool UnpackAndInvoke(NetworkReader reader, int channelId) { if (MessagePacker.Unpack(reader, out int msgType)) { @@ -231,25 +231,22 @@ protected void UnpackAndInvoke(NetworkReader reader, int channelId) { msgDelegate.Invoke(this, reader, channelId); lastMessageTime = Time.time; + return true; } else { if (logger.LogEnabled()) logger.Log("Unknown message ID " + msgType + " " + this + ". May be due to no existing RegisterHandler for this message."); + return false; } } else { logger.LogError("Closed connection: " + this + ". Invalid message header."); Disconnect(); + return false; } } - // note: original HLAPI HandleBytes function handled >1 message in a while loop, but this wasn't necessary - // anymore because NetworkServer/NetworkClient Update both use while loops to handle >1 data events per - // frame already. - // -> in other words, we always receive 1 message per Receive call, never two. - // -> can be tested easily with a 1000ms send delay and then logging amount received in while loops here - // and in NetworkServer/Client Update. HandleBytes already takes exactly one. /// /// This function allows custom network connection classes to process data from the network before it is passed to the application. /// @@ -266,7 +263,13 @@ internal void TransportReceive(ArraySegment buffer, int channelId) // unpack message using (PooledNetworkReader reader = NetworkReaderPool.GetReader(buffer)) { - UnpackAndInvoke(reader, channelId); + // the other end might batch multiple messages into one packet. + // we need to try to unpack multiple times. + while (reader.Position < reader.Length) + { + if (!UnpackAndInvoke(reader, channelId)) + break; + } } } diff --git a/Assets/Mirror/Runtime/NetworkConnectionToClient.cs b/Assets/Mirror/Runtime/NetworkConnectionToClient.cs index 977e36066..11ee3ca28 100644 --- a/Assets/Mirror/Runtime/NetworkConnectionToClient.cs +++ b/Assets/Mirror/Runtime/NetworkConnectionToClient.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using UnityEngine; namespace Mirror @@ -9,16 +10,150 @@ public class NetworkConnectionToClient : NetworkConnection public override string address => Transport.activeTransport.ServerGetClientAddress(connectionId); - public NetworkConnectionToClient(int networkConnectionId) : base(networkConnectionId) { } + // batching from server to client. + // fewer transport calls give us significantly better performance/scale. + // + // for a 64KB max message transport and 64 bytes/message on average, we + // reduce transport calls by a factor of 1000. + // + // depending on the transport, this can give 10x performance. + // + // Dictionary because we have multiple channels. + internal class Batch + { + // each batch needs a writer for batching + // => we allocate one writer per channel + // => it grows to Transport MaxMessageSize automatically + // TODO maybe use a pooled writer and return when disconnecting? + internal NetworkWriter writer = new NetworkWriter(); + + // each channel's batch has its own lastSendTime. + // (use NetworkTime for maximum precision over days) + // + // channel batches are full and flushed at different times. using + // one global time wouldn't make sense. + // -> we want to be able to reset a channels send time after Send() + // flushed it because full. global time wouldn't allow that, so + // we would often flush in Send() and then flush again in Update + // even though we just flushed in Send(). + // -> initialize with current NetworkTime so first update doesn't + // calculate elapsed via 'now - 0' + internal double lastSendTime = NetworkTime.time; + } + Dictionary batches = new Dictionary(); + + // batching is optional because due to mirror's non-optimal update order + // it would increase latency. + + // batching is still optional until we improve mirror's update order. + // right now it increases latency because: + // enabling batching flushes all state updates in same frame, but + // transport processes incoming messages afterwards so server would + // batch them until next frame's flush + // => disable it for super fast paced games + // => enable it for high scale / cpu heavy games + bool batching; + + // batch interval is 0 by default, meaning that we send immediately. + // (useful to run tests without waiting for intervals too) + float batchInterval; + + public NetworkConnectionToClient(int networkConnectionId, bool batching, float batchInterval) + : base(networkConnectionId) + { + this.batching = batching; + this.batchInterval = batchInterval; + } + + Batch GetBatchForChannelId(int channelId) + { + // get existing or create new writer for the channelId + Batch batch; + if (!batches.TryGetValue(channelId, out batch)) + { + batch = new Batch(); + batches[channelId] = batch; + } + return batch; + } + + void SendBatch(int channelId, Batch batch) + { + // send batch + Transport.activeTransport.ServerSend(connectionId, channelId, batch.writer.ToArraySegment()); + + // clear batch + batch.writer.Reset(); + + // reset send time for this channel's batch + batch.lastSendTime = NetworkTime.time; + } internal override void Send(ArraySegment segment, int channelId = Channels.DefaultReliable) { if (logger.LogEnabled()) logger.Log("ConnectionSend " + this + " bytes:" + BitConverter.ToString(segment.Array, segment.Offset, segment.Count)); + //Debug.Log("ConnectionSend " + this + " bytes:" + BitConverter.ToString(segment.Array, segment.Offset, segment.Count)); + // validate packet size first. if (ValidatePacketSize(segment, channelId)) { - Transport.activeTransport.ServerSend(connectionId, channelId, segment); + // batching? + if (batching) + { + // always batch! + // (even if interval == 0, in which case we flush in Update()) + // + // if batch would become bigger than MaxBatchPacketSize for this + // channel then send out the previous batch first. + // + // IMPORTANT: we use maxBATCHsize not maxPACKETsize. + // some transports like kcp have large maxPACKETsize + // like 144kb, but those would extremely slow to use + // all the time for batching. + // (maxPACKETsize messages still work fine, we just + // aim for maxBATCHsize where possible) + Batch batch = GetBatchForChannelId(channelId); + int max = Transport.activeTransport.GetMaxBatchSize(channelId); + if (batch.writer.Position + segment.Count > max) + { + //UnityEngine.Debug.LogWarning($"sending batch {batch.writer.Position} / {max} after full for segment={segment.Count} for connectionId={connectionId}"); + SendBatch(channelId, batch); + } + + // now add segment to batch + batch.writer.WriteBytes(segment.Array, segment.Offset, segment.Count); + } + // otherwise send directly to minimize latency + else + { + Transport.activeTransport.ServerSend(connectionId, channelId, segment); + } + } + } + + // flush batched messages every batchInterval to make sure that they are + // sent out every now and then, even if the batch isn't full yet. + // (avoids 30s latency if batches would only get full every 30s) + internal void Update() + { + // batching? + if (batching) + { + // go through batches for all channels + foreach (KeyValuePair kvp in batches) + { + // enough time elapsed to flush this channel's batch? + // and not empty? + double elapsed = NetworkTime.time - kvp.Value.lastSendTime; + if (elapsed >= batchInterval && + kvp.Value.writer.Position > 0) + { + // send the batch. time will be reset internally. + //Debug.Log($"sending batch of {kvp.Value.writer.Position} bytes for channel={kvp.Key} connId={connectionId}"); + SendBatch(kvp.Key, kvp.Value); + } + } } } diff --git a/Assets/Mirror/Runtime/NetworkManager.cs b/Assets/Mirror/Runtime/NetworkManager.cs index 94836bbf1..24b246765 100644 --- a/Assets/Mirror/Runtime/NetworkManager.cs +++ b/Assets/Mirror/Runtime/NetworkManager.cs @@ -64,6 +64,26 @@ public class NetworkManager : MonoBehaviour [Tooltip("Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.")] public int serverTickRate = 30; + /// + /// batching is still optional until we improve mirror's update order. + /// right now it increases latency because: + /// enabling batching flushes all state updates in same frame, but + /// transport processes incoming messages afterwards so server would + /// batch them until next frame's flush + /// => disable it for super fast paced games + /// => enable it for high scale / cpu heavy games + /// + [Tooltip("Batching greatly reduces CPU & Transport load, but increases latency by one frame time. Use for high scale games / CPU intensive games. Don't use for fast paced games.")] + public bool serverBatching; + + /// + /// batching from server to client. + /// fewer transport calls give us significantly better performance/scale. + /// if batch interval is 0, then we only batch until the Update() call + /// + [Tooltip("Server can batch messages up to Transport.GetMaxPacketSize to significantly reduce transport calls and improve performance/scale./nIf batch interval is 0, then we only batch until the Update() call. Otherwise we batch until interval elapsed (note that this increases latency).")] + public float serverBatchInterval = 0; + /// /// The scene to switch to when offline. /// Setting this makes the NetworkManager do scene management. This scene will be switched to when a network session is completed - such as a client disconnect, or a server shutdown. @@ -310,6 +330,10 @@ void SetupServer() ConfigureServerFrameRate(); + // batching + NetworkServer.batching = serverBatching; + NetworkServer.batchInterval = serverBatchInterval; + // Copy auto-disconnect settings to NetworkServer NetworkServer.disconnectInactiveTimeout = disconnectInactiveTimeout; NetworkServer.disconnectInactiveConnections = disconnectInactiveConnections; diff --git a/Assets/Mirror/Runtime/NetworkServer.cs b/Assets/Mirror/Runtime/NetworkServer.cs index 734cc0f68..1ab0d3380 100644 --- a/Assets/Mirror/Runtime/NetworkServer.cs +++ b/Assets/Mirror/Runtime/NetworkServer.cs @@ -57,6 +57,25 @@ public static class NetworkServer /// public static bool active { get; internal set; } + + /// + /// batching is still optional until we improve mirror's update order. + /// right now it increases latency because: + /// enabling batching flushes all state updates in same frame, but + /// transport processes incoming messages afterwards so server would + /// batch them until next frame's flush + /// => disable it for super fast paced games + /// => enable it for high scale / cpu heavy games + /// + public static bool batching; + + /// + /// batching from server to client. + /// fewer transport calls give us significantly better performance/scale. + /// if batch interval is 0, then we only batch until the Update() call. + /// + public static float batchInterval = 0; + /// /// Should the server disconnect remote connections that have gone silent for more than Server Idle Timeout? /// This value is initially set from NetworkManager in SetupServer and can be changed at runtime @@ -470,6 +489,12 @@ public static void Update() logger.LogWarning("Found 'null' entry in spawned list for netId=" + kvp.Key + ". Please call NetworkServer.Destroy to destroy networked objects. Don't use GameObject.Destroy."); } } + + // update all connections to send out batched messages in interval + foreach (NetworkConnectionToClient conn in connections.Values) + { + conn.Update(); + } } static void CheckForInactiveConnections() @@ -525,7 +550,7 @@ static void OnConnected(int connectionId) if (connections.Count < maxConnections) { // add connection - NetworkConnectionToClient conn = new NetworkConnectionToClient(connectionId); + NetworkConnectionToClient conn = new NetworkConnectionToClient(connectionId, batching, batchInterval); OnConnected(conn); } else diff --git a/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs b/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs index 8accfb507..6d54fec47 100644 --- a/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs +++ b/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs @@ -197,6 +197,17 @@ public override int GetMaxPacketSize(int channelId = Channels.DefaultReliable) } } + // kcp reliable channel max packet size is MTU * WND_RCV + // this allows 144kb messages. but due to head of line blocking, all + // other messages would have to wait until the maxed size one is + // delivered. batching 144kb messages each time would be EXTREMELY slow + // and fill the send queue nearly immediately when using it over the + // network. + // => instead we always use MTU sized batches. + // => people can still send maxed size if needed. + public override int GetMaxBatchSize(int channelId) => + KcpConnection.UnreliableMaxMessageSize; + public override string ToString() { return "KCP"; diff --git a/Assets/Mirror/Runtime/Transport/Transport.cs b/Assets/Mirror/Runtime/Transport/Transport.cs index bc3818819..8bf384b4f 100644 --- a/Assets/Mirror/Runtime/Transport/Transport.cs +++ b/Assets/Mirror/Runtime/Transport/Transport.cs @@ -8,7 +8,7 @@ namespace Mirror /// /// ///

- /// Transport Rules + /// Transport Rules ///

/// /// @@ -206,6 +206,18 @@ public virtual void ClientConnect(Uri uri) /// the size in bytes that can be sent via the provided channel public abstract int GetMaxPacketSize(int channelId = Channels.DefaultReliable); + /// + /// The maximum batch(!) size for a given channel. + /// Uses GetMaxPacketSize by default. + /// Some transports like kcp support large max packet sizes which should + /// not be used for batching all the time because they end up being too + /// slow (head of line blocking etc.). + /// + /// channel id + /// the size in bytes that should be batched via the provided channel + public virtual int GetMaxBatchSize(int channelId) => + GetMaxPacketSize(channelId); + /// /// Shut down the transport, both as client and server /// diff --git a/Assets/Mirror/Tests/Common/FakeNetworkConnection.cs b/Assets/Mirror/Tests/Common/FakeNetworkConnection.cs index c06933acf..f212a40ad 100644 --- a/Assets/Mirror/Tests/Common/FakeNetworkConnection.cs +++ b/Assets/Mirror/Tests/Common/FakeNetworkConnection.cs @@ -4,7 +4,7 @@ namespace Mirror.Tests { public class FakeNetworkConnection : NetworkConnectionToClient { - public FakeNetworkConnection() : base(1) + public FakeNetworkConnection() : base(1, false, 0) { } diff --git a/Assets/Mirror/Tests/Editor/NetworkConnectionToClientTests.cs b/Assets/Mirror/Tests/Editor/NetworkConnectionToClientTests.cs new file mode 100644 index 000000000..2d3701fed --- /dev/null +++ b/Assets/Mirror/Tests/Editor/NetworkConnectionToClientTests.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using NUnit.Framework; +using UnityEngine; + +namespace Mirror.Tests +{ + public class NetworkConnectionToClientTests + { + GameObject transportGO; + MemoryTransport transport; + List clientReceived = new List(); + + [SetUp] + public void SetUp() + { + // transport is needed by server and client. + // it needs to be on a gameobject because client.connect enables it, + // which throws a NRE if not on a gameobject + transportGO = new GameObject(); + Transport.activeTransport = transport = transportGO.AddComponent(); + transport.OnClientDataReceived = (message, channelId) => { + byte[] array = new byte[message.Count]; + Buffer.BlockCopy(message.Array, message.Offset, array, 0, message.Count); + clientReceived.Add(array); + }; + transport.ServerStart(); + transport.ClientConnect("localhost"); + Assert.That(transport.ServerActive, Is.True); + Assert.That(transport.ClientConnected, Is.True); + } + + [TearDown] + public void TearDown() + { + clientReceived.Clear(); + GameObject.DestroyImmediate(transportGO); + } + + [Test] + public void Send_WithoutBatching_SendsImmediately() + { + // create connection and send + NetworkConnectionToClient connection = new NetworkConnectionToClient(42, false, 0); + byte[] message = {0x01, 0x02}; + connection.Send(new ArraySegment(message)); + + // Send() should send immediately, not only in server.update flushing + transport.LateUpdate(); + Assert.That(clientReceived.Count, Is.EqualTo(1)); + } + + [Test] + public void Send_BatchesUntilUpdate() + { + // create connection and send + NetworkConnectionToClient connection = new NetworkConnectionToClient(42, true, 0); + byte[] message = {0x01, 0x02}; + connection.Send(new ArraySegment(message)); + + // Send() should only add to batch, not send anything yet + transport.LateUpdate(); + Assert.That(clientReceived.Count, Is.EqualTo(0)); + + // updating the connection should now send + connection.Update(); + transport.LateUpdate(); + Assert.That(clientReceived.Count, Is.EqualTo(1)); + } + + [Test] + public void Send_BatchesUntilInterval() + { + // create connection and send + int intervalMilliseconds = 10; + float intervalSeconds = intervalMilliseconds / 1000f; + NetworkConnectionToClient connection = new NetworkConnectionToClient(42, true, intervalSeconds); + byte[] message = {0x01, 0x02}; + connection.Send(new ArraySegment(message)); + + // Send() and update shouldn't send yet until interval elapsed + connection.Update(); + transport.LateUpdate(); + Assert.That(clientReceived.Count, Is.EqualTo(0)); + + // wait 'interval' + Thread.Sleep(intervalMilliseconds); + + // updating again should flush out the batch + connection.Update(); + transport.LateUpdate(); + Assert.That(clientReceived.Count, Is.EqualTo(1)); + } + + // IMPORTANT + // + // there was a bug where batching resets .Position instead of .Length, + // resulting in extremely high bandwidth where if the last message's + // Length was 2, and the current message's Length was 1, then we would + // still send a writer with Length = 2 because we did not reset .Length! + // -> let's try to send a big message, update, then send a small message + [Test] + public void SendBatchingResetsPreviousWriter() + { + // create connection + NetworkConnectionToClient connection = new NetworkConnectionToClient(42, true, 0); + + // send and update big message + byte[] message = {0x01, 0x02}; + connection.Send(new ArraySegment(message)); + connection.Update(); + transport.LateUpdate(); + Assert.That(clientReceived.Count, Is.EqualTo(1)); + Assert.That(clientReceived[0].Length, Is.EqualTo(2)); + Assert.That(clientReceived[0][0], Is.EqualTo(0x01)); + Assert.That(clientReceived[0][1], Is.EqualTo(0x02)); + + // clear previous + clientReceived.Clear(); + + // send a smaller message + message = new byte[]{0xFF}; + connection.Send(new ArraySegment(message)); + connection.Update(); + transport.LateUpdate(); + Assert.That(clientReceived.Count, Is.EqualTo(1)); + Assert.That(clientReceived[0].Length, Is.EqualTo(1)); + Assert.That(clientReceived[0][0], Is.EqualTo(0xFF)); + } + } +} diff --git a/Assets/Mirror/Tests/Editor/NetworkConnectionToClientTests.cs.meta b/Assets/Mirror/Tests/Editor/NetworkConnectionToClientTests.cs.meta new file mode 100644 index 000000000..94948fcd6 --- /dev/null +++ b/Assets/Mirror/Tests/Editor/NetworkConnectionToClientTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 22aee0cf91224ec9925f7faabc073b09 +timeCreated: 1611722538 \ No newline at end of file diff --git a/Assets/Mirror/Tests/Editor/NetworkIdentityTests.cs b/Assets/Mirror/Tests/Editor/NetworkIdentityTests.cs index 4f5ac7550..ebcf9328a 100644 --- a/Assets/Mirror/Tests/Editor/NetworkIdentityTests.cs +++ b/Assets/Mirror/Tests/Editor/NetworkIdentityTests.cs @@ -510,11 +510,11 @@ public void RemoveObserverInternal() identity.OnStartServer(); // add an observer connection - NetworkConnectionToClient connection = new NetworkConnectionToClient(42); + NetworkConnectionToClient connection = new NetworkConnectionToClient(42, false, 0); identity.observers[connection.connectionId] = connection; // RemoveObserverInternal with invalid connection should do nothing - identity.RemoveObserverInternal(new NetworkConnectionToClient(43)); + identity.RemoveObserverInternal(new NetworkConnectionToClient(43, false, 0)); Assert.That(identity.observers.Count, Is.EqualTo(1)); // RemoveObserverInternal with existing connection should remove it @@ -711,7 +711,7 @@ public void AssignAndRemoveClientAuthority() // another connection // error log is expected LogAssert.ignoreFailingMessages = true; - result = identity.AssignClientAuthority(new NetworkConnectionToClient(43)); + result = identity.AssignClientAuthority(new NetworkConnectionToClient(43, false, 0)); LogAssert.ignoreFailingMessages = false; Assert.That(result, Is.False); Assert.That(identity.connectionToClient, Is.EqualTo(owner)); @@ -874,7 +874,7 @@ public void OnCheckObserverCatchesException() // add component CheckObserverExceptionNetworkBehaviour compExc = gameObject.AddComponent(); - NetworkConnection connection = new NetworkConnectionToClient(42); + NetworkConnection connection = new NetworkConnectionToClient(42, false, 0); // an exception in OnCheckObserver should be caught // (an error log is expected) @@ -896,7 +896,7 @@ public void OnCheckObserverTrue() // create a networkidentity with a component that returns true // result should be true. CheckObserverTrueNetworkBehaviour compTrue = gameObject.AddComponent(); - NetworkConnection connection = new NetworkConnectionToClient(42); + NetworkConnection connection = new NetworkConnectionToClient(42, false, 0); bool result = identity.OnCheckObserver(connection); Assert.That(result, Is.True); Assert.That(compTrue.called, Is.EqualTo(1)); @@ -908,7 +908,7 @@ public void OnCheckObserverFalse() // create a networkidentity with a component that returns false // result should be false. CheckObserverFalseNetworkBehaviour compFalse = gameObject.AddComponent(); - NetworkConnection connection = new NetworkConnectionToClient(42); + NetworkConnection connection = new NetworkConnectionToClient(42, false, 0); bool result = identity.OnCheckObserver(connection); Assert.That(result, Is.False); Assert.That(compFalse.called, Is.EqualTo(1)); @@ -1142,8 +1142,8 @@ public void OnStopServerEx() public void AddObserver() { // create some connections - NetworkConnectionToClient connection1 = new NetworkConnectionToClient(42); - NetworkConnectionToClient connection2 = new NetworkConnectionToClient(43); + NetworkConnectionToClient connection1 = new NetworkConnectionToClient(42, false, 0); + NetworkConnectionToClient connection2 = new NetworkConnectionToClient(43, false, 0); // AddObserver should return early if called before .observers was // created @@ -1167,7 +1167,7 @@ public void AddObserver() Assert.That(identity.observers[connection2.connectionId], Is.EqualTo(connection2)); // adding a duplicate connectionId shouldn't overwrite the original - NetworkConnectionToClient duplicate = new NetworkConnectionToClient(connection1.connectionId); + NetworkConnectionToClient duplicate = new NetworkConnectionToClient(connection1.connectionId, false, 0); identity.AddObserver(duplicate); Assert.That(identity.observers.Count, Is.EqualTo(2)); Assert.That(identity.observers.ContainsKey(connection1.connectionId)); @@ -1183,8 +1183,8 @@ public void ClearObservers() identity.OnStartServer(); // add some observers - identity.observers[42] = new NetworkConnectionToClient(42); - identity.observers[43] = new NetworkConnectionToClient(43); + identity.observers[42] = new NetworkConnectionToClient(42, false, 0); + identity.observers[43] = new NetworkConnectionToClient(43, false, 0); // call ClearObservers identity.ClearObservers(); @@ -1262,9 +1262,9 @@ public void Reset() identity.isClient = true; // creates .observers and generates a netId identity.OnStartServer(); - identity.connectionToClient = new NetworkConnectionToClient(1); + identity.connectionToClient = new NetworkConnectionToClient(1, false, 0); identity.connectionToServer = new NetworkConnectionToServer(); - identity.observers[43] = new NetworkConnectionToClient(2); + identity.observers[43] = new NetworkConnectionToClient(2, false, 0); // mark for reset and reset identity.Reset(); @@ -1279,7 +1279,7 @@ public void HandleCommand() { // add component CommandTestNetworkBehaviour comp0 = gameObject.AddComponent(); - NetworkConnectionToClient connection = new NetworkConnectionToClient(1); + NetworkConnectionToClient connection = new NetworkConnectionToClient(1, false, 0); Assert.That(comp0.called, Is.EqualTo(0)); Assert.That(comp0.senderConnectionInCall, Is.Null); @@ -1446,7 +1446,7 @@ public void GetNewObservers() { // add components RebuildObserversNetworkBehaviour comp = gameObject.AddComponent(); - comp.observer = new NetworkConnectionToClient(12); + comp.observer = new NetworkConnectionToClient(12, false, 0); // get new observers HashSet observers = new HashSet(); @@ -1462,7 +1462,7 @@ public void GetNewObserversClearsHashSet() // get new observers. no observer components so it should just clear // it and not do anything else HashSet observers = new HashSet(); - observers.Add(new NetworkConnectionToClient(42)); + observers.Add(new NetworkConnectionToClient(42, false, 0)); identity.GetNewObservers(observers, true); Assert.That(observers.Count, Is.EqualTo(0)); } @@ -1480,8 +1480,8 @@ public void GetNewObserversFalseIfNoComponents() public void AddAllReadyServerConnectionsToObservers() { // add some server connections - NetworkServer.connections[12] = new NetworkConnectionToClient(12) { isReady = true }; - NetworkServer.connections[13] = new NetworkConnectionToClient(13) { isReady = false }; + NetworkServer.connections[12] = new NetworkConnectionToClient(12, false, 0) { isReady = true }; + NetworkServer.connections[13] = new NetworkConnectionToClient(13, false, 0) { isReady = false }; // add a host connection ULocalConnectionToClient localConnection = new ULocalConnectionToClient(); @@ -1554,7 +1554,7 @@ public void RebuildObserversAddsReadyConnectionsIfImplemented() // add a proximity checker // one with a ready connection, one with no ready connection, one with null connection RebuildObserversNetworkBehaviour comp = gameObject.AddComponent(); - comp.observer = new NetworkConnectionToClient(42) { isReady = true }; + comp.observer = new NetworkConnectionToClient(42, false, 0) { isReady = true }; // call OnStartServer so that observers dict is created identity.OnStartServer(); @@ -1575,7 +1575,7 @@ public void RebuildObserversDoesntAddNotReadyConnectionsIfImplemented() // add a proximity checker // one with a ready connection, one with no ready connection, one with null connection RebuildObserversNetworkBehaviour comp = gameObject.AddComponent(); - comp.observer = new NetworkConnectionToClient(42) { isReady = false }; + comp.observer = new NetworkConnectionToClient(42, false, 0) { isReady = false }; // call OnStartServer so that observers dict is created identity.OnStartServer(); @@ -1592,8 +1592,8 @@ public void RebuildObserversDoesntAddNotReadyConnectionsIfImplemented() public void RebuildObserversAddsReadyServerConnectionsIfNotImplemented() { // add some server connections - NetworkServer.connections[12] = new NetworkConnectionToClient(12) { isReady = true }; - NetworkServer.connections[13] = new NetworkConnectionToClient(13) { isReady = false }; + NetworkServer.connections[12] = new NetworkConnectionToClient(12, false, 0) { isReady = true }; + NetworkServer.connections[13] = new NetworkConnectionToClient(13, false, 0) { isReady = false }; // call OnStartServer so that observers dict is created identity.OnStartServer(); @@ -1612,7 +1612,7 @@ public void RebuildObserversAddsReadyServerConnectionsIfNotImplemented() public void RebuildObserversDoesNotAddServerConnectionsIfImplemented() { // add a server connection - NetworkServer.connections[12] = new NetworkConnectionToClient(12) { isReady = true }; + NetworkServer.connections[12] = new NetworkConnectionToClient(12, false, 0) { isReady = true }; // add at least one observers component, otherwise it will just add // all server connections @@ -1636,7 +1636,7 @@ public void RebuildObserversAddRemoveAndVisListTest() { // add observer component with ready observer RebuildObserversNetworkBehaviour comp = gameObject.AddComponent(); - NetworkConnectionToClient observerA = new NetworkConnectionToClient(42) { isReady = true }; + NetworkConnectionToClient observerA = new NetworkConnectionToClient(42, false, 0) { isReady = true }; comp.observer = observerA; // call OnStartServer so that observers dict is created @@ -1652,7 +1652,7 @@ public void RebuildObserversAddRemoveAndVisListTest() Assert.That(observerA.visList.Contains(identity), Is.True); // let the component find another observer - NetworkConnectionToClient observerB = new NetworkConnectionToClient(43) { isReady = true }; + NetworkConnectionToClient observerB = new NetworkConnectionToClient(43, false, 0) { isReady = true }; comp.observer = observerB; // rebuild observers should remove the old observer and add the new one @@ -1703,7 +1703,7 @@ public void RebuildObserversSetsHostVisibility() public void RebuildObserversReturnsIfNull() { // add a server connection - NetworkServer.connections[12] = new NetworkConnectionToClient(12) { isReady = true }; + NetworkServer.connections[12] = new NetworkConnectionToClient(12, false, 0) { isReady = true }; // call RebuildObservers without calling OnStartServer first. // .observers will be null and it should simply return early. diff --git a/Assets/Mirror/Tests/Editor/NetworkMatchCheckerTest.cs b/Assets/Mirror/Tests/Editor/NetworkMatchCheckerTest.cs index 182d7ad5c..d3387a525 100644 --- a/Assets/Mirror/Tests/Editor/NetworkMatchCheckerTest.cs +++ b/Assets/Mirror/Tests/Editor/NetworkMatchCheckerTest.cs @@ -50,7 +50,7 @@ static Dictionary> GetMatchPlayersDictionary() static NetworkConnection CreateNetworkConnection(GameObject player) { - NetworkConnectionToClient connection = new NetworkConnectionToClient(++nextConnectionId); + NetworkConnectionToClient connection = new NetworkConnectionToClient(++nextConnectionId, false, 0); connection.identity = player.GetComponent(); connection.identity.connectionToClient = connection; connection.identity.observers = new Dictionary(); diff --git a/Assets/Mirror/Tests/Editor/NetworkServerTest.cs b/Assets/Mirror/Tests/Editor/NetworkServerTest.cs index c426d7bdd..aace3a2cd 100644 --- a/Assets/Mirror/Tests/Editor/NetworkServerTest.cs +++ b/Assets/Mirror/Tests/Editor/NetworkServerTest.cs @@ -324,7 +324,7 @@ public void AddConnectionTest() Assert.That(NetworkServer.connections.Count, Is.EqualTo(0)); // add first connection - NetworkConnectionToClient conn42 = new NetworkConnectionToClient(42); + NetworkConnectionToClient conn42 = new NetworkConnectionToClient(42, false, 0); bool result42 = NetworkServer.AddConnection(conn42); Assert.That(result42, Is.True); Assert.That(NetworkServer.connections.Count, Is.EqualTo(1)); @@ -332,7 +332,7 @@ public void AddConnectionTest() Assert.That(NetworkServer.connections[42], Is.EqualTo(conn42)); // add second connection - NetworkConnectionToClient conn43 = new NetworkConnectionToClient(43); + NetworkConnectionToClient conn43 = new NetworkConnectionToClient(43, false, 0); bool result43 = NetworkServer.AddConnection(conn43); Assert.That(result43, Is.True); Assert.That(NetworkServer.connections.Count, Is.EqualTo(2)); @@ -342,7 +342,7 @@ public void AddConnectionTest() Assert.That(NetworkServer.connections[43], Is.EqualTo(conn43)); // add duplicate connectionId - NetworkConnectionToClient connDup = new NetworkConnectionToClient(42); + NetworkConnectionToClient connDup = new NetworkConnectionToClient(42, false, 0); bool resultDup = NetworkServer.AddConnection(connDup); Assert.That(resultDup, Is.False); Assert.That(NetworkServer.connections.Count, Is.EqualTo(2)); @@ -365,7 +365,7 @@ public void RemoveConnectionTest() Assert.That(NetworkServer.connections.Count, Is.EqualTo(0)); // add connection - NetworkConnectionToClient conn42 = new NetworkConnectionToClient(42); + NetworkConnectionToClient conn42 = new NetworkConnectionToClient(42, false, 0); bool result42 = NetworkServer.AddConnection(conn42); Assert.That(result42, Is.True); Assert.That(NetworkServer.connections.Count, Is.EqualTo(1)); @@ -391,7 +391,7 @@ public void DisconnectAllConnectionsTest() Assert.That(NetworkServer.connections.Count, Is.EqualTo(0)); // add connection - NetworkConnectionToClient conn42 = new NetworkConnectionToClient(42); + NetworkConnectionToClient conn42 = new NetworkConnectionToClient(42, false, 0); NetworkServer.AddConnection(conn42); Assert.That(NetworkServer.connections.Count, Is.EqualTo(1)); @@ -418,7 +418,7 @@ public void DisconnectAllTest() Assert.That(NetworkServer.localConnection, Is.EqualTo(localConnection)); // add connection - NetworkConnectionToClient conn42 = new NetworkConnectionToClient(42); + NetworkConnectionToClient conn42 = new NetworkConnectionToClient(42, false, 0); NetworkServer.AddConnection(conn42); Assert.That(NetworkServer.connections.Count, Is.EqualTo(1)); @@ -452,7 +452,7 @@ public void OnDataReceivedTest() Assert.That(NetworkServer.connections.Count, Is.EqualTo(0)); // add a connection - NetworkConnectionToClient connection = new NetworkConnectionToClient(42); + NetworkConnectionToClient connection = new NetworkConnectionToClient(42, false, 0); NetworkServer.AddConnection(connection); Assert.That(NetworkServer.connections.Count, Is.EqualTo(1)); @@ -776,7 +776,7 @@ public void RegisterUnregisterClearHandlerTest() Assert.That(NetworkServer.connections.Count, Is.EqualTo(0)); // add a connection - NetworkConnectionToClient connection = new NetworkConnectionToClient(42); + NetworkConnectionToClient connection = new NetworkConnectionToClient(42, false, 0); NetworkServer.AddConnection(connection); Assert.That(NetworkServer.connections.Count, Is.EqualTo(1)); diff --git a/Assets/Mirror/Tests/Performance/Editor/FakeNetworkConnection.cs b/Assets/Mirror/Tests/Performance/Editor/FakeNetworkConnection.cs index 9a72b4ea8..14a6d274c 100644 --- a/Assets/Mirror/Tests/Performance/Editor/FakeNetworkConnection.cs +++ b/Assets/Mirror/Tests/Performance/Editor/FakeNetworkConnection.cs @@ -5,7 +5,7 @@ namespace Mirror.Tests.Performance { public class FakeNetworkConnection : NetworkConnectionToClient { - public FakeNetworkConnection(int networkConnectionId) : base(networkConnectionId) + public FakeNetworkConnection(int networkConnectionId) : base(networkConnectionId, false, 0) { } diff --git a/Assets/Mirror/Tests/Runtime/NetworkServerRuntimeTest.cs b/Assets/Mirror/Tests/Runtime/NetworkServerRuntimeTest.cs index f661e5df5..0eb63281c 100644 --- a/Assets/Mirror/Tests/Runtime/NetworkServerRuntimeTest.cs +++ b/Assets/Mirror/Tests/Runtime/NetworkServerRuntimeTest.cs @@ -36,7 +36,7 @@ public void TearDown() public IEnumerator DestroyPlayerForConnectionTest() { GameObject player = new GameObject("testPlayer", typeof(NetworkIdentity)); - NetworkConnectionToClient conn = new NetworkConnectionToClient(1); + NetworkConnectionToClient conn = new NetworkConnectionToClient(1, false, 0); NetworkServer.AddPlayerForConnection(conn, player); @@ -55,7 +55,7 @@ public IEnumerator DestroyPlayerForConnectionTest() public IEnumerator RemovePlayerForConnectionTest() { GameObject player = new GameObject("testPlayer", typeof(NetworkIdentity)); - NetworkConnectionToClient conn = new NetworkConnectionToClient(1); + NetworkConnectionToClient conn = new NetworkConnectionToClient(1, false, 0); NetworkServer.AddPlayerForConnection(conn, player); diff --git a/Assets/Mirror/Tests/Runtime/NetworkServerWithHostRuntimeTest.cs b/Assets/Mirror/Tests/Runtime/NetworkServerWithHostRuntimeTest.cs index e96706272..bd40556f7 100644 --- a/Assets/Mirror/Tests/Runtime/NetworkServerWithHostRuntimeTest.cs +++ b/Assets/Mirror/Tests/Runtime/NetworkServerWithHostRuntimeTest.cs @@ -55,7 +55,7 @@ public IEnumerator DisconnectTimeoutTest() GameObject remotePlayer = new GameObject("RemotePlayer", typeof(NetworkIdentity)); const int remoteConnectionId = 1; const int localConnectionId = 0; - NetworkConnectionToClient remoteConnection = new NetworkConnectionToClient(remoteConnectionId); + NetworkConnectionToClient remoteConnection = new NetworkConnectionToClient(remoteConnectionId, false, 0); NetworkServer.OnConnected(remoteConnection); NetworkServer.AddPlayerForConnection(remoteConnection, remotePlayer);