Skip to content

Commit 347c00f

Browse files
authored
fix: InScenePlaced edge cases (#4073)
* fix: InScenePlaced edge cases * Fix tests * Dont use scene origin if it isn't valid * Fix tests * Fix build error * Ensure spawn count is reset on NetworkManager shutdown * Fix broken test
1 parent c538a0f commit 347c00f

47 files changed

Lines changed: 1733 additions & 1574 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ Additional documentation and release notes are available at [Multiplayer Documen
2222

2323
### Fixed
2424

25-
- Fixed AnticipatedNetworkTransform not respecting the InLocalSpace flag (#3995)
25+
- Issue where scene migration in a distributed authority session would throw an exception on clients migrating their owned `NetworkObject` instances to a different scene.(#4086)
26+
- Issue where migrating a dynamically spawned or in-scene placed `NetworkObject` into a different scene during awake could result in that spawned instance to not be synchronized. (#4086)
2627
- Issue where a NullReferenceException was thrown when a non-authority failed to spawn a NetworkObject. (#4067)
2728
- Issue where the active scene was not being serialized as the 1st scene which could result in various errors including a soft synchronization error if, on the client-side, other synchronized scenes had already been loaded prior to the active scene, which is always loaded as `LoadSceneMode.SingleMode` when client synchronization is set to `LoadSceneMode.SingleMode`, resulting in the previously loaded scene(s) to be unloaded. (#4065)
2829
- Issue when FastBufferReader is attempting to read a string and all or a portion of the character count has already been read by user script, it could read a character length that results in a negative byte length which could result in an editor crash. (#4052)
2930
- Issue where NetworkRigidbodyBase was not applying rotation correctly when using Rigidbody2D. (#4012)
3031
- Issue where NetworkRigidbodyBase was always checking the 3D rigid body's interpolation mode when determining if it is kinematic and needs to put the rigid body to sleep and then switch to interpolation. (#4012)
32+
- Fixed AnticipatedNetworkTransform not respecting the InLocalSpace flag. (#3995)
3133

3234
### Security
3335

com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Unity.Netcode.Logging;
12
using UnityEditor;
23
using UnityEditor.Build;
34
using UnityEditor.Build.Reporting;
@@ -19,8 +20,22 @@ internal class SetInScenePlaced : IProcessSceneWithReport
1920
public int callbackOrder => 0;
2021
public void OnProcessScene(Scene scene, BuildReport report)
2122
{
23+
var log = new ContextualLogger();
24+
log.AddInfo(scene.name, scene.handle);
2225
foreach (var networkObject in FindObjects.FromSceneByType<NetworkObject>(scene, true))
2326
{
27+
if (networkObject.SceneOrigin.IsValid() && networkObject.SceneOrigin.handle != scene.handle)
28+
{
29+
log.Warning(new Context(LogLevel.Developer, $"{nameof(NetworkObject)}'s SceneOrigin doesn't match current scene being processed! Skipping processing.").AddInfo("SceneOrigin", networkObject.SceneOriginHandle).AddNetworkObject(networkObject));
30+
continue;
31+
}
32+
33+
if (networkObject.HasBeenSpawned)
34+
{
35+
log.Error(new Context(LogLevel.Normal, $"Processing {nameof(NetworkObject)} that has already been spawned! This should not be possible. Skipping processing.").AddNetworkObject(networkObject));
36+
continue;
37+
}
38+
2439
networkObject.InScenePlaced = true;
2540
}
2641
}

com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,11 @@ public bool NotifyUserOfNestedNetworkManager(NetworkManager networkManager, bool
195195
{
196196
return isParented;
197197
}
198-
else // If we are no longer a child, then we can remove ourself from this list
199-
if (transform.root == gameObject.transform)
200-
{
201-
s_LastKnownNetworkManagerParents.Remove(networkManager);
202-
}
198+
else if (transform.root == gameObject.transform)
199+
{
200+
// If we are no longer a child, then we can remove ourself from this list
201+
s_LastKnownNetworkManagerParents.Remove(networkManager);
202+
}
203203
}
204204
if (!EditorApplication.isUpdating && isParented)
205205
{

com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -467,20 +467,20 @@ internal T Update(float deltaTime, double tickLatencyAsTime, double minDeltaTime
467467
InterpolateState.CurrentValue = InterpolateState.NextValue;
468468
}
469469
}
470-
else // If the target is reached and we have no more state updates, we want to check to see if we need to reset.
471-
if (m_BufferQueue.Count == 0)
470+
// If the target is reached and we have no more state updates, we want to check to see if we need to reset.
471+
else if (m_BufferQueue.Count == 0)
472+
{
473+
// When the delta between the time sent and the current tick latency time-window is greater than the max delta time
474+
// plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero),
475+
// we will want to reset the interpolator with the current known value. This prevents the next received state update's
476+
// time to be calculated against the last calculated time which if there is an extended period of time between the two
477+
// it would cause a large delta time period between the two states (i.e. it stops moving for a second or two and then
478+
// starts moving again).
479+
if ((tickLatencyAsTime - InterpolateState.Target.Value.TimeSent) > InterpolateState.MaxDeltaTime + minDeltaTime)
472480
{
473-
// When the delta between the time sent and the current tick latency time-window is greater than the max delta time
474-
// plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero),
475-
// we will want to reset the interpolator with the current known value. This prevents the next received state update's
476-
// time to be calculated against the last calculated time which if there is an extended period of time between the two
477-
// it would cause a large delta time period between the two states (i.e. it stops moving for a second or two and then
478-
// starts moving again).
479-
if ((tickLatencyAsTime - InterpolateState.Target.Value.TimeSent) > InterpolateState.MaxDeltaTime + minDeltaTime)
480-
{
481-
InterpolateState.Reset(InterpolateState.CurrentValue);
482-
}
481+
InterpolateState.Reset(InterpolateState.CurrentValue);
483482
}
483+
}
484484
}
485485
m_NbItemsReceivedThisFrame = 0;
486486
return InterpolateState.CurrentValue;
@@ -593,20 +593,20 @@ public T Update(float deltaTime, double renderTime, double serverTime)
593593
// Determine if we have reached our target
594594
InterpolateState.TargetReached = IsApproximately(InterpolateState.CurrentValue, InterpolateState.Target.Value.Item, GetPrecision());
595595
}
596-
else // If the target is reached and we have no more state updates, we want to check to see if we need to reset.
597-
if (InterpolateState.TargetReached && m_BufferQueue.Count == 0)
596+
// If the target is reached and we have no more state updates, we want to check to see if we need to reset.
597+
else if (InterpolateState.TargetReached && m_BufferQueue.Count == 0)
598+
{
599+
// When the delta between the time sent and the current tick latency time-window is greater than the max delta time
600+
// plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero),
601+
// we will want to reset the interpolator with the current known value. This prevents the next received state update's
602+
// time to be calculated against the last calculated time which if there is an extended period of time between the two
603+
// it would cause a large delta time period between the two states (i.e. it stops moving for a second or two and then
604+
// starts moving again).
605+
if ((renderTime - InterpolateState.Target.Value.TimeSent) > 0.3f) // If we haven't recevied anything within 300ms, assume we stopped motion.
598606
{
599-
// When the delta between the time sent and the current tick latency time-window is greater than the max delta time
600-
// plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero),
601-
// we will want to reset the interpolator with the current known value. This prevents the next received state update's
602-
// time to be calculated against the last calculated time which if there is an extended period of time between the two
603-
// it would cause a large delta time period between the two states (i.e. it stops moving for a second or two and then
604-
// starts moving again).
605-
if ((renderTime - InterpolateState.Target.Value.TimeSent) > 0.3f) // If we haven't recevied anything within 300ms, assume we stopped motion.
606-
{
607-
InterpolateState.Reset(InterpolateState.CurrentValue);
608-
}
607+
InterpolateState.Reset(InterpolateState.CurrentValue);
609608
}
609+
}
610610
m_NbItemsReceivedThisFrame = 0;
611611
return InterpolateState.CurrentValue;
612612
}

com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,26 +1180,25 @@ internal void CheckForAnimatorChanges()
11801180
{
11811181
SendAnimStateRpc(m_AnimationMessage);
11821182
}
1183+
else if (!IsServer && IsOwner)
1184+
{
1185+
SendServerAnimStateRpc(m_AnimationMessage);
1186+
}
11831187
else
1184-
if (!IsServer && IsOwner)
1185-
{
1186-
SendServerAnimStateRpc(m_AnimationMessage);
1187-
}
1188-
else
1188+
{
1189+
// Just notify all remote clients and not the local server
1190+
m_TargetGroup.Clear();
1191+
foreach (var clientId in LocalNetworkManager.ConnectionManager.ConnectedClientIds)
11891192
{
1190-
// Just notify all remote clients and not the local server
1191-
m_TargetGroup.Clear();
1192-
foreach (var clientId in LocalNetworkManager.ConnectionManager.ConnectedClientIds)
1193+
if (clientId == LocalNetworkManager.LocalClientId || !NetworkObject.Observers.Contains(clientId))
11931194
{
1194-
if (clientId == LocalNetworkManager.LocalClientId || !NetworkObject.Observers.Contains(clientId))
1195-
{
1196-
continue;
1197-
}
1198-
m_TargetGroup.Add(clientId);
1195+
continue;
11991196
}
1200-
m_RpcParams.Send.Target = m_TargetGroup.Target;
1201-
SendClientAnimStateRpc(m_AnimationMessage, m_RpcParams);
1197+
m_TargetGroup.Add(clientId);
12021198
}
1199+
m_RpcParams.Send.Target = m_TargetGroup.Target;
1200+
SendClientAnimStateRpc(m_AnimationMessage, m_RpcParams);
1201+
}
12031202
}
12041203
}
12051204

@@ -1346,25 +1345,24 @@ private unsafe void WriteParameters(ref FastBufferWriter writer)
13461345
BytePacker.WriteValuePacked(writer, (uint)valueInt);
13471346
}
13481347
}
1349-
else
1350-
if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterBool)
1348+
else if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterBool)
1349+
{
1350+
var valueBool = m_Animator.GetBool(hash);
1351+
fixed (void* value = cacheValue.Value)
13511352
{
1352-
var valueBool = m_Animator.GetBool(hash);
1353-
fixed (void* value = cacheValue.Value)
1354-
{
1355-
UnsafeUtility.WriteArrayElement(value, 0, valueBool);
1356-
BytePacker.WriteValuePacked(writer, valueBool);
1357-
}
1353+
UnsafeUtility.WriteArrayElement(value, 0, valueBool);
1354+
BytePacker.WriteValuePacked(writer, valueBool);
13581355
}
1359-
else if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterFloat)
1356+
}
1357+
else if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterFloat)
1358+
{
1359+
var valueFloat = m_Animator.GetFloat(hash);
1360+
fixed (void* value = cacheValue.Value)
13601361
{
1361-
var valueFloat = m_Animator.GetFloat(hash);
1362-
fixed (void* value = cacheValue.Value)
1363-
{
1364-
UnsafeUtility.WriteArrayElement(value, 0, valueFloat);
1365-
BytePacker.WriteValuePacked(writer, valueFloat);
1366-
}
1362+
UnsafeUtility.WriteArrayElement(value, 0, valueFloat);
1363+
BytePacker.WriteValuePacked(writer, valueFloat);
13671364
}
1365+
}
13681366
}
13691367
}
13701368

com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2515,24 +2515,24 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, bool is
25152515
}
25162516
}
25172517
}
2518-
else // Just apply the full local scale when synchronizing
2519-
if (SynchronizeScale)
2518+
// Just apply the full local scale when synchronizing
2519+
else if (SynchronizeScale)
2520+
{
2521+
var localScale = CachedTransform.localScale;
2522+
if (!UseHalfFloatPrecision)
25202523
{
2521-
var localScale = CachedTransform.localScale;
2522-
if (!UseHalfFloatPrecision)
2523-
{
25242524

2525-
networkState.ScaleX = localScale.x;
2526-
networkState.ScaleY = localScale.y;
2527-
networkState.ScaleZ = localScale.z;
2528-
}
2529-
else
2530-
{
2531-
networkState.Scale = localScale;
2532-
}
2533-
flagStates.MarkChanged(AxialType.Scale, true);
2534-
isScaleDirty = true;
2525+
networkState.ScaleX = localScale.x;
2526+
networkState.ScaleY = localScale.y;
2527+
networkState.ScaleZ = localScale.z;
25352528
}
2529+
else
2530+
{
2531+
networkState.Scale = localScale;
2532+
}
2533+
flagStates.MarkChanged(AxialType.Scale, true);
2534+
isScaleDirty = true;
2535+
}
25362536
isDirty |= isPositionDirty || isRotationDirty || isScaleDirty;
25372537

25382538
if (isDirty)
@@ -3488,12 +3488,12 @@ private void NonAuthorityFinalizeSynchronization()
34883488
child.InternalInitialization();
34893489
}
34903490
}
3491-
else // Otherwise, just run through standard synchronization of this instance
3492-
if (!CanCommitToTransform)
3493-
{
3494-
ApplySynchronization();
3495-
InternalInitialization();
3496-
}
3491+
// Otherwise, just run through standard synchronization of this instance
3492+
else if (!CanCommitToTransform)
3493+
{
3494+
ApplySynchronization();
3495+
InternalInitialization();
3496+
}
34973497
}
34983498
}
34993499

com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,22 @@ public bool Validate(int index = -1)
166166
return false;
167167
}
168168

169+
if (networkObject.InScenePlaced)
170+
{
171+
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
172+
{
173+
NetworkLog.LogWarning($"{NetworkPrefabHandler.PrefabDebugHelper(this)} InScenePlaced {nameof(NetworkObject)} is being registered as a Prefab. This can cause issues!");
174+
}
175+
}
176+
177+
if (networkObject.IsSpawned)
178+
{
179+
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
180+
{
181+
NetworkLog.LogWarning($"{NetworkPrefabHandler.PrefabDebugHelper(this)} Currently spawned {nameof(NetworkObject)} is being registered as a Prefab. This can cause issues!");
182+
}
183+
}
184+
169185
return true;
170186
}
171187

com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -967,19 +967,18 @@ internal void ProcessClientsToDisconnect()
967967
{
968968
return (true, playerPrefabHash.Value);
969969
}
970-
else
971-
if (NetworkManager.NetworkConfig.PlayerPrefab != null)
970+
else if (NetworkManager.NetworkConfig.PlayerPrefab != null)
971+
{
972+
var networkObject = NetworkManager.NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>();
973+
if (networkObject != null)
972974
{
973-
var networkObject = NetworkManager.NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>();
974-
if (networkObject != null)
975-
{
976-
return (true, networkObject.GlobalObjectIdHash);
977-
}
978-
else
979-
{
980-
NetworkManager.Log.Error(new Logging.Context(LogLevel.Error, $"Player prefab {NetworkManager.NetworkConfig.PlayerPrefab.name} has no {nameof(NetworkObject)}!"));
981-
}
975+
return (true, networkObject.GlobalObjectIdHash);
982976
}
977+
else
978+
{
979+
NetworkManager.Log.Error(new Logging.Context(LogLevel.Error, $"Player prefab {NetworkManager.NetworkConfig.PlayerPrefab.name} has no {nameof(NetworkObject)}!"));
980+
}
981+
}
983982
return (false, 0);
984983
}
985984

0 commit comments

Comments
 (0)