Skip to content

Commit 7970113

Browse files
feat: hybrid and NGO spawn counts in editor analytics (#4205)
* feat: count NGO and hybrid spawns per session in editor analytics NetworkSpawnManager counts local spawns (editor only) and the hybrid ones among them. NetcodeAnalytics reads both when the session stops and adds NgoSpawnCount and HybridSpawnCount to the NGO_NetworkManager event. * feat: report whether the session was hybrid in editor analytics HybridSession is true when the session started with hybrid prefabs registered, so a hybrid session that spawned no hybrid instances is still identifiable. * fix: guard the unified cases in SpawnCountAnalyticsTests --------- Co-authored-by: Unity Netcode CI <74025435+netcode-ci-service@users.noreply.github.com>
1 parent 5313d3f commit 7970113

5 files changed

Lines changed: 135 additions & 0 deletions

File tree

‎com.unity.netcode.gameobjects/Editor/Analytics/NetcodeAnalytics.cs‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ internal struct NetworkSessionInfo
1818
public bool UsedCMBService;
1919
public string Transport;
2020
public NetworkConfig NetworkConfig;
21+
public bool HybridSession;
22+
public int NgoSpawnCount;
23+
public int HybridSpawnCount;
2124
}
2225

2326
/// <summary>
@@ -123,7 +126,16 @@ internal override void SessionStopped(NetworkManager networkManager)
123126
{
124127
return;
125128
}
129+
#if UNIFIED_NETCODE
130+
recentSession.HybridSession = networkManager.NetworkConfig.Prefabs.HasGhostPrefabs;
131+
#endif
126132
recentSession.UsedCMBService = networkManager.CMBServiceConnection;
133+
var spawnManager = networkManager.SpawnManager;
134+
if (spawnManager != null)
135+
{
136+
recentSession.HybridSpawnCount = spawnManager.HybridSpawnCount;
137+
recentSession.NgoSpawnCount = spawnManager.SpawnCount - spawnManager.HybridSpawnCount;
138+
}
127139
recentSession.SessionStopped = true;
128140
RecentSessions[lastIndex] = recentSession;
129141
}
@@ -220,6 +232,9 @@ private NetworkManagerAnalytics GetNetworkManagerAnalytics(NetworkSessionInfo ne
220232
NetworkTransport = networkSession.Transport,
221233
EnableSceneManagement = networkSession.NetworkConfig.EnableSceneManagement,
222234
TickRate = (int)networkSession.NetworkConfig.TickRate,
235+
HybridSession = networkSession.HybridSession,
236+
NgoSpawnCount = networkSession.NgoSpawnCount,
237+
HybridSpawnCount = networkSession.HybridSpawnCount,
223238
};
224239
return networkManagerAnalytics;
225240
}

‎com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalytics.cs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ internal struct NetworkManagerAnalytics : IAnalytic.IData, IEquatable<NetworkMan
1717
public string NetworkTransport;
1818
public bool EnableSceneManagement;
1919
public int TickRate;
20+
public bool HybridSession;
21+
public int NgoSpawnCount;
22+
public int HybridSpawnCount;
2023
public override string ToString()
2124
{
2225
var message = new StringBuilder();
@@ -28,6 +31,9 @@ public override string ToString()
2831
message.AppendLine($"{nameof(NetworkTransport)}: {NetworkTransport}");
2932
message.AppendLine($"{nameof(EnableSceneManagement)}: {EnableSceneManagement}");
3033
message.AppendLine($"{nameof(TickRate)}: {TickRate}");
34+
message.AppendLine($"{nameof(HybridSession)}: {HybridSession}");
35+
message.AppendLine($"{nameof(NgoSpawnCount)}: {NgoSpawnCount}");
36+
message.AppendLine($"{nameof(HybridSpawnCount)}: {HybridSpawnCount}");
3137
return message.ToString();
3238
}
3339

@@ -40,6 +46,7 @@ public bool Equals(NetworkManagerAnalytics other)
4046
return IsDistributedAuthority == other.IsDistributedAuthority && WasServer == other.WasServer && WasClient == other.WasClient
4147
&& UsedCMBService == other.UsedCMBService && IsUsingMultiplayerSDK == other.IsUsingMultiplayerSDK
4248
&& EnableSceneManagement == other.EnableSceneManagement && TickRate == other.TickRate
49+
&& NgoSpawnCount == other.NgoSpawnCount && HybridSpawnCount == other.HybridSpawnCount && HybridSession == other.HybridSession
4350
&& NetworkTransport.Equals(other.NetworkTransport);
4451
}
4552
}

‎com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ public class NetworkSpawnManager
3838
/// </summary>
3939
public readonly HashSet<NetworkObject> SpawnedObjectsList = new HashSet<NetworkObject>();
4040

41+
#if UNITY_EDITOR
42+
// Spawns this peer made or received during the session, reported by the editor analytics.
43+
internal int SpawnCount;
44+
internal int HybridSpawnCount;
45+
#endif
46+
4147
/// <summary>
4248
/// Use to get all NetworkObjects owned by a client
4349
/// Ownership to Objects Table Format:
@@ -1366,11 +1372,17 @@ internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong
13661372
if (networkObject.HasGhost)
13671373
{
13681374
networkObject.NetworkObjectBridge.UpdateGhostOwner(NetworkManager, ownerClientId);
1375+
#if UNITY_EDITOR
1376+
HybridSpawnCount++;
1377+
#endif
13691378
}
13701379
#endif
13711380

13721381
SpawnedObjects.Add(networkObject.NetworkObjectId, networkObject);
13731382
SpawnedObjectsList.Add(networkObject);
1383+
#if UNITY_EDITOR
1384+
SpawnCount++;
1385+
#endif
13741386
networkObject.ApplyNetworkParenting();
13751387

13761388
NetworkObject.CheckOrphanChildren();
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#if UNITY_EDITOR
2+
using System.Collections;
3+
using NUnit.Framework;
4+
using Unity.Netcode.TestHelpers.Runtime;
5+
using UnityEngine;
6+
using UnityEngine.TestTools;
7+
8+
namespace Unity.Netcode.RuntimeTests
9+
{
10+
/// <summary>
11+
/// Validates the spawn counts the editor analytics reads from <see cref="NetworkSpawnManager"/>:<br />
12+
/// - Every peer counts each instance it spawns locally, whether it is the authority or received the spawn.<br />
13+
/// - Hybrid instances are also counted on their own.<br />
14+
/// </summary>
15+
[TestFixture(HostOrServer.Host)]
16+
#if UNIFIED_NETCODE
17+
[TestFixture(HostOrServer.UnifiedHost)]
18+
#endif
19+
internal class SpawnCountAnalyticsTests : NetcodeIntegrationTest
20+
{
21+
private const int k_DefaultInstances = 3;
22+
private const int k_NgoInstances = 2;
23+
24+
protected override int NumberOfClients => 2;
25+
26+
// Hybrid during a unified test pass.
27+
private GameObject m_DefaultPrefab;
28+
private GameObject m_NgoPrefab;
29+
30+
public SpawnCountAnalyticsTests(HostOrServer hostOrServer) : base(hostOrServer)
31+
{
32+
}
33+
34+
#if UNIFIED_NETCODE
35+
protected override bool UseUnifiedTests()
36+
{
37+
return true;
38+
}
39+
#endif
40+
41+
protected override void OnServerAndClientsCreated()
42+
{
43+
m_DefaultPrefab = CreateNetworkObjectPrefab("SpawnCountDefault");
44+
#if UNIFIED_NETCODE
45+
m_NgoPrefab = CreateNetworkObjectPrefab("SpawnCountNgo", false);
46+
#else
47+
m_NgoPrefab = CreateNetworkObjectPrefab("SpawnCountNgo");
48+
#endif
49+
base.OnServerAndClientsCreated();
50+
}
51+
52+
[UnityTest]
53+
public IEnumerator SpawnsAreCountedOnEveryPeer()
54+
{
55+
// Player objects are already spawned, so only the increase is checked.
56+
var spawnCounts = new int[m_NetworkManagers.Length];
57+
var hybridSpawnCounts = new int[m_NetworkManagers.Length];
58+
for (int i = 0; i < m_NetworkManagers.Length; i++)
59+
{
60+
spawnCounts[i] = m_NetworkManagers[i].SpawnManager.SpawnCount;
61+
hybridSpawnCounts[i] = m_NetworkManagers[i].SpawnManager.HybridSpawnCount;
62+
}
63+
64+
var authority = GetAuthorityNetworkManager();
65+
var instances = SpawnObjects(m_DefaultPrefab, authority, k_DefaultInstances);
66+
instances.AddRange(SpawnObjects(m_NgoPrefab, authority, k_NgoInstances));
67+
foreach (var instance in instances)
68+
{
69+
yield return WaitForSpawnedOnAllOrTimeOut(instance.GetComponent<NetworkObject>());
70+
AssertOnTimeout($"Failed to spawn {instance.name} on all clients!");
71+
}
72+
73+
var expectedHybridSpawns = 0;
74+
#if UNIFIED_NETCODE
75+
if (m_UseUnifiedTests)
76+
{
77+
expectedHybridSpawns = k_DefaultInstances;
78+
}
79+
#endif
80+
for (int i = 0; i < m_NetworkManagers.Length; i++)
81+
{
82+
var spawnManager = m_NetworkManagers[i].SpawnManager;
83+
var clientId = m_NetworkManagers[i].LocalClientId;
84+
Assert.AreEqual(k_DefaultInstances + k_NgoInstances, spawnManager.SpawnCount - spawnCounts[i], $"Client-{clientId} counted the wrong number of spawns!");
85+
Assert.AreEqual(expectedHybridSpawns, spawnManager.HybridSpawnCount - hybridSpawnCounts[i], $"Client-{clientId} counted the wrong number of hybrid spawns!");
86+
}
87+
}
88+
}
89+
}
90+
#endif

‎com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/SpawnCountAnalyticsTests.cs.meta‎

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)