Skip to content
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
3b7d98a
fix
NoelStephensUnity Aug 3, 2022
19a4c88
update
NoelStephensUnity Aug 3, 2022
6150b21
fix
NoelStephensUnity Aug 3, 2022
11ddbd7
test
NoelStephensUnity Aug 3, 2022
053ee6e
fix
NoelStephensUnity Aug 3, 2022
4d4c658
style
NoelStephensUnity Aug 3, 2022
c0e94d6
Merge branch 'develop' into fix/networktransform-Bitset-not-being-pro…
NoelStephensUnity Aug 3, 2022
4744ee6
update
NoelStephensUnity Aug 4, 2022
e09e0a0
style
NoelStephensUnity Aug 4, 2022
7a2bdb3
style
NoelStephensUnity Aug 4, 2022
1100a1f
Merge branch 'develop' into fix/networktransform-Bitset-not-being-pro…
NoelStephensUnity Aug 4, 2022
ba114f7
fix
NoelStephensUnity Aug 5, 2022
e84cd5c
fix
NoelStephensUnity Aug 5, 2022
08f1ef4
manual test updates
NoelStephensUnity Aug 5, 2022
b15ce6a
update
NoelStephensUnity Aug 5, 2022
ef854bf
test update
NoelStephensUnity Aug 5, 2022
d2a68e1
update
NoelStephensUnity Aug 5, 2022
8e0e11d
fix
NoelStephensUnity Aug 6, 2022
5b2f6a2
test manual
NoelStephensUnity Aug 6, 2022
bc9ce02
manual test
NoelStephensUnity Aug 6, 2022
f267e7c
test manual
NoelStephensUnity Aug 6, 2022
8d0eb79
update
NoelStephensUnity Aug 6, 2022
cbfdf1f
fix
NoelStephensUnity Aug 8, 2022
ea8124d
fix
NoelStephensUnity Aug 8, 2022
7c2f265
update
NoelStephensUnity Aug 9, 2022
5e74820
Merge branch 'develop' into fix/networktransform-Bitset-not-being-pro…
NoelStephensUnity Aug 9, 2022
f98b373
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 9, 2022
4603d9a
fix
NoelStephensUnity Aug 9, 2022
504fa61
style
NoelStephensUnity Aug 9, 2022
fa8f56f
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 9, 2022
e0c91fd
update
NoelStephensUnity Aug 9, 2022
709705b
Merge branch 'develop' into fix/networktransform-Bitset-not-being-pro…
NoelStephensUnity Aug 9, 2022
dfd12bc
Merge branch 'fix/networktransform-Bitset-not-being-properly-reset' i…
NoelStephensUnity Aug 9, 2022
6166469
update
NoelStephensUnity Aug 9, 2022
3b63770
Merge branch 'fix/networktransform-Bitset-not-being-properly-reset' i…
NoelStephensUnity Aug 9, 2022
b39ca1a
update
NoelStephensUnity Aug 9, 2022
b55f88a
update
NoelStephensUnity Aug 9, 2022
e2d1cf6
update
NoelStephensUnity Aug 10, 2022
3b4cd8d
update
NoelStephensUnity Aug 10, 2022
5a164b1
style
NoelStephensUnity Aug 10, 2022
72494c7
style
NoelStephensUnity Aug 10, 2022
77f6ef2
update
NoelStephensUnity Aug 10, 2022
ddcbb0f
Test Manual
NoelStephensUnity Aug 10, 2022
1f5b5d7
update
NoelStephensUnity Aug 10, 2022
0855770
update
NoelStephensUnity Aug 10, 2022
ba84be3
tests update
NoelStephensUnity Aug 10, 2022
5c9c262
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 10, 2022
50058ea
Update
NoelStephensUnity Aug 11, 2022
c1abed1
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 11, 2022
0caa0c5
test
NoelStephensUnity Aug 11, 2022
e52e3c8
fix and update
NoelStephensUnity Aug 12, 2022
c33914a
fix
NoelStephensUnity Aug 12, 2022
7b6e609
test manual
NoelStephensUnity Aug 12, 2022
295f553
update
NoelStephensUnity Aug 12, 2022
5dbcee7
fix
NoelStephensUnity Aug 12, 2022
60f59af
update
NoelStephensUnity Aug 12, 2022
4a81b70
update
NoelStephensUnity Aug 14, 2022
3e0707e
style
NoelStephensUnity Aug 14, 2022
22ac853
test manual
NoelStephensUnity Aug 14, 2022
a1d6c64
style
NoelStephensUnity Aug 14, 2022
5db3f7e
style
NoelStephensUnity Aug 14, 2022
466717f
style
NoelStephensUnity Aug 14, 2022
39eed88
style
NoelStephensUnity Aug 14, 2022
5fe7c51
update
NoelStephensUnity Aug 14, 2022
9c92b22
update
NoelStephensUnity Aug 14, 2022
13672f9
update
NoelStephensUnity Aug 15, 2022
0cbab31
test manual update
NoelStephensUnity Aug 15, 2022
766ab5d
revert
NoelStephensUnity Aug 15, 2022
9c7004e
style
NoelStephensUnity Aug 15, 2022
7d7479b
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 16, 2022
07282c4
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 16, 2022
4326518
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 17, 2022
aaad7b3
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 17, 2022
c259e0f
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 17, 2022
c8738f5
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 17, 2022
bdce763
Merge branch 'develop' into fix/networktransform-teleport
NoelStephensUnity Aug 18, 2022
c998354
Style
NoelStephensUnity Aug 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
570 changes: 360 additions & 210 deletions com.unity.netcode.gameobjects/Components/NetworkTransform.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Collections;
#if NGO_TRANSFORM_DEBUG
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -57,7 +56,7 @@ protected override void OnCreatePlayerPrefab()
else
{
var networkTransform = m_PlayerPrefab.AddComponent<NetworkTransformTestComponent>();
networkTransform.Interpolate = false;
networkTransform.Interpolate = true;
}
}

Expand All @@ -74,8 +73,8 @@ protected override void OnServerAndClientsCreated()
protected override IEnumerator OnServerAndClientsConnected()
{
// Get the client player representation on both the server and the client side
m_ServerSideClientPlayer = m_PlayerNetworkObjects[m_ServerNetworkManager.LocalClientId][m_ClientNetworkManagers[0].LocalClientId];
m_ClientSideClientPlayer = m_PlayerNetworkObjects[m_ClientNetworkManagers[0].LocalClientId][m_ClientNetworkManagers[0].LocalClientId];
m_ServerSideClientPlayer = m_ServerNetworkManager.ConnectedClients[m_ClientNetworkManagers[0].LocalClientId].PlayerObject;
m_ClientSideClientPlayer = m_ClientNetworkManagers[0].LocalClient.PlayerObject;

// Get the NetworkTransformTestComponent to make sure the client side is ready before starting test
var otherSideNetworkTransformComponent = m_ClientSideClientPlayer.GetComponent<NetworkTransformTestComponent>();
Expand Down Expand Up @@ -118,38 +117,38 @@ public IEnumerator TestAuthoritativeTransformChangeOneAtATime([Values] bool test

authPlayerTransform.position = new Vector3(10, 20, 30);

yield return WaitForConditionOrTimeOut(() => otherSideNetworkTransform.transform.position.x > approximation);
yield return WaitForConditionOrTimeOut(ServerClientPositionMatches);

Assert.False(s_GlobalTimeoutHelper.TimedOut, $"timeout while waiting for position change! Otherside value {otherSideNetworkTransform.transform.position.x} vs. Approximation {approximation}");
AssertOnTimeout($"timeout while waiting for position change! Otherside value {otherSideNetworkTransform.transform.position.x} vs. Approximation {approximation}");

Assert.True(new Vector3(10, 20, 30) == otherSideNetworkTransform.transform.position, $"wrong position on ghost, {otherSideNetworkTransform.transform.position}"); // Vector3 already does float approximation with ==
//Assert.True(new Vector3(10, 20, 30) == otherSideNetworkTransform.transform.position, $"wrong position on ghost, {otherSideNetworkTransform.transform.position}"); // Vector3 already does float approximation with ==

// test rotation
authPlayerTransform.rotation = Quaternion.Euler(45, 40, 35); // using euler angles instead of quaternions directly to really see issues users might encounter
Assert.AreEqual(Quaternion.identity, otherSideNetworkTransform.transform.rotation, "wrong initial value for rotation"); // sanity check

yield return WaitForConditionOrTimeOut(() => otherSideNetworkTransform.transform.rotation.eulerAngles.x > approximation);
yield return WaitForConditionOrTimeOut(ServerClientRotationMatches);

Assert.False(s_GlobalTimeoutHelper.TimedOut, "timeout while waiting for rotation change");
AssertOnTimeout("timeout while waiting for rotation change");

// approximation needed here since eulerAngles isn't super precise.
Assert.LessOrEqual(Math.Abs(45 - otherSideNetworkTransform.transform.rotation.eulerAngles.x), approximation, $"wrong rotation on ghost on x, got {otherSideNetworkTransform.transform.rotation.eulerAngles.x}");
Assert.LessOrEqual(Math.Abs(40 - otherSideNetworkTransform.transform.rotation.eulerAngles.y), approximation, $"wrong rotation on ghost on y, got {otherSideNetworkTransform.transform.rotation.eulerAngles.y}");
Assert.LessOrEqual(Math.Abs(35 - otherSideNetworkTransform.transform.rotation.eulerAngles.z), approximation, $"wrong rotation on ghost on z, got {otherSideNetworkTransform.transform.rotation.eulerAngles.z}");
//// approximation needed here since eulerAngles isn't super precise.
//Assert.LessOrEqual(Math.Abs(45 - otherSideNetworkTransform.transform.rotation.eulerAngles.x), approximation, $"wrong rotation on ghost on x, got {otherSideNetworkTransform.transform.rotation.eulerAngles.x}");
Comment thread
NoelStephensUnity marked this conversation as resolved.
Outdated
//Assert.LessOrEqual(Math.Abs(40 - otherSideNetworkTransform.transform.rotation.eulerAngles.y), approximation, $"wrong rotation on ghost on y, got {otherSideNetworkTransform.transform.rotation.eulerAngles.y}");
//Assert.LessOrEqual(Math.Abs(35 - otherSideNetworkTransform.transform.rotation.eulerAngles.z), approximation, $"wrong rotation on ghost on z, got {otherSideNetworkTransform.transform.rotation.eulerAngles.z}");

// test scale
UnityEngine.Assertions.Assert.AreApproximatelyEqual(1f, otherSideNetworkTransform.transform.lossyScale.x, "wrong initial value for scale"); // sanity check
UnityEngine.Assertions.Assert.AreApproximatelyEqual(1f, otherSideNetworkTransform.transform.lossyScale.y, "wrong initial value for scale"); // sanity check
UnityEngine.Assertions.Assert.AreApproximatelyEqual(1f, otherSideNetworkTransform.transform.lossyScale.z, "wrong initial value for scale"); // sanity check
//UnityEngine.Assertions.Assert.AreApproximatelyEqual(1f, otherSideNetworkTransform.transform.lossyScale.x, "wrong initial value for scale"); // sanity check
//UnityEngine.Assertions.Assert.AreApproximatelyEqual(1f, otherSideNetworkTransform.transform.lossyScale.y, "wrong initial value for scale"); // sanity check
//UnityEngine.Assertions.Assert.AreApproximatelyEqual(1f, otherSideNetworkTransform.transform.lossyScale.z, "wrong initial value for scale"); // sanity check
authPlayerTransform.localScale = new Vector3(2, 3, 4);

yield return WaitForConditionOrTimeOut(() => otherSideNetworkTransform.transform.lossyScale.x > 1f + approximation);
yield return WaitForConditionOrTimeOut(ServerClientScaleMatches);

Assert.False(s_GlobalTimeoutHelper.TimedOut, "timeout while waiting for scale change");
AssertOnTimeout("timeout while waiting for scale change");

UnityEngine.Assertions.Assert.AreApproximatelyEqual(2f, otherSideNetworkTransform.transform.lossyScale.x, "wrong scale on ghost");
UnityEngine.Assertions.Assert.AreApproximatelyEqual(3f, otherSideNetworkTransform.transform.lossyScale.y, "wrong scale on ghost");
UnityEngine.Assertions.Assert.AreApproximatelyEqual(4f, otherSideNetworkTransform.transform.lossyScale.z, "wrong scale on ghost");
//UnityEngine.Assertions.Assert.AreApproximatelyEqual(2f, otherSideNetworkTransform.transform.lossyScale.x, "wrong scale on ghost");
//UnityEngine.Assertions.Assert.AreApproximatelyEqual(3f, otherSideNetworkTransform.transform.lossyScale.y, "wrong scale on ghost");
//UnityEngine.Assertions.Assert.AreApproximatelyEqual(4f, otherSideNetworkTransform.transform.lossyScale.z, "wrong scale on ghost");

// todo reparent and test
// todo test all public API
Expand Down Expand Up @@ -251,6 +250,93 @@ public IEnumerator TestRotationThresholdDeltaCheck()
Assert.IsTrue(results.isRotationDirty, $"Rotation was not dirty when rotated by {Mathf.DeltaAngle(0, serverEulerRotation.y)} degrees!");
}

private bool ValidateBitSetValues(NetworkTransform.NetworkTransformState serverState, NetworkTransform.NetworkTransformState clientState)
{
if (serverState.HasPositionX == clientState.HasPositionX && serverState.HasPositionY == clientState.HasPositionY && serverState.HasPositionZ == clientState.HasPositionZ &&
serverState.HasRotAngleX == clientState.HasRotAngleX && serverState.HasRotAngleY == clientState.HasRotAngleY && serverState.HasRotAngleZ == clientState.HasRotAngleZ &&
serverState.HasScaleX == clientState.HasScaleX && serverState.HasScaleY == clientState.HasScaleY && serverState.HasScaleZ == clientState.HasScaleZ)
{
return true;
}
return false;
}

/// <summary>
/// </summary>
[UnityTest]
public IEnumerator TestBitsetValue()
{
// Get the client player's NetworkTransform for both instances
var authoritativeNetworkTransform = m_ServerSideClientPlayer.GetComponent<NetworkTransformTestComponent>();
var otherSideNetworkTransform = m_ClientSideClientPlayer.GetComponent<NetworkTransformTestComponent>();
otherSideNetworkTransform.RotAngleThreshold = authoritativeNetworkTransform.RotAngleThreshold = 0.1f;
yield return s_DefaultWaitForTick;

authoritativeNetworkTransform.Interpolate = true;
otherSideNetworkTransform.Interpolate = true;

yield return s_DefaultWaitForTick;

authoritativeNetworkTransform.transform.rotation = Quaternion.Euler(1, 2, 3);
var serverLastSentState = authoritativeNetworkTransform.GetLastSentState();
var clientReplicatedState = otherSideNetworkTransform.ReplicatedNetworkState.Value;
yield return WaitForConditionOrTimeOut(() => ValidateBitSetValues(serverLastSentState, clientReplicatedState));
AssertOnTimeout($"Server-side sent Bitset state != Client-side replicated Bitset state!");

yield return WaitForConditionOrTimeOut(ServerClientRotationMatches);
AssertOnTimeout($"[Timed-Out] Server-side client rotation {m_ServerSideClientPlayer.transform.rotation.eulerAngles} != Client-side client rotation {m_ClientSideClientPlayer.transform.rotation.eulerAngles}");
}

private bool Aproximately(float x, float y)
{
return Mathf.Abs(x - y) <= k_AproximateDeltaVariance;
}

private const float k_AproximateDeltaVariance = 0.01f;

private bool ServerClientRotationMatches()
{
var serverEulerRotation = m_ServerSideClientPlayer.transform.rotation.eulerAngles;
var clientEulerRotation = m_ClientSideClientPlayer.transform.rotation.eulerAngles;
var xIsEqual = Aproximately(serverEulerRotation.x, clientEulerRotation.x);
var yIsEqual = Aproximately(serverEulerRotation.y, clientEulerRotation.y);
var zIsEqual = Aproximately(serverEulerRotation.z, clientEulerRotation.z);
if (!xIsEqual || !yIsEqual || !zIsEqual)
{
VerboseDebug($"Server-side client rotation {m_ServerSideClientPlayer.transform.rotation.eulerAngles} != Client-side client rotation {m_ClientSideClientPlayer.transform.rotation.eulerAngles}");
}
return xIsEqual && yIsEqual && zIsEqual;
}

private bool ServerClientPositionMatches()
{
var serverPosition = m_ServerSideClientPlayer.transform.position;
var clientPosition = m_ClientSideClientPlayer.transform.position;
var xIsEqual = Aproximately(serverPosition.x, clientPosition.x);
var yIsEqual = Aproximately(serverPosition.y, clientPosition.y);
var zIsEqual = Aproximately(serverPosition.z, clientPosition.z);
if (!xIsEqual || !yIsEqual || !zIsEqual)
{
VerboseDebug($"Server-side client position {m_ServerSideClientPlayer.transform.position} != Client-side client position {m_ClientSideClientPlayer.transform.position}");
}
return xIsEqual && yIsEqual && zIsEqual;
}

private bool ServerClientScaleMatches()
{
var serverScale = m_ServerSideClientPlayer.transform.localScale;
var clientScale = m_ClientSideClientPlayer.transform.localScale;
var xIsEqual = Aproximately(serverScale.x, clientScale.x);
var yIsEqual = Aproximately(serverScale.y, clientScale.y);
var zIsEqual = Aproximately(serverScale.z, clientScale.z);
if (!xIsEqual || !yIsEqual || !zIsEqual)
{
VerboseDebug($"Server-side client scale {m_ServerSideClientPlayer.transform.localScale} != Client-side client scale {m_ClientSideClientPlayer.transform.localScale}");
}
return xIsEqual && yIsEqual && zIsEqual;
}


/*
* ownership change
* test teleport with interpolation
Expand All @@ -259,7 +345,8 @@ public IEnumerator TestRotationThresholdDeltaCheck()
*/
protected override IEnumerator OnTearDown()
{
UnityEngine.Object.DestroyImmediate(m_PlayerPrefab);
m_EnableVerboseDebug = false;
Object.DestroyImmediate(m_PlayerPrefab);
yield return base.OnTearDown();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,19 @@ namespace Unity.Netcode.RuntimeTests
{
public class TransformInterpolationObject : NetworkBehaviour
{
// Set the minimum threshold which we will use as our margin of error
public const float MinThreshold = 0.001f;

public bool CheckPosition;
public bool IsMoving;
public bool IsFixed;

private void Update()
{
// Since the local position is transformed from local to global and vice-versa on the server and client
// it may accumulate some error. We allow an error of 0.01 over the range of 1000 used in this test.
// This requires precision to 5 digits, so it doesn't weaken the test, while preventing spurious failures
const float maxRoundingError = 0.01f;

// Check the position of the nested object on the client
if (CheckPosition)
{
if (transform.position.y < -maxRoundingError || transform.position.y > 100.0f + maxRoundingError)
if (transform.position.y < -MinThreshold || transform.position.y > 100.0f + MinThreshold)
{
Debug.LogError($"Interpolation failure. transform.position.y is {transform.position.y}. Should be between 0.0 and 100.0");
}
Expand Down Expand Up @@ -65,7 +63,8 @@ public class TransformInterpolationTests : NetcodeIntegrationTest
protected override void OnServerAndClientsCreated()
{
m_PrefabToSpawn = CreateNetworkObjectPrefab("InterpTestObject");
m_PrefabToSpawn.AddComponent<NetworkTransform>();
var networkTransform = m_PrefabToSpawn.AddComponent<NetworkTransform>();
networkTransform.PositionThreshold = TransformInterpolationObject.MinThreshold;
m_PrefabToSpawn.AddComponent<TransformInterpolationObject>();
}

Expand All @@ -85,8 +84,6 @@ private IEnumerator RefreshNetworkObjects()
m_SpawnedObjectOnClient = s_GlobalNetworkObjects[clientId][m_SpawnedAsNetworkObject.NetworkObjectId];
// make sure the objects are set with the right network manager
m_SpawnedObjectOnClient.NetworkManagerOwner = m_ClientNetworkManagers[0];


}

[UnityTest]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,10 @@ PrefabInstance:
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4600632750638426092, guid: 29cabf623d47bb345a9bb4140e4397d7,
type: 3}
propertyPath: PositionThreshold
value: 0.01
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 29cabf623d47bb345a9bb4140e4397d7, type: 3}
13 changes: 8 additions & 5 deletions testproject/Assets/Prefabs/Player.prefab
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4079352819444256614}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 5, y: 0.625, z: 5}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1.25, y: 1.25, z: 1.25}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3519470446676406143}
m_Father: {fileID: 0}
Expand All @@ -62,12 +63,11 @@ MonoBehaviour:
SyncScaleX: 1
SyncScaleY: 1
SyncScaleZ: 1
PositionThreshold: 0
RotAngleThreshold: 0
ScaleThreshold: 0
PositionThreshold: 0.01
RotAngleThreshold: 0.01
ScaleThreshold: 0.1
InLocalSpace: 0
Interpolate: 1
FixedSendsPerSecond: 15
--- !u!114 &-3775814466963834669
MonoBehaviour:
m_ObjectHideFlags: 0
Expand Down Expand Up @@ -103,6 +103,7 @@ MeshRenderer:
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
Expand Down Expand Up @@ -239,6 +240,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1.045, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4079352819444256611}
m_RootOrder: 0
Expand All @@ -262,6 +264,7 @@ MeshRenderer:
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
Expand Down
Loading