Skip to content

Commit aee018c

Browse files
fix: NetworkTransform initial synchronization, parenting, smooth transitions between transform spaces, and UI updates (#3013)
* fix This fixes a synchronization issue with owner authoritative instances when running in client-server mode and parenting. When the server sends a parent sync message back with the position of the client's owned object it is out of sync with the client's position by the time the message is received. This fix gives users the option to not synchronize the transform position of a NetworkObject when using an owner authoritative motion mode. * fix This fix provides users with the option to have child `NetworkTransform`(s) tick synchronized with their parent. When the parent has `TickSyncChildren` enabled, any child `NetworkTransform`(s) that the local client has authority over will force a synchronization of their transform state. When a client is not the authority of the parent but it is the authority of one or more children, then when the parent sends a state update it will force the child/children the client has authority over to send a state update. Children will still send state updates if the transform has a delta that exceeds an axis threshold and the parent has yet to send a synchronization, but if a parent sends a synchronization within the same tick period the child/children will still send another state update. * wip Better approach, but still flawed. I think converting any remaining items in the interpolators when the transform space changes will yield consistent results. * fix Seamless transform space transitions when parenting. * update We no longer need to send lossy scale since we defer applying the initial synchronization data until the non-authority side has finished synchronizing. * fix Fixing some minor issues with nested `NetworkTransforms` (i.e. under the same `NetworkObject`) and adding additional comments. Reverting back to just checking `InLocalSpace` (as opposed to the interpolator's) when applying a position on the non-authority side. * test fix Fixing some issues with `NestedNetworkTransformTests` assets to account for some past updates. Fixing an issue with `NetworkTransformTests` where it needs to not just advance the tick (for updates) but needs to also advance to the next tick. * fix caught scenario where `NetworkObject.NetworkTransforms` could not be set properly. * fix This fixes a minor "blip" when transitioning from world to local space, * test disabling two tests that need to be reviewed by Kitty and/or re-written. * fix Updating all NetworkTransform instances that belong to a specific NetworkObject as opposed to just the root. Also not updating when not spawned or disabled NetworkTransforms. * test Making test asset adjustments for recent updates in NetworkTransform. * update Adding change log entry. * update mid-point check-in * test Updating interpolation test to recent NetworkTransform updates. * update wip towards getting a cleaner divide between the two modes. * update Some adjustments to when nested children check their own state updates or exit early. * update Cleaning up some Rigidbody references and making Rigidbody & Rigidbody2D accessible via NetworkRigidbody and NetworkRigidbody2D. * update Adding an internal InternalOnNetworkObjectParentChanged method that gets invoked ahead of OnNetworkObjectParentChanged so user code can't override any NGO components that need this kind of notification. * update Adding InternalOnNetworkSessionSynchronized to be invoked by NGO components to assure they don't get overridden by user script. * update Renaming some internal properties that are common names and would conflict with serialization if a user defined them in a derived class. Making sure both the position and rotation interpolators are configured for the transform space when reset. Adding the ability to change the parent locally when running with a client-server network topology. Adding SwitchTransformSpaceWhenParented property to the NetworkTransformEditor. Shifting all of the non-authority's final synchronization logic to occur either once a client's initial connection synchronization is complete or when all of the NetworkObject's components have run through the spawn process. * update Adding some improved and needed UI updates to NetworkBehaviour derived components and NetworkManager. This includes a new NetcodeEditorBase class that allows users to more easily create customized, multi-generation, components that have their properties organized based on the generation of each child. * fix Wrapping the NetworkRigidbodyBaseEditor within physics defines. * style >.< (sigh) null checks can be simplified style/standards update. * update switching from TT as a class to TT as a MonoBehaviour. * fix This fixes an issue where a server instance parenting with AllowOwnerToParent set would send to itself. Adding check within the NetworkObject parenting logic to pass through to the server portion of sending the parenting message. * test adding some validation tests for the updates made in #3013 * update adding changelog entries * fix This fixes the two failing tests within NetworkTransformAnticipationTest and updates AnticipatedNetworkTransform to account for #3013's updates/changes. * fix Removing the added base.OnInspectorGUI() call (was causing duplicated properties) * update Assure the callouts and call-to-action buttons show up outside of the Foldout Group when extending NetworkManager. Assure that the NetworkManager has no Foldout Group when it is not extended.
1 parent 21cf55e commit aee018c

25 files changed

+1363
-374
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,26 @@ Additional documentation and release notes are available at [Multiplayer Documen
1111
### Added
1212

1313
- Added "Check for NetworkObject Component" property to the Multiplayer->Netcode for GameObjects project settings. When disabled, this will bypass the in-editor `NetworkObject` check on `NetworkBehaviour` components. (#3031)
14+
- Added `NetworkTransform.SwitchTransformSpaceWhenParented` property that, when enabled, will handle the world to local, local to world, and local to local transform space transitions when interpolation is enabled. (#3013)
15+
- Added `NetworkTransform.TickSyncChildren` that, when enabled, will tick synchronize nested and/or child `NetworkTransform` components to eliminate any potential visual jittering that could occur if the `NetworkTransform` instances get into a state where their state updates are landing on different network ticks. (#3013)
16+
- Added `NetworkObject.AllowOwnerToParent` property to provide the ability to allow clients to parent owned objects when running in a client-server network topology. (#3013)
17+
- Added `NetworkObject.SyncOwnerTransformWhenParented` property to provide a way to disable applying the server's transform information in the parenting message on the client owner instance which can be useful for owner authoritative motion models. (#3013)
18+
- Added `NetcodeEditorBase` editor helper class to provide easier modification and extension of the SDK's components. (#3013)
1419

1520
### Fixed
1621

17-
-Fixed issue where the `NetworkSpawnManager.HandleNetworkObjectShow` could throw an exception if one of the `NetworkObject` components to show was destroyed during the same frame. (#3030)
22+
- Fixed issue where the `NetworkSpawnManager.HandleNetworkObjectShow` could throw an exception if one of the `NetworkObject` components to show was destroyed during the same frame. (#3030)
1823
- Fixed issue where the `NetworkManagerHelper` was continuing to check for hierarchy changes when in play mode. (#3026)
24+
- Fixed issue with newly/late joined clients and `NetworkTransform` synchronization of parented `NetworkObject` instances. (#3013)
25+
- Fixed issue with smooth transitions between transform spaces when interpolation is enabled (requires `NetworkTransform.SwitchTransformSpaceWhenParented` to be enabled). (#3013)
1926

2027
### Changed
2128

29+
- Changed `NetworkTransformEditor` so it now derives from `NetcodeEditorBase`. (#3013)
30+
- Changed `NetworkRigidbodyBaseEditor` so it now derives from `NetcodeEditorBase`. (#3013)
31+
- Changed `NetworkManagerEditor` so it now derives from `NetcodeEditorBase`. (#3013)
32+
33+
2234
## [2.0.0-pre.4] - 2024-08-21
2335

2436
### Added
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using UnityEditor;
3+
using UnityEngine;
4+
5+
namespace Unity.Netcode.Editor
6+
{
7+
/// <summary>
8+
/// The base Netcode Editor helper class to display derived <see cref="MonoBehaviour"/> based components <br />
9+
/// where each child generation's properties will be displayed within a FoldoutHeaderGroup.
10+
/// </summary>
11+
[CanEditMultipleObjects]
12+
public partial class NetcodeEditorBase<TT> : UnityEditor.Editor where TT : MonoBehaviour
13+
{
14+
/// <inheritdoc/>
15+
public virtual void OnEnable()
16+
{
17+
}
18+
19+
/// <summary>
20+
/// Helper method to draw the properties of the specified child type <typeparamref name="T"/> component within a FoldoutHeaderGroup.
21+
/// </summary>
22+
/// <typeparam name="T">The specific child type that should have its properties drawn.</typeparam>
23+
/// <param name="type">The component type of the <see cref="UnityEditor.Editor.target"/>.</param>
24+
/// <param name="displayProperties">The <see cref="Action"/> to invoke that will draw the type <typeparamref name="T"/> properties.</param>
25+
/// <param name="expanded">The <typeparamref name="T"/> current expanded property value</param>
26+
/// <param name="setExpandedProperty">The <see cref="Action{bool}"/> invoked to apply the updated <paramref name="expanded"/> value.</param>
27+
protected void DrawFoldOutGroup<T>(Type type, Action displayProperties, bool expanded, Action<bool> setExpandedProperty)
28+
{
29+
var baseClass = target as TT;
30+
EditorGUI.BeginChangeCheck();
31+
serializedObject.Update();
32+
var currentClass = typeof(T);
33+
if (type.IsSubclassOf(currentClass) || (!type.IsSubclassOf(currentClass) && currentClass.IsSubclassOf(typeof(TT))))
34+
{
35+
var expandedValue = EditorGUILayout.BeginFoldoutHeaderGroup(expanded, $"{currentClass.Name} Properties");
36+
if (expandedValue)
37+
{
38+
EditorGUILayout.EndFoldoutHeaderGroup();
39+
displayProperties.Invoke();
40+
}
41+
else
42+
{
43+
EditorGUILayout.EndFoldoutHeaderGroup();
44+
}
45+
EditorGUILayout.Space();
46+
setExpandedProperty.Invoke(expandedValue);
47+
}
48+
else
49+
{
50+
displayProperties.Invoke();
51+
}
52+
serializedObject.ApplyModifiedProperties();
53+
EditorGUI.EndChangeCheck();
54+
}
55+
56+
/// <inheritdoc/>
57+
public override void OnInspectorGUI()
58+
{
59+
serializedObject.ApplyModifiedProperties();
60+
}
61+
}
62+
}

com.unity.netcode.gameobjects/Editor/NetcodeEditorBase.cs.meta

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,8 @@ public override void OnInspectorGUI()
301301

302302
expanded = false;
303303
}
304-
305-
serializedObject.ApplyModifiedProperties();
306304
EditorGUI.EndChangeCheck();
305+
serializedObject.ApplyModifiedProperties();
307306
}
308307

309308
/// <summary>

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

+47-38
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Unity.Netcode.Editor
1313
/// </summary>
1414
[CustomEditor(typeof(NetworkManager), true)]
1515
[CanEditMultipleObjects]
16-
public class NetworkManagerEditor : UnityEditor.Editor
16+
public class NetworkManagerEditor : NetcodeEditorBase<NetworkManager>
1717
{
1818
private static GUIStyle s_CenteredWordWrappedLabelStyle;
1919
private static GUIStyle s_HelpBoxStyle;
@@ -168,16 +168,8 @@ private void CheckNullProperties()
168168
.FindPropertyRelative(nameof(NetworkPrefabs.NetworkPrefabsLists));
169169
}
170170

171-
/// <inheritdoc/>
172-
public override void OnInspectorGUI()
171+
private void DisplayNetworkManagerProperties()
173172
{
174-
Initialize();
175-
CheckNullProperties();
176-
177-
#if !MULTIPLAYER_TOOLS
178-
DrawInstallMultiplayerToolsTip();
179-
#endif
180-
181173
if (!m_NetworkManager.IsServer && !m_NetworkManager.IsClient)
182174
{
183175
serializedObject.Update();
@@ -298,48 +290,50 @@ public override void OnInspectorGUI()
298290
}
299291

300292
serializedObject.ApplyModifiedProperties();
293+
}
294+
}
301295

296+
private void DisplayCallToActionButtons()
297+
{
298+
if (!m_NetworkManager.IsServer && !m_NetworkManager.IsClient)
299+
{
300+
string buttonDisabledReasonSuffix = "";
302301

303-
// Start buttons below
302+
if (!EditorApplication.isPlaying)
304303
{
305-
string buttonDisabledReasonSuffix = "";
304+
buttonDisabledReasonSuffix = ". This can only be done in play mode";
305+
GUI.enabled = false;
306+
}
306307

307-
if (!EditorApplication.isPlaying)
308+
if (m_NetworkManager.NetworkConfig.NetworkTopology == NetworkTopologyTypes.ClientServer)
309+
{
310+
if (GUILayout.Button(new GUIContent("Start Host", "Starts a host instance" + buttonDisabledReasonSuffix)))
308311
{
309-
buttonDisabledReasonSuffix = ". This can only be done in play mode";
310-
GUI.enabled = false;
312+
m_NetworkManager.StartHost();
311313
}
312314

313-
if (m_NetworkManager.NetworkConfig.NetworkTopology == NetworkTopologyTypes.ClientServer)
315+
if (GUILayout.Button(new GUIContent("Start Server", "Starts a server instance" + buttonDisabledReasonSuffix)))
314316
{
315-
if (GUILayout.Button(new GUIContent("Start Host", "Starts a host instance" + buttonDisabledReasonSuffix)))
316-
{
317-
m_NetworkManager.StartHost();
318-
}
319-
320-
if (GUILayout.Button(new GUIContent("Start Server", "Starts a server instance" + buttonDisabledReasonSuffix)))
321-
{
322-
m_NetworkManager.StartServer();
323-
}
317+
m_NetworkManager.StartServer();
318+
}
324319

325-
if (GUILayout.Button(new GUIContent("Start Client", "Starts a client instance" + buttonDisabledReasonSuffix)))
326-
{
327-
m_NetworkManager.StartClient();
328-
}
320+
if (GUILayout.Button(new GUIContent("Start Client", "Starts a client instance" + buttonDisabledReasonSuffix)))
321+
{
322+
m_NetworkManager.StartClient();
329323
}
330-
else
324+
}
325+
else
326+
{
327+
if (GUILayout.Button(new GUIContent("Start Client", "Starts a distributed authority client instance" + buttonDisabledReasonSuffix)))
331328
{
332-
if (GUILayout.Button(new GUIContent("Start Client", "Starts a distributed authority client instance" + buttonDisabledReasonSuffix)))
333-
{
334-
m_NetworkManager.StartClient();
335-
}
329+
m_NetworkManager.StartClient();
336330
}
331+
}
337332

338333

339-
if (!EditorApplication.isPlaying)
340-
{
341-
GUI.enabled = true;
342-
}
334+
if (!EditorApplication.isPlaying)
335+
{
336+
GUI.enabled = true;
343337
}
344338
}
345339
else
@@ -368,6 +362,21 @@ public override void OnInspectorGUI()
368362
}
369363
}
370364

365+
/// <inheritdoc/>
366+
public override void OnInspectorGUI()
367+
{
368+
var networkManager = target as NetworkManager;
369+
Initialize();
370+
CheckNullProperties();
371+
#if !MULTIPLAYER_TOOLS
372+
DrawInstallMultiplayerToolsTip();
373+
#endif
374+
void SetExpanded(bool expanded) { networkManager.NetworkManagerExpanded = expanded; };
375+
DrawFoldOutGroup<NetworkManager>(networkManager.GetType(), DisplayNetworkManagerProperties, networkManager.NetworkManagerExpanded, SetExpanded);
376+
DisplayCallToActionButtons();
377+
base.OnInspectorGUI();
378+
}
379+
371380
private static void DrawInstallMultiplayerToolsTip()
372381
{
373382
const string getToolsText = "Access additional tools for multiplayer development by installing the Multiplayer Tools package in the Package Manager.";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
2+
using Unity.Netcode.Components;
3+
using UnityEditor;
4+
5+
namespace Unity.Netcode.Editor
6+
{
7+
[CustomEditor(typeof(NetworkRigidbodyBase), true)]
8+
[CanEditMultipleObjects]
9+
public class NetworkRigidbodyBaseEditor : NetcodeEditorBase<NetworkBehaviour>
10+
{
11+
private SerializedProperty m_UseRigidBodyForMotion;
12+
private SerializedProperty m_AutoUpdateKinematicState;
13+
private SerializedProperty m_AutoSetKinematicOnDespawn;
14+
15+
16+
public override void OnEnable()
17+
{
18+
m_UseRigidBodyForMotion = serializedObject.FindProperty(nameof(NetworkRigidbodyBase.UseRigidBodyForMotion));
19+
m_AutoUpdateKinematicState = serializedObject.FindProperty(nameof(NetworkRigidbodyBase.AutoUpdateKinematicState));
20+
m_AutoSetKinematicOnDespawn = serializedObject.FindProperty(nameof(NetworkRigidbodyBase.AutoSetKinematicOnDespawn));
21+
22+
base.OnEnable();
23+
}
24+
25+
private void DisplayNetworkRigidbodyProperties()
26+
{
27+
EditorGUILayout.PropertyField(m_UseRigidBodyForMotion);
28+
EditorGUILayout.PropertyField(m_AutoUpdateKinematicState);
29+
EditorGUILayout.PropertyField(m_AutoSetKinematicOnDespawn);
30+
}
31+
32+
/// <inheritdoc/>
33+
public override void OnInspectorGUI()
34+
{
35+
var networkRigidbodyBase = target as NetworkRigidbodyBase;
36+
void SetExpanded(bool expanded) { networkRigidbodyBase.NetworkRigidbodyBaseExpanded = expanded; };
37+
DrawFoldOutGroup<NetworkRigidbodyBase>(networkRigidbodyBase.GetType(), DisplayNetworkRigidbodyProperties, networkRigidbodyBase.NetworkRigidbodyBaseExpanded, SetExpanded);
38+
base.OnInspectorGUI();
39+
}
40+
}
41+
}
42+
#endif

com.unity.netcode.gameobjects/Editor/NetworkRigidbodyBaseEditor.cs.meta

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

+27-8
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ namespace Unity.Netcode.Editor
88
/// The <see cref="CustomEditor"/> for <see cref="NetworkTransform"/>
99
/// </summary>
1010
[CustomEditor(typeof(NetworkTransform), true)]
11-
public class NetworkTransformEditor : UnityEditor.Editor
11+
[CanEditMultipleObjects]
12+
public class NetworkTransformEditor : NetcodeEditorBase<NetworkBehaviour>
1213
{
14+
private SerializedProperty m_SwitchTransformSpaceWhenParented;
15+
private SerializedProperty m_TickSyncChildren;
1316
private SerializedProperty m_UseUnreliableDeltas;
1417
private SerializedProperty m_SyncPositionXProperty;
1518
private SerializedProperty m_SyncPositionYProperty;
@@ -39,8 +42,10 @@ public class NetworkTransformEditor : UnityEditor.Editor
3942
private static GUIContent s_ScaleLabel = EditorGUIUtility.TrTextContent("Scale");
4043

4144
/// <inheritdoc/>
42-
public virtual void OnEnable()
45+
public override void OnEnable()
4346
{
47+
m_SwitchTransformSpaceWhenParented = serializedObject.FindProperty(nameof(NetworkTransform.SwitchTransformSpaceWhenParented));
48+
m_TickSyncChildren = serializedObject.FindProperty(nameof(NetworkTransform.TickSyncChildren));
4449
m_UseUnreliableDeltas = serializedObject.FindProperty(nameof(NetworkTransform.UseUnreliableDeltas));
4550
m_SyncPositionXProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncPositionX));
4651
m_SyncPositionYProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncPositionY));
@@ -61,10 +66,10 @@ public virtual void OnEnable()
6166
m_UseHalfFloatPrecision = serializedObject.FindProperty(nameof(NetworkTransform.UseHalfFloatPrecision));
6267
m_SlerpPosition = serializedObject.FindProperty(nameof(NetworkTransform.SlerpPosition));
6368
m_AuthorityMode = serializedObject.FindProperty(nameof(NetworkTransform.AuthorityMode));
69+
base.OnEnable();
6470
}
6571

66-
/// <inheritdoc/>
67-
public override void OnInspectorGUI()
72+
private void DisplayNetworkTransformProperties()
6873
{
6974
var networkTransform = target as NetworkTransform;
7075
EditorGUILayout.LabelField("Axis to Synchronize", EditorStyles.boldLabel);
@@ -141,9 +146,15 @@ public override void OnInspectorGUI()
141146
EditorGUILayout.PropertyField(m_ScaleThresholdProperty);
142147
EditorGUILayout.Space();
143148
EditorGUILayout.LabelField("Delivery", EditorStyles.boldLabel);
149+
EditorGUILayout.PropertyField(m_TickSyncChildren);
144150
EditorGUILayout.PropertyField(m_UseUnreliableDeltas);
145151
EditorGUILayout.Space();
146152
EditorGUILayout.LabelField("Configurations", EditorStyles.boldLabel);
153+
EditorGUILayout.PropertyField(m_SwitchTransformSpaceWhenParented);
154+
if (m_SwitchTransformSpaceWhenParented.boolValue)
155+
{
156+
m_TickSyncChildren.boolValue = true;
157+
}
147158
EditorGUILayout.PropertyField(m_InLocalSpaceProperty);
148159
if (!networkTransform.HideInterpolateValue)
149160
{
@@ -163,23 +174,31 @@ public override void OnInspectorGUI()
163174

164175
#if COM_UNITY_MODULES_PHYSICS
165176
// if rigidbody is present but network rigidbody is not present
166-
var go = ((NetworkTransform)target).gameObject;
167-
if (go.TryGetComponent<Rigidbody>(out _) && go.TryGetComponent<NetworkRigidbody>(out _) == false)
177+
if (networkTransform.TryGetComponent<Rigidbody>(out _) && networkTransform.TryGetComponent<NetworkRigidbody>(out _) == false)
168178
{
169179
EditorGUILayout.HelpBox("This GameObject contains a Rigidbody but no NetworkRigidbody.\n" +
170180
"Add a NetworkRigidbody component to improve Rigidbody synchronization.", MessageType.Warning);
171181
}
172182
#endif // COM_UNITY_MODULES_PHYSICS
173183

174184
#if COM_UNITY_MODULES_PHYSICS2D
175-
if (go.TryGetComponent<Rigidbody2D>(out _) && go.TryGetComponent<NetworkRigidbody2D>(out _) == false)
185+
if (networkTransform.TryGetComponent<Rigidbody2D>(out _) && networkTransform.TryGetComponent<NetworkRigidbody2D>(out _) == false)
176186
{
177187
EditorGUILayout.HelpBox("This GameObject contains a Rigidbody2D but no NetworkRigidbody2D.\n" +
178188
"Add a NetworkRigidbody2D component to improve Rigidbody2D synchronization.", MessageType.Warning);
179189
}
180190
#endif // COM_UNITY_MODULES_PHYSICS2D
191+
}
192+
181193

182-
serializedObject.ApplyModifiedProperties();
194+
195+
/// <inheritdoc/>
196+
public override void OnInspectorGUI()
197+
{
198+
var networkTransform = target as NetworkTransform;
199+
void SetExpanded(bool expanded) { networkTransform.NetworkTransformExpanded = expanded; };
200+
DrawFoldOutGroup<NetworkTransform>(networkTransform.GetType(), DisplayNetworkTransformProperties, networkTransform.NetworkTransformExpanded, SetExpanded);
201+
base.OnInspectorGUI();
183202
}
184203
}
185204
}

0 commit comments

Comments
 (0)