Skip to content

Commit f0dab01

Browse files
committed
fix: Exception with disabled GameObjects and NetworkTransforms
1 parent b665499 commit f0dab01

File tree

3 files changed

+139
-3
lines changed

3 files changed

+139
-3
lines changed

com.unity.netcode.gameobjects/Runtime/Messaging/Messages/NetworkTransformMessage.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,21 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
7171
if (isSpawnedLocally)
7272
{
7373
networkObject = networkManager.SpawnManager.SpawnedObjects[networkObjectId];
74+
if (networkObject.ChildNetworkBehaviours.Count <= networkBehaviourId || networkObject.ChildNetworkBehaviours[networkBehaviourId] == null)
75+
{
76+
Debug.LogError($"[{nameof(NetworkTransformMessage)}][Invalid][length] Targeted {nameof(NetworkTransform)}, {nameof(NetworkBehaviour.NetworkBehaviourId)} ({networkBehaviourId}), does not exist! Make sure you are not spawning {nameof(NetworkObject)}s with disabled {nameof(GameObject)}s that have {nameof(NetworkBehaviour)} components on them.");
77+
return false;
78+
}
79+
7480
// Get the target NetworkTransform
75-
NetworkTransform = networkObject.ChildNetworkBehaviours[networkBehaviourId] as NetworkTransform;
81+
var transform = networkObject.ChildNetworkBehaviours[networkBehaviourId] as NetworkTransform;
82+
if (transform == null)
83+
{
84+
Debug.LogError($"[{nameof(NetworkTransformMessage)}][Invalid][cast] Targeted {nameof(NetworkTransform)}, {nameof(NetworkBehaviour.NetworkBehaviourId)} ({networkBehaviourId}), does not exist! Make sure you are not spawning {nameof(NetworkObject)}s with disabled {nameof(GameObject)}s that have {nameof(NetworkBehaviour)} components on them.");
85+
return false;
86+
}
87+
88+
NetworkTransform = transform;
7689
isServerAuthoritative = NetworkTransform.IsServerAuthoritative();
7790
ownerAuthoritativeServerSide = !isServerAuthoritative && networkManager.IsServer;
7891

@@ -81,8 +94,8 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
8194
}
8295
else
8396
{
84-
// Deserialize the state
85-
reader.ReadNetworkSerializableInPlace(ref State);
97+
Debug.LogError($"[{nameof(NetworkTransformMessage)}][Invalid] Target NetworkObject does not exist!");
98+
return false;
8699
}
87100

88101
unsafe
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System.Collections;
2+
using Unity.Netcode.Components;
3+
using Unity.Netcode.TestHelpers.Runtime;
4+
using UnityEngine;
5+
using UnityEngine.TestTools;
6+
7+
8+
namespace Unity.Netcode.RuntimeTests
9+
{
10+
internal class NetworkTransformErrorTests : NetcodeIntegrationTest
11+
{
12+
protected override int NumberOfClients => 1;
13+
14+
private GameObject m_ServerPrefab;
15+
private GameObject m_ClientPrefab;
16+
17+
private HostAndClientPrefabHandler m_HostAndClientPrefabHandler;
18+
19+
public class EmptyNetworkBehaviour : NetworkBehaviour { }
20+
21+
/// <summary>
22+
/// PrefabHandler that tracks and separates the client GameObject from the host GameObject.
23+
/// Allows independent management of client and host game world while still instantiating NetworkObjects as expected.
24+
/// </summary>
25+
private class HostAndClientPrefabHandler : INetworkPrefabInstanceHandler
26+
{
27+
private readonly GameObject m_HostPrefab;
28+
private readonly GameObject m_ClientPrefab;
29+
30+
public HostAndClientPrefabHandler(GameObject hostPrefab, GameObject clientPrefab)
31+
{
32+
m_HostPrefab = hostPrefab;
33+
m_ClientPrefab = clientPrefab;
34+
}
35+
36+
public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation)
37+
{
38+
// Owner clientID
39+
if (ownerClientId == 0)
40+
{
41+
return Object.Instantiate(m_ClientPrefab).GetComponent<NetworkObject>();
42+
}
43+
return Object.Instantiate(m_HostPrefab).GetComponent<NetworkObject>();
44+
}
45+
46+
public void Destroy(NetworkObject networkObject)
47+
{
48+
Object.Destroy(networkObject.gameObject);
49+
}
50+
51+
public void Register(NetworkManager networkManager)
52+
{
53+
networkManager.PrefabHandler.AddHandler(m_HostPrefab, this);
54+
}
55+
}
56+
57+
/// <summary>
58+
/// Creates a GameObject and sets the transform parent to the given transform
59+
/// Adds a component of the given type to the GameObject
60+
/// </summary>
61+
private static void AddChildToNetworkObject<T>(Transform transform) where T : Component
62+
{
63+
var gameObj = new GameObject();
64+
gameObj.transform.parent = transform;
65+
gameObj.AddComponent<T>();
66+
}
67+
68+
protected override void OnServerAndClientsCreated()
69+
{
70+
// Full non-disabled GameObjects prefab on server side
71+
m_ServerPrefab = CreateNetworkObjectPrefab("ServerPrefab");
72+
AddChildToNetworkObject<EmptyNetworkBehaviour>(m_ServerPrefab.transform);
73+
AddChildToNetworkObject<EmptyNetworkBehaviour>(m_ServerPrefab.transform);
74+
AddChildToNetworkObject<NetworkTransform>(m_ServerPrefab.transform);
75+
76+
// Mock disabled GameObjects prefab on client side
77+
m_ClientPrefab = CreateNetworkObjectPrefab("ClientPrefab");
78+
AddChildToNetworkObject<NetworkTransform>(m_ClientPrefab.transform);
79+
80+
// Create and register prefab handler to handle server and client versions of prefabs
81+
m_HostAndClientPrefabHandler = new HostAndClientPrefabHandler(m_ServerPrefab, m_ClientPrefab);
82+
m_HostAndClientPrefabHandler.Register(m_ServerNetworkManager);
83+
foreach (var client in m_ClientNetworkManagers)
84+
{
85+
m_HostAndClientPrefabHandler.Register(client);
86+
}
87+
88+
base.OnServerAndClientsCreated();
89+
}
90+
91+
92+
[UnityTest]
93+
public IEnumerator DisabledGameObjectErrorTest()
94+
{
95+
var instance = SpawnObject(m_ServerPrefab, m_ServerNetworkManager);
96+
var networkObjectInstance = instance.GetComponent<NetworkObject>();
97+
98+
yield return WaitForConditionOrTimeOut(() => ObjectSpawnedOnAllClients(networkObjectInstance.NetworkObjectId));
99+
AssertOnTimeout("Timed out waiting for object to spawn!");
100+
101+
LogAssert.Expect(LogType.Error, "[Netcode] NetworkBehaviour index 3 was out of bounds for ClientPrefab(Clone). NetworkBehaviours must be the same, and in the same order, between server and client.");
102+
LogAssert.Expect(LogType.Error, "[NetworkTransformMessage][Invalid][length] Targeted NetworkTransform, NetworkBehaviourId (3), does not exist! Make sure you are not spawning NetworkObjects with disabled GameObjects that have NetworkBehaviour components on them.");
103+
104+
yield return new WaitForSeconds(0.3f);
105+
}
106+
107+
private bool ObjectSpawnedOnAllClients(ulong networkObjectId)
108+
{
109+
foreach (var client in m_ClientNetworkManagers)
110+
{
111+
if (!client.SpawnManager.SpawnedObjects.ContainsKey(networkObjectId))
112+
{
113+
return false;
114+
}
115+
}
116+
return true;
117+
}
118+
}
119+
120+
}

com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformErrorTests.cs.meta

Lines changed: 3 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)