Skip to content

Commit f9c6731

Browse files
fix: in-scene networkobject with networktransform synchronization when parented under gameobject [MTT-8402] (#2895)
* fix Fixing issue where parenting synchronization on the authority side was not properly handling the scenario where a NetworkObject is parented under a GameObject (with or without auto object parent sync enabled). * fix Fixing issue where parenting synchronization on the non-authority side was not properly handling the scenario where a NetworkObject is parented under a GameObject (with or without auto object parent sync enabled). * update migrate when to apply in local space above the parenting check. * test Adding an integration test to validate an in-scene placed NetworkObject's initial synchronization when parented under a GameObject. This also test both scenarios where the in-scene placed NetworkObject does and does not have a NetworkTransform. * style Removing unused namespace * update Updating change log entry
1 parent bcb891b commit f9c6731

File tree

10 files changed

+735
-25
lines changed

10 files changed

+735
-25
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).
8+
## [Unreleased]
9+
10+
### Added
11+
12+
### Fixed
13+
14+
- Fixed issue where an in-scene placed `NetworkObject` with `NetworkTransform` that is also parented under a `GameObject` would not properly synchronize when the parent `GameObject` had a world space position other than 0,0,0. (#2895)
15+
16+
### Changed
817

918
## [Unreleased]
1019

com.unity.netcode.gameobjects/Components/NetworkTransform.cs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,15 @@ private bool ApplyTransformToNetworkStateWithInfo(ref NetworkTransformState netw
16821682
var scale = transformToUse.localScale;
16831683
networkState.IsSynchronizing = isSynchronization;
16841684

1685+
// All of the checks below, up to the delta position checking portion, are to determine if the
1686+
// authority changed a property during runtime that requires a full synchronizing.
1687+
if (InLocalSpace != networkState.InLocalSpace)
1688+
{
1689+
networkState.InLocalSpace = InLocalSpace;
1690+
isDirty = true;
1691+
networkState.IsTeleportingNextFrame = true;
1692+
}
1693+
16851694
// Check for parenting when synchronizing and/or teleporting
16861695
if (isSynchronization || networkState.IsTeleportingNextFrame)
16871696
{
@@ -1691,11 +1700,13 @@ private bool ApplyTransformToNetworkStateWithInfo(ref NetworkTransformState netw
16911700
// values are applied.
16921701
var hasParentNetworkObject = false;
16931702

1703+
var parentNetworkObject = (NetworkObject)null;
1704+
16941705
// If the NetworkObject belonging to this NetworkTransform instance has a parent
16951706
// (i.e. this handles nested NetworkTransforms under a parent at some layer above)
16961707
if (NetworkObject.transform.parent != null)
16971708
{
1698-
var parentNetworkObject = NetworkObject.transform.parent.GetComponent<NetworkObject>();
1709+
parentNetworkObject = NetworkObject.transform.parent.GetComponent<NetworkObject>();
16991710

17001711
// In-scene placed NetworkObjects parented under a GameObject with no
17011712
// NetworkObject preserve their lossyScale when synchronizing.
@@ -1716,28 +1727,25 @@ private bool ApplyTransformToNetworkStateWithInfo(ref NetworkTransformState netw
17161727
// the NetworkTransform is using world or local space synchronization.
17171728
// WorldPositionStays: (always use world space)
17181729
// !WorldPositionStays: (always use local space)
1719-
if (isSynchronization)
1730+
// Exception: If it is an in-scene placed NetworkObject and it is parented under a GameObject
1731+
// then always use local space unless AutoObjectParentSync is disabled and the NetworkTransform
1732+
// is synchronizing in world space.
1733+
if (isSynchronization && networkState.IsParented)
17201734
{
1721-
if (NetworkObject.WorldPositionStays())
1735+
var parentedUnderGameObject = NetworkObject.transform.parent != null && !parentNetworkObject && NetworkObject.IsSceneObject.Value;
1736+
if (NetworkObject.WorldPositionStays() && (!parentedUnderGameObject || (parentedUnderGameObject && !NetworkObject.AutoObjectParentSync && !InLocalSpace)))
17221737
{
17231738
position = transformToUse.position;
1739+
networkState.InLocalSpace = false;
17241740
}
17251741
else
17261742
{
17271743
position = transformToUse.localPosition;
1744+
networkState.InLocalSpace = true;
17281745
}
17291746
}
17301747
}
17311748

1732-
// All of the checks below, up to the delta position checking portion, are to determine if the
1733-
// authority changed a property during runtime that requires a full synchronizing.
1734-
if (InLocalSpace != networkState.InLocalSpace)
1735-
{
1736-
networkState.InLocalSpace = InLocalSpace;
1737-
isDirty = true;
1738-
networkState.IsTeleportingNextFrame = true;
1739-
}
1740-
17411749
if (Interpolate != networkState.UseInterpolation)
17421750
{
17431751
networkState.UseInterpolation = Interpolate;

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,20 +531,27 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SceneObject sceneO
531531
networkObject.DestroyWithScene = sceneObject.DestroyWithScene;
532532
networkObject.NetworkSceneHandle = sceneObject.NetworkSceneHandle;
533533

534+
535+
var nonNetworkObjectParent = false;
534536
// SPECIAL CASE FOR IN-SCENE PLACED: (only when the parent has a NetworkObject)
535537
// This is a special case scenario where a late joining client has joined and loaded one or
536538
// more scenes that contain nested in-scene placed NetworkObject children yet the server's
537539
// synchronization information does not indicate the NetworkObject in question has a parent.
538540
// Under this scenario, we want to remove the parent before spawning and setting the transform values.
539-
if (sceneObject.IsSceneObject && !sceneObject.HasParent && networkObject.transform.parent != null)
541+
if (sceneObject.IsSceneObject && networkObject.transform.parent != null)
540542
{
543+
var parentNetworkObject = networkObject.transform.parent.GetComponent<NetworkObject>();
541544
// if the in-scene placed NetworkObject has a parent NetworkObject but the synchronization information does not
542545
// include parenting, then we need to force the removal of that parent
543-
if (networkObject.transform.parent.GetComponent<NetworkObject>() != null)
546+
if (!sceneObject.HasParent && parentNetworkObject)
544547
{
545548
// remove the parent
546549
networkObject.ApplyNetworkParenting(true, true);
547550
}
551+
else if (sceneObject.HasParent && !parentNetworkObject)
552+
{
553+
nonNetworkObjectParent = true;
554+
}
548555
}
549556

550557
// Set the transform unless we were spawned by a prefab handler
@@ -554,7 +561,7 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SceneObject sceneO
554561
{
555562
// If world position stays is true or we have auto object parent synchronization disabled
556563
// then we want to apply the position and rotation values world space relative
557-
if (worldPositionStays || !networkObject.AutoObjectParentSync)
564+
if ((worldPositionStays && !nonNetworkObjectParent) || !networkObject.AutoObjectParentSync)
558565
{
559566
networkObject.transform.position = position;
560567
networkObject.transform.rotation = rotation;
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
%YAML 1.1
2+
%TAG !u! tag:unity3d.com,2011:
3+
--- !u!29 &1
4+
OcclusionCullingSettings:
5+
m_ObjectHideFlags: 0
6+
serializedVersion: 2
7+
m_OcclusionBakeSettings:
8+
smallestOccluder: 5
9+
smallestHole: 0.25
10+
backfaceThreshold: 100
11+
m_SceneGUID: 00000000000000000000000000000000
12+
m_OcclusionCullingData: {fileID: 0}
13+
--- !u!104 &2
14+
RenderSettings:
15+
m_ObjectHideFlags: 0
16+
serializedVersion: 9
17+
m_Fog: 0
18+
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
19+
m_FogMode: 3
20+
m_FogDensity: 0.01
21+
m_LinearFogStart: 0
22+
m_LinearFogEnd: 300
23+
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
24+
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
25+
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
26+
m_AmbientIntensity: 1
27+
m_AmbientMode: 0
28+
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
29+
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
30+
m_HaloStrength: 0.5
31+
m_FlareStrength: 1
32+
m_FlareFadeSpeed: 3
33+
m_HaloTexture: {fileID: 0}
34+
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
35+
m_DefaultReflectionMode: 0
36+
m_DefaultReflectionResolution: 128
37+
m_ReflectionBounces: 1
38+
m_ReflectionIntensity: 1
39+
m_CustomReflection: {fileID: 0}
40+
m_Sun: {fileID: 0}
41+
m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1}
42+
m_UseRadianceAmbientProbe: 0
43+
--- !u!157 &3
44+
LightmapSettings:
45+
m_ObjectHideFlags: 0
46+
serializedVersion: 12
47+
m_GIWorkflowMode: 1
48+
m_GISettings:
49+
serializedVersion: 2
50+
m_BounceScale: 1
51+
m_IndirectOutputScale: 1
52+
m_AlbedoBoost: 1
53+
m_EnvironmentLightingMode: 0
54+
m_EnableBakedLightmaps: 1
55+
m_EnableRealtimeLightmaps: 0
56+
m_LightmapEditorSettings:
57+
serializedVersion: 12
58+
m_Resolution: 2
59+
m_BakeResolution: 40
60+
m_AtlasSize: 1024
61+
m_AO: 0
62+
m_AOMaxDistance: 1
63+
m_CompAOExponent: 1
64+
m_CompAOExponentDirect: 0
65+
m_ExtractAmbientOcclusion: 0
66+
m_Padding: 2
67+
m_LightmapParameters: {fileID: 0}
68+
m_LightmapsBakeMode: 1
69+
m_TextureCompression: 1
70+
m_FinalGather: 0
71+
m_FinalGatherFiltering: 1
72+
m_FinalGatherRayCount: 256
73+
m_ReflectionCompression: 2
74+
m_MixedBakeMode: 2
75+
m_BakeBackend: 1
76+
m_PVRSampling: 1
77+
m_PVRDirectSampleCount: 32
78+
m_PVRSampleCount: 512
79+
m_PVRBounces: 2
80+
m_PVREnvironmentSampleCount: 256
81+
m_PVREnvironmentReferencePointCount: 2048
82+
m_PVRFilteringMode: 1
83+
m_PVRDenoiserTypeDirect: 1
84+
m_PVRDenoiserTypeIndirect: 1
85+
m_PVRDenoiserTypeAO: 1
86+
m_PVRFilterTypeDirect: 0
87+
m_PVRFilterTypeIndirect: 0
88+
m_PVRFilterTypeAO: 0
89+
m_PVREnvironmentMIS: 1
90+
m_PVRCulling: 1
91+
m_PVRFilteringGaussRadiusDirect: 1
92+
m_PVRFilteringGaussRadiusIndirect: 5
93+
m_PVRFilteringGaussRadiusAO: 2
94+
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
95+
m_PVRFilteringAtrousPositionSigmaIndirect: 2
96+
m_PVRFilteringAtrousPositionSigmaAO: 1
97+
m_ExportTrainingData: 0
98+
m_TrainingDataDestination: TrainingData
99+
m_LightProbeSampleCountMultiplier: 4
100+
m_LightingDataAsset: {fileID: 0}
101+
m_LightingSettings: {fileID: 0}
102+
--- !u!196 &4
103+
NavMeshSettings:
104+
serializedVersion: 2
105+
m_ObjectHideFlags: 0
106+
m_BuildSettings:
107+
serializedVersion: 3
108+
agentTypeID: 0
109+
agentRadius: 0.5
110+
agentHeight: 2
111+
agentSlope: 45
112+
agentClimb: 0.4
113+
ledgeDropHeight: 0
114+
maxJumpAcrossDistance: 0
115+
minRegionArea: 2
116+
manualCellSize: 0
117+
cellSize: 0.16666667
118+
manualTileSize: 0
119+
tileSize: 256
120+
buildHeightMesh: 0
121+
maxJobWorkers: 0
122+
preserveTilesOutsideBounds: 0
123+
debug:
124+
m_Flags: 0
125+
m_NavMeshData: {fileID: 0}
126+
--- !u!1 &151892557
127+
GameObject:
128+
m_ObjectHideFlags: 0
129+
m_CorrespondingSourceObject: {fileID: 0}
130+
m_PrefabInstance: {fileID: 0}
131+
m_PrefabAsset: {fileID: 0}
132+
serializedVersion: 6
133+
m_Component:
134+
- component: {fileID: 151892558}
135+
m_Layer: 0
136+
m_Name: ParentNoNT
137+
m_TagString: Untagged
138+
m_Icon: {fileID: 0}
139+
m_NavMeshLayer: 0
140+
m_StaticEditorFlags: 0
141+
m_IsActive: 1
142+
--- !u!4 &151892558
143+
Transform:
144+
m_ObjectHideFlags: 0
145+
m_CorrespondingSourceObject: {fileID: 0}
146+
m_PrefabInstance: {fileID: 0}
147+
m_PrefabAsset: {fileID: 0}
148+
m_GameObject: {fileID: 151892557}
149+
serializedVersion: 2
150+
m_LocalRotation: {x: 0.6465042, y: 0.021078281, z: 0.723563, w: -0.24092445}
151+
m_LocalPosition: {x: 2, y: 4, z: 1}
152+
m_LocalScale: {x: 1, y: 1, z: 1}
153+
m_ConstrainProportionsScale: 0
154+
m_Children:
155+
- {fileID: 386611893}
156+
m_Father: {fileID: 0}
157+
m_LocalEulerAnglesHint: {x: -20, y: 80, z: 200}
158+
--- !u!1 &386611892
159+
GameObject:
160+
m_ObjectHideFlags: 0
161+
m_CorrespondingSourceObject: {fileID: 0}
162+
m_PrefabInstance: {fileID: 0}
163+
m_PrefabAsset: {fileID: 0}
164+
serializedVersion: 6
165+
m_Component:
166+
- component: {fileID: 386611893}
167+
- component: {fileID: 386611894}
168+
- component: {fileID: 386611895}
169+
m_Layer: 0
170+
m_Name: ChildNoNT
171+
m_TagString: Untagged
172+
m_Icon: {fileID: 0}
173+
m_NavMeshLayer: 0
174+
m_StaticEditorFlags: 0
175+
m_IsActive: 1
176+
--- !u!4 &386611893
177+
Transform:
178+
m_ObjectHideFlags: 0
179+
m_CorrespondingSourceObject: {fileID: 0}
180+
m_PrefabInstance: {fileID: 0}
181+
m_PrefabAsset: {fileID: 0}
182+
m_GameObject: {fileID: 386611892}
183+
serializedVersion: 2
184+
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
185+
m_LocalPosition: {x: 0, y: 0, z: 0}
186+
m_LocalScale: {x: 1, y: 1, z: 1}
187+
m_ConstrainProportionsScale: 0
188+
m_Children: []
189+
m_Father: {fileID: 151892558}
190+
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
191+
--- !u!114 &386611894
192+
MonoBehaviour:
193+
m_ObjectHideFlags: 0
194+
m_CorrespondingSourceObject: {fileID: 0}
195+
m_PrefabInstance: {fileID: 0}
196+
m_PrefabAsset: {fileID: 0}
197+
m_GameObject: {fileID: 386611892}
198+
m_Enabled: 1
199+
m_EditorHideFlags: 0
200+
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
201+
m_Name:
202+
m_EditorClassIdentifier:
203+
GlobalObjectIdHash: 4010782011
204+
InScenePlacedSourceGlobalObjectIdHash: 0
205+
AlwaysReplicateAsRoot: 0
206+
SynchronizeTransform: 1
207+
ActiveSceneSynchronization: 0
208+
SceneMigrationSynchronization: 1
209+
SpawnWithObservers: 1
210+
DontDestroyWithOwner: 0
211+
AutoObjectParentSync: 1
212+
--- !u!114 &386611895
213+
MonoBehaviour:
214+
m_ObjectHideFlags: 0
215+
m_CorrespondingSourceObject: {fileID: 0}
216+
m_PrefabInstance: {fileID: 0}
217+
m_PrefabAsset: {fileID: 0}
218+
m_GameObject: {fileID: 386611892}
219+
m_Enabled: 1
220+
m_EditorHideFlags: 0
221+
m_Script: {fileID: 11500000, guid: bd877da52a3b48f4f867ac2c973c0265, type: 3}
222+
m_Name:
223+
m_EditorClassIdentifier:
224+
ObjectWasDisabledUponSpawn: 0
225+
--- !u!1660057539 &9223372036854775807
226+
SceneRoots:
227+
m_ObjectHideFlags: 0
228+
m_Roots:
229+
- {fileID: 151892558}

testproject/Assets/Tests/Manual/IntegrationTestScenes/InSceneUnderGameObject.unity.meta

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