fix: NetworkObjects do not honor when Auto Object Parent Sync is turned off (#2281)

* fix
This resolves the issue where NetworkObjects were not taking Auto Object Parent Sync into consideration.

* test
The test to validate that nested in-scene placed NetworkObjects that both have Auto Object Parent Synchronization enabled and disabled synchronize their transforms properly on the client side. The same test covers NetworkObjects nested under GameObjects with no NetworkObject components.  All nested instances have varying position, rotation, and scale values.
This commit is contained in:
Noel Stephens 2022-10-28 17:48:58 -05:00 коммит произвёл GitHub
Родитель b5f82eea15
Коммит f43e700228
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 832 добавлений и 9 удалений

Просмотреть файл

@ -11,6 +11,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Fixed
- Fixed issue where in-scene placed `NetworkObjects` were not honoring the `AutoObjectParentSync` property. (#2281)
- Fixed the issue where `NetworkManager.OnClientConnectedCallback` was being invoked before in-scene placed `NetworkObject`s had been spawned when starting `NetworkManager` as a host. (#2277)
- Creating a `FastBufferReader` with `Allocator.None` will not result in extra memory being allocated for the buffer (since it's owned externally in that scenario). (#2265)

Просмотреть файл

@ -830,6 +830,9 @@ namespace Unity.Netcode
// parent and then re-parents the child under a GameObject with a NetworkObject component attached.
if (parentNetworkObject == null)
{
// If we are parented under a GameObject, go ahead and mark the world position stays as false
// so clients synchronize their transform in local space. (only for in-scene placed NetworkObjects)
m_CachedWorldPositionStays = false;
return true;
}
else // If the parent still isn't spawned add this to the orphaned children and return false
@ -841,8 +844,11 @@ namespace Unity.Netcode
else
{
// If we made it this far, go ahead and set the network parenting values
// with the default WorldPoisitonSays value
SetNetworkParenting(parentNetworkObject.NetworkObjectId, true);
// with the WorldPoisitonSays value set to false
// Note: Since in-scene placed NetworkObjects are parented in the scene
// the default "assumption" is that children are parenting local space
// relative.
SetNetworkParenting(parentNetworkObject.NetworkObjectId, false);
// Set the cached parent
m_CachedParent = parentNetworkObject.transform;
@ -1235,6 +1241,13 @@ namespace Unity.Netcode
if (!AlwaysReplicateAsRoot && transform.parent != null)
{
parentNetworkObject = transform.parent.GetComponent<NetworkObject>();
// In-scene placed NetworkObjects parented under GameObjects with no NetworkObject
// should set the has parent flag and preserve the world position stays value
if (parentNetworkObject == null && obj.Header.IsSceneObject)
{
obj.Header.HasParent = true;
obj.WorldPositionStays = m_CachedWorldPositionStays;
}
}
if (parentNetworkObject != null)
@ -1254,19 +1267,37 @@ namespace Unity.Netcode
if (IncludeTransformWhenSpawning == null || IncludeTransformWhenSpawning(OwnerClientId))
{
obj.Header.HasTransform = true;
// We start with the default AutoObjectParentSync values to determine which transform space we will
// be synchronizing clients with.
var syncRotationPositionLocalSpaceRelative = obj.Header.HasParent && !m_CachedWorldPositionStays;
var syncScaleLocalSpaceRelative = obj.Header.HasParent && !m_CachedWorldPositionStays;
// If auto object synchronization is turned off
if (!AutoObjectParentSync)
{
// We always synchronize position and rotation world space relative
syncRotationPositionLocalSpaceRelative = false;
// Scale is special, it synchronizes local space relative if it has a
// parent since applying the world space scale under a parent with scale
// will result in the improper scale for the child
syncScaleLocalSpaceRelative = obj.Header.HasParent;
}
obj.Transform = new SceneObject.TransformData
{
// If we are parented and we have the m_CachedWorldPositionStays disabled, then use local space
// values as opposed world space values.
Position = parentNetworkObject && !m_CachedWorldPositionStays ? transform.localPosition : transform.position,
Rotation = parentNetworkObject && !m_CachedWorldPositionStays ? transform.localRotation : transform.rotation,
Position = syncRotationPositionLocalSpaceRelative ? transform.localPosition : transform.position,
Rotation = syncRotationPositionLocalSpaceRelative ? transform.localRotation : transform.rotation,
// We only use the lossyScale if the NetworkObject has a parent. Multi-generation nested children scales can
// impact the final scale of the child NetworkObject in question. The solution is to use the lossy scale
// which can be thought of as "world space scale".
// More information:
// https://docs.unity3d.com/ScriptReference/Transform-lossyScale.html
Scale = parentNetworkObject && !m_CachedWorldPositionStays ? transform.localScale : transform.lossyScale,
Scale = syncScaleLocalSpaceRelative ? transform.localScale : transform.lossyScale,
};
}

Просмотреть файл

@ -402,7 +402,7 @@ namespace Unity.Netcode
if (networkObject != null)
{
// SPECIAL CASE:
// SPECIAL CASE FOR IN-SCENE PLACED: (only when the parent has a NetworkObject)
// This is a special case scenario where a late joining client has joined and loaded one or
// more scenes that contain nested in-scene placed NetworkObject children yet the server's
// synchronization information does not indicate the NetworkObject in question has a parent.
@ -423,7 +423,9 @@ namespace Unity.Netcode
// but it is up to the user to set those values
if (sceneObject.Header.HasTransform && !isSpawnedByPrefabHandler)
{
if (worldPositionStays)
// If world position stays is true or we have auto object parent synchronization disabled
// then we want to apply the position and rotation values world space relative
if (worldPositionStays || !networkObject.AutoObjectParentSync)
{
networkObject.transform.position = position;
networkObject.transform.rotation = rotation;
@ -443,6 +445,9 @@ namespace Unity.Netcode
// that is the default value of Vector3.
if (!sceneObject.Header.IsPlayerObject)
{
// Since scale is always applied to local space scale, we do the transform
// space logic during serialization such that it works out whether AutoObjectParentSync
// is enabled or not (see NetworkObject.SceneObject)
networkObject.transform.localScale = scale;
}
}

Просмотреть файл

@ -0,0 +1,64 @@
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
namespace TestProject.RuntimeTests
{
/// <summary>
/// Helper class that builds 4 transform lists based on parent-child hierarchy
/// for the <see cref="ParentingInSceneObjectsTests.InSceneNestedAutoSyncObjectTest"/>
/// </summary>
public class ParentingAutoSyncManager : NetworkBehaviour
{
public static ParentingAutoSyncManager ServerInstance;
public static Dictionary<ulong, ParentingAutoSyncManager> ClientInstances = new Dictionary<ulong, ParentingAutoSyncManager>();
public GameObject WithNetworkObjectAutoSyncOn;
public GameObject WithNetworkObjectAutoSyncOff;
public GameObject GameObjectAutoSyncOn;
public GameObject GameObjectAutoSyncOff;
public List<Transform> NetworkObjectAutoSyncOnTransforms = new List<Transform>();
public List<Transform> NetworkObjectAutoSyncOffTransforms = new List<Transform>();
public List<Transform> GameObjectAutoSyncOnTransforms = new List<Transform>();
public List<Transform> GameObjectAutoSyncOffTransforms = new List<Transform>();
public static void Reset()
{
ServerInstance = null;
ClientInstances.Clear();
}
public override void OnNetworkSpawn()
{
if (IsServer)
{
ServerInstance = this;
}
else
{
ClientInstances.Add(NetworkManager.LocalClientId, this);
}
var currentRoot = WithNetworkObjectAutoSyncOn.transform;
NetworkObjectAutoSyncOnTransforms.Add(currentRoot);
NetworkObjectAutoSyncOnTransforms.Add(currentRoot.GetChild(0));
NetworkObjectAutoSyncOnTransforms.Add(currentRoot.GetChild(0).GetChild(0));
currentRoot = WithNetworkObjectAutoSyncOff.transform;
NetworkObjectAutoSyncOffTransforms.Add(currentRoot);
NetworkObjectAutoSyncOffTransforms.Add(currentRoot.GetChild(0));
NetworkObjectAutoSyncOffTransforms.Add(currentRoot.GetChild(0).GetChild(0));
currentRoot = GameObjectAutoSyncOn.transform;
GameObjectAutoSyncOnTransforms.Add(currentRoot);
GameObjectAutoSyncOnTransforms.Add(currentRoot.GetChild(0));
GameObjectAutoSyncOnTransforms.Add(currentRoot.GetChild(0).GetChild(0));
currentRoot = GameObjectAutoSyncOff.transform;
GameObjectAutoSyncOffTransforms.Add(currentRoot);
GameObjectAutoSyncOffTransforms.Add(currentRoot.GetChild(0));
GameObjectAutoSyncOffTransforms.Add(currentRoot.GetChild(0).GetChild(0));
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3326399105afcf4459b51991aeeaacd2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -123,6 +123,55 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &69934937
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 69934939}
- component: {fileID: 69934938}
m_Layer: 0
m_Name: ParentedAutoSyncOn
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &69934938
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 69934937}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 2988556371
AlwaysReplicateAsRoot: 0
DontDestroyWithOwner: 0
AutoObjectParentSync: 1
--- !u!4 &69934939
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 69934937}
m_LocalRotation: {x: 0, y: 0.53729963, z: 0, w: 0.8433915}
m_LocalPosition: {x: 10, y: 10, z: 10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1353280373}
m_Father: {fileID: 0}
m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 65, z: 0}
--- !u!1 &118026864
GameObject:
m_ObjectHideFlags: 0
@ -157,7 +206,6 @@ MonoBehaviour:
m_ProtocolType: 0
m_MaxPacketQueueSize: 128
m_MaxPayloadSize: 6144
m_MaxSendQueueSize: 98304
m_HeartbeatTimeoutMS: 500
m_ConnectTimeoutMS: 1000
m_MaxConnectAttempts: 60
@ -231,6 +279,38 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: cf54eec7d39507743a95b32caf5b7c2a, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &153482222
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 153482223}
m_Layer: 0
m_Name: Child1
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &153482223
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 153482222}
m_LocalRotation: {x: 0.18730325, y: -0.036408048, z: 0.18730325, w: 0.963592}
m_LocalPosition: {x: 2, y: 0, z: 2}
m_LocalScale: {x: 0.1, y: 0.1, z: 0.1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1934730583}
m_Father: {fileID: 1351092234}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 22, y: 0, z: 22}
--- !u!1 &295758851
GameObject:
m_ObjectHideFlags: 0
@ -408,6 +488,70 @@ Camera:
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!1 &364512791
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 364512792}
m_Layer: 0
m_Name: Child1
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &364512792
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 364512791}
m_LocalRotation: {x: 0.18730325, y: -0.036408048, z: 0.18730325, w: 0.963592}
m_LocalPosition: {x: 2, y: 0, z: 2}
m_LocalScale: {x: 0.1, y: 0.1, z: 0.1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 700085893}
m_Father: {fileID: 366400900}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 22, y: 0, z: 22}
--- !u!1 &366400899
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 366400900}
m_Layer: 0
m_Name: GameObjectParentAutoSyncOn
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &366400900
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 366400899}
m_LocalRotation: {x: 0, y: 0.53729963, z: 0, w: 0.8433915}
m_LocalPosition: {x: 10, y: 10, z: 10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 364512792}
m_Father: {fileID: 0}
m_RootOrder: 7
m_LocalEulerAnglesHint: {x: 0, y: 65, z: 0}
--- !u!1 &505911173
GameObject:
m_ObjectHideFlags: 0
@ -532,6 +676,103 @@ MonoBehaviour:
RotationMin: {x: 0.01, y: 0.01, z: 0.01}
ScaleMax: 3
ScaleMin: 0.25
--- !u!1 &518555745
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 518555746}
- component: {fileID: 518555747}
m_Layer: 0
m_Name: Child2
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &518555746
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 518555745}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 10, y: 10, z: 10}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1353280373}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &518555747
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 518555745}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 4284572620
AlwaysReplicateAsRoot: 0
DontDestroyWithOwner: 0
AutoObjectParentSync: 1
--- !u!1 &582431330
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 582431331}
- component: {fileID: 582431332}
m_Layer: 0
m_Name: Child1
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &582431331
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 582431330}
m_LocalRotation: {x: 0.18730325, y: -0.036408048, z: 0.18730325, w: 0.963592}
m_LocalPosition: {x: 2, y: 0, z: 2}
m_LocalScale: {x: 0.1, y: 0.1, z: 0.1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1546803112}
m_Father: {fileID: 1282066021}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 22, y: 0, z: 22}
--- !u!114 &582431332
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 582431330}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 3027368638
AlwaysReplicateAsRoot: 0
DontDestroyWithOwner: 0
AutoObjectParentSync: 0
--- !u!1 &605493856
GameObject:
m_ObjectHideFlags: 0
@ -577,6 +818,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
m_Name:
m_EditorClassIdentifier:
m_SendPointerHoverToParent: 1
m_HorizontalAxis: Horizontal
m_VerticalAxis: Vertical
m_SubmitButton: Submit
@ -722,6 +964,123 @@ MonoBehaviour:
RotationMin: {x: 0.01, y: 0.01, z: 0.01}
ScaleMax: 3
ScaleMin: 0.25
--- !u!1 &694186461
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 694186464}
- component: {fileID: 694186463}
- component: {fileID: 694186462}
m_Layer: 0
m_Name: AutoSyncManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &694186462
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 694186461}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 2343724113
AlwaysReplicateAsRoot: 0
DontDestroyWithOwner: 0
AutoObjectParentSync: 1
--- !u!114 &694186463
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 694186461}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3326399105afcf4459b51991aeeaacd2, type: 3}
m_Name:
m_EditorClassIdentifier:
WithNetworkObjectAutoSyncOn: {fileID: 69934937}
WithNetworkObjectAutoSyncOff: {fileID: 1282066019}
GameObjectAutoSyncOn: {fileID: 366400899}
GameObjectAutoSyncOff: {fileID: 1351092233}
NetworkObjectAutoSyncOnTransforms: []
NetworkObjectAutoSyncOffTransforms: []
GameObjectAutoSyncOnTransforms: []
GameObjectAutoSyncOffTransforms: []
--- !u!4 &694186464
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 694186461}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 561, y: 144.52359, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 8
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &700085892
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 700085893}
- component: {fileID: 700085894}
m_Layer: 0
m_Name: Child2
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &700085893
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 700085892}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 10, y: 10, z: 10}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 364512792}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &700085894
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 700085892}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 1482043520
AlwaysReplicateAsRoot: 0
DontDestroyWithOwner: 0
AutoObjectParentSync: 0
--- !u!1 &733348965
GameObject:
m_ObjectHideFlags: 0
@ -1095,6 +1454,55 @@ MonoBehaviour:
RotationMin: {x: 0.01, y: 0.01, z: 0.01}
ScaleMax: 3
ScaleMin: 0.25
--- !u!1 &1282066019
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1282066021}
- component: {fileID: 1282066020}
m_Layer: 0
m_Name: ParentedAutoSyncOff
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1282066020
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1282066019}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 3624362024
AlwaysReplicateAsRoot: 0
DontDestroyWithOwner: 0
AutoObjectParentSync: 0
--- !u!4 &1282066021
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1282066019}
m_LocalRotation: {x: 0, y: 0.53729963, z: 0, w: 0.8433915}
m_LocalPosition: {x: 10, y: 10, z: 10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 582431331}
m_Father: {fileID: 0}
m_RootOrder: 5
m_LocalEulerAnglesHint: {x: 0, y: 65, z: 0}
--- !u!1 &1343771061
GameObject:
m_ObjectHideFlags: 0
@ -1189,6 +1597,87 @@ Light:
m_UseViewFrustumForShadowCasterCull: 1
m_ShadowRadius: 0
m_ShadowAngle: 0
--- !u!1 &1351092233
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1351092234}
m_Layer: 0
m_Name: GameObjectParentAutoSyncOff
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1351092234
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1351092233}
m_LocalRotation: {x: 0, y: 0.53729963, z: 0, w: 0.8433915}
m_LocalPosition: {x: 10, y: 10, z: 10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 153482223}
m_Father: {fileID: 0}
m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 65, z: 0}
--- !u!1 &1353280372
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1353280373}
- component: {fileID: 1353280374}
m_Layer: 0
m_Name: Child1
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1353280373
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1353280372}
m_LocalRotation: {x: 0.18730325, y: -0.036408048, z: 0.18730325, w: 0.963592}
m_LocalPosition: {x: 2, y: 0, z: 2}
m_LocalScale: {x: 0.1, y: 0.1, z: 0.1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 518555746}
m_Father: {fileID: 69934939}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 22, y: 0, z: 22}
--- !u!114 &1353280374
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1353280372}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 2685148660
AlwaysReplicateAsRoot: 0
DontDestroyWithOwner: 0
AutoObjectParentSync: 1
--- !u!1 &1392712513
GameObject:
m_ObjectHideFlags: 0
@ -1253,6 +1742,54 @@ MonoBehaviour:
AlwaysReplicateAsRoot: 0
DontDestroyWithOwner: 0
AutoObjectParentSync: 1
--- !u!1 &1546803111
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1546803112}
- component: {fileID: 1546803113}
m_Layer: 0
m_Name: Child2
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1546803112
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1546803111}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 10, y: 10, z: 10}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 582431331}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1546803113
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1546803111}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 136657534
AlwaysReplicateAsRoot: 0
DontDestroyWithOwner: 0
AutoObjectParentSync: 0
--- !u!1 &1601792188
GameObject:
m_ObjectHideFlags: 0
@ -1409,6 +1946,54 @@ Transform:
m_Father: {fileID: 0}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1934730582
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1934730583}
- component: {fileID: 1934730584}
m_Layer: 0
m_Name: Child2
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1934730583
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1934730582}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 10, y: 10, z: 10}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 153482223}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1934730584
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1934730582}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 638354969
AlwaysReplicateAsRoot: 0
DontDestroyWithOwner: 0
AutoObjectParentSync: 0
--- !u!1 &2062433906
GameObject:
m_ObjectHideFlags: 0
@ -1470,4 +2055,3 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 8384b01f654da304ebe165da1624cf56, type: 3}
m_Name:
m_EditorClassIdentifier:
Instances: []

Просмотреть файл

@ -41,6 +41,7 @@ namespace TestProject.RuntimeTests
{
InSceneParentChildHandler.ResetInstancesTracking(m_EnableVerboseDebug);
InSceneParentedUnderGameObjectHandler.Instances.Clear();
ParentingAutoSyncManager.Reset();
return base.OnSetup();
}
@ -383,5 +384,131 @@ namespace TestProject.RuntimeTests
Assert.False(instance.transform.parent == null, $"{instance.name}'s parent is null when it should not be!");
}
}
/// <summary>
/// Validates that all client transforms match all server transforms for the InSceneNestedAutoSyncObjectTest
/// </summary>
private bool AllClientInstancesMatchServerInstance()
{
for (int i = 0; i < ParentingAutoSyncManager.ServerInstance.NetworkObjectAutoSyncOnTransforms.Count; i++)
{
var serverTransformToTest = ParentingAutoSyncManager.ServerInstance.NetworkObjectAutoSyncOnTransforms[i];
for (int j = 0; j < m_ClientNetworkManagers.Length; j++)
{
var clientRelativeAutoSyncManager = ParentingAutoSyncManager.ClientInstances[m_ClientNetworkManagers[j].LocalClientId];
var clientTransformToTest = clientRelativeAutoSyncManager.NetworkObjectAutoSyncOnTransforms[i];
if (!Approximately(clientTransformToTest.position, serverTransformToTest.position))
{
return false;
}
if (!Approximately(clientTransformToTest.rotation, serverTransformToTest.rotation))
{
return false;
}
if (!Approximately(clientTransformToTest.localScale, serverTransformToTest.localScale))
{
return false;
}
}
}
for (int i = 0; i < ParentingAutoSyncManager.ServerInstance.NetworkObjectAutoSyncOffTransforms.Count; i++)
{
var serverTransformToTest = ParentingAutoSyncManager.ServerInstance.NetworkObjectAutoSyncOffTransforms[i];
for (int j = 0; j < m_ClientNetworkManagers.Length; j++)
{
var clientRelativeAutoSyncManager = ParentingAutoSyncManager.ClientInstances[m_ClientNetworkManagers[j].LocalClientId];
var clientTransformToTest = clientRelativeAutoSyncManager.NetworkObjectAutoSyncOffTransforms[i];
if (!Approximately(clientTransformToTest.position, serverTransformToTest.position))
{
return false;
}
if (!Approximately(clientTransformToTest.rotation, serverTransformToTest.rotation))
{
return false;
}
if (!Approximately(clientTransformToTest.localScale, serverTransformToTest.localScale))
{
return false;
}
}
}
for (int i = 0; i < ParentingAutoSyncManager.ServerInstance.GameObjectAutoSyncOnTransforms.Count; i++)
{
var serverTransformToTest = ParentingAutoSyncManager.ServerInstance.GameObjectAutoSyncOnTransforms[i];
for (int j = 0; j < m_ClientNetworkManagers.Length; j++)
{
var clientRelativeAutoSyncManager = ParentingAutoSyncManager.ClientInstances[m_ClientNetworkManagers[j].LocalClientId];
var clientTransformToTest = clientRelativeAutoSyncManager.GameObjectAutoSyncOnTransforms[i];
if (!Approximately(clientTransformToTest.position, serverTransformToTest.position))
{
return false;
}
if (!Approximately(clientTransformToTest.rotation, serverTransformToTest.rotation))
{
return false;
}
if (!Approximately(clientTransformToTest.localScale, serverTransformToTest.localScale))
{
return false;
}
}
}
for (int i = 0; i < ParentingAutoSyncManager.ServerInstance.GameObjectAutoSyncOffTransforms.Count; i++)
{
var serverTransformToTest = ParentingAutoSyncManager.ServerInstance.GameObjectAutoSyncOffTransforms[i];
for (int j = 0; j < m_ClientNetworkManagers.Length; j++)
{
var clientRelativeAutoSyncManager = ParentingAutoSyncManager.ClientInstances[m_ClientNetworkManagers[j].LocalClientId];
var clientTransformToTest = clientRelativeAutoSyncManager.GameObjectAutoSyncOffTransforms[i];
if (!Approximately(clientTransformToTest.position, serverTransformToTest.position))
{
return false;
}
if (!Approximately(clientTransformToTest.rotation, serverTransformToTest.rotation))
{
return false;
}
if (!Approximately(clientTransformToTest.localScale, serverTransformToTest.localScale))
{
return false;
}
}
}
return true;
}
/// <summary>
/// Validates that both nested in-scene NetworkObjects and in-scene NetworkObjects
/// nested under GameObjects synchronize clients with the appropriate transform
/// space values (world vs local).
/// </summary>
[UnityTest]
public IEnumerator InSceneNestedAutoSyncObjectTest()
{
SceneManager.sceneLoaded += SceneManager_sceneLoaded;
SceneManager.LoadScene(k_BaseSceneToLoad, LoadSceneMode.Additive);
m_InitialClientsLoadedScene = false;
m_ServerNetworkManager.SceneManager.OnSceneEvent += SceneManager_OnSceneEvent;
var sceneEventStartedStatus = m_ServerNetworkManager.SceneManager.LoadScene(k_TestSceneToLoad, LoadSceneMode.Additive);
Assert.True(sceneEventStartedStatus == SceneEventProgressStatus.Started, $"Failed to load scene {k_TestSceneToLoad} with a return status of {sceneEventStartedStatus}.");
yield return WaitForConditionOrTimeOut(() => m_InitialClientsLoadedScene);
AssertOnTimeout($"Timed out waiting for all clients to load scene {k_TestSceneToLoad}!");
yield return WaitForConditionOrTimeOut(AllClientInstancesMatchServerInstance);
AssertOnTimeout($"Timed out waiting for all client transforms to match the server-side values in test scene {k_TestSceneToLoad}!");
}
}
}