com.unity.netcode.gameobjects@1.5.2
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.2] - 2023-07-24 ### Added ### Fixed - Fixed issue where `NetworkClient.OwnedObjects` was not returning any owned objects due to the `NetworkClient.IsConnected` not being properly set. (#2631) - Fixed a crash when calling TrySetParent with a null Transform (#2625) - Fixed issue where a `NetworkTransform` using full precision state updates was losing transform state updates when interpolation was enabled. (#2624) - Fixed issue where `NetworkObject.SpawnWithObservers` was not being honored for late joining clients. (#2623) - Fixed issue where invoking `NetworkManager.Shutdown` multiple times, depending upon the timing, could cause an exception. (#2622) - Fixed issue where removing ownership would not notify the server that it gained ownership. This also resolves the issue where an owner authoritative NetworkTransform would not properly initialize upon removing ownership from a remote client. (#2618) - Fixed ILPP issues when using CoreCLR and for certain dedicated server builds. (#2614) - Fixed an ILPP compile error when creating a generic NetworkBehaviour singleton with a static T instance. (#2603) ### Changed
This commit is contained in:
17
CHANGELOG.md
17
CHANGELOG.md
@@ -6,6 +6,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
|
||||
Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).
|
||||
|
||||
## [1.5.2] - 2023-07-24
|
||||
|
||||
### Added
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed issue where `NetworkClient.OwnedObjects` was not returning any owned objects due to the `NetworkClient.IsConnected` not being properly set. (#2631)
|
||||
- Fixed a crash when calling TrySetParent with a null Transform (#2625)
|
||||
- Fixed issue where a `NetworkTransform` using full precision state updates was losing transform state updates when interpolation was enabled. (#2624)
|
||||
- Fixed issue where `NetworkObject.SpawnWithObservers` was not being honored for late joining clients. (#2623)
|
||||
- Fixed issue where invoking `NetworkManager.Shutdown` multiple times, depending upon the timing, could cause an exception. (#2622)
|
||||
- Fixed issue where removing ownership would not notify the server that it gained ownership. This also resolves the issue where an owner authoritative NetworkTransform would not properly initialize upon removing ownership from a remote client. (#2618)
|
||||
- Fixed ILPP issues when using CoreCLR and for certain dedicated server builds. (#2614)
|
||||
- Fixed an ILPP compile error when creating a generic NetworkBehaviour singleton with a static T instance. (#2603)
|
||||
|
||||
### Changed
|
||||
|
||||
## [1.5.1] - 2023-06-07
|
||||
|
||||
### Added
|
||||
|
||||
@@ -1159,8 +1159,11 @@ namespace Unity.Netcode.Components
|
||||
// Non-Authoritative's current position, scale, and rotation that is used to assure the non-authoritative side cannot make adjustments to
|
||||
// the portions of the transform being synchronized.
|
||||
private Vector3 m_CurrentPosition;
|
||||
private Vector3 m_TargetPosition;
|
||||
private Vector3 m_CurrentScale;
|
||||
private Vector3 m_TargetScale;
|
||||
private Quaternion m_CurrentRotation;
|
||||
private Vector3 m_TargetRotation;
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -2009,6 +2012,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
|
||||
m_CurrentPosition = currentPosition;
|
||||
m_TargetPosition = currentPosition;
|
||||
|
||||
// Apply the position
|
||||
if (newState.InLocalSpace)
|
||||
@@ -2026,7 +2030,6 @@ namespace Unity.Netcode.Components
|
||||
if (UseHalfFloatPrecision)
|
||||
{
|
||||
currentScale = newState.Scale;
|
||||
m_CurrentScale = currentScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2049,6 +2052,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
|
||||
m_CurrentScale = currentScale;
|
||||
m_TargetScale = currentScale;
|
||||
m_ScaleInterpolator.ResetTo(currentScale, sentTime);
|
||||
|
||||
// Apply the adjusted scale
|
||||
@@ -2082,6 +2086,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
|
||||
m_CurrentRotation = currentRotation;
|
||||
m_TargetRotation = currentRotation.eulerAngles;
|
||||
m_RotationInterpolator.ResetTo(currentRotation, sentTime);
|
||||
|
||||
if (InLocalSpace)
|
||||
@@ -2158,28 +2163,29 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
var currentPosition = GetSpaceRelativePosition();
|
||||
var newTargetPosition = m_TargetPosition;
|
||||
if (m_LocalAuthoritativeNetworkState.HasPositionX)
|
||||
{
|
||||
currentPosition.x = m_LocalAuthoritativeNetworkState.PositionX;
|
||||
newTargetPosition.x = m_LocalAuthoritativeNetworkState.PositionX;
|
||||
}
|
||||
|
||||
if (m_LocalAuthoritativeNetworkState.HasPositionY)
|
||||
{
|
||||
currentPosition.y = m_LocalAuthoritativeNetworkState.PositionY;
|
||||
newTargetPosition.y = m_LocalAuthoritativeNetworkState.PositionY;
|
||||
}
|
||||
|
||||
if (m_LocalAuthoritativeNetworkState.HasPositionZ)
|
||||
{
|
||||
currentPosition.z = m_LocalAuthoritativeNetworkState.PositionZ;
|
||||
newTargetPosition.z = m_LocalAuthoritativeNetworkState.PositionZ;
|
||||
}
|
||||
UpdatePositionInterpolator(currentPosition, sentTime);
|
||||
UpdatePositionInterpolator(newTargetPosition, sentTime);
|
||||
m_TargetPosition = newTargetPosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_LocalAuthoritativeNetworkState.HasScaleChange)
|
||||
{
|
||||
var currentScale = transform.localScale;
|
||||
var currentScale = m_TargetScale;
|
||||
if (UseHalfFloatPrecision)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
@@ -2207,6 +2213,7 @@ namespace Unity.Netcode.Components
|
||||
currentScale.z = m_LocalAuthoritativeNetworkState.ScaleZ;
|
||||
}
|
||||
}
|
||||
m_TargetScale = currentScale;
|
||||
m_ScaleInterpolator.AddMeasurement(currentScale, sentTime);
|
||||
}
|
||||
|
||||
@@ -2221,7 +2228,9 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
currentEulerAngles = m_TargetRotation;
|
||||
// Adjust based on which axis changed
|
||||
// (both half precision and full precision apply Eulers to the RotAngle properties when reading the update)
|
||||
if (m_LocalAuthoritativeNetworkState.HasRotAngleX)
|
||||
{
|
||||
currentEulerAngles.x = m_LocalAuthoritativeNetworkState.RotAngleX;
|
||||
@@ -2236,6 +2245,7 @@ namespace Unity.Netcode.Components
|
||||
{
|
||||
currentEulerAngles.z = m_LocalAuthoritativeNetworkState.RotAngleZ;
|
||||
}
|
||||
m_TargetRotation = currentEulerAngles;
|
||||
currentRotation.eulerAngles = currentEulerAngles;
|
||||
}
|
||||
|
||||
@@ -2489,8 +2499,11 @@ namespace Unity.Netcode.Components
|
||||
|
||||
ResetInterpolatedStateToCurrentAuthoritativeState();
|
||||
m_CurrentPosition = currentPosition;
|
||||
m_TargetPosition = currentPosition;
|
||||
m_CurrentScale = transform.localScale;
|
||||
m_TargetScale = transform.localScale;
|
||||
m_CurrentRotation = currentRotation;
|
||||
m_TargetRotation = currentRotation.eulerAngles;
|
||||
|
||||
}
|
||||
|
||||
@@ -2649,7 +2662,7 @@ namespace Unity.Netcode.Components
|
||||
var serverTime = NetworkManager.ServerTime;
|
||||
var cachedDeltaTime = NetworkManager.RealTimeProvider.DeltaTime;
|
||||
var cachedServerTime = serverTime.Time;
|
||||
// TODO: Investigate Further
|
||||
|
||||
// With owner authoritative mode, non-authority clients can lag behind
|
||||
// by more than 1 tick period of time. The current "solution" for now
|
||||
// is to make their cachedRenderTime run 2 ticks behind.
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
|
||||
public static bool IsSubclassOf(this TypeDefinition typeDefinition, string classTypeFullName)
|
||||
{
|
||||
if (!typeDefinition.IsClass)
|
||||
if (typeDefinition == null || !typeDefinition.IsClass)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -154,6 +154,10 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
|
||||
public static bool IsSubclassOf(this TypeReference typeReference, TypeReference baseClass)
|
||||
{
|
||||
if (typeReference == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var type = typeReference.Resolve();
|
||||
if (type?.BaseType == null || type.BaseType.Name == nameof(Object))
|
||||
{
|
||||
|
||||
@@ -396,6 +396,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
#endif
|
||||
private MethodReference m_NetworkVariableSerializationTypes_InitializeEqualityChecker_ManagedClassEquals_MethodRef;
|
||||
|
||||
private MethodReference m_RuntimeInitializeOnLoadAttribute_Ctor;
|
||||
|
||||
private MethodReference m_ExceptionCtorMethodReference;
|
||||
private MethodReference m_List_NetworkVariableBase_Add;
|
||||
|
||||
@@ -509,6 +511,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
}
|
||||
}
|
||||
|
||||
m_RuntimeInitializeOnLoadAttribute_Ctor = moduleDefinition.ImportReference(typeof(RuntimeInitializeOnLoadMethodAttribute).GetConstructor(new Type[] { }));
|
||||
|
||||
TypeDefinition networkManagerTypeDef = null;
|
||||
TypeDefinition networkBehaviourTypeDef = null;
|
||||
TypeDefinition networkVariableBaseTypeDef = null;
|
||||
@@ -1200,19 +1204,14 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
|
||||
if (rpcHandlers.Count > 0 || rpcNames.Count > 0)
|
||||
{
|
||||
var staticCtorMethodDef = typeDefinition.GetStaticConstructor();
|
||||
if (staticCtorMethodDef == null)
|
||||
{
|
||||
staticCtorMethodDef = new MethodDefinition(
|
||||
".cctor", // Static Constructor (constant-constructor)
|
||||
MethodAttributes.HideBySig |
|
||||
MethodAttributes.SpecialName |
|
||||
MethodAttributes.RTSpecialName |
|
||||
var staticCtorMethodDef = new MethodDefinition(
|
||||
$"InitializeRPCS_{typeDefinition.Name}",
|
||||
MethodAttributes.Assembly |
|
||||
MethodAttributes.Static,
|
||||
typeDefinition.Module.TypeSystem.Void);
|
||||
staticCtorMethodDef.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
|
||||
typeDefinition.Methods.Add(staticCtorMethodDef);
|
||||
}
|
||||
staticCtorMethodDef.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
|
||||
staticCtorMethodDef.CustomAttributes.Add(new CustomAttribute(m_RuntimeInitializeOnLoadAttribute_Ctor));
|
||||
typeDefinition.Methods.Add(staticCtorMethodDef);
|
||||
|
||||
var instructions = new List<Instruction>();
|
||||
var processor = staticCtorMethodDef.Body.GetILProcessor();
|
||||
@@ -1254,7 +1253,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
baseGetTypeNameMethod.ReturnType)
|
||||
{
|
||||
ImplAttributes = baseGetTypeNameMethod.ImplAttributes,
|
||||
SemanticsAttributes = baseGetTypeNameMethod.SemanticsAttributes
|
||||
SemanticsAttributes = baseGetTypeNameMethod.SemanticsAttributes,
|
||||
IsFamilyOrAssembly = true
|
||||
};
|
||||
|
||||
var processor = newGetTypeNameMethod.Body.GetILProcessor();
|
||||
@@ -2225,6 +2225,12 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
}
|
||||
field = new FieldReference(fieldDefinition.Name, fieldDefinition.FieldType, genericType);
|
||||
}
|
||||
|
||||
if (field.FieldType.Resolve() == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!field.FieldType.IsArray && !field.FieldType.Resolve().IsArray && field.FieldType.IsSubclassOf(m_NetworkVariableBase_TypeRef))
|
||||
{
|
||||
// if({variable} == null) {
|
||||
|
||||
@@ -98,6 +98,14 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
fieldDefinition.IsPublic = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var nestedTypeDefinition in typeDefinition.NestedTypes)
|
||||
{
|
||||
if (nestedTypeDefinition.Name == nameof(NetworkManager.RpcReceiveHandler))
|
||||
{
|
||||
nestedTypeDefinition.IsNestedPublic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessNetworkBehaviour(TypeDefinition typeDefinition)
|
||||
@@ -114,7 +122,7 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
{
|
||||
if (fieldDefinition.Name == nameof(NetworkBehaviour.__rpc_exec_stage) || fieldDefinition.Name == nameof(NetworkBehaviour.NetworkVariableFields))
|
||||
{
|
||||
fieldDefinition.IsFamily = true;
|
||||
fieldDefinition.IsFamilyOrAssembly = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +138,11 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
{
|
||||
methodDefinition.IsFamily = true;
|
||||
}
|
||||
|
||||
if (methodDefinition.Name == nameof(NetworkBehaviour.__getTypeName))
|
||||
{
|
||||
methodDefinition.IsFamilyOrAssembly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,15 +36,11 @@ namespace Unity.Netcode
|
||||
/// <summary>
|
||||
/// The ClientId of the NetworkClient
|
||||
/// </summary>
|
||||
// TODO-2023-Q2: Determine if we want to make this property a public get and internal/private set
|
||||
// There is no reason for a user to want to set this, but this will fail the package-validation-suite
|
||||
public ulong ClientId;
|
||||
|
||||
/// <summary>
|
||||
/// The PlayerObject of the Client
|
||||
/// </summary>
|
||||
// TODO-2023-Q2: Determine if we want to make this property a public get and internal/private set
|
||||
// There is no reason for a user to want to set this, but this will fail the package-validation-suite
|
||||
public NetworkObject PlayerObject;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace Unity.Netcode
|
||||
/// - Processing <see cref="NetworkEvent"/>s.
|
||||
/// - Client Disconnection
|
||||
/// </summary>
|
||||
// TODO 2023-Q2: Discuss what kind of public API exposure we want for this
|
||||
public sealed class NetworkConnectionManager
|
||||
{
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
@@ -628,6 +627,8 @@ namespace Unity.Netcode
|
||||
};
|
||||
if (!NetworkManager.NetworkConfig.EnableSceneManagement)
|
||||
{
|
||||
// Update the observed spawned NetworkObjects for the newly connected player when scene management is disabled
|
||||
NetworkManager.SpawnManager.UpdateObservedNetworkObjects(ownerClientId);
|
||||
if (NetworkManager.SpawnManager.SpawnedObjectsList.Count != 0)
|
||||
{
|
||||
message.SpawnedObjectsList = NetworkManager.SpawnManager.SpawnedObjectsList;
|
||||
@@ -651,12 +652,13 @@ namespace Unity.Netcode
|
||||
SendMessage(ref message, NetworkDelivery.ReliableFragmentedSequenced, ownerClientId);
|
||||
message.MessageVersions.Dispose();
|
||||
|
||||
// If scene management is enabled, then let NetworkSceneManager handle the initial scene and NetworkObject synchronization
|
||||
// If scene management is disabled, then we are done and notify the local host-server the client is connected
|
||||
if (!NetworkManager.NetworkConfig.EnableSceneManagement)
|
||||
{
|
||||
NetworkManager.ConnectedClients[ownerClientId].IsConnected = true;
|
||||
InvokeOnClientConnectedCallback(ownerClientId);
|
||||
}
|
||||
else
|
||||
else // Otherwise, let NetworkSceneManager handle the initial scene and NetworkObject synchronization
|
||||
{
|
||||
NetworkManager.SceneManager.SynchronizeNetworkObjects(ownerClientId);
|
||||
}
|
||||
@@ -665,6 +667,7 @@ namespace Unity.Netcode
|
||||
{
|
||||
LocalClient = client;
|
||||
NetworkManager.SpawnManager.UpdateObservedNetworkObjects(ownerClientId);
|
||||
LocalClient.IsConnected = true;
|
||||
}
|
||||
|
||||
if (!response.CreatePlayerObject || (response.PlayerPrefabHash == null && NetworkManager.NetworkConfig.PlayerPrefab == null))
|
||||
@@ -730,12 +733,10 @@ namespace Unity.Netcode
|
||||
internal NetworkClient AddClient(ulong clientId)
|
||||
{
|
||||
var networkClient = LocalClient;
|
||||
if (clientId != NetworkManager.ServerClientId)
|
||||
{
|
||||
networkClient = new NetworkClient();
|
||||
networkClient.SetRole(isServer: false, isClient: true, NetworkManager);
|
||||
networkClient.ClientId = clientId;
|
||||
}
|
||||
|
||||
networkClient = new NetworkClient();
|
||||
networkClient.SetRole(clientId == NetworkManager.ServerClientId, isClient: true, NetworkManager);
|
||||
networkClient.ClientId = clientId;
|
||||
|
||||
ConnectedClients.Add(clientId, networkClient);
|
||||
ConnectedClientsList.Add(networkClient);
|
||||
@@ -799,7 +800,6 @@ namespace Unity.Netcode
|
||||
else
|
||||
{
|
||||
// Handle changing ownership and prefab handlers
|
||||
// TODO-2023: Look into whether in-scene placed NetworkObjects could be destroyed if ownership changes to a client
|
||||
for (int i = clientOwnedObjects.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var ownedObject = clientOwnedObjects[i];
|
||||
|
||||
@@ -18,8 +18,6 @@ namespace Unity.Netcode
|
||||
Server = 1,
|
||||
Client = 2
|
||||
}
|
||||
|
||||
|
||||
// NetworkBehaviourILPP will override this in derived classes to return the name of the concrete type
|
||||
internal virtual string __getTypeName() => nameof(NetworkBehaviour);
|
||||
|
||||
@@ -98,7 +96,6 @@ namespace Unity.Netcode
|
||||
}
|
||||
|
||||
bufferWriter.Dispose();
|
||||
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
if (NetworkManager.__rpc_name_table.TryGetValue(rpcMethodId, out var rpcMethodName))
|
||||
{
|
||||
@@ -230,7 +227,6 @@ namespace Unity.Netcode
|
||||
}
|
||||
|
||||
bufferWriter.Dispose();
|
||||
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
if (NetworkManager.__rpc_name_table.TryGetValue(rpcMethodId, out var rpcMethodName))
|
||||
{
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Unity.Netcode
|
||||
m_NetworkManager.NetworkTickSystem.Tick -= NetworkBehaviourUpdater_Tick;
|
||||
}
|
||||
|
||||
// TODO 2023-Q2: Order of operations requires NetworkVariable updates first then showing NetworkObjects
|
||||
// Order of operations requires NetworkVariable updates first then showing NetworkObjects
|
||||
private void NetworkBehaviourUpdater_Tick()
|
||||
{
|
||||
// First update NetworkVariables
|
||||
|
||||
@@ -59,13 +59,12 @@ namespace Unity.Netcode
|
||||
// Metrics update needs to be driven by NetworkConnectionManager's update to assure metrics are dispatched after the send queue is processed.
|
||||
MetricsManager.UpdateMetrics();
|
||||
|
||||
// TODO 2023-Q2: Determine a better way to handle this
|
||||
// TODO: Determine a better way to handle this
|
||||
NetworkObject.VerifyParentingStatus();
|
||||
|
||||
// This is "ok" to invoke when not processing messages since it is just cleaning up messages that never got handled within their timeout period.
|
||||
DeferredMessageManager.CleanupStaleTriggers();
|
||||
|
||||
// TODO 2023-Q2: Determine a better way to handle this
|
||||
if (m_ShuttingDown)
|
||||
{
|
||||
ShutdownInternal();
|
||||
@@ -834,9 +833,7 @@ namespace Unity.Netcode
|
||||
}
|
||||
|
||||
ConnectionManager.LocalClient.SetRole(true, true, this);
|
||||
|
||||
Initialize(true);
|
||||
|
||||
try
|
||||
{
|
||||
IsListening = NetworkConfig.NetworkTransport.StartServer();
|
||||
@@ -942,10 +939,16 @@ namespace Unity.Netcode
|
||||
if (IsServer || IsClient)
|
||||
{
|
||||
m_ShuttingDown = true;
|
||||
MessageManager.StopProcessing = discardMessageQueue;
|
||||
if (MessageManager != null)
|
||||
{
|
||||
MessageManager.StopProcessing = discardMessageQueue;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkConfig.NetworkTransport.OnTransportEvent -= ConnectionManager.HandleNetworkEvent;
|
||||
if (NetworkConfig != null && NetworkConfig.NetworkTransport != null)
|
||||
{
|
||||
NetworkConfig.NetworkTransport.OnTransportEvent -= ConnectionManager.HandleNetworkEvent;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensures that the NetworkManager is cleaned up before OnDestroy is run on NetworkObjects and NetworkBehaviours when unloading a scene with a NetworkManager
|
||||
@@ -1029,6 +1032,8 @@ namespace Unity.Netcode
|
||||
// Ensures that the NetworkManager is cleaned up before OnDestroy is run on NetworkObjects and NetworkBehaviours when quitting the application.
|
||||
private void OnApplicationQuit()
|
||||
{
|
||||
// Make sure ShutdownInProgress returns true during this time
|
||||
m_ShuttingDown = true;
|
||||
OnDestroy();
|
||||
}
|
||||
|
||||
|
||||
@@ -733,6 +733,12 @@ namespace Unity.Netcode
|
||||
/// <returns>Whether or not reparenting was successful.</returns>
|
||||
public bool TrySetParent(Transform parent, bool worldPositionStays = true)
|
||||
{
|
||||
// If we are removing ourself from a parent
|
||||
if (parent == null)
|
||||
{
|
||||
return TrySetParent((NetworkObject)null, worldPositionStays);
|
||||
}
|
||||
|
||||
var networkObject = parent.GetComponent<NetworkObject>();
|
||||
|
||||
// If the parent doesn't have a NetworkObjet then return false, otherwise continue trying to parent
|
||||
@@ -1192,7 +1198,6 @@ namespace Unity.Netcode
|
||||
{
|
||||
NetworkLog.LogError($"{nameof(NetworkBehaviour)} index {index} was out of bounds for {name}. NetworkBehaviours must be the same, and in the same order, between server and client.");
|
||||
}
|
||||
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
|
||||
{
|
||||
var currentKnownChildren = new System.Text.StringBuilder();
|
||||
@@ -1205,7 +1210,6 @@ namespace Unity.Netcode
|
||||
}
|
||||
NetworkLog.LogInfo(currentKnownChildren.ToString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,6 @@ namespace Unity.Netcode
|
||||
{
|
||||
networkVariable.WriteDelta(writer);
|
||||
}
|
||||
|
||||
NetworkBehaviour.NetworkManager.NetworkMetrics.TrackNetworkVariableDeltaSent(
|
||||
TargetClientId,
|
||||
NetworkBehaviour.NetworkObject,
|
||||
@@ -207,7 +206,6 @@ namespace Unity.Netcode
|
||||
networkBehaviour.__getTypeName(),
|
||||
context.MessageSize);
|
||||
|
||||
|
||||
if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
|
||||
{
|
||||
if (m_ReceivedNetworkVariableData.Position > (readStartPos + varSize))
|
||||
|
||||
@@ -72,6 +72,14 @@ namespace Unity.Netcode
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(new Exception("Unhandled RPC exception!", ex));
|
||||
if (networkManager.LogLevel == LogLevel.Developer)
|
||||
{
|
||||
Debug.Log($"RPC Table Contents");
|
||||
foreach (var entry in NetworkManager.__rpc_func_table)
|
||||
{
|
||||
Debug.Log($"{entry.Key} | {entry.Value.Method.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2191,6 +2191,10 @@ namespace Unity.Netcode
|
||||
ClientId = clientId
|
||||
});
|
||||
|
||||
// At this point the client is considered fully "connected"
|
||||
NetworkManager.ConnectedClients[clientId].IsConnected = true;
|
||||
|
||||
// All scenes are synchronized, let the server know we are done synchronizing
|
||||
OnSynchronizeComplete?.Invoke(clientId);
|
||||
|
||||
// At this time the client is fully synchronized with all loaded scenes and
|
||||
|
||||
@@ -113,12 +113,6 @@ namespace Unity.Netcode
|
||||
// Remove the previous owner's entry
|
||||
OwnershipToObjectsTable[previousOwner].Remove(networkObject.NetworkObjectId);
|
||||
|
||||
// Server or Host alway invokes the lost ownership notification locally
|
||||
if (NetworkManager.IsServer)
|
||||
{
|
||||
networkObject.InvokeBehaviourOnLostOwnership();
|
||||
}
|
||||
|
||||
// If we are removing the entry (i.e. despawning or client lost ownership)
|
||||
if (isRemoving)
|
||||
{
|
||||
@@ -143,12 +137,6 @@ namespace Unity.Netcode
|
||||
{
|
||||
// Add the new ownership entry
|
||||
OwnershipToObjectsTable[newOwner].Add(networkObject.NetworkObjectId, networkObject);
|
||||
|
||||
// Server or Host always invokes the gained ownership notification locally
|
||||
if (NetworkManager.IsServer)
|
||||
{
|
||||
networkObject.InvokeBehaviourOnGainedOwnership();
|
||||
}
|
||||
}
|
||||
else if (isRemoving)
|
||||
{
|
||||
@@ -227,43 +215,6 @@ namespace Unity.Netcode
|
||||
return null;
|
||||
}
|
||||
|
||||
internal void RemoveOwnership(NetworkObject networkObject)
|
||||
{
|
||||
if (!NetworkManager.IsServer)
|
||||
{
|
||||
throw new NotServerException("Only the server can change ownership");
|
||||
}
|
||||
|
||||
if (!networkObject.IsSpawned)
|
||||
{
|
||||
throw new SpawnStateException("Object is not spawned");
|
||||
}
|
||||
|
||||
// If we made it here then we are the server and if the server is determined to already be the owner
|
||||
// then ignore the RemoveOwnership invocation.
|
||||
if (networkObject.OwnerClientId == NetworkManager.ServerClientId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkObject.OwnerClientId = NetworkManager.ServerClientId;
|
||||
|
||||
// Server removes the entry and takes over ownership before notifying
|
||||
UpdateOwnershipTable(networkObject, NetworkManager.ServerClientId, true);
|
||||
|
||||
var message = new ChangeOwnershipMessage
|
||||
{
|
||||
NetworkObjectId = networkObject.NetworkObjectId,
|
||||
OwnerClientId = networkObject.OwnerClientId
|
||||
};
|
||||
var size = NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, NetworkManager.ConnectedClientsIds);
|
||||
|
||||
foreach (var client in NetworkManager.ConnectedClients)
|
||||
{
|
||||
NetworkManager.NetworkMetrics.TrackOwnershipChangeSent(client.Key, networkObject, size);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function to get a network client for a clientId from the NetworkManager.
|
||||
/// On the server this will check the <see cref="NetworkManager.ConnectedClients"/> list.
|
||||
@@ -289,6 +240,11 @@ namespace Unity.Netcode
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void RemoveOwnership(NetworkObject networkObject)
|
||||
{
|
||||
ChangeOwnership(networkObject, NetworkManager.ServerClientId);
|
||||
}
|
||||
|
||||
internal void ChangeOwnership(NetworkObject networkObject, ulong clientId)
|
||||
{
|
||||
if (!NetworkManager.IsServer)
|
||||
@@ -301,14 +257,21 @@ namespace Unity.Netcode
|
||||
throw new SpawnStateException("Object is not spawned");
|
||||
}
|
||||
|
||||
// Assign the new owner
|
||||
networkObject.OwnerClientId = clientId;
|
||||
|
||||
// Always notify locally on the server when ownership is lost
|
||||
networkObject.InvokeBehaviourOnLostOwnership();
|
||||
|
||||
networkObject.MarkVariablesDirty(true);
|
||||
NetworkManager.BehaviourUpdater.AddForUpdate(networkObject);
|
||||
|
||||
// Server adds entries for all client ownership
|
||||
UpdateOwnershipTable(networkObject, networkObject.OwnerClientId);
|
||||
|
||||
// Always notify locally on the server when a new owner is assigned
|
||||
networkObject.InvokeBehaviourOnGainedOwnership();
|
||||
|
||||
var message = new ChangeOwnershipMessage
|
||||
{
|
||||
NetworkObjectId = networkObject.NetworkObjectId,
|
||||
@@ -952,27 +915,35 @@ namespace Unity.Netcode
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates all spawned <see cref="NetworkObject.Observers"/> for the specified client
|
||||
/// Updates all spawned <see cref="NetworkObject.Observers"/> for the specified newly connected client
|
||||
/// Note: if the clientId is the server then it is observable to all spawned <see cref="NetworkObject"/>'s
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method is to only to be used for newly connected clients in order to update the observers list for
|
||||
/// each NetworkObject instance.
|
||||
/// </remarks>
|
||||
internal void UpdateObservedNetworkObjects(ulong clientId)
|
||||
{
|
||||
foreach (var sobj in SpawnedObjectsList)
|
||||
{
|
||||
// If the NetworkObject has no visibility check then prepare to add this client as an observer
|
||||
if (sobj.CheckObjectVisibility == null)
|
||||
{
|
||||
if (!sobj.Observers.Contains(clientId))
|
||||
// If the client is not part of the observers and spawn with observers is enabled on this instance or the clientId is the server
|
||||
if (!sobj.Observers.Contains(clientId) && (sobj.SpawnWithObservers || clientId == NetworkManager.ServerClientId))
|
||||
{
|
||||
sobj.Observers.Add(clientId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// CheckObject visibility overrides SpawnWithObservers under this condition
|
||||
if (sobj.CheckObjectVisibility(clientId))
|
||||
{
|
||||
sobj.Observers.Add(clientId);
|
||||
}
|
||||
else if (sobj.Observers.Contains(clientId))
|
||||
else // Otherwise, if the observers contains the clientId (shouldn't happen) then remove it since CheckObjectVisibility returned false
|
||||
if (sobj.Observers.Contains(clientId))
|
||||
{
|
||||
sobj.Observers.Remove(clientId);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,6 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
public class NetworkTimeSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// TODO 2023-Q2: Not sure if this just needs to go away, but there is nothing that ever replaces this
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This was the original comment when it lived in NetworkManager:
|
||||
/// todo talk with UX/Product, find good default value for this
|
||||
|
||||
@@ -121,9 +121,7 @@ namespace Unity.Netcode.EditorTests
|
||||
|
||||
LogAssert.Expect(LogType.Error, "Invalid network endpoint: 127.0.0.:4242.");
|
||||
LogAssert.Expect(LogType.Error, "Network listen address (127.0.0.) is Invalid!");
|
||||
#if UTP_TRANSPORT_2_0_ABOVE
|
||||
LogAssert.Expect(LogType.Error, "Socket creation failed (error Unity.Baselib.LowLevel.Binding+Baselib_ErrorState: Invalid argument (0x01000003) <argument name stripped>");
|
||||
#endif
|
||||
|
||||
transport.SetConnectionData("127.0.0.1", 4242, "127.0.0.1");
|
||||
Assert.True(transport.StartServer());
|
||||
|
||||
|
||||
@@ -67,7 +67,6 @@ namespace Unity.Netcode.RuntimeTests
|
||||
// Set the child object to be inactive in the hierarchy
|
||||
childObject.SetActive(false);
|
||||
|
||||
LogAssert.Expect(LogType.Warning, $"{childObject.name} is disabled! Netcode for GameObjects does not support disabled NetworkBehaviours! The {childBehaviour.GetType().Name} component was skipped during ownership assignment!");
|
||||
LogAssert.Expect(LogType.Warning, $"{childObject.name} is disabled! Netcode for GameObjects does not support spawning disabled NetworkBehaviours! The {childBehaviour.GetType().Name} component was skipped during spawn!");
|
||||
|
||||
parentNetworkObject.Spawn();
|
||||
|
||||
@@ -61,8 +61,26 @@ namespace Unity.Netcode.RuntimeTests
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assures the <see cref="ObserverSpawnTests"/> late joining client has all
|
||||
/// NetworkPrefabs required to connect.
|
||||
/// </summary>
|
||||
protected override void OnNewClientCreated(NetworkManager networkManager)
|
||||
{
|
||||
foreach (var networkPrefab in m_ServerNetworkManager.NetworkConfig.Prefabs.Prefabs)
|
||||
{
|
||||
if (!networkManager.NetworkConfig.Prefabs.Contains(networkPrefab.Prefab))
|
||||
{
|
||||
networkManager.NetworkConfig.Prefabs.Add(networkPrefab);
|
||||
}
|
||||
}
|
||||
base.OnNewClientCreated(networkManager);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This test validates <see cref="NetworkObject.SpawnWithObservers"/> property
|
||||
/// </summary>
|
||||
/// <param name="observerTestTypes">whether to spawn with or without observers</param>
|
||||
[UnityTest]
|
||||
public IEnumerator ObserverSpawnTests([Values] ObserverTestTypes observerTestTypes)
|
||||
{
|
||||
@@ -92,6 +110,23 @@ namespace Unity.Netcode.RuntimeTests
|
||||
m_ObserverTestType = ObserverTestTypes.WithObservers;
|
||||
yield return WaitForConditionOrTimeOut(CheckClientsSideObserverTestObj);
|
||||
AssertOnTimeout($"{k_WithObserversError} {k_ObserverTestObjName} object!");
|
||||
|
||||
// Validate that a late joining client does not see the NetworkObject when it spawns
|
||||
yield return CreateAndStartNewClient();
|
||||
|
||||
m_ObserverTestType = ObserverTestTypes.WithoutObservers;
|
||||
// Just give a little time to make sure nothing spawned
|
||||
yield return s_DefaultWaitForTick;
|
||||
yield return WaitForConditionOrTimeOut(CheckClientsSideObserverTestObj);
|
||||
AssertOnTimeout($"{(withoutObservers ? k_WithoutObserversError : k_WithObserversError)} {k_ObserverTestObjName} object!");
|
||||
|
||||
// Now validate that we can make the NetworkObject visible to the newly joined client
|
||||
m_ObserverTestNetworkObject.NetworkShow(m_ClientNetworkManagers[NumberOfClients].LocalClientId);
|
||||
|
||||
// Validate the NetworkObject is visible to all connected clients (including the recently joined client)
|
||||
m_ObserverTestType = ObserverTestTypes.WithObservers;
|
||||
yield return WaitForConditionOrTimeOut(CheckClientsSideObserverTestObj);
|
||||
AssertOnTimeout($"{k_WithObserversError} {k_ObserverTestObjName} object!");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
|
||||
@@ -42,6 +42,12 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
public NetworkObjectOwnershipTests(HostOrServer hostOrServer) : base(hostOrServer) { }
|
||||
|
||||
public enum OwnershipChecks
|
||||
{
|
||||
Change,
|
||||
Remove
|
||||
}
|
||||
|
||||
protected override void OnServerAndClientsCreated()
|
||||
{
|
||||
m_OwnershipPrefab = CreateNetworkObjectPrefab("OnwershipPrefab");
|
||||
@@ -62,7 +68,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestOwnershipCallbacks()
|
||||
public IEnumerator TestOwnershipCallbacks([Values] OwnershipChecks ownershipChecks)
|
||||
{
|
||||
m_OwnershipObject = SpawnObject(m_OwnershipPrefab, m_ServerNetworkManager);
|
||||
m_OwnershipNetworkObject = m_OwnershipObject.GetComponent<NetworkObject>();
|
||||
@@ -109,7 +115,17 @@ namespace Unity.Netcode.RuntimeTests
|
||||
serverComponent.ResetFlags();
|
||||
clientComponent.ResetFlags();
|
||||
|
||||
serverObject.ChangeOwnership(NetworkManager.ServerClientId);
|
||||
if (ownershipChecks == OwnershipChecks.Change)
|
||||
{
|
||||
// Validates that when ownership is changed back to the server it will get an OnGainedOwnership notification
|
||||
serverObject.ChangeOwnership(NetworkManager.ServerClientId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Validates that when ownership is removed the server gets an OnGainedOwnership notification
|
||||
serverObject.RemoveOwnership();
|
||||
}
|
||||
|
||||
yield return s_DefaultWaitForTick;
|
||||
|
||||
Assert.That(serverComponent.OnGainedOwnershipFired);
|
||||
@@ -125,7 +141,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
/// Verifies that switching ownership between several clients works properly
|
||||
/// </summary>
|
||||
[UnityTest]
|
||||
public IEnumerator TestOwnershipCallbacksSeveralClients()
|
||||
public IEnumerator TestOwnershipCallbacksSeveralClients([Values] OwnershipChecks ownershipChecks)
|
||||
{
|
||||
// Build our message hook entries tables so we can determine if all clients received spawn or ownership messages
|
||||
var messageHookEntriesForSpawn = new List<MessageHookEntry>();
|
||||
@@ -247,8 +263,17 @@ namespace Unity.Netcode.RuntimeTests
|
||||
previousClientComponent = currentClientComponent;
|
||||
}
|
||||
|
||||
// Now change ownership back to the server
|
||||
serverObject.ChangeOwnership(NetworkManager.ServerClientId);
|
||||
if (ownershipChecks == OwnershipChecks.Change)
|
||||
{
|
||||
// Validates that when ownership is changed back to the server it will get an OnGainedOwnership notification
|
||||
serverObject.ChangeOwnership(NetworkManager.ServerClientId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Validates that when ownership is removed the server gets an OnGainedOwnership notification
|
||||
serverObject.RemoveOwnership();
|
||||
}
|
||||
|
||||
yield return WaitForConditionOrTimeOut(ownershipMessageHooks);
|
||||
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for all clients to receive the {nameof(ChangeOwnershipMessage)} message (back to server).");
|
||||
|
||||
@@ -269,5 +294,69 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
serverComponent.ResetFlags();
|
||||
}
|
||||
|
||||
private const int k_NumberOfSpawnedObjects = 5;
|
||||
|
||||
private bool AllClientsHaveCorrectObjectCount()
|
||||
{
|
||||
|
||||
foreach (var clientNetworkManager in m_ClientNetworkManagers)
|
||||
{
|
||||
if (clientNetworkManager.LocalClient.OwnedObjects.Count < k_NumberOfSpawnedObjects)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ServerHasCorrectClientOwnedObjectCount()
|
||||
{
|
||||
// Only check when we are the host
|
||||
if (m_ServerNetworkManager.IsHost)
|
||||
{
|
||||
if (m_ServerNetworkManager.LocalClient.OwnedObjects.Count < k_NumberOfSpawnedObjects)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var connectedClient in m_ServerNetworkManager.ConnectedClients)
|
||||
{
|
||||
if (connectedClient.Value.OwnedObjects.Count < k_NumberOfSpawnedObjects)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestOwnedObjectCounts()
|
||||
{
|
||||
if (m_ServerNetworkManager.IsHost)
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
SpawnObject(m_OwnershipPrefab, m_ServerNetworkManager);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var clientNetworkManager in m_ClientNetworkManagers)
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
SpawnObject(m_OwnershipPrefab, clientNetworkManager);
|
||||
}
|
||||
}
|
||||
|
||||
yield return WaitForConditionOrTimeOut(AllClientsHaveCorrectObjectCount);
|
||||
AssertOnTimeout($"Not all clients spawned {k_NumberOfSpawnedObjects} {nameof(NetworkObject)}s!");
|
||||
|
||||
yield return WaitForConditionOrTimeOut(ServerHasCorrectClientOwnedObjectCount);
|
||||
AssertOnTimeout($"Server does not have the correct count for all clients spawned {k_NumberOfSpawnedObjects} {nameof(NetworkObject)}s!");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using Unity.Netcode.Components;
|
||||
using Unity.Netcode.TestHelpers.Runtime;
|
||||
@@ -378,7 +379,7 @@ namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
var success = WaitForConditionOrTimeOutWithTimeTravel(AllInstancesKeptLocalTransformValues);
|
||||
//TimeTravelToNextTick();
|
||||
var infoMessage = new System.Text.StringBuilder($"Timed out waiting for all children to have the correct local space values:\n");
|
||||
var infoMessage = new 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;
|
||||
@@ -568,8 +569,8 @@ namespace Unity.Netcode.RuntimeTests
|
||||
}
|
||||
|
||||
// The number of iterations to change position, rotation, and scale for NetworkTransformMultipleChangesOverTime
|
||||
// Note: this was reduced from 8 iterations to 3 due to the number of tests based on all of the various parameter combinations
|
||||
private const int k_PositionRotationScaleIterations = 3;
|
||||
private const int k_PositionRotationScaleIterations3Axis = 8;
|
||||
|
||||
protected override void OnNewClientCreated(NetworkManager networkManager)
|
||||
{
|
||||
@@ -594,22 +595,69 @@ namespace Unity.Netcode.RuntimeTests
|
||||
|
||||
|
||||
private Axis m_CurrentAxis;
|
||||
|
||||
private bool m_AxisExcluded;
|
||||
|
||||
/// <summary>
|
||||
/// Randomly determine if an axis should be excluded.
|
||||
/// If so, then randomly pick one of the axis to be excluded.
|
||||
/// </summary>
|
||||
private Vector3 RandomlyExcludeAxis(Vector3 delta)
|
||||
{
|
||||
if (Random.Range(0.0f, 1.0f) >= 0.5f)
|
||||
{
|
||||
m_AxisExcluded = true;
|
||||
var axisToIgnore = Random.Range(0, 2);
|
||||
switch (axisToIgnore)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
delta.x = 0;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
delta.y = 0;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
delta.z = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This validates that multiple changes can occur within the same tick or over
|
||||
/// several ticks while still keeping non-authoritative instances synchronized.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When testing < 3 axis: Interpolation is disabled and only 3 delta updates are applied per unique test
|
||||
/// When testing 3 axis: Interpolation is enabled, sometimes an axis is intentionally excluded during a
|
||||
/// delta update, and it runs through 8 delta updates per unique test.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void NetworkTransformMultipleChangesOverTime([Values] TransformSpace testLocalTransform, [Values] OverrideState overideState,
|
||||
[Values] Precision precision, [Values] Rotation rotationSynch, [Values] Axis axis)
|
||||
{
|
||||
// In the name of reducing the very long time it takes to interpolate and run all of the possible combinations,
|
||||
// we only interpolate when the second client joins
|
||||
m_AuthoritativeTransform.Interpolate = false;
|
||||
m_AuthoritativeTransform.InLocalSpace = testLocalTransform == TransformSpace.Local;
|
||||
bool axisX = axis == Axis.X || axis == Axis.XY || axis == Axis.XZ || axis == Axis.XYZ;
|
||||
bool axisY = axis == Axis.Y || axis == Axis.XY || axis == Axis.YZ || axis == Axis.XYZ;
|
||||
bool axisZ = axis == Axis.Z || axis == Axis.XZ || axis == Axis.YZ || axis == Axis.XYZ;
|
||||
|
||||
var axisCount = axisX ? 1 : 0;
|
||||
axisCount += axisY ? 1 : 0;
|
||||
axisCount += axisZ ? 1 : 0;
|
||||
|
||||
// Enable interpolation when all 3 axis are selected to make sure we are synchronizing properly
|
||||
// when interpolation is enabled.
|
||||
m_AuthoritativeTransform.Interpolate = axisCount == 3 ? true : false;
|
||||
|
||||
m_CurrentAxis = axis;
|
||||
|
||||
// Authority dictates what is synchronized and what the precision is going to be
|
||||
// so we only need to set this on the authoritative side.
|
||||
m_AuthoritativeTransform.UseHalfFloatPrecision = precision == Precision.Half;
|
||||
@@ -640,29 +688,49 @@ namespace Unity.Netcode.RuntimeTests
|
||||
m_AuthoritativeTransform.SyncScaleY = axisY;
|
||||
m_AuthoritativeTransform.SyncScaleZ = axisZ;
|
||||
|
||||
|
||||
var positionStart = GetRandomVector3(0.25f, 1.75f);
|
||||
var rotationStart = GetRandomVector3(1f, 15f);
|
||||
var scaleStart = GetRandomVector3(0.25f, 2.0f);
|
||||
var position = positionStart;
|
||||
var rotation = rotationStart;
|
||||
var scale = scaleStart;
|
||||
var success = false;
|
||||
|
||||
m_AuthoritativeTransform.StatePushed = false;
|
||||
// Wait for the deltas to be pushed
|
||||
WaitForConditionOrTimeOutWithTimeTravel(() => m_AuthoritativeTransform.StatePushed);
|
||||
// Allow the precision settings to propagate first as changing precision
|
||||
// causes a teleport event to occur
|
||||
WaitForNextTick();
|
||||
var iterations = axisCount == 3 ? k_PositionRotationScaleIterations3Axis : k_PositionRotationScaleIterations;
|
||||
|
||||
// Move and rotate within the same tick, validate the non-authoritative instance updates
|
||||
// to each set of changes. Repeat several times.
|
||||
for (int i = 0; i < k_PositionRotationScaleIterations; i++)
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
// Always reset this per delta update pass
|
||||
m_AxisExcluded = false;
|
||||
var deltaPositionDelta = GetRandomVector3(-1.5f, 1.5f);
|
||||
var deltaRotationDelta = GetRandomVector3(-3.5f, 3.5f);
|
||||
var deltaScaleDelta = GetRandomVector3(-0.5f, 0.5f);
|
||||
|
||||
m_NonAuthoritativeTransform.StateUpdated = false;
|
||||
m_AuthoritativeTransform.StatePushed = false;
|
||||
position = positionStart * i;
|
||||
rotation = rotationStart * i;
|
||||
scale = scaleStart * i;
|
||||
|
||||
// With two or more axis, excluding one of them while chaging another will validate that
|
||||
// full precision updates are maintaining their target state value(s) to interpolate towards
|
||||
if (axisCount == 3)
|
||||
{
|
||||
position += RandomlyExcludeAxis(deltaPositionDelta);
|
||||
rotation += RandomlyExcludeAxis(deltaRotationDelta);
|
||||
scale += RandomlyExcludeAxis(deltaScaleDelta);
|
||||
}
|
||||
else
|
||||
{
|
||||
position += deltaPositionDelta;
|
||||
rotation += deltaRotationDelta;
|
||||
scale += deltaScaleDelta;
|
||||
}
|
||||
|
||||
// Apply delta between ticks
|
||||
MoveRotateAndScaleAuthority(position, rotation, scale, overideState);
|
||||
@@ -670,54 +738,37 @@ namespace Unity.Netcode.RuntimeTests
|
||||
// Wait for the deltas to be pushed
|
||||
Assert.True(WaitForConditionOrTimeOutWithTimeTravel(() => m_AuthoritativeTransform.StatePushed && m_NonAuthoritativeTransform.StateUpdated), $"[Non-Interpolate {i}] Timed out waiting for state to be pushed ({m_AuthoritativeTransform.StatePushed}) or state to be updated ({m_NonAuthoritativeTransform.StateUpdated})!");
|
||||
|
||||
// Wait for deltas to synchronize on non-authoritative side
|
||||
var success = WaitForConditionOrTimeOutWithTimeTravel(PositionRotationScaleMatches);
|
||||
// Provide additional debug info about what failed (if it fails)
|
||||
if (!success)
|
||||
// For 3 axis, we will skip validating that the non-authority interpolates to its target point at least once.
|
||||
// This will validate that non-authoritative updates are maintaining their target state axis values if only 2
|
||||
// of the axis are being updated to assure interpolation maintains the targeted axial value per axis.
|
||||
// For 2 and 1 axis tests we always validate per delta update
|
||||
if (m_AxisExcluded || axisCount < 3)
|
||||
{
|
||||
m_EnableVerboseDebug = true;
|
||||
PositionRotationScaleMatches();
|
||||
m_EnableVerboseDebug = false;
|
||||
// Wait for deltas to synchronize on non-authoritative side
|
||||
success = WaitForConditionOrTimeOutWithTimeTravel(PositionRotationScaleMatches);
|
||||
// Provide additional debug info about what failed (if it fails)
|
||||
if (!success)
|
||||
{
|
||||
m_EnableVerboseDebug = true;
|
||||
success = PositionRotationScaleMatches();
|
||||
m_EnableVerboseDebug = false;
|
||||
}
|
||||
Assert.True(success, $"[Non-Interpolate {i}] Timed out waiting for non-authority to match authority's position or rotation");
|
||||
}
|
||||
Assert.True(success, $"[Non-Interpolate {i}] Timed out waiting for non-authority to match authority's position or rotation");
|
||||
}
|
||||
|
||||
// Only enable interpolation when all axis are set (to reduce the test times)
|
||||
if (axis == Axis.XYZ)
|
||||
if (axisCount == 3)
|
||||
{
|
||||
// Now, enable interpolation
|
||||
m_AuthoritativeTransform.Interpolate = true;
|
||||
m_NonAuthoritativeTransform.StateUpdated = false;
|
||||
m_AuthoritativeTransform.StatePushed = false;
|
||||
// Wait for the delta (change in interpolation) to be pushed
|
||||
var success = WaitForConditionOrTimeOutWithTimeTravel(() => m_AuthoritativeTransform.StatePushed && m_NonAuthoritativeTransform.StateUpdated);
|
||||
Assert.True(success, $"[Interpolation Enable] Timed out waiting for state to be pushed ({m_AuthoritativeTransform.StatePushed}) or state to be updated ({m_NonAuthoritativeTransform.StateUpdated})!");
|
||||
|
||||
// Continue for one more update with interpolation enabled
|
||||
// Note: We are just verifying one update with interpolation enabled due to the number of tests this integration test has to run
|
||||
// and since the NestedNetworkTransformTests already tests interpolation under the same number of conditions (excluding Axis).
|
||||
// This is just to verify selecting specific axis doesn't cause issues when interpolating as well.
|
||||
m_NonAuthoritativeTransform.StateUpdated = false;
|
||||
m_AuthoritativeTransform.StatePushed = false;
|
||||
position = positionStart * k_PositionRotationScaleIterations;
|
||||
rotation = rotationStart * k_PositionRotationScaleIterations;
|
||||
scale = scaleStart * k_PositionRotationScaleIterations;
|
||||
MoveRotateAndScaleAuthority(position, rotation, scale, overideState);
|
||||
|
||||
// Wait for the deltas to be pushed and updated
|
||||
success = WaitForConditionOrTimeOutWithTimeTravel(() => m_AuthoritativeTransform.StatePushed && m_NonAuthoritativeTransform.StateUpdated);
|
||||
Assert.True(success, $"[Interpolation {k_PositionRotationScaleIterations}] Timed out waiting for state to be pushed ({m_AuthoritativeTransform.StatePushed}) or state to be updated ({m_NonAuthoritativeTransform.StateUpdated})!");
|
||||
|
||||
success = WaitForConditionOrTimeOutWithTimeTravel(PositionRotationScaleMatches, 120);
|
||||
|
||||
// As a final test, wait for deltas to synchronize on non-authoritative side to assure it interpolates to th
|
||||
success = WaitForConditionOrTimeOutWithTimeTravel(PositionRotationScaleMatches);
|
||||
// Provide additional debug info about what failed (if it fails)
|
||||
if (!success)
|
||||
{
|
||||
m_EnableVerboseDebug = true;
|
||||
PositionRotationScaleMatches();
|
||||
success = PositionRotationScaleMatches();
|
||||
m_EnableVerboseDebug = false;
|
||||
}
|
||||
Assert.True(success, $"[Interpolation {k_PositionRotationScaleIterations}] Timed out waiting for non-authority to match authority's position or rotation");
|
||||
Assert.True(success, $"Timed out waiting for non-authority to match authority's position or rotation");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
ValidationExceptions.json
Normal file
10
ValidationExceptions.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ErrorExceptions": [
|
||||
{
|
||||
"ValidationTest": "API Validation",
|
||||
"ExceptionMessage": "Additions require a new minor or major version.",
|
||||
"PackageVersion": "1.5.2"
|
||||
}
|
||||
],
|
||||
"WarningExceptions": []
|
||||
}
|
||||
7
ValidationExceptions.json.meta
Normal file
7
ValidationExceptions.json.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a43005be301c9043aab7034757d4868
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -2,23 +2,23 @@
|
||||
"name": "com.unity.netcode.gameobjects",
|
||||
"displayName": "Netcode for GameObjects",
|
||||
"description": "Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.",
|
||||
"version": "1.5.1",
|
||||
"version": "1.5.2",
|
||||
"unity": "2020.3",
|
||||
"dependencies": {
|
||||
"com.unity.nuget.mono-cecil": "1.10.1",
|
||||
"com.unity.transport": "1.3.4"
|
||||
},
|
||||
"_upm": {
|
||||
"changelog": "### Added\n\n- 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)\n- The location of the automatically-created default network prefab list can now be configured (#2544)\n- 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)\n- 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)\n\n### Fixed\n\n- Fixed: Fixed a null reference in codegen in some projects (#2581)\n- Fixed issue where the `OnClientDisconnected` client identifier was incorrect after a pending client connection was denied. (#2569)\n- Fixed warning \"Runtime Network Prefabs was not empty at initialization time.\" being erroneously logged when no runtime network prefabs had been added (#2565)\n- Fixed issue where some temporary debug console logging was left in a merged PR. (#2562)\n- Fixed the \"Generate Default Network Prefabs List\" setting not loading correctly and always reverting to being checked. (#2545)\n- Fixed issue where users could not use NetworkSceneManager.VerifySceneBeforeLoading to exclude runtime generated scenes from client synchronization. (#2550)\n- Fixed missing value on `NetworkListEvent` for `EventType.RemoveAt` events. (#2542,#2543)\n- 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)\n- Fixed issue where a server would include scene migrated and then despawned NetworkObjects to a client that was being synchronized. (#2532)\n- Fixed the inspector throwing exceptions when attempting to render `NetworkVariable`s of enum types. (#2529)\n- 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)\n- Fixed Multiplayer Tools package installation docs page link on the NetworkManager popup. (#2526)\n- Fixed an exception and error logging when two different objects are shown and hidden on the same frame (#2524)\n- Fixed a memory leak in `UnityTransport` that occurred if `StartClient` failed. (#2518)\n- Fixed issue where a client could throw an exception if abruptly disconnected from a network session with one or more spawned `NetworkObject`(s). (#2510)\n- Fixed issue where invalid endpoint addresses were not being detected and returning false from NGO UnityTransport. (#2496)\n- Fixed some errors that could occur if a connection is lost and the loss is detected when attempting to write to the socket. (#2495)\n\n## Changed\n\n- Adding network prefabs before NetworkManager initialization is now supported. (#2565)\n- Connecting clients being synchronized now switch to the server's active scene before spawning and synchronizing NetworkObjects. (#2532)\n- Updated `UnityTransport` dependency on `com.unity.transport` to 1.3.4. (#2533)\n- 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)"
|
||||
"changelog": "### Added\n\n### Fixed\n\n- Fixed issue where `NetworkClient.OwnedObjects` was not returning any owned objects due to the `NetworkClient.IsConnected` not being properly set. (#2631)\n- Fixed a crash when calling TrySetParent with a null Transform (#2625)\n- Fixed issue where a `NetworkTransform` using full precision state updates was losing transform state updates when interpolation was enabled. (#2624)\n- Fixed issue where `NetworkObject.SpawnWithObservers` was not being honored for late joining clients. (#2623)\n- Fixed issue where invoking `NetworkManager.Shutdown` multiple times, depending upon the timing, could cause an exception. (#2622)\n- Fixed issue where removing ownership would not notify the server that it gained ownership. This also resolves the issue where an owner authoritative NetworkTransform would not properly initialize upon removing ownership from a remote client. (#2618)\n- Fixed ILPP issues when using CoreCLR and for certain dedicated server builds. (#2614)\n- Fixed an ILPP compile error when creating a generic NetworkBehaviour singleton with a static T instance. (#2603)\n\n### Changed"
|
||||
},
|
||||
"upmCi": {
|
||||
"footprint": "35c5325acc3edf18c37ef8c9d19e0944fae0d42a"
|
||||
"footprint": "e7549ba358ade416ab85285cdf53c5a6aac35cef"
|
||||
},
|
||||
"documentationUrl": "https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@1.5/manual/index.html",
|
||||
"repository": {
|
||||
"url": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git",
|
||||
"type": "git",
|
||||
"revision": "7a969f89d6dda65ac373ce552c0c997c9116f21a"
|
||||
"revision": "36368846c5bfe6cfb93adc36282507614955955c"
|
||||
},
|
||||
"samples": [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user