Skip to content

Commit 0d1feea

Browse files
Merge branch 'develop-2.0.0' into bacport-information-in-pr-test-develop-2.0.0
2 parents 1aa8d5b + 9329b80 commit 0d1feea

File tree

6 files changed

+108
-69
lines changed

6 files changed

+108
-69
lines changed

.yamato/webgl-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ webgl_build_{{ project.name }}_{{ platform.name }}_{{ editor }}:
4545
# Engine is initialized in ‘nographics’ mode since we don't need any graphics for this case (--extra-editor-arg=-nographics)
4646
# In case of failure the job will be rerunned once (--reruncount=1) with clean library (--clean-library-on-rerun)
4747
# This will perform only building phase (--build-only) with a timeout of 3m (--timeout=1800)
48-
- UnifiedTestRunner --suite=playmode --platform=WebGL --scripting-backend=il2cpp --testproject={{ project.path }} --editor-location=.Editor --artifacts_path=artifacts --player-save-path=build/players --extra-editor-arg=-batchmode --extra-editor-arg=-nographics --reruncount=1 --clean-library-on-rerun --build-only --timeout=1800
48+
- UnifiedTestRunner --suite=playmode --platform=WebGL --scripting-backend=il2cpp --testproject={{ project.path }} --editor-location=.Editor --artifacts_path=artifacts --player-save-path=build/players --extra-editor-arg=-batchmode --extra-editor-arg=-nographics --reruncount=1 --clean-library-on-rerun --build-only --timeout=2400
4949
artifacts:
5050
logs:
5151
paths:

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
2222

2323
### Fixed
2424

25+
- Fixed issue where in-scene placed `NetworkObjects` could fail to synchronize its transform properly (especially without a `NetworkTransform`) if their parenting changes from the default when the scene is loaded and if the same scene remains loaded between network sessions while the parenting is completely different from the original hierarchy. (#3387)
2526
- Fixed an issue in `UnityTransport` where the transport would accept sends on invalid connections, leading to a useless memory allocation and confusing error message. (#3382)
2627
- Fixed issue where the time delta that interpolators used would not be properly updated during multiple fixed update invocations within the same player loop frame. (#3355)
2728
- Fixed issue when using a distributed authority network topology and many clients attempt to connect simultaneously the session owner could max-out the maximum in-flight reliable messages allowed, start dropping packets, and some of the connecting clients would fail to fully synchronize. (#3350)
@@ -44,6 +45,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
4445

4546
### Changed
4647

48+
- Changed the scene loading event serialization order for in-scene placed `NetworkObject`s to be based on their parent-child hierarchy. (#3387)
4749
- Changed the original `Lerp` interpolation type to `LegacyLerp`. (#3355)
4850
- Changed `BufferedLinearInterpolator<T>.Update(float deltaTime, NetworkTime serverTime)` as being deprecated since this method is only used for internal testing purposes. (#3337)
4951
- Changed error thrown when attempting to build a dedicated server with Unity Transport that uses websockets to provide more useful information to the user. (#3336)

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,13 +2074,6 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
20742074
// buffered values to the correct world or local space values.
20752075
forceState = SwitchTransformSpaceWhenParented;
20762076
}
2077-
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
2078-
else if (InLocalSpace && m_UseRigidbodyForMotion)
2079-
{
2080-
// TODO: Provide more options than just FixedJoint
2081-
Debug.LogError($"[Rigidbody] WHen using a Rigidbody for motion, you cannot use {nameof(InLocalSpace)}! If parenting, use the integrated FixedJoint or use a Joint on Authority side.");
2082-
}
2083-
#endif
20842077

20852078
// Check for parenting when synchronizing and/or teleporting
20862079
if (isSynchronization || networkState.IsTeleportingNextFrame)
@@ -3543,7 +3536,10 @@ private void InternalInitialization(bool isOwnershipChange = false)
35433536
{
35443537
if (CanCommitToTransform)
35453538
{
3546-
InLocalSpace = transform.parent != null;
3539+
if (NetworkObject.HasParentNetworkObject(transform))
3540+
{
3541+
InLocalSpace = true;
3542+
}
35473543
}
35483544
// Always apply this if SwitchTransformSpaceWhenParented is set.
35493545
TickSyncChildren = true;

com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs

Lines changed: 55 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -308,15 +308,18 @@ internal void OnValidate()
308308
/// </remarks>
309309
private void CheckForInScenePlaced()
310310
{
311-
if (PrefabUtility.IsPartOfAnyPrefab(this) && gameObject.scene.IsValid() && gameObject.scene.isLoaded && gameObject.scene.buildIndex >= 0)
311+
if (gameObject.scene.IsValid() && gameObject.scene.isLoaded && gameObject.scene.buildIndex >= 0)
312312
{
313-
var prefab = PrefabUtility.GetCorrespondingObjectFromSource(gameObject);
314-
var assetPath = AssetDatabase.GetAssetPath(prefab);
315-
var sourceAsset = AssetDatabase.LoadAssetAtPath<NetworkObject>(assetPath);
316-
if (sourceAsset != null && sourceAsset.GlobalObjectIdHash != 0 && InScenePlacedSourceGlobalObjectIdHash != sourceAsset.GlobalObjectIdHash)
313+
if (PrefabUtility.IsPartOfAnyPrefab(this))
317314
{
318-
InScenePlacedSourceGlobalObjectIdHash = sourceAsset.GlobalObjectIdHash;
319-
EditorUtility.SetDirty(this);
315+
var prefab = PrefabUtility.GetCorrespondingObjectFromSource(gameObject);
316+
var assetPath = AssetDatabase.GetAssetPath(prefab);
317+
var sourceAsset = AssetDatabase.LoadAssetAtPath<NetworkObject>(assetPath);
318+
if (sourceAsset != null && sourceAsset.GlobalObjectIdHash != 0 && InScenePlacedSourceGlobalObjectIdHash != sourceAsset.GlobalObjectIdHash)
319+
{
320+
InScenePlacedSourceGlobalObjectIdHash = sourceAsset.GlobalObjectIdHash;
321+
EditorUtility.SetDirty(this);
322+
}
320323
}
321324
IsSceneObject = true;
322325

@@ -335,6 +338,24 @@ private void CheckForInScenePlaced()
335338
}
336339
#endif // UNITY_EDITOR
337340

341+
internal bool HasParentNetworkObject(Transform transform)
342+
{
343+
if (transform.parent != null)
344+
{
345+
var networkObject = transform.parent.GetComponent<NetworkObject>();
346+
if (networkObject != null && networkObject != this)
347+
{
348+
return true;
349+
}
350+
351+
if (transform.parent.parent != null)
352+
{
353+
return HasParentNetworkObject(transform.parent);
354+
}
355+
}
356+
return false;
357+
}
358+
338359
/// <summary>
339360
/// Gets the NetworkManager that owns this NetworkObject instance
340361
/// </summary>
@@ -2295,7 +2316,7 @@ private void OnTransformParentChanged()
22952316
// we call CheckOrphanChildren() method and quickly iterate over OrphanChildren set and see if we can reparent/adopt one.
22962317
internal static HashSet<NetworkObject> OrphanChildren = new HashSet<NetworkObject>();
22972318

2298-
internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpawned = false, bool orphanedChildPass = false)
2319+
internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpawned = false, bool orphanedChildPass = false, bool enableNotification = true)
22992320
{
23002321
if (!AutoObjectParentSync)
23012322
{
@@ -2368,7 +2389,10 @@ internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpa
23682389
// to WorldPositionStays which can cause scaling issues if the parent's
23692390
// scale is not the default (Vetctor3.one) value.
23702391
transform.SetParent(null, m_CachedWorldPositionStays);
2371-
InvokeBehaviourOnNetworkObjectParentChanged(null);
2392+
if (enableNotification)
2393+
{
2394+
InvokeBehaviourOnNetworkObjectParentChanged(null);
2395+
}
23722396
return true;
23732397
}
23742398

@@ -2393,7 +2417,10 @@ internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpa
23932417
}
23942418
SetCachedParent(parentObject.transform);
23952419
transform.SetParent(parentObject.transform, m_CachedWorldPositionStays);
2396-
InvokeBehaviourOnNetworkObjectParentChanged(parentObject);
2420+
if (enableNotification)
2421+
{
2422+
InvokeBehaviourOnNetworkObjectParentChanged(parentObject);
2423+
}
23972424
return true;
23982425
}
23992426

@@ -3030,6 +3057,8 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager
30303057
{
30313058
var obj = new SceneObject
30323059
{
3060+
HasParent = transform.parent != null,
3061+
WorldPositionStays = m_CachedWorldPositionStays,
30333062
NetworkObjectId = NetworkObjectId,
30343063
OwnerClientId = OwnerClientId,
30353064
IsPlayerObject = IsPlayerObject,
@@ -3046,31 +3075,16 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager
30463075
TargetClientId = targetClientId
30473076
};
30483077

3049-
NetworkObject parentNetworkObject = null;
3050-
3051-
if (!AlwaysReplicateAsRoot && transform.parent != null)
3078+
// Handle Parenting
3079+
if (!AlwaysReplicateAsRoot && obj.HasParent)
30523080
{
3053-
parentNetworkObject = transform.parent.GetComponent<NetworkObject>();
3054-
// In-scene placed NetworkObjects parented under GameObjects with no NetworkObject
3055-
// should set the has parent flag and preserve the world position stays value
3056-
if (parentNetworkObject == null && obj.IsSceneObject)
3057-
{
3058-
obj.HasParent = true;
3059-
obj.WorldPositionStays = m_CachedWorldPositionStays;
3060-
}
3061-
}
3081+
var parentNetworkObject = transform.parent.GetComponent<NetworkObject>();
30623082

3063-
if (parentNetworkObject != null)
3064-
{
3065-
obj.HasParent = true;
3066-
obj.ParentObjectId = parentNetworkObject.NetworkObjectId;
3067-
obj.WorldPositionStays = m_CachedWorldPositionStays;
3068-
var latestParent = GetNetworkParenting();
3069-
var isLatestParentSet = latestParent != null && latestParent.HasValue;
3070-
obj.IsLatestParentSet = isLatestParentSet;
3071-
if (isLatestParentSet)
3083+
if (parentNetworkObject)
30723084
{
3073-
obj.LatestParent = latestParent.Value;
3085+
obj.ParentObjectId = parentNetworkObject.NetworkObjectId;
3086+
obj.LatestParent = GetNetworkParenting();
3087+
obj.IsLatestParentSet = obj.LatestParent != null && obj.LatestParent.HasValue;
30743088
}
30753089
}
30763090

@@ -3083,12 +3097,6 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager
30833097
var syncRotationPositionLocalSpaceRelative = obj.HasParent && !m_CachedWorldPositionStays;
30843098
var syncScaleLocalSpaceRelative = obj.HasParent && !m_CachedWorldPositionStays;
30853099

3086-
// Always synchronize in-scene placed object's scale using local space
3087-
if (obj.IsSceneObject)
3088-
{
3089-
syncScaleLocalSpaceRelative = obj.HasParent;
3090-
}
3091-
30923100
// If auto object synchronization is turned off
30933101
if (!AutoObjectParentSync)
30943102
{
@@ -3166,6 +3174,15 @@ internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBuf
31663174
var bufferSerializer = new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
31673175
networkObject.SynchronizeNetworkBehaviours(ref bufferSerializer, networkManager.LocalClientId);
31683176

3177+
// If we are an in-scene placed NetworkObject and we originally had a parent but when synchronized we are
3178+
// being told we do not have a parent, then we want to clear the latest parent so it is not automatically
3179+
// "re-parented" to the original parent. This can happen if not unloading the scene and the parenting of
3180+
// the in-scene placed Networkobject changes several times over different sessions.
3181+
if (sceneObject.IsSceneObject && !sceneObject.HasParent && networkObject.m_LatestParent.HasValue)
3182+
{
3183+
networkObject.m_LatestParent = null;
3184+
}
3185+
31693186
// Spawn the NetworkObject
31703187
networkManager.SpawnManager.SpawnNetworkObjectLocally(networkObject, sceneObject, sceneObject.DestroyWithScene);
31713188

com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,14 @@ internal void AddSpawnedNetworkObjects()
329329
m_NetworkObjectsSync.Add(sobj);
330330
}
331331
}
332+
SortObjectsToSync();
333+
}
332334

335+
/// <summary>
336+
/// Used to order the object serialization for both synchronization and scene loading
337+
/// </summary>
338+
private void SortObjectsToSync()
339+
{
333340
// Sort by INetworkPrefabInstanceHandler implementation before the
334341
// NetworkObjects spawned by the implementation
335342
m_NetworkObjectsSync.Sort(SortNetworkObjects);
@@ -671,20 +678,31 @@ internal void SerializeScenePlacedObjects(FastBufferWriter writer)
671678
// If distributed authority mode and sending to the service, then ignore observers
672679
var distributedAuthoritySendingToService = distributedAuthority && TargetClientId == NetworkManager.ServerClientId;
673680

681+
// Clear our objects to sync and build a list of the in-scene placed NetworkObjects instantiated and spawned locally
682+
m_NetworkObjectsSync.Clear();
674683
foreach (var keyValuePairByGlobalObjectIdHash in m_NetworkManager.SceneManager.ScenePlacedObjects)
675684
{
676685
foreach (var keyValuePairBySceneHandle in keyValuePairByGlobalObjectIdHash.Value)
677686
{
678687
if (keyValuePairBySceneHandle.Value.Observers.Contains(TargetClientId) || distributedAuthoritySendingToService)
679688
{
680-
// Serialize the NetworkObject
681-
var sceneObject = keyValuePairBySceneHandle.Value.GetMessageSceneObject(TargetClientId, distributedAuthority);
682-
sceneObject.Serialize(writer);
683-
numberOfObjects++;
689+
m_NetworkObjectsSync.Add(keyValuePairBySceneHandle.Value);
684690
}
685691
}
686692
}
687693

694+
// Sort the objects to sync based on parenting hierarchy
695+
SortObjectsToSync();
696+
697+
// Serialize the sorted objects to sync.
698+
foreach (var objectToSycn in m_NetworkObjectsSync)
699+
{
700+
// Serialize the NetworkObject
701+
var sceneObject = objectToSycn.GetMessageSceneObject(TargetClientId, distributedAuthority);
702+
sceneObject.Serialize(writer);
703+
numberOfObjects++;
704+
}
705+
688706
// Write the number of despawned in-scene placed NetworkObjects
689707
writer.WriteValueSafe(m_DespawnedInSceneObjectsSync.Count);
690708
// Write the scene handle and GlobalObjectIdHash value

0 commit comments

Comments
 (0)