From 70da1eabf2cd599014c70af853837c905985ef36 Mon Sep 17 00:00:00 2001
From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com>
Date: Thu, 27 Apr 2023 17:08:32 -0500
Subject: [PATCH 1/7] fix
This fixes an issue with interpolation causing nonauthoritative NetworkTransform instances to not properly reflect the final axis values when parenting changes.
---
.../Components/NetworkTransform.cs | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/com.unity.netcode.gameobjects/Components/NetworkTransform.cs b/com.unity.netcode.gameobjects/Components/NetworkTransform.cs
index 26d66cc39a..993e75e8f7 100644
--- a/com.unity.netcode.gameobjects/Components/NetworkTransform.cs
+++ b/com.unity.netcode.gameobjects/Components/NetworkTransform.cs
@@ -2503,6 +2503,33 @@ protected void Initialize()
OnInitialize(ref replicatedState);
}
+ ///
+ ///
+ /// When a parent changes, non-authoritative instances should:
+ /// - Apply the resultant position, rotation, and scale from the parenting action.
+ /// - Clear interpolators (even if not enabled on this frame)
+ /// - Reset the interpolators to the position, rotation, and scale resultant values.
+ /// This prevents interpolation visual anomalies and issues during initial synchronization
+ ///
+ public override void OnNetworkObjectParentChanged(NetworkObject parentNetworkObject)
+ {
+ // Only if we are not authority
+ if (!CanCommitToTransform)
+ {
+ m_CurrentPosition = GetSpaceRelativePosition();
+ m_CurrentRotation = GetSpaceRelativeRotation();
+ m_CurrentScale = GetScale();
+ m_ScaleInterpolator.Clear();
+ m_PositionInterpolator.Clear();
+ m_RotationInterpolator.Clear();
+ var tempTime = new NetworkTime(NetworkManager.NetworkConfig.TickRate, NetworkManager.ServerTime.Tick).Time;
+ UpdatePositionInterpolator(m_CurrentPosition, tempTime, true);
+ m_ScaleInterpolator.ResetTo(m_CurrentScale, tempTime);
+ m_RotationInterpolator.ResetTo(m_CurrentRotation, tempTime);
+ }
+ base.OnNetworkObjectParentChanged(parentNetworkObject);
+ }
+
///
/// Directly sets a state on the authoritative transform.
/// Owner clients can directly set the state on a server authoritative transform
From c069ea053efbd52c10ee40b23485c70f4c39e873 Mon Sep 17 00:00:00 2001
From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com>
Date: Thu, 27 Apr 2023 17:32:06 -0500
Subject: [PATCH 2/7] test
Updating the parenting test to validate the fix for parenting a nested NetworkTransform and assuring that values are the same.
---
.../NetworkTransform/NetworkTransformTests.cs | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs
index d1adb38fc2..0abf75141e 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs
@@ -367,10 +367,19 @@ private void WaitForAllChildrenLocalTransformValuesToMatch()
/// parented under another NetworkTransform
///
[Test]
- public void NetworkTransformParentedLocalSpaceTest([Values] Interpolation interpolation)
+ public void NetworkTransformParentedLocalSpaceTest([Values] Interpolation interpolation, [Values(0.5f, 1.0f, 5.0f)] float scale)
{
m_AuthoritativeTransform.Interpolate = interpolation == Interpolation.EnableInterpolate;
m_NonAuthoritativeTransform.Interpolate = interpolation == Interpolation.EnableInterpolate;
+ // Change the parent scale to assure that it will impact the child's scale when not Vector3.one
+ if (m_AuthoritativeTransform.IsServerAuthoritative())
+ {
+ m_AuthoritativeTransform.transform.localScale = new Vector3(scale, scale, scale);
+ }
+ else
+ {
+ m_NonAuthoritativeTransform.transform.localScale = new Vector3(scale, scale, scale);
+ }
var authoritativeChildObject = SpawnObject(m_ChildObjectToBeParented.gameObject, m_AuthoritativeTransform.NetworkManager);
// Assure all of the child object instances are spawned
@@ -395,6 +404,10 @@ public void NetworkTransformParentedLocalSpaceTest([Values] Interpolation interp
// This validates each child instance has preserved their local space values
WaitForAllChildrenLocalTransformValuesToMatch();
+
+ // This validates that a late joining client will synchronize to the other players with parented NetworkObjects
+ CreateAndStartNewClientWithTimeTravel();
+ WaitForAllChildrenLocalTransformValuesToMatch();
}
///
From b41162fc00620ff6df6fac2986c6ae9e21cdb1b4 Mon Sep 17 00:00:00 2001
From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com>
Date: Fri, 28 Apr 2023 17:55:12 -0500
Subject: [PATCH 3/7] fix
Handle the condition that no new states have been pushed for a late joining client.
(i.e. it just synchronized a nested NetworkTransform and that is it)
---
.../Components/NetworkTransform.cs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/com.unity.netcode.gameobjects/Components/NetworkTransform.cs b/com.unity.netcode.gameobjects/Components/NetworkTransform.cs
index e1418edc2d..a5eb83c555 100644
--- a/com.unity.netcode.gameobjects/Components/NetworkTransform.cs
+++ b/com.unity.netcode.gameobjects/Components/NetworkTransform.cs
@@ -2683,6 +2683,12 @@ protected virtual void Update()
}
}
+ // If we have not received any additional state updates since the very
+ // initial synchronization, then exit early.
+ if (m_LocalAuthoritativeNetworkState.IsSynchronizing)
+ {
+ return;
+ }
// Apply the current authoritative state
ApplyAuthoritativeState();
}
From 0c476f635c601e1c1089f4441722a11614fa31d3 Mon Sep 17 00:00:00 2001
From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com>
Date: Fri, 28 Apr 2023 17:59:48 -0500
Subject: [PATCH 4/7] test
Did an overhaul on the parented NetworkTransformTest (formerly NetworkTransformParentedLocalSpaceTest), renamed it to ParentedNetworkTransformTest, and now it tests both world and local space values depending upon how the NetworkObject is parented.
---
.../NetworkTransform/NetworkTransformTests.cs | 218 +++++++++++++-----
1 file changed, 157 insertions(+), 61 deletions(-)
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs
index 0abf75141e..956edc1b12 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs
@@ -37,10 +37,17 @@ protected override bool OnIsServerAuthoritative()
return ServerAuthority;
}
+ public static NetworkTransformTestComponent AuthorityInstance;
+
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
+ if (CanCommitToTransform)
+ {
+ AuthorityInstance = this;
+ }
+
ReadyToReceivePositionUpdate = true;
}
@@ -59,31 +66,38 @@ public void CommitToTransform()
///
/// Helper component for NetworkTransform parenting tests
///
- public class ChildObjectComponent : NetworkBehaviour
+ public class ChildObjectComponent : NetworkTransform
{
public static readonly List Instances = new List();
- public static ChildObjectComponent ServerInstance { get; internal set; }
+ public static ChildObjectComponent AuthorityInstance { get; internal set; }
public static readonly Dictionary ClientInstances = new Dictionary();
public static void Reset()
{
- ServerInstance = null;
+ AuthorityInstance = null;
ClientInstances.Clear();
Instances.Clear();
}
+ public bool ServerAuthority;
+
+ protected override bool OnIsServerAuthoritative()
+ {
+ return ServerAuthority;
+ }
+
public override void OnNetworkSpawn()
{
- if (IsServer)
+ base.OnNetworkSpawn();
+ if (CanCommitToTransform)
{
- ServerInstance = this;
+ AuthorityInstance = this;
}
else
{
- ClientInstances.Add(NetworkManager.LocalClientId, NetworkObject);
+ Instances.Add(this);
}
- Instances.Add(this);
- base.OnNetworkSpawn();
+ ClientInstances.Add(NetworkManager.LocalClientId, NetworkObject);
}
}
@@ -101,7 +115,8 @@ public class NetworkTransformTests : IntegrationTestWithApproximation
{
private NetworkObject m_AuthoritativePlayer;
private NetworkObject m_NonAuthoritativePlayer;
- private NetworkObject m_ChildObjectToBeParented;
+ private NetworkObject m_ChildObject;
+ private NetworkObject m_ParentObject;
private NetworkTransformTestComponent m_AuthoritativeTransform;
private NetworkTransformTestComponent m_NonAuthoritativeTransform;
@@ -133,6 +148,13 @@ public enum Rotation
Quaternion
}
+ public enum RotationCompression
+ {
+ None,
+ QuaternionCompress
+ }
+
+
public enum TransformSpace
{
World,
@@ -190,6 +212,7 @@ protected override void OnOneTimeTearDown()
protected override void OnInlineSetup()
{
+ NetworkTransformTestComponent.AuthorityInstance = null;
m_Precision = Precision.Full;
ChildObjectComponent.Reset();
}
@@ -209,17 +232,22 @@ protected override void OnCreatePlayerPrefab()
protected override void OnServerAndClientsCreated()
{
var childObject = CreateNetworkObjectPrefab("ChildObject");
- childObject.AddComponent();
- var childNetworkTransform = childObject.AddComponent();
- childNetworkTransform.InLocalSpace = true;
- m_ChildObjectToBeParented = childObject.GetComponent();
+ var childNetworkTransform = childObject.AddComponent();
+ childNetworkTransform.ServerAuthority = m_Authority == Authority.ServerAuthority;
+ m_ChildObject = childObject.GetComponent();
+
+ var parentObject = CreateNetworkObjectPrefab("ParentObject");
+ var parentNetworkTransform = parentObject.AddComponent();
+ parentNetworkTransform.ServerAuthority = m_Authority == Authority.ServerAuthority;
+ m_ParentObject = parentObject.GetComponent();
+
// Now apply local transform values
- m_ChildObjectToBeParented.transform.position = m_ChildObjectLocalPosition;
- var childRotation = m_ChildObjectToBeParented.transform.rotation;
+ m_ChildObject.transform.position = m_ChildObjectLocalPosition;
+ var childRotation = m_ChildObject.transform.rotation;
childRotation.eulerAngles = m_ChildObjectLocalRotation;
- m_ChildObjectToBeParented.transform.rotation = childRotation;
- m_ChildObjectToBeParented.transform.localScale = m_ChildObjectLocalScale;
+ m_ChildObject.transform.rotation = childRotation;
+ m_ChildObject.transform.localScale = m_ChildObjectLocalScale;
if (m_EnableVerboseDebug)
{
m_ServerNetworkManager.LogLevel = LogLevel.Developer;
@@ -268,7 +296,7 @@ protected override void OnTimeTravelServerAndClientsConnected()
///
private bool AllChildObjectInstancesAreSpawned()
{
- if (ChildObjectComponent.ServerInstance == null)
+ if (ChildObjectComponent.AuthorityInstance == null)
{
return false;
}
@@ -306,21 +334,37 @@ private bool AllChildObjectInstancesHaveChild()
///
private bool AllInstancesKeptLocalTransformValues()
{
+ //var authorityObjectLocalPosition = ChildObjectComponent.ServerInstance.transform.localPosition;
+ //var authorityObjectLocalRotation = ChildObjectComponent.ServerInstance.transform.localRotation.eulerAngles;
+ //var authorityObjectLocalScale = ChildObjectComponent.ServerInstance.transform.localScale;
+ var authorityObjectLocalPosition = m_AuthorityChildObject.transform.localPosition;
+ var authorityObjectLocalRotation = m_AuthorityChildObject.transform.localRotation.eulerAngles;
+ var authorityObjectLocalScale = m_AuthorityChildObject.transform.localScale;
+
foreach (var childInstance in ChildObjectComponent.Instances)
{
var childLocalPosition = childInstance.transform.localPosition;
var childLocalRotation = childInstance.transform.localRotation.eulerAngles;
var childLocalScale = childInstance.transform.localScale;
-
- if (!Approximately(childLocalPosition, m_ChildObjectLocalPosition))
+ // Adjust approximation based on precision
+ if (m_Precision == Precision.Half)
+ {
+ m_CurrentHalfPrecision = k_HalfPrecisionPosScale;
+ }
+ if (!Approximately(childLocalPosition, authorityObjectLocalPosition))
{
return false;
}
- if (!ApproximatelyEuler(childLocalRotation, m_ChildObjectLocalRotation))
+ if (!Approximately(childLocalScale, authorityObjectLocalScale))
{
return false;
}
- if (!Approximately(childLocalScale, m_ChildObjectLocalScale))
+ // Adjust approximation based on precision
+ if (m_Precision == Precision.Half)
+ {
+ m_CurrentHalfPrecision = k_HalfPrecisionRot;
+ }
+ if (!ApproximatelyEuler(childLocalRotation, authorityObjectLocalRotation))
{
return false;
}
@@ -333,81 +377,133 @@ private bool AllInstancesKeptLocalTransformValues()
/// If not, it generates a message containing the axial values that did not match
/// the target/start local space values.
///
- private void WaitForAllChildrenLocalTransformValuesToMatch()
+ private void AllChildrenLocalTransformValuesMatch()
{
var success = WaitForConditionOrTimeOutWithTimeTravel(AllInstancesKeptLocalTransformValues);
- var infoMessage = string.Empty;
- if (s_GlobalTimeoutHelper.TimedOut)
+ //TimeTravelToNextTick();
+ var infoMessage = new System.Text.StringBuilder($"Timed out waiting for all children to have the correct local space values:\n");
+ var authorityObjectLocalPosition = m_AuthorityChildObject.transform.localPosition;
+ var authorityObjectLocalRotation = m_AuthorityChildObject.transform.localRotation.eulerAngles;
+ var authorityObjectLocalScale = m_AuthorityChildObject.transform.localScale;
+
+ if (s_GlobalTimeoutHelper.TimedOut || !success)
{
foreach (var childInstance in ChildObjectComponent.Instances)
{
var childLocalPosition = childInstance.transform.localPosition;
var childLocalRotation = childInstance.transform.localRotation.eulerAngles;
var childLocalScale = childInstance.transform.localScale;
-
- if (!Approximately(childLocalPosition, m_ChildObjectLocalPosition))
+ // Adjust approximation based on precision
+ if (m_Precision == Precision.Half)
{
- infoMessage += $"[{childInstance.name}] Child's Local Position ({childLocalPosition}) | Original Local Position ({m_ChildObjectLocalPosition})\n";
+ m_CurrentHalfPrecision = k_HalfPrecisionPosScale;
}
- if (!ApproximatelyEuler(childLocalRotation, m_ChildObjectLocalRotation))
+ if (!Approximately(childLocalPosition, authorityObjectLocalPosition))
{
- infoMessage += $"[{childInstance.name}] Child's Local Rotation ({childLocalRotation}) | Original Local Rotation ({m_ChildObjectLocalRotation})\n";
+ infoMessage.AppendLine($"[{childInstance.name}] Child's Local Position ({childLocalPosition}) | Authority Local Position ({authorityObjectLocalPosition})");
+ success = false;
}
- if (!Approximately(childLocalScale, m_ChildObjectLocalScale))
+ if (!Approximately(childLocalScale, authorityObjectLocalScale))
{
- infoMessage += $"[{childInstance.name}] Child's Local Scale ({childLocalScale}) | Original Local Rotation ({m_ChildObjectLocalScale})\n";
+ infoMessage.AppendLine($"[{childInstance.name}] Child's Local Scale ({childLocalScale}) | Authority Local Scale ({authorityObjectLocalScale})");
+ success = false;
+ }
+
+ // Adjust approximation based on precision
+ if (m_Precision == Precision.Half)
+ {
+ m_CurrentHalfPrecision = k_HalfPrecisionRot;
+ }
+ if (!ApproximatelyEuler(childLocalRotation, authorityObjectLocalRotation))
+ {
+ infoMessage.AppendLine($"[{childInstance.name}] Child's Local Rotation ({childLocalRotation}) | Authority Local Rotation ({authorityObjectLocalRotation})");
+ success = false;
}
}
- Assert.True(success, $"Timed out waiting for all children to have the correct local space values:\n {infoMessage}");
+ if (!success)
+ {
+ Assert.True(success, infoMessage.ToString());
+ }
}
}
+ private NetworkObject m_AuthorityParentObject;
+ private NetworkTransformTestComponent m_AuthorityParentNetworkTransform;
+ private NetworkObject m_AuthorityChildObject;
+ private ChildObjectComponent m_AuthorityChildNetworkTransform;
+
///
- /// Validates that local space transform values remain the same when a NetworkTransform is
- /// parented under another NetworkTransform
+ /// Validates that transform values remain the same when a NetworkTransform is
+ /// parented under another NetworkTransform under all of the possible axial conditions
+ /// as well as when the parent has a varying scale.
///
[Test]
- public void NetworkTransformParentedLocalSpaceTest([Values] Interpolation interpolation, [Values(0.5f, 1.0f, 5.0f)] float scale)
+ public void ParentedNetworkTransformTest([Values] Precision precision, [Values] Rotation rotation,
+ [Values] RotationCompression rotationCompression, [Values] Interpolation interpolation, [Values] bool worldPositionStays,
+ [Values(0.5f, 1.0f, 5.0f)] float scale)
{
- m_AuthoritativeTransform.Interpolate = interpolation == Interpolation.EnableInterpolate;
- m_NonAuthoritativeTransform.Interpolate = interpolation == Interpolation.EnableInterpolate;
- // Change the parent scale to assure that it will impact the child's scale when not Vector3.one
- if (m_AuthoritativeTransform.IsServerAuthoritative())
- {
- m_AuthoritativeTransform.transform.localScale = new Vector3(scale, scale, scale);
- }
- else
+ // Set the precision being used for threshold adjustments
+ m_Precision = precision;
+
+ // Get the NetworkManager that will have authority in order to spawn with the correct authority
+ var isServerAuthority = m_Authority == Authority.ServerAuthority;
+ var authorityNetworkManager = m_ServerNetworkManager;
+ if (!isServerAuthority)
{
- m_NonAuthoritativeTransform.transform.localScale = new Vector3(scale, scale, scale);
+ authorityNetworkManager = m_ClientNetworkManagers[0];
}
- var authoritativeChildObject = SpawnObject(m_ChildObjectToBeParented.gameObject, m_AuthoritativeTransform.NetworkManager);
- // Assure all of the child object instances are spawned
+ // Spawn a parent and child object
+ var serverSideParent = SpawnObject(m_ParentObject.gameObject, authorityNetworkManager).GetComponent();
+ var serverSideChild = SpawnObject(m_ChildObject.gameObject, authorityNetworkManager).GetComponent();
+
+ // Assure all of the child object instances are spawned before proceeding to parenting
var success = WaitForConditionOrTimeOutWithTimeTravel(AllChildObjectInstancesAreSpawned);
Assert.True(success, "Timed out waiting for all child instances to be spawned!");
- // Just a sanity check as it should have timed out before this check
- Assert.IsNotNull(ChildObjectComponent.ServerInstance, $"The server-side {nameof(ChildObjectComponent)} instance is null!");
- // This determines which parent on the server side should be the parent
- if (m_AuthoritativeTransform.IsServerAuthoritative())
- {
- Assert.True(ChildObjectComponent.ServerInstance.NetworkObject.TrySetParent(m_AuthoritativeTransform.transform, false), "[Authoritative] Failed to parent the child object!");
- }
- else
- {
- Assert.True(ChildObjectComponent.ServerInstance.NetworkObject.TrySetParent(m_NonAuthoritativeTransform.transform, false), "[Non-Authoritative] Failed to parent the child object!");
- }
+ // Get the authority parent and child instances
+ m_AuthorityParentObject = NetworkTransformTestComponent.AuthorityInstance.NetworkObject;
+ m_AuthorityChildObject = ChildObjectComponent.AuthorityInstance.NetworkObject;
+
+ // The child NetworkTransform will use world space when world position stays and
+ // local space when world position does not stay when parenting.
+ ChildObjectComponent.AuthorityInstance.InLocalSpace = !worldPositionStays;
+ ChildObjectComponent.AuthorityInstance.UseHalfFloatPrecision = precision == Precision.Half;
+ ChildObjectComponent.AuthorityInstance.UseQuaternionSynchronization = rotation == Rotation.Quaternion;
+ ChildObjectComponent.AuthorityInstance.UseQuaternionCompression = rotationCompression == RotationCompression.QuaternionCompress;
+
+ // Set whether we are interpolating or not
+ m_AuthorityParentNetworkTransform = m_AuthorityParentObject.GetComponent();
+ m_AuthorityParentNetworkTransform.Interpolate = interpolation == Interpolation.EnableInterpolate;
+ m_AuthorityChildNetworkTransform = m_AuthorityChildObject.GetComponent();
+ m_AuthorityChildNetworkTransform.Interpolate = interpolation == Interpolation.EnableInterpolate;
+
+ // Apply a scale to the parent object to make sure the scale on the child is properly updated on
+ // non-authority instances.
+ m_AuthorityParentObject.transform.localScale = new Vector3(scale, scale, scale);
+
+ // Allow one tick for authority to update these changes
+ TimeTravelToNextTick();
+
+ // Parent the child under the parent with the current world position stays setting
+ Assert.True(serverSideChild.TrySetParent(serverSideParent.transform, worldPositionStays), "[Server-Side Child] Failed to set child's parent!");
// This waits for all child instances to be parented
success = WaitForConditionOrTimeOutWithTimeTravel(AllChildObjectInstancesHaveChild);
Assert.True(success, "Timed out waiting for all instances to have parented a child!");
// This validates each child instance has preserved their local space values
- WaitForAllChildrenLocalTransformValuesToMatch();
+ AllChildrenLocalTransformValuesMatch();
- // This validates that a late joining client will synchronize to the other players with parented NetworkObjects
+ // Verify that a late joining client will synchronize to the parented NetworkObjects properly
CreateAndStartNewClientWithTimeTravel();
- WaitForAllChildrenLocalTransformValuesToMatch();
+
+ // Assure all of the child object instances are spawned (basically for the newly connected client)
+ success = WaitForConditionOrTimeOutWithTimeTravel(AllChildObjectInstancesAreSpawned);
+ Assert.True(success, "Timed out waiting for all child instances to be spawned!");
+
+ // Assure the newly connected client's child object's transform values are correct
+ AllChildrenLocalTransformValuesMatch();
}
///
From 1b5c2d03e505c75ffa7c45c10d06382db153db6c Mon Sep 17 00:00:00 2001
From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com>
Date: Fri, 28 Apr 2023 18:06:59 -0500
Subject: [PATCH 5/7] style
removing commented out code.
---
.../Tests/Runtime/NetworkTransform/NetworkTransformTests.cs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs
index 956edc1b12..0f246b2078 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformTests.cs
@@ -334,9 +334,6 @@ private bool AllChildObjectInstancesHaveChild()
///
private bool AllInstancesKeptLocalTransformValues()
{
- //var authorityObjectLocalPosition = ChildObjectComponent.ServerInstance.transform.localPosition;
- //var authorityObjectLocalRotation = ChildObjectComponent.ServerInstance.transform.localRotation.eulerAngles;
- //var authorityObjectLocalScale = ChildObjectComponent.ServerInstance.transform.localScale;
var authorityObjectLocalPosition = m_AuthorityChildObject.transform.localPosition;
var authorityObjectLocalRotation = m_AuthorityChildObject.transform.localRotation.eulerAngles;
var authorityObjectLocalScale = m_AuthorityChildObject.transform.localScale;
From 7209483c526d720ea0651ad1852b407b03f7ed09 Mon Sep 17 00:00:00 2001
From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com>
Date: Fri, 28 Apr 2023 18:36:02 -0500
Subject: [PATCH 6/7] update
Adding entry to changelog
---
com.unity.netcode.gameobjects/CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md
index ecfcaaec67..9642ab8c6a 100644
--- a/com.unity.netcode.gameobjects/CHANGELOG.md
+++ b/com.unity.netcode.gameobjects/CHANGELOG.md
@@ -11,7 +11,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Added
### Fixed
-
+- Fixed issue where parenting a NetworkTransform under a transform with a scale other than Vector3.one would result in incorrect values on non-authoritative instances. (#2538)
- Fixed Multiplayer Tools package installation docs page link on the NetworkManager popup. (#2526)
- Fixed a memory leak in `UnityTransport` that occurred if `StartClient` failed. (#2518)
- Fixed issue where a client could throw an exception if abruptly disconnected from a network session with one or more spawned `NetworkObject`(s). (#2510)
From 77596113db4af36abee2eb4de664b23bab510a36 Mon Sep 17 00:00:00 2001
From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com>
Date: Wed, 17 May 2023 07:42:43 -0500
Subject: [PATCH 7/7] fix
Migrating SetStateInternal into the Initialization method so it handles change of ownership.
---
.../Components/NetworkTransform.cs | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/com.unity.netcode.gameobjects/Components/NetworkTransform.cs b/com.unity.netcode.gameobjects/Components/NetworkTransform.cs
index a5eb83c555..587b263836 100644
--- a/com.unity.netcode.gameobjects/Components/NetworkTransform.cs
+++ b/com.unity.netcode.gameobjects/Components/NetworkTransform.cs
@@ -2392,16 +2392,6 @@ public override void OnNetworkSpawn()
m_CachedNetworkManager = NetworkManager;
Initialize();
- // This assures the initial spawning of the object synchronizes all connected clients
- // with the current transform values. This should not be placed within Initialize since
- // that can be invoked when ownership changes.
- if (CanCommitToTransform)
- {
- var currentPosition = GetSpaceRelativePosition();
- var currentRotation = GetSpaceRelativeRotation();
- // Teleport to current position
- SetStateInternal(currentPosition, currentRotation, transform.localScale, true);
- }
}
///
@@ -2472,6 +2462,7 @@ protected void Initialize()
CanCommitToTransform = IsServerAuthoritative() ? IsServer : IsOwner;
var replicatedState = ReplicatedNetworkState;
var currentPosition = GetSpaceRelativePosition();
+ var currentRotation = GetSpaceRelativeRotation();
if (CanCommitToTransform)
{
@@ -2483,6 +2474,9 @@ protected void Initialize()
// Authority only updates once per network tick
NetworkManager.NetworkTickSystem.Tick -= NetworkTickSystem_Tick;
NetworkManager.NetworkTickSystem.Tick += NetworkTickSystem_Tick;
+
+ // Teleport to current position
+ SetStateInternal(currentPosition, currentRotation, transform.localScale, true);
}
else
{
@@ -2494,9 +2488,9 @@ protected void Initialize()
NetworkManager.NetworkTickSystem.Tick -= NetworkTickSystem_Tick;
ResetInterpolatedStateToCurrentAuthoritativeState();
- m_CurrentPosition = GetSpaceRelativePosition();
+ m_CurrentPosition = currentPosition;
m_CurrentScale = transform.localScale;
- m_CurrentRotation = GetSpaceRelativeRotation();
+ m_CurrentRotation = currentRotation;
}