com.unity.netcode.gameobjects@1.5.1
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com). ## [1.5.1] - 2023-06-07 ### Added - Added support for serializing `NativeArray<>` and `NativeList<>` in `FastBufferReader`/`FastBufferWriter`, `BufferSerializer`, `NetworkVariable`, and RPCs. (To use `NativeList<>`, add `UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT` to your Scripting Define Symbols in `Project Settings > Player`) (#2375) - The location of the automatically-created default network prefab list can now be configured (#2544) - Added: Message size limits (max single message and max fragmented message) can now be set using NetworkManager.MaximumTransmissionUnitSize and NetworkManager.MaximumFragmentedMessageSize for transports that don't work with the default values (#2530) - Added `NetworkObject.SpawnWithObservers` property (default is true) that when set to false will spawn a `NetworkObject` with no observers and will not be spawned on any client until `NetworkObject.NetworkShow` is invoked. (#2568) ### Fixed - Fixed: Fixed a null reference in codegen in some projects (#2581) - Fixed issue where the `OnClientDisconnected` client identifier was incorrect after a pending client connection was denied. (#2569) - Fixed warning "Runtime Network Prefabs was not empty at initialization time." being erroneously logged when no runtime network prefabs had been added (#2565) - Fixed issue where some temporary debug console logging was left in a merged PR. (#2562) - Fixed the "Generate Default Network Prefabs List" setting not loading correctly and always reverting to being checked. (#2545) - Fixed issue where users could not use NetworkSceneManager.VerifySceneBeforeLoading to exclude runtime generated scenes from client synchronization. (#2550) - Fixed missing value on `NetworkListEvent` for `EventType.RemoveAt` events. (#2542,#2543) - 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 issue where a server would include scene migrated and then despawned NetworkObjects to a client that was being synchronized. (#2532) - Fixed the inspector throwing exceptions when attempting to render `NetworkVariable`s of enum types. (#2529) - Making a `NetworkVariable` with an `INetworkSerializable` type that doesn't meet the `new()` constraint will now create a compile-time error instead of an editor crash (#2528) - Fixed Multiplayer Tools package installation docs page link on the NetworkManager popup. (#2526) - Fixed an exception and error logging when two different objects are shown and hidden on the same frame (#2524) - 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) - Fixed issue where invalid endpoint addresses were not being detected and returning false from NGO UnityTransport. (#2496) - Fixed some errors that could occur if a connection is lost and the loss is detected when attempting to write to the socket. (#2495) ## Changed - Adding network prefabs before NetworkManager initialization is now supported. (#2565) - Connecting clients being synchronized now switch to the server's active scene before spawning and synchronizing NetworkObjects. (#2532) - Updated `UnityTransport` dependency on `com.unity.transport` to 1.3.4. (#2533) - Improved performance of NetworkBehaviour initialization by replacing reflection when initializing NetworkVariables with compile-time code generation, which should help reduce hitching during additive scene loads. (#2522)
This commit is contained in:
@@ -37,10 +37,17 @@ namespace Unity.Netcode.RuntimeTests
|
||||
return ServerAuthority;
|
||||
}
|
||||
|
||||
public static NetworkTransformTestComponent AuthorityInstance;
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
base.OnNetworkSpawn();
|
||||
|
||||
if (CanCommitToTransform)
|
||||
{
|
||||
AuthorityInstance = this;
|
||||
}
|
||||
|
||||
ReadyToReceivePositionUpdate = true;
|
||||
}
|
||||
|
||||
@@ -59,31 +66,38 @@ namespace Unity.Netcode.RuntimeTests
|
||||
/// <summary>
|
||||
/// Helper component for NetworkTransform parenting tests
|
||||
/// </summary>
|
||||
public class ChildObjectComponent : NetworkBehaviour
|
||||
public class ChildObjectComponent : NetworkTransform
|
||||
{
|
||||
public static readonly List<ChildObjectComponent> Instances = new List<ChildObjectComponent>();
|
||||
public static ChildObjectComponent ServerInstance { get; internal set; }
|
||||
public static ChildObjectComponent AuthorityInstance { get; internal set; }
|
||||
public static readonly Dictionary<ulong, NetworkObject> ClientInstances = new Dictionary<ulong, NetworkObject>();
|
||||
|
||||
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 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
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 @@ namespace Unity.Netcode.RuntimeTests
|
||||
Quaternion
|
||||
}
|
||||
|
||||
public enum RotationCompression
|
||||
{
|
||||
None,
|
||||
QuaternionCompress
|
||||
}
|
||||
|
||||
|
||||
public enum TransformSpace
|
||||
{
|
||||
World,
|
||||
@@ -190,6 +212,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
protected override void OnInlineSetup()
|
||||
{
|
||||
NetworkTransformTestComponent.AuthorityInstance = null;
|
||||
m_Precision = Precision.Full;
|
||||
ChildObjectComponent.Reset();
|
||||
}
|
||||
@@ -209,17 +232,22 @@ namespace Unity.Netcode.RuntimeTests
|
||||
protected override void OnServerAndClientsCreated()
|
||||
{
|
||||
var childObject = CreateNetworkObjectPrefab("ChildObject");
|
||||
childObject.AddComponent<ChildObjectComponent>();
|
||||
var childNetworkTransform = childObject.AddComponent<NetworkTransform>();
|
||||
childNetworkTransform.InLocalSpace = true;
|
||||
m_ChildObjectToBeParented = childObject.GetComponent<NetworkObject>();
|
||||
var childNetworkTransform = childObject.AddComponent<ChildObjectComponent>();
|
||||
childNetworkTransform.ServerAuthority = m_Authority == Authority.ServerAuthority;
|
||||
m_ChildObject = childObject.GetComponent<NetworkObject>();
|
||||
|
||||
var parentObject = CreateNetworkObjectPrefab("ParentObject");
|
||||
var parentNetworkTransform = parentObject.AddComponent<NetworkTransformTestComponent>();
|
||||
parentNetworkTransform.ServerAuthority = m_Authority == Authority.ServerAuthority;
|
||||
m_ParentObject = parentObject.GetComponent<NetworkObject>();
|
||||
|
||||
|
||||
// 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 @@ namespace Unity.Netcode.RuntimeTests
|
||||
/// <returns></returns>
|
||||
private bool AllChildObjectInstancesAreSpawned()
|
||||
{
|
||||
if (ChildObjectComponent.ServerInstance == null)
|
||||
if (ChildObjectComponent.AuthorityInstance == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -306,21 +334,34 @@ namespace Unity.Netcode.RuntimeTests
|
||||
/// </summary>
|
||||
private bool AllInstancesKeptLocalTransformValues()
|
||||
{
|
||||
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,68 +374,133 @@ namespace Unity.Netcode.RuntimeTests
|
||||
/// If not, it generates a message containing the axial values that did not match
|
||||
/// the target/start local space values.
|
||||
/// </summary>
|
||||
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;
|
||||
// Adjust approximation based on precision
|
||||
if (m_Precision == Precision.Half)
|
||||
{
|
||||
m_CurrentHalfPrecision = k_HalfPrecisionPosScale;
|
||||
}
|
||||
if (!Approximately(childLocalPosition, authorityObjectLocalPosition))
|
||||
{
|
||||
infoMessage.AppendLine($"[{childInstance.name}] Child's Local Position ({childLocalPosition}) | Authority Local Position ({authorityObjectLocalPosition})");
|
||||
success = false;
|
||||
}
|
||||
if (!Approximately(childLocalScale, authorityObjectLocalScale))
|
||||
{
|
||||
infoMessage.AppendLine($"[{childInstance.name}] Child's Local Scale ({childLocalScale}) | Authority Local Scale ({authorityObjectLocalScale})");
|
||||
success = false;
|
||||
}
|
||||
|
||||
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_HalfPrecisionRot;
|
||||
}
|
||||
if (!ApproximatelyEuler(childLocalRotation, m_ChildObjectLocalRotation))
|
||||
if (!ApproximatelyEuler(childLocalRotation, authorityObjectLocalRotation))
|
||||
{
|
||||
infoMessage += $"[{childInstance.name}] Child's Local Rotation ({childLocalRotation}) | Original Local Rotation ({m_ChildObjectLocalRotation})\n";
|
||||
}
|
||||
if (!Approximately(childLocalScale, m_ChildObjectLocalScale))
|
||||
{
|
||||
infoMessage += $"[{childInstance.name}] Child's Local Scale ({childLocalScale}) | Original Local Rotation ({m_ChildObjectLocalScale})\n";
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void NetworkTransformParentedLocalSpaceTest([Values] Interpolation interpolation)
|
||||
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;
|
||||
var authoritativeChildObject = SpawnObject(m_ChildObjectToBeParented.gameObject, m_AuthoritativeTransform.NetworkManager);
|
||||
// Set the precision being used for threshold adjustments
|
||||
m_Precision = precision;
|
||||
|
||||
// Assure all of the child object instances are spawned
|
||||
// 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)
|
||||
{
|
||||
authorityNetworkManager = m_ClientNetworkManagers[0];
|
||||
}
|
||||
|
||||
// Spawn a parent and child object
|
||||
var serverSideParent = SpawnObject(m_ParentObject.gameObject, authorityNetworkManager).GetComponent<NetworkObject>();
|
||||
var serverSideChild = SpawnObject(m_ChildObject.gameObject, authorityNetworkManager).GetComponent<NetworkObject>();
|
||||
|
||||
// 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<NetworkTransformTestComponent>();
|
||||
m_AuthorityParentNetworkTransform.Interpolate = interpolation == Interpolation.EnableInterpolate;
|
||||
m_AuthorityChildNetworkTransform = m_AuthorityChildObject.GetComponent<ChildObjectComponent>();
|
||||
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();
|
||||
|
||||
// Verify that a late joining client will synchronize to the parented NetworkObjects properly
|
||||
CreateAndStartNewClientWithTimeTravel();
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user