mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
perf: Batching (#2552)
* perf: Batching. Batches message into Transport.GetMaxPacketSize sized chunks and sends them every batchInterval * don't log time * Transport.GetMaxBatchSize and kcp override it to always use MTU * remove comment * NetworkConnectionToClient tests * Test: Send_BatchesUntilUpdate * Test: Send_BatchesUntilInterval * fix: initialize last send time with NetworkTime.time * better comment * fixing reset after sending batch Need to reset both position and length * revert the transportreceive change for localconnections. before it didn't work because of the length bug that is fixed now. * added test to avoid length bug in the future * optional * enable batching in benchmark demo for max scale Co-authored-by: James Frowen <jamesfrowendev@gmail.com>
This commit is contained in:
parent
d870351afb
commit
1ff4fe30b7
@ -293,6 +293,8 @@ MonoBehaviour:
|
||||
autoStartServerBuild: 1
|
||||
showDebugMessages: 0
|
||||
serverTickRate: 30
|
||||
serverBatching: 1
|
||||
serverBatchInterval: 0
|
||||
offlineScene:
|
||||
onlineScene:
|
||||
transport: {fileID: 1282001521}
|
||||
|
@ -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";
|
||||
|
||||
|
@ -222,7 +222,7 @@ public bool InvokeHandler<T>(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.
|
||||
/// <summary>
|
||||
/// This function allows custom network connection classes to process data from the network before it is passed to the application.
|
||||
/// </summary>
|
||||
@ -266,7 +263,13 @@ internal void TransportReceive(ArraySegment<byte> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<channelId, batch> 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<int, Batch> batches = new Dictionary<int, Batch>();
|
||||
|
||||
// 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<byte> 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<int, Batch> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// The scene to switch to when offline.
|
||||
/// <para>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.</para>
|
||||
@ -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;
|
||||
|
@ -57,6 +57,25 @@ public static class NetworkServer
|
||||
/// </summary>
|
||||
public static bool active { get; internal set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
public static bool batching;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public static float batchInterval = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Should the server disconnect remote connections that have gone silent for more than Server Idle Timeout?
|
||||
/// <para>This value is initially set from NetworkManager in SetupServer and can be changed at runtime</para>
|
||||
@ -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
|
||||
|
@ -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";
|
||||
|
@ -8,7 +8,7 @@ namespace Mirror
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <h2>
|
||||
/// Transport Rules
|
||||
/// Transport Rules
|
||||
/// </h2>
|
||||
/// <list type="bullet">
|
||||
/// <listheader><description>
|
||||
@ -206,6 +206,18 @@ public virtual void ClientConnect(Uri uri)
|
||||
/// <returns>the size in bytes that can be sent via the provided channel</returns>
|
||||
public abstract int GetMaxPacketSize(int channelId = Channels.DefaultReliable);
|
||||
|
||||
/// <summary>
|
||||
/// 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.).
|
||||
/// </summary>
|
||||
/// <param name="channelId">channel id</param>
|
||||
/// <returns>the size in bytes that should be batched via the provided channel</returns>
|
||||
public virtual int GetMaxBatchSize(int channelId) =>
|
||||
GetMaxPacketSize(channelId);
|
||||
|
||||
/// <summary>
|
||||
/// Shut down the transport, both as client and server
|
||||
/// </summary>
|
||||
|
@ -4,7 +4,7 @@ namespace Mirror.Tests
|
||||
{
|
||||
public class FakeNetworkConnection : NetworkConnectionToClient
|
||||
{
|
||||
public FakeNetworkConnection() : base(1)
|
||||
public FakeNetworkConnection() : base(1, false, 0)
|
||||
{
|
||||
}
|
||||
|
||||
|
132
Assets/Mirror/Tests/Editor/NetworkConnectionToClientTests.cs
Normal file
132
Assets/Mirror/Tests/Editor/NetworkConnectionToClientTests.cs
Normal file
@ -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<byte[]> clientReceived = new List<byte[]>();
|
||||
|
||||
[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<MemoryTransport>();
|
||||
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<byte>(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<byte>(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<byte>(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<byte>(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<byte>(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));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22aee0cf91224ec9925f7faabc073b09
|
||||
timeCreated: 1611722538
|
@ -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<CheckObserverExceptionNetworkBehaviour>();
|
||||
|
||||
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<CheckObserverTrueNetworkBehaviour>();
|
||||
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<CheckObserverFalseNetworkBehaviour>();
|
||||
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<CommandTestNetworkBehaviour>();
|
||||
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<RebuildObserversNetworkBehaviour>();
|
||||
comp.observer = new NetworkConnectionToClient(12);
|
||||
comp.observer = new NetworkConnectionToClient(12, false, 0);
|
||||
|
||||
// get new observers
|
||||
HashSet<NetworkConnection> observers = new HashSet<NetworkConnection>();
|
||||
@ -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<NetworkConnection> observers = new HashSet<NetworkConnection>();
|
||||
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<RebuildObserversNetworkBehaviour>();
|
||||
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<RebuildObserversNetworkBehaviour>();
|
||||
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<RebuildObserversNetworkBehaviour>();
|
||||
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.
|
||||
|
@ -50,7 +50,7 @@ static Dictionary<Guid, HashSet<NetworkIdentity>> GetMatchPlayersDictionary()
|
||||
|
||||
static NetworkConnection CreateNetworkConnection(GameObject player)
|
||||
{
|
||||
NetworkConnectionToClient connection = new NetworkConnectionToClient(++nextConnectionId);
|
||||
NetworkConnectionToClient connection = new NetworkConnectionToClient(++nextConnectionId, false, 0);
|
||||
connection.identity = player.GetComponent<NetworkIdentity>();
|
||||
connection.identity.connectionToClient = connection;
|
||||
connection.identity.observers = new Dictionary<int, NetworkConnection>();
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user