diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md
index bdc42ccb2c..466cc59122 100644
--- a/com.unity.netcode.gameobjects/CHANGELOG.md
+++ b/com.unity.netcode.gameobjects/CHANGELOG.md
@@ -12,6 +12,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Fixed
+- Fixed a crash when calling TrySetParent with a null Transform (#2625)
- Fixed issue where a `NetworkTransform` using full precision state updates was losing transform state updates when interpolation was enabled. (#2624)
- Fixed issue where `NetworkObject.SpawnWithObservers` was not being honored for late joining clients. (#2623)
- Fixed issue where invoking `NetworkManager.Shutdown` multiple times, depending upon the timing, could cause an exception. (#2622)
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
index 3643d44a57..cd98c11e20 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
@@ -733,6 +733,12 @@ internal void SetNetworkParenting(ulong? latestParent, bool worldPositionStays)
/// Whether or not reparenting was successful.
public bool TrySetParent(Transform parent, bool worldPositionStays = true)
{
+ // If we are removing ourself from a parent
+ if (parent == null)
+ {
+ return TrySetParent((NetworkObject)null, worldPositionStays);
+ }
+
var networkObject = parent.GetComponent();
// If the parent doesn't have a NetworkObjet then return false, otherwise continue trying to parent
diff --git a/testproject/Assets/Tests/Runtime/ObjectParenting/NetworkObjectParentingTests.cs b/testproject/Assets/Tests/Runtime/ObjectParenting/NetworkObjectParentingTests.cs
index 65fb476822..1b1257a6c3 100644
--- a/testproject/Assets/Tests/Runtime/ObjectParenting/NetworkObjectParentingTests.cs
+++ b/testproject/Assets/Tests/Runtime/ObjectParenting/NetworkObjectParentingTests.cs
@@ -309,6 +309,49 @@ public IEnumerator SetParentTryAPI()
Assert.That(m_Cube_NetObjs[setIndex + 1].parent, Is.EqualTo(m_Dude_LeftArm_NetObjs[setIndex + 1]));
Assert.That(m_Cube_NetBhvs[setIndex + 1].ParentNetworkObject, Is.EqualTo(m_Dude_LeftArm_NetObjs[setIndex + 1].GetComponent()));
}
+
+ Transform nullTransform = null;
+ GameObject nullGameObject = null;
+ NetworkObject nullNetworkObject = null;
+
+
+ Assert.That(m_Cube_NetObjs[0].GetComponent().TrySetParent(nullTransform));
+ Assert.That(m_Cube_NetBhvs[0].ParentNetworkObject, Is.EqualTo(null));
+
+ nextFrameNumber = Time.frameCount + 2;
+ yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
+
+ for (int setIndex = 0; setIndex < k_ClientInstanceCount; setIndex++)
+ {
+ Assert.That(m_Cube_NetObjs[setIndex + 1].parent, Is.EqualTo(null));
+ Assert.That(m_Cube_NetBhvs[setIndex + 1].ParentNetworkObject, Is.EqualTo(null));
+ }
+
+
+ Assert.That(m_Cube_NetObjs[0].GetComponent().TrySetParent(nullGameObject));
+ Assert.That(m_Cube_NetBhvs[0].ParentNetworkObject, Is.EqualTo(null));
+
+ nextFrameNumber = Time.frameCount + 2;
+ yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
+
+ for (int setIndex = 0; setIndex < k_ClientInstanceCount; setIndex++)
+ {
+ Assert.That(m_Cube_NetObjs[setIndex + 1].parent, Is.EqualTo(null));
+ Assert.That(m_Cube_NetBhvs[setIndex + 1].ParentNetworkObject, Is.EqualTo(null));
+ }
+
+
+ Assert.That(m_Cube_NetObjs[0].GetComponent().TrySetParent(nullNetworkObject));
+ Assert.That(m_Cube_NetBhvs[0].ParentNetworkObject, Is.EqualTo(null));
+
+ nextFrameNumber = Time.frameCount + 2;
+ yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
+
+ for (int setIndex = 0; setIndex < k_ClientInstanceCount; setIndex++)
+ {
+ Assert.That(m_Cube_NetObjs[setIndex + 1].parent, Is.EqualTo(null));
+ Assert.That(m_Cube_NetBhvs[setIndex + 1].ParentNetworkObject, Is.EqualTo(null));
+ }
}
}
}