Skip to content

Commit 78160ae

Browse files
Josie MessaBenoit Doyon
andauthored
feat: Add metrics for multiple objects spawned and destroyed (i.e. NetworkShow/Hide) (#935)
Make use of existing network object spawn destroy metrics individually for each network object, so that sent metrics mirror the received metrics, and to avoid allocations. Co-authored-by: Benoit Doyon <benoit.doyon@unity3d.com>
1 parent c009c3a commit 78160ae

File tree

2 files changed

+83
-4
lines changed

2 files changed

+83
-4
lines changed

com.unity.multiplayer.mlapi/Runtime/Core/NetworkObject.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,23 +286,23 @@ public static void NetworkShow(List<NetworkObject> networkObjects, ulong clientI
286286
throw new ArgumentNullException("All " + nameof(NetworkObject) + "s must belong to the same " + nameof(NetworkManager));
287287
}
288288
}
289-
290289
using (var buffer = PooledNetworkBuffer.Get())
291290
using (var writer = PooledNetworkWriter.Get(buffer))
292291
{
293292
writer.WriteUInt16Packed((ushort)networkObjects.Count);
294-
293+
long prevLength = 0;
295294
for (int i = 0; i < networkObjects.Count; i++)
296295
{
297296
// Send spawn call
298297
networkObjects[i].Observers.Add(clientId);
299298

300299
networkManager.SpawnManager.WriteSpawnCallForObject(buffer, clientId, networkObjects[i], payload);
300+
networkManager.NetworkMetrics.TrackObjectSpawnSent(clientId, networkObjects[i].NetworkObjectId, networkObjects[i].name, (ulong)(buffer.Length - prevLength));
301+
prevLength = buffer.Length;
301302
}
302303

303304
networkManager.MessageSender.Send(clientId, NetworkConstants.ADD_OBJECTS, NetworkChannel.Internal, buffer);
304305
}
305-
// TODO: add metric for spawn objects here
306306
}
307307

308308
/// <summary>
@@ -392,17 +392,20 @@ public static void NetworkHide(List<NetworkObject> networkObjects, ulong clientI
392392
{
393393
writer.WriteUInt16Packed((ushort)networkObjects.Count);
394394

395+
long prevLength = 0;
396+
395397
for (int i = 0; i < networkObjects.Count; i++)
396398
{
397399
// Send destroy call
398400
networkObjects[i].Observers.Remove(clientId);
399401

400402
writer.WriteUInt64Packed(networkObjects[i].NetworkObjectId);
403+
networkManager.NetworkMetrics.TrackObjectDestroySent(clientId, networkObjects[i].NetworkObjectId, networkObjects[i].name, (ulong)(buffer.Length - prevLength));
404+
prevLength = buffer.Length;
401405
}
402406

403407
networkManager.MessageSender.Send(clientId, NetworkConstants.DESTROY_OBJECTS, NetworkChannel.Internal, buffer);
404408
}
405-
// TODO: add metric for destroy objects here
406409
}
407410

408411
private void OnDestroy()

com.unity.multiplayer.mlapi/Tests/Runtime/Metrics/NetworkObjects/NetworkObjectMetricsTests.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using MLAPI.Metrics;
45
using NUnit.Framework;
@@ -144,5 +145,80 @@ public IEnumerator TrackNetworkObjectDestroyReceivedMetric()
144145
// Bug: Currently the object name is always "Player Clone"
145146
// Assert.AreEqual(m_NewNetworkObjectName, objectDestroyed.NetworkId.Name);
146147
}
148+
149+
[UnityTest]
150+
public IEnumerator TrackMultipleNetworkObjectDestroySentMetric()
151+
{
152+
m_NewNetworkObject.Spawn();
153+
154+
// Spawn another network object so we can hide multiple.
155+
var gameObject = new GameObject(m_NewNetworkObjectName);
156+
var anotherNetworkObject = gameObject.AddComponent<NetworkObject>();
157+
anotherNetworkObject.NetworkManagerOwner = m_Server;
158+
anotherNetworkObject.Spawn();
159+
160+
var waitForMetricEvent = new WaitForMetricValues<ObjectDestroyedEvent>(m_ServerMetrics.Dispatcher, MetricNames.ObjectDestroyedSent);
161+
yield return waitForMetricEvent.WaitForAFewFrames();
162+
163+
NetworkObject.NetworkHide(new List<NetworkObject>{m_NewNetworkObject, anotherNetworkObject}, m_Client.LocalClientId);
164+
165+
yield return waitForMetricEvent.Wait(60);
166+
167+
var objectDestroyedSentMetricValues = waitForMetricEvent.EnsureMetricValuesHaveBeenFound();
168+
// As there's a client and server, this event is emitted twice.
169+
Assert.AreEqual(2, objectDestroyedSentMetricValues.Count);
170+
171+
var networkIDFound = true;
172+
var networkNameFound = true;
173+
// not sure that we can guarantee the order of these so just ensure the data is in the received metrics.
174+
foreach (var metricValue in objectDestroyedSentMetricValues)
175+
{
176+
Assert.AreEqual(m_Client.LocalClientId, metricValue.Connection.Id);
177+
networkIDFound &= metricValue.NetworkId.NetworkId == m_NewNetworkObject.NetworkObjectId || metricValue.NetworkId.NetworkId == anotherNetworkObject.NetworkObjectId;
178+
networkNameFound &= metricValue.NetworkId.Name == m_NewNetworkObject.name || metricValue.NetworkId.Name == anotherNetworkObject.name;
179+
}
180+
Assert.IsTrue(networkIDFound);
181+
Assert.IsTrue(networkNameFound);
182+
}
183+
184+
[UnityTest]
185+
public IEnumerator TrackMultipleNetworkObjectSpawnSentMetric()
186+
{
187+
m_NewNetworkObject.Spawn();
188+
189+
// Spawn another network object so we can hide multiple.
190+
var gameObject = new GameObject(m_NewNetworkObjectName);
191+
var anotherNetworkObject = gameObject.AddComponent<NetworkObject>();
192+
anotherNetworkObject.NetworkManagerOwner = m_Server;
193+
anotherNetworkObject.Spawn();
194+
195+
var waitForMetricEvent = new WaitForMetricValues<ObjectSpawnedEvent>(m_ServerMetrics.Dispatcher, MetricNames.ObjectSpawnedSent);
196+
yield return waitForMetricEvent.WaitForAFewFrames();
197+
198+
NetworkObject.NetworkHide(new List<NetworkObject>{m_NewNetworkObject, anotherNetworkObject}, m_Client.LocalClientId);
199+
200+
yield return waitForMetricEvent.WaitForAFewFrames();
201+
202+
NetworkObject.NetworkShow(new List<NetworkObject>{m_NewNetworkObject, anotherNetworkObject}, m_Client.LocalClientId);
203+
204+
yield return waitForMetricEvent.Wait(60);
205+
206+
var objectSpawnedSentMetricValues = waitForMetricEvent.EnsureMetricValuesHaveBeenFound();
207+
// As there's a client and server, this event is emitted twice.
208+
Assert.AreEqual(2, objectSpawnedSentMetricValues.Count);
209+
210+
var networkIDFound = true;
211+
var networkNameFound = true;
212+
// not sure that we can guarantee the order of these so just ensure the data is in the received metrics.
213+
foreach (var metricValue in objectSpawnedSentMetricValues)
214+
{
215+
Assert.AreEqual(m_Client.LocalClientId, metricValue.Connection.Id);
216+
networkIDFound &= metricValue.NetworkId.NetworkId == m_NewNetworkObject.NetworkObjectId || metricValue.NetworkId.NetworkId == anotherNetworkObject.NetworkObjectId;
217+
networkNameFound &= metricValue.NetworkId.Name == m_NewNetworkObject.name || metricValue.NetworkId.Name == anotherNetworkObject.name;
218+
}
219+
220+
Assert.IsTrue(networkIDFound);
221+
Assert.IsTrue(networkNameFound);
222+
}
147223
}
148224
}

0 commit comments

Comments
 (0)