Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 6 additions & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).

## [Unreleased]

### Fixed

- Fixed ClientRpcs always reporting in the profiler view as going to all clients, even when limited to a subset of clients by ClientRpcParams. (#2144)

## [1.0.1] - 2022-08-23

### Changed
Expand Down
42 changes: 35 additions & 7 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,14 +235,42 @@ internal void __endSendClientRpc(ref FastBufferWriter bufferWriter, uint rpcMeth
#if DEVELOPMENT_BUILD || UNITY_EDITOR
if (NetworkManager.__rpc_name_table.TryGetValue(rpcMethodId, out var rpcMethodName))
{
foreach (var client in NetworkManager.ConnectedClients)
if (clientRpcParams.Send.TargetClientIds != null)
{
NetworkManager.NetworkMetrics.TrackRpcSent(
client.Key,
NetworkObject,
rpcMethodName,
__getTypeName(),
rpcWriteSize);
foreach (var targetClientId in clientRpcParams.Send.TargetClientIds)
{
NetworkManager.NetworkMetrics.TrackRpcSent(
targetClientId,
NetworkObject,
rpcMethodName,
__getTypeName(),
rpcWriteSize);
}
}
else if (clientRpcParams.Send.TargetClientIdsNativeArray != null)
{
foreach (var targetClientId in clientRpcParams.Send.TargetClientIdsNativeArray)
{
NetworkManager.NetworkMetrics.TrackRpcSent(
targetClientId,
NetworkObject,
rpcMethodName,
__getTypeName(),
rpcWriteSize);
}
}
else
{
var observerEnumerator = NetworkObject.Observers.GetEnumerator();
while (observerEnumerator.MoveNext())
{
NetworkManager.NetworkMetrics.TrackRpcSent(
observerEnumerator.Current,
NetworkObject,
rpcMethodName,
__getTypeName(),
rpcWriteSize);
}
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.

If the clientRpcParams.Send.TargetClientIdsNativeArray didn't cause Boxing allocation I would suggest using something like:

IEnumerable<ulong> enumerable;

if (clientRpcParams.Send.TargetClientIds != null)
{
    enumerable = clientRpcParams.Send.TargetClientIds;
}
else if (clientRpcParams.Send.TargetClientIdsNativeArray != null)
{
    enumerable = clientRpcParams.Send.TargetClientIdsNativeArray;
}
else
{
    enumerable = NetworkObject.Observers;
}

foreach (var networkObject in enumerable)
{
    NetworkManager.NetworkMetrics.TrackRpcSent(
        networkObject,
        NetworkObject,
        methodName,
        __getTypeName(),
        rpcWriteSize);
}

But in this case, it seems there's no other way to achieve the most efficient code without sacrificing a bit of readability.

So I believe your code is the best choice here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, that was my thought, too.

}
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public void MyServerRpc()
}

[ClientRpc]
public void MyClientRpc()
public void MyClientRpc(ClientRpcParams rpcParams = default)
{
OnClientRpcAction?.Invoke();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
using System.Collections;
using System.Linq;
using NUnit.Framework;
using Unity.Collections;
using Unity.Multiplayer.Tools.MetricTypes;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime.Metrics;

namespace Unity.Netcode.RuntimeTests.Metrics
{
internal class RpcMetricsTests : SingleClientMetricTestBase
internal class RpcMetricsTests : DualClientMetricTestBase
{
protected override void OnCreatePlayerPrefab()
{
Expand All @@ -17,30 +18,79 @@ protected override void OnCreatePlayerPrefab()
}

[UnityTest]
public IEnumerator TrackRpcSentMetricOnServer()
public IEnumerator TrackRpcSentMetricOnServerToOnlyOneClientWithArray()
{
var waitForMetricValues = new WaitForEventMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcSent);

m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc();
m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc(new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIds = new []{FirstClient.LocalClientId}
}
});

yield return waitForMetricValues.WaitForMetricsReceived();

var serverRpcSentValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
Assert.AreEqual(2, serverRpcSentValues.Count); // Server will receive this, since it's host
Assert.AreEqual(1, serverRpcSentValues.Count);

Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.Name == nameof(RpcTestComponent.MyClientRpc)));
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.NetworkBehaviourName == nameof(RpcTestComponent)));
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.BytesCount != 0));
Assert.AreEqual(FirstClient.LocalClientId, serverRpcSentValues.First().Connection.Id);
}

[UnityTest]
public IEnumerator TrackRpcSentMetricOnServerToOnlyOneClientWithNativeArray()
{
var waitForMetricValues = new WaitForEventMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcSent);

m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc(new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIdsNativeArray = new NativeArray<ulong>(new []{FirstClient.LocalClientId}, Allocator.Temp)
}
});

yield return waitForMetricValues.WaitForMetricsReceived();

var serverRpcSentValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
Assert.AreEqual(1, serverRpcSentValues.Count);

Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.Name == nameof(RpcTestComponent.MyClientRpc)));
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.NetworkBehaviourName == nameof(RpcTestComponent)));
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.BytesCount != 0));
Assert.AreEqual(FirstClient.LocalClientId, serverRpcSentValues.First().Connection.Id);
}

[UnityTest]
public IEnumerator TrackRpcSentMetricOnServerToAllClients()
{
var waitForMetricValues = new WaitForEventMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcSent);

m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc();

yield return waitForMetricValues.WaitForMetricsReceived();

var serverRpcSentValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
Assert.AreEqual(3, serverRpcSentValues.Count); // Server will receive this, since it's host

Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.Name == nameof(RpcTestComponent.MyClientRpc)));
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.NetworkBehaviourName == nameof(RpcTestComponent)));
Assert.That(serverRpcSentValues, Has.All.Matches<RpcEvent>(x => x.BytesCount != 0));
Assert.Contains(Server.LocalClientId, serverRpcSentValues.Select(x => x.Connection.Id).ToArray());
Assert.Contains(Client.LocalClientId, serverRpcSentValues.Select(x => x.Connection.Id).ToArray());
Assert.Contains(FirstClient.LocalClientId, serverRpcSentValues.Select(x => x.Connection.Id).ToArray());
Assert.Contains(SecondClient.LocalClientId, serverRpcSentValues.Select(x => x.Connection.Id).ToArray());
}

[UnityTest]
public IEnumerator TrackRpcSentMetricOnClient()
{
var waitForClientMetricsValues = new WaitForEventMetricValues<RpcEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.RpcSent);
var waitForClientMetricsValues = new WaitForEventMetricValues<RpcEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.RpcSent);

m_PlayerNetworkObjects[Client.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyServerRpc();
m_PlayerNetworkObjects[FirstClient.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyServerRpc();

yield return waitForClientMetricsValues.WaitForMetricsReceived();

Expand All @@ -58,15 +108,15 @@ public IEnumerator TrackRpcSentMetricOnClient()
public IEnumerator TrackRpcReceivedMetricOnServer()
{
var waitForServerMetricsValues = new WaitForEventMetricValues<RpcEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.RpcReceived);
m_PlayerNetworkObjects[Client.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyServerRpc();
m_PlayerNetworkObjects[FirstClient.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyServerRpc();

yield return waitForServerMetricsValues.WaitForMetricsReceived();

var serverRpcReceivedValues = waitForServerMetricsValues.AssertMetricValuesHaveBeenFound();
Assert.AreEqual(1, serverRpcReceivedValues.Count);

var rpcReceived = serverRpcReceivedValues.First();
Assert.AreEqual(Client.LocalClientId, rpcReceived.Connection.Id);
Assert.AreEqual(FirstClient.LocalClientId, rpcReceived.Connection.Id);
Assert.AreEqual(nameof(RpcTestComponent.MyServerRpc), rpcReceived.Name);
Assert.AreEqual(nameof(RpcTestComponent), rpcReceived.NetworkBehaviourName);
Assert.AreNotEqual(0, rpcReceived.BytesCount);
Expand All @@ -75,9 +125,9 @@ public IEnumerator TrackRpcReceivedMetricOnServer()
[UnityTest]
public IEnumerator TrackRpcReceivedMetricOnClient()
{
var waitForClientMetricsValues = new WaitForEventMetricValues<RpcEvent>(ClientMetrics.Dispatcher, NetworkMetricTypes.RpcReceived);
var waitForClientMetricsValues = new WaitForEventMetricValues<RpcEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.RpcReceived);

m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][Client.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc();
m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][FirstClient.LocalClientId].GetComponent<RpcTestComponent>().MyClientRpc();

yield return waitForClientMetricsValues.WaitForMetricsReceived();

Expand Down