Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions com.unity.multiplayer.mlapi/Runtime/Core/NetworkBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,19 @@ internal void __endSendServerRpc(NetworkSerializer serializer, uint rpcMethodId,
}

var rpcQueueContainer = NetworkManager.RpcQueueContainer;
var rpcMessageSize = 0L;
if (IsHost)
{
rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, RpcQueueHistoryFrame.QueueFrameType.Inbound, serverRpcParams.Send.UpdateStage);
rpcMessageSize = rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, RpcQueueHistoryFrame.QueueFrameType.Inbound, serverRpcParams.Send.UpdateStage);
}
else
{
rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, RpcQueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateStage.PostLateUpdate);
rpcMessageSize = rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, RpcQueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateStage.PostLateUpdate);
}

if (NetworkManager.__rpc_name_table.TryGetValue(rpcMethodId, out var rpcMethodName))
{
NetworkManager.NetworkMetrics.TrackRpcSent(NetworkManager.ServerClientId, NetworkObjectId, rpcMethodName, (ulong)rpcMessageSize);
}
}

Expand Down Expand Up @@ -183,7 +189,8 @@ internal void __endSendClientRpc(NetworkSerializer serializer, uint rpcMethodId,
}

var rpcQueueContainer = NetworkManager.RpcQueueContainer;

var messageSize = 0L;
string rpcMethodName;
if (IsHost)
{
ulong[] clientIds = clientRpcParams.Send.TargetClientIds ?? NetworkManager.ConnectedClientsList.Select(c => c.ClientId).ToArray();
Expand All @@ -195,12 +202,23 @@ internal void __endSendClientRpc(NetworkSerializer serializer, uint rpcMethodId,
var containsServerClientId = clientIds.Contains(NetworkManager.ServerClientId);
if (containsServerClientId && clientIds.Length == 1)
{
rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, RpcQueueHistoryFrame.QueueFrameType.Inbound, clientRpcParams.Send.UpdateStage);
messageSize = rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, RpcQueueHistoryFrame.QueueFrameType.Inbound, clientRpcParams.Send.UpdateStage);

if (NetworkManager.__rpc_name_table.TryGetValue(rpcMethodId, out rpcMethodName))
{
NetworkManager.NetworkMetrics.TrackRpcSent(clientIds, NetworkObjectId, rpcMethodName, (ulong)messageSize);
}

return;
}
}

rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, RpcQueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateStage.PostLateUpdate);
messageSize = rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, RpcQueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateStage.PostLateUpdate);

if (NetworkManager.__rpc_name_table.TryGetValue(rpcMethodId, out rpcMethodName))
{
NetworkManager.NetworkMetrics.TrackRpcSent(NetworkManager.ServerClientId, NetworkObjectId, rpcMethodName, (ulong)messageSize);
}
}

/// <summary>
Expand Down
5 changes: 5 additions & 0 deletions com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,11 @@ internal void InvokeRpc(RpcFrameQueueItem queueItem)
}

__rpc_func_table[networkRpcMethodId](networkBehaviour, new NetworkSerializer(queueItem.NetworkReader), rpcParams);

if (__rpc_name_table.TryGetValue(networkRpcMethodId, out var rpcMethodName))
{
NetworkMetrics.TrackRpcReceived(queueItem.NetworkId, networkObjectId, rpcMethodName, (ulong)queueItem.MessageData.Count);
}
}

#if DEVELOPMENT_BUILD || UNITY_EDITOR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ public PooledNetworkWriter BeginAddQueueItemToFrame(QueueItemType qItemType, flo
/// <param name="writer">NetworkWriter that was used</param>
/// <param name="queueFrameType">type of the queue frame that was used</param>
/// <param name="updateStage">stage the RPC is going to be invoked</param>
public void EndAddQueueItemToFrame(NetworkWriter writer, RpcQueueHistoryFrame.QueueFrameType queueFrameType, NetworkUpdateStage updateStage)
public long EndAddQueueItemToFrame(NetworkWriter writer, RpcQueueHistoryFrame.QueueFrameType queueFrameType, NetworkUpdateStage updateStage)
{
bool getNextFrame = NetworkManager.IsHost && queueFrameType == RpcQueueHistoryFrame.QueueFrameType.Inbound;

Expand Down Expand Up @@ -525,6 +525,8 @@ public void EndAddQueueItemToFrame(NetworkWriter writer, RpcQueueHistoryFrame.Qu

//Add the packed size to the offsets for parsing over various entries
rpcQueueHistoryItem.QueueItemOffsets.Add((uint)rpcQueueHistoryItem.QueueBuffer.Position);

return messageSize;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ public interface INetworkMetrics

void TrackObjectDestroyReceived(ulong senderClientId, ulong networkObjectId, string gameObjectName, ulong bytesCount);

void TrackRpcSent(ulong receiverClientId, ulong networkObjectId, string rpcName, ulong bytesCount);

void TrackRpcSent(ulong[] receiverClientIds, ulong networkObjectId, string rpcName, ulong bytesCount);

void TrackRpcReceived(ulong senderClientId, ulong networkObjectId, string rpcName, ulong bytesCount);

void DispatchFrame();
}
}
32 changes: 32 additions & 0 deletions com.unity.multiplayer.mlapi/Runtime/Metrics/NetworkMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public class NetworkMetrics : INetworkMetrics
private readonly EventMetric<ObjectDestroyedEvent> m_ObjectDestroySentEvent = new EventMetric<ObjectDestroyedEvent>(MetricNames.ObjectDestroyedSent);
private readonly EventMetric<ObjectDestroyedEvent> m_ObjectDestroyReceivedEvent = new EventMetric<ObjectDestroyedEvent>(MetricNames.ObjectDestroyedReceived);

readonly EventMetric<RpcEvent> m_RpcSentEvent = new EventMetric<RpcEvent>(MetricNames.RpcSent);
readonly EventMetric<RpcEvent> m_RpcReceivedEvent = new EventMetric<RpcEvent>(MetricNames.RpcReceived);

private Dictionary<ulong, NetworkObjectIdentifier> m_NetworkGameObjects = new Dictionary<ulong, NetworkObjectIdentifier>();

public NetworkMetrics(NetworkManager networkManager)
Expand All @@ -36,6 +39,7 @@ public NetworkMetrics(NetworkManager networkManager)
.WithMetricEvents(m_NetworkVariableDeltaSentEvent, m_NetworkVariableDeltaReceivedEvent)
.WithMetricEvents(m_ObjectSpawnSentEvent, m_ObjectSpawnReceivedEvent)
.WithMetricEvents(m_ObjectDestroySentEvent, m_ObjectDestroyReceivedEvent)
.WithMetricEvents(m_RpcSentEvent, m_RpcReceivedEvent)
.Build();

Dispatcher.RegisterObserver(MLAPIObserver.Observer);
Expand Down Expand Up @@ -128,6 +132,34 @@ public void TrackObjectDestroyReceived(ulong senderClientId, ulong networkObject
m_ObjectDestroyReceivedEvent.Mark(new ObjectDestroyedEvent(new ConnectionInfo(senderClientId), new NetworkObjectIdentifier(gameObjectName, networkObjectId), bytesCount));
}

public void TrackRpcSent(ulong receiverClientId, ulong networkObjectId, string rpcName, ulong bytesCount)
{
if (!m_NetworkGameObjects.TryGetValue(networkObjectId, out var networkObjectIdentifier))
{
networkObjectIdentifier = new NetworkObjectIdentifier("", networkObjectId);
}

m_RpcSentEvent.Mark(new RpcEvent(new ConnectionInfo(receiverClientId), networkObjectIdentifier, rpcName, bytesCount));
}

public void TrackRpcSent(ulong[] receiverClientIds, ulong networkObjectId, string rpcName, ulong bytesCount)
{
foreach (var receiverClientId in receiverClientIds)
{
TrackRpcSent(receiverClientId, networkObjectId, rpcName, bytesCount);
}
}

public void TrackRpcReceived(ulong senderClientId, ulong networkObjectId, string rpcName, ulong bytesCount)
{
if (!m_NetworkGameObjects.TryGetValue(networkObjectId, out var networkObjectIdentifier))
{
networkObjectIdentifier = new NetworkObjectIdentifier("", networkObjectId);
}

m_RpcReceivedEvent.Mark(new RpcEvent(new ConnectionInfo(senderClientId), networkObjectIdentifier, rpcName, bytesCount));
}

public void DispatchFrame()
{
Dispatcher.Dispatch();
Expand Down
12 changes: 12 additions & 0 deletions com.unity.multiplayer.mlapi/Runtime/Metrics/NullNetworkMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ public void TrackObjectDestroyReceived(ulong senderClientId, ulong networkObject
{
}

public void TrackRpcSent(ulong receiverClientId, ulong networkObjectId, string rpcName, ulong bytesCount)
{
}

public void TrackRpcSent(ulong[] receiverClientIds, ulong networkObjectId, string rpcName, ulong bytesCount)
{
}

public void TrackRpcReceived(ulong senderClientId, ulong networkObjectId, string rpcName, ulong bytesCount)
{
}

public void DispatchFrame()
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public IEnumerator SetUp()
Debug.LogError("Failed to create instances");
Assert.Fail("Failed to create instances");
}

var playerPrefab = new GameObject("Player");
var networkObject = playerPrefab.AddComponent<NetworkObject>();
playerPrefab.AddComponent<NetworkVariableComponent>();
Expand Down
8 changes: 8 additions & 0 deletions com.unity.multiplayer.mlapi/Tests/Runtime/Metrics/RPC.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using MLAPI.Metrics;
using NUnit.Framework;
using Unity.Multiplayer.NetworkProfiler;
using Unity.Multiplayer.NetworkProfiler.Models;
using UnityEngine;
using UnityEngine.TestTools;

namespace MLAPI.RuntimeTests.Metrics.RPC
{
public class NetworkMetricsRpcTests
{
NetworkManager m_Server;
NetworkManager m_Client;
NetworkMetrics m_ClientMetrics;
NetworkMetrics m_ServerMetrics;

[UnitySetUp]
public IEnumerator SetUp()
{
if (!MultiInstanceHelpers.Create(1, out m_Server, out NetworkManager[] clients))
{
Assert.Fail("Failed to create instances");
}

var playerPrefab = new GameObject("Player");
NetworkObject networkObject = playerPrefab.AddComponent<NetworkObject>();
playerPrefab.AddComponent<RpcTestComponent>();

MultiInstanceHelpers.MakeNetworkedObjectTestPrefab(networkObject);

m_Server.NetworkConfig.PlayerPrefab = playerPrefab;
m_Client = clients.First();

m_Client.NetworkConfig.PlayerPrefab = playerPrefab;

if (!MultiInstanceHelpers.Start(true, m_Server, clients))
{
Assert.Fail("Failed to start instances");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same about logging here

}

yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients));
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientConnectedToServer(m_Server));

m_ClientMetrics = m_Client.NetworkMetrics as NetworkMetrics;
m_ServerMetrics = m_Server.NetworkMetrics as NetworkMetrics;
}

[TearDown]
public void TearDown()
{
MultiInstanceHelpers.Destroy();
}

[UnityTest]
public IEnumerator TrackServerRpcMetrics()
{
var waitForClientMetricsValues = new WaitForMetricValues<RpcEvent>(m_ClientMetrics.Dispatcher, MetricNames.RpcSent);
var waitForServerMetricsValues = new WaitForMetricValues<RpcEvent>(m_ServerMetrics.Dispatcher, MetricNames.RpcReceived);

var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_Client.LocalClientId), m_Server, serverClientPlayerResult));

var clientClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_Client.LocalClientId), m_Client, clientClientPlayerResult));

bool hasReceivedServerRpc = false;
serverClientPlayerResult.Result.GetComponent<RpcTestComponent>().OnServerRpcAction += () =>
{
hasReceivedServerRpc = true;
};

clientClientPlayerResult.Result.GetComponent<RpcTestComponent>().MyServerRpc();

yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => hasReceivedServerRpc));

// Client Check
yield return waitForClientMetricsValues.WaitForAFewFrames();

var clientMetricSentValues = waitForClientMetricsValues.EnsureMetricValuesHaveBeenFound();
Assert.AreEqual(1, clientMetricSentValues.Count);

var clientMetric = clientMetricSentValues.First();
Assert.AreEqual(m_Server.LocalClientId, clientMetric.Connection.Id);
Assert.AreEqual("MyServerRpc", clientMetric.Name);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, would recommend using nameof(RpcTestComponent.MyServerRpc)


// Server Check
yield return waitForServerMetricsValues.WaitForAFewFrames();

var serverMetricReceivedValues = waitForServerMetricsValues.EnsureMetricValuesHaveBeenFound();
Assert.AreEqual(1, serverMetricReceivedValues.Count);

var serverMetric = serverMetricReceivedValues.First();
Assert.AreEqual(m_Client.LocalClientId, serverMetric.Connection.Id);
Assert.AreEqual("MyServerRpc", serverMetric.Name);
}

[UnityTest]
public IEnumerator TrackClientRpcMetrics()
{
var waitForServerMetricsValues = new WaitForMetricValues<RpcEvent>(m_ServerMetrics.Dispatcher, MetricNames.RpcReceived);

var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_Client.LocalClientId), m_Server, serverClientPlayerResult));

var clientClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.GetNetworkObjectByRepresentation((x => x.IsPlayerObject && x.OwnerClientId == m_Client.LocalClientId), m_Client, clientClientPlayerResult));

bool hasReceivedClientRpcOnServer = false;
bool hasReceivedClientRpcRemotely = false;
serverClientPlayerResult.Result.GetComponent<RpcTestComponent>().OnClientRpcAction += () =>
{
hasReceivedClientRpcOnServer = true;
};
clientClientPlayerResult.Result.GetComponent<RpcTestComponent>().OnClientRpcAction += () =>
{
Debug.Log("ClientRpc received on client object");
hasReceivedClientRpcRemotely = true;
};

serverClientPlayerResult.Result.GetComponent<RpcTestComponent>().MyClientRpc();

yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => hasReceivedClientRpcOnServer && hasReceivedClientRpcRemotely));

yield return waitForServerMetricsValues.WaitForAFewFrames();

var serverMetricReceivedValues = waitForServerMetricsValues.EnsureMetricValuesHaveBeenFound();
Assert.AreEqual(1, serverMetricReceivedValues.Count);

var serverMetric = serverMetricReceivedValues.First();
Assert.AreEqual(m_Server.LocalClientId, serverMetric.Connection.Id);
Assert.AreEqual("MyClientRpc", serverMetric.Name);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using MLAPI.Messaging;

namespace MLAPI.RuntimeTests.Metrics.RPC
{
public class RpcTestComponent : NetworkBehaviour
{
public event Action OnServerRpcAction;
public event Action OnClientRpcAction;

[ServerRpc]
public void MyServerRpc()
{
OnServerRpcAction?.Invoke();
}

[ClientRpc]
public void MyClientRpc()
{
OnClientRpcAction?.Invoke();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion com.unity.multiplayer.mlapi/Tests/Runtime/RpcQueueTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public IEnumerator UpdateStagesInvocation()
}

/// <summary>
/// This tests the RPC Queue outbound and inbound buffer capabilities.
/// This tests the RPC Queue outbound and inbound buffer capabilities.
/// </summary>
/// <returns>IEnumerator</returns>
[UnityTest, Order(2)]
Expand Down