diff --git a/com.unity.netcode.gameobjects/Editor/Analytics/NetcodeAnalytics.cs b/com.unity.netcode.gameobjects/Editor/Analytics/NetcodeAnalytics.cs index b1c4e69698..cf29198f89 100644 --- a/com.unity.netcode.gameobjects/Editor/Analytics/NetcodeAnalytics.cs +++ b/com.unity.netcode.gameobjects/Editor/Analytics/NetcodeAnalytics.cs @@ -18,6 +18,9 @@ internal struct NetworkSessionInfo public bool UsedCMBService; public string Transport; public NetworkConfig NetworkConfig; + public bool HybridSession; + public int NgoSpawnCount; + public int HybridSpawnCount; } /// @@ -123,7 +126,16 @@ internal override void SessionStopped(NetworkManager networkManager) { return; } +#if UNIFIED_NETCODE + recentSession.HybridSession = networkManager.NetworkConfig.Prefabs.HasGhostPrefabs; +#endif recentSession.UsedCMBService = networkManager.CMBServiceConnection; + var spawnManager = networkManager.SpawnManager; + if (spawnManager != null) + { + recentSession.HybridSpawnCount = spawnManager.HybridSpawnCount; + recentSession.NgoSpawnCount = spawnManager.SpawnCount - spawnManager.HybridSpawnCount; + } recentSession.SessionStopped = true; RecentSessions[lastIndex] = recentSession; } @@ -220,6 +232,9 @@ private NetworkManagerAnalytics GetNetworkManagerAnalytics(NetworkSessionInfo ne NetworkTransport = networkSession.Transport, EnableSceneManagement = networkSession.NetworkConfig.EnableSceneManagement, TickRate = (int)networkSession.NetworkConfig.TickRate, + HybridSession = networkSession.HybridSession, + NgoSpawnCount = networkSession.NgoSpawnCount, + HybridSpawnCount = networkSession.HybridSpawnCount, }; return networkManagerAnalytics; } diff --git a/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalytics.cs b/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalytics.cs index cd1ca3b1de..df2887c758 100644 --- a/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalytics.cs +++ b/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalytics.cs @@ -17,6 +17,9 @@ internal struct NetworkManagerAnalytics : IAnalytic.IData, IEquatable public readonly HashSet SpawnedObjectsList = new HashSet(); +#if UNITY_EDITOR + // Spawns this peer made or received during the session, reported by the editor analytics. + internal int SpawnCount; + internal int HybridSpawnCount; +#endif + /// /// Use to get all NetworkObjects owned by a client /// Ownership to Objects Table Format: @@ -1313,11 +1319,17 @@ internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong if (networkObject.HasGhost) { networkObject.NetworkObjectBridge.UpdateGhostOwner(NetworkManager, ownerClientId); +#if UNITY_EDITOR + HybridSpawnCount++; +#endif } #endif SpawnedObjects.Add(networkObject.NetworkObjectId, networkObject); SpawnedObjectsList.Add(networkObject); +#if UNITY_EDITOR + SpawnCount++; +#endif networkObject.ApplyNetworkParenting(); NetworkObject.CheckOrphanChildren(); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/SpawnCountAnalyticsTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/SpawnCountAnalyticsTests.cs new file mode 100644 index 0000000000..8a04d4a585 --- /dev/null +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/SpawnCountAnalyticsTests.cs @@ -0,0 +1,90 @@ +#if UNITY_EDITOR +using System.Collections; +using NUnit.Framework; +using Unity.Netcode.TestHelpers.Runtime; +using UnityEngine; +using UnityEngine.TestTools; + +namespace Unity.Netcode.RuntimeTests +{ + /// + /// Validates the spawn counts the editor analytics reads from :
+ /// - Every peer counts each instance it spawns locally, whether it is the authority or received the spawn.
+ /// - Hybrid instances are also counted on their own.
+ ///
+ [TestFixture(HostOrServer.Host)] +#if UNIFIED_NETCODE + [TestFixture(HostOrServer.UnifiedHost)] +#endif + internal class SpawnCountAnalyticsTests : NetcodeIntegrationTest + { + private const int k_DefaultInstances = 3; + private const int k_NgoInstances = 2; + + protected override int NumberOfClients => 2; + + // Hybrid during a unified test pass. + private GameObject m_DefaultPrefab; + private GameObject m_NgoPrefab; + + public SpawnCountAnalyticsTests(HostOrServer hostOrServer) : base(hostOrServer) + { + } + +#if UNIFIED_NETCODE + protected override bool UseUnifiedTests() + { + return true; + } +#endif + + protected override void OnServerAndClientsCreated() + { + m_DefaultPrefab = CreateNetworkObjectPrefab("SpawnCountDefault"); +#if UNIFIED_NETCODE + m_NgoPrefab = CreateNetworkObjectPrefab("SpawnCountNgo", false); +#else + m_NgoPrefab = CreateNetworkObjectPrefab("SpawnCountNgo"); +#endif + base.OnServerAndClientsCreated(); + } + + [UnityTest] + public IEnumerator SpawnsAreCountedOnEveryPeer() + { + // Player objects are already spawned, so only the increase is checked. + var spawnCounts = new int[m_NetworkManagers.Length]; + var hybridSpawnCounts = new int[m_NetworkManagers.Length]; + for (int i = 0; i < m_NetworkManagers.Length; i++) + { + spawnCounts[i] = m_NetworkManagers[i].SpawnManager.SpawnCount; + hybridSpawnCounts[i] = m_NetworkManagers[i].SpawnManager.HybridSpawnCount; + } + + var authority = GetAuthorityNetworkManager(); + var instances = SpawnObjects(m_DefaultPrefab, authority, k_DefaultInstances); + instances.AddRange(SpawnObjects(m_NgoPrefab, authority, k_NgoInstances)); + foreach (var instance in instances) + { + yield return WaitForSpawnedOnAllOrTimeOut(instance.GetComponent()); + AssertOnTimeout($"Failed to spawn {instance.name} on all clients!"); + } + + var expectedHybridSpawns = 0; +#if UNIFIED_NETCODE + if (m_UseUnifiedTests) + { + expectedHybridSpawns = k_DefaultInstances; + } +#endif + for (int i = 0; i < m_NetworkManagers.Length; i++) + { + var spawnManager = m_NetworkManagers[i].SpawnManager; + var clientId = m_NetworkManagers[i].LocalClientId; + Assert.AreEqual(k_DefaultInstances + k_NgoInstances, spawnManager.SpawnCount - spawnCounts[i], $"Client-{clientId} counted the wrong number of spawns!"); + Assert.AreEqual(expectedHybridSpawns, spawnManager.HybridSpawnCount - hybridSpawnCounts[i], $"Client-{clientId} counted the wrong number of hybrid spawns!"); + } + } + } +} +#endif diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/SpawnCountAnalyticsTests.cs.meta b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/SpawnCountAnalyticsTests.cs.meta new file mode 100644 index 0000000000..2dcbf0e25a --- /dev/null +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/SpawnCountAnalyticsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 69dc919eea8f49b6801cbb8b868f9237 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: