Skip to content

fix: NetworkTransform initial synchronization, parenting, smooth transitions between transform spaces, and UI updates #3013

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7d5073a
fix
NoelStephensUnity Aug 13, 2024
cd158f7
fix
NoelStephensUnity Aug 13, 2024
1fe5a95
wip
NoelStephensUnity Aug 15, 2024
7099d55
fix
NoelStephensUnity Aug 15, 2024
f574314
update
NoelStephensUnity Aug 16, 2024
ee03337
fix
NoelStephensUnity Aug 16, 2024
e521c2a
test fix
NoelStephensUnity Aug 16, 2024
1965056
fix
NoelStephensUnity Aug 16, 2024
3a50f7f
fix
NoelStephensUnity Aug 17, 2024
4af00c1
test
NoelStephensUnity Aug 17, 2024
73c0e05
fix
NoelStephensUnity Aug 19, 2024
7343471
test
NoelStephensUnity Aug 19, 2024
ef5f8ec
update
NoelStephensUnity Aug 19, 2024
3cd9210
Merge branch 'develop-2.0.0' into fix/nested-networktransforms-not-up…
NoelStephensUnity Aug 19, 2024
f60c29e
update
NoelStephensUnity Aug 19, 2024
ba770e4
test
NoelStephensUnity Aug 19, 2024
dd01870
Merge branch 'fix/nested-networktransforms-not-updating' into fix/own…
NoelStephensUnity Aug 19, 2024
074710c
update
NoelStephensUnity Aug 20, 2024
c943803
Merge branch 'develop-2.0.0' into fix/owner-object-parenting-no-sync-…
NoelStephensUnity Aug 20, 2024
5da0a92
update
NoelStephensUnity Aug 22, 2024
9cb8f06
update
NoelStephensUnity Aug 28, 2024
4c02ab0
update
NoelStephensUnity Aug 28, 2024
e5d2603
update
NoelStephensUnity Aug 29, 2024
e9673e8
update
NoelStephensUnity Aug 30, 2024
a2ee9c0
update
NoelStephensUnity Aug 30, 2024
d500bc9
fix
NoelStephensUnity Aug 30, 2024
eb94b5e
style
NoelStephensUnity Aug 30, 2024
dc1be1f
update
NoelStephensUnity Aug 30, 2024
ff21e36
fix
NoelStephensUnity Aug 30, 2024
542f9ab
test
NoelStephensUnity Aug 30, 2024
bc940ef
Merge branch 'develop-2.0.0' into fix/owner-object-parenting-no-sync-…
NoelStephensUnity Aug 30, 2024
e033bf5
update
NoelStephensUnity Aug 30, 2024
2ede073
fix
NoelStephensUnity Aug 30, 2024
e1b0046
fix
NoelStephensUnity Aug 31, 2024
337376d
Merge branch 'develop-2.0.0' into fix/owner-object-parenting-no-sync-…
NoelStephensUnity Aug 31, 2024
c1e9615
update
NoelStephensUnity Sep 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,26 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Added

- 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)
- 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)
- 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)
- Added `NetworkObject.AllowOwnerToParent` property to provide the ability to allow clients to parent owned objects when running in a client-server network topology. (#3013)
- 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)
- Added `NetcodeEditorBase` editor helper class to provide easier modification and extension of the SDK's components. (#3013)

### Fixed

-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)
- 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)
- Fixed issue where the `NetworkManagerHelper` was continuing to check for hierarchy changes when in play mode. (#3026)
- Fixed issue with newly/late joined clients and `NetworkTransform` synchronization of parented `NetworkObject` instances. (#3013)
- Fixed issue with smooth transitions between transform spaces when interpolation is enabled (requires `NetworkTransform.SwitchTransformSpaceWhenParented` to be enabled). (#3013)

### Changed

- Changed `NetworkTransformEditor` so it now derives from `NetcodeEditorBase`. (#3013)
- Changed `NetworkRigidbodyBaseEditor` so it now derives from `NetcodeEditorBase`. (#3013)
- Changed `NetworkManagerEditor` so it now derives from `NetcodeEditorBase`. (#3013)


## [2.0.0-pre.4] - 2024-08-21

### Added
Expand Down
62 changes: 62 additions & 0 deletions com.unity.netcode.gameobjects/Editor/NetcodeEditorBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using UnityEditor;
using UnityEngine;

namespace Unity.Netcode.Editor
{
/// <summary>
/// The base Netcode Editor helper class to display derived <see cref="MonoBehaviour"/> based components <br />
/// where each child generation's properties will be displayed within a FoldoutHeaderGroup.
/// </summary>
[CanEditMultipleObjects]
public partial class NetcodeEditorBase<TT> : UnityEditor.Editor where TT : MonoBehaviour
{
/// <inheritdoc/>
public virtual void OnEnable()
{
}

/// <summary>
/// Helper method to draw the properties of the specified child type <typeparamref name="T"/> component within a FoldoutHeaderGroup.
/// </summary>
/// <typeparam name="T">The specific child type that should have its properties drawn.</typeparam>
/// <param name="type">The component type of the <see cref="UnityEditor.Editor.target"/>.</param>
/// <param name="displayProperties">The <see cref="Action"/> to invoke that will draw the type <typeparamref name="T"/> properties.</param>
/// <param name="expanded">The <typeparamref name="T"/> current expanded property value</param>
/// <param name="setExpandedProperty">The <see cref="Action{bool}"/> invoked to apply the updated <paramref name="expanded"/> value.</param>
protected void DrawFoldOutGroup<T>(Type type, Action displayProperties, bool expanded, Action<bool> setExpandedProperty)
{
var baseClass = target as TT;
EditorGUI.BeginChangeCheck();
serializedObject.Update();
var currentClass = typeof(T);
if (type.IsSubclassOf(currentClass) || (!type.IsSubclassOf(currentClass) && currentClass.IsSubclassOf(typeof(TT))))
{
var expandedValue = EditorGUILayout.BeginFoldoutHeaderGroup(expanded, $"{currentClass.Name} Properties");
if (expandedValue)
{
EditorGUILayout.EndFoldoutHeaderGroup();
displayProperties.Invoke();
}
else
{
EditorGUILayout.EndFoldoutHeaderGroup();
}
EditorGUILayout.Space();
setExpandedProperty.Invoke(expandedValue);
}
else
{
displayProperties.Invoke();
}
serializedObject.ApplyModifiedProperties();
EditorGUI.EndChangeCheck();
}

/// <inheritdoc/>
public override void OnInspectorGUI()
{
serializedObject.ApplyModifiedProperties();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,8 @@ public override void OnInspectorGUI()

expanded = false;
}

serializedObject.ApplyModifiedProperties();
EditorGUI.EndChangeCheck();
serializedObject.ApplyModifiedProperties();
}

/// <summary>
Expand Down
85 changes: 47 additions & 38 deletions com.unity.netcode.gameobjects/Editor/NetworkManagerEditor.cs
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a little comment here. I like the foldout idea, but I think maybe we can take the call-to-action buttons out so users can access them without expanding the foldout content, especially during runtime when there's nothing much within the foldout section. I made a quick mock here! Please lemme know if this makes sense!

Side note: would it make sense to show network manager properties during runtime? will people need this information?

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome feedback... and good points.
Made the suggested changes and pushed the update.
👍

Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Unity.Netcode.Editor
/// </summary>
[CustomEditor(typeof(NetworkManager), true)]
[CanEditMultipleObjects]
public class NetworkManagerEditor : UnityEditor.Editor
public class NetworkManagerEditor : NetcodeEditorBase<NetworkManager>
{
private static GUIStyle s_CenteredWordWrappedLabelStyle;
private static GUIStyle s_HelpBoxStyle;
Expand Down Expand Up @@ -168,16 +168,8 @@ private void CheckNullProperties()
.FindPropertyRelative(nameof(NetworkPrefabs.NetworkPrefabsLists));
}

/// <inheritdoc/>
public override void OnInspectorGUI()
private void DisplayNetworkManagerProperties()
{
Initialize();
CheckNullProperties();

#if !MULTIPLAYER_TOOLS
DrawInstallMultiplayerToolsTip();
#endif

if (!m_NetworkManager.IsServer && !m_NetworkManager.IsClient)
{
serializedObject.Update();
Expand Down Expand Up @@ -298,48 +290,50 @@ public override void OnInspectorGUI()
}

serializedObject.ApplyModifiedProperties();
}
}

private void DisplayCallToActionButtons()
{
if (!m_NetworkManager.IsServer && !m_NetworkManager.IsClient)
{
string buttonDisabledReasonSuffix = "";

// Start buttons below
if (!EditorApplication.isPlaying)
{
string buttonDisabledReasonSuffix = "";
buttonDisabledReasonSuffix = ". This can only be done in play mode";
GUI.enabled = false;
}

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

if (m_NetworkManager.NetworkConfig.NetworkTopology == NetworkTopologyTypes.ClientServer)
if (GUILayout.Button(new GUIContent("Start Server", "Starts a server instance" + buttonDisabledReasonSuffix)))
{
if (GUILayout.Button(new GUIContent("Start Host", "Starts a host instance" + buttonDisabledReasonSuffix)))
{
m_NetworkManager.StartHost();
}

if (GUILayout.Button(new GUIContent("Start Server", "Starts a server instance" + buttonDisabledReasonSuffix)))
{
m_NetworkManager.StartServer();
}
m_NetworkManager.StartServer();
}

if (GUILayout.Button(new GUIContent("Start Client", "Starts a client instance" + buttonDisabledReasonSuffix)))
{
m_NetworkManager.StartClient();
}
if (GUILayout.Button(new GUIContent("Start Client", "Starts a client instance" + buttonDisabledReasonSuffix)))
{
m_NetworkManager.StartClient();
}
else
}
else
{
if (GUILayout.Button(new GUIContent("Start Client", "Starts a distributed authority client instance" + buttonDisabledReasonSuffix)))
{
if (GUILayout.Button(new GUIContent("Start Client", "Starts a distributed authority client instance" + buttonDisabledReasonSuffix)))
{
m_NetworkManager.StartClient();
}
m_NetworkManager.StartClient();
}
}


if (!EditorApplication.isPlaying)
{
GUI.enabled = true;
}
if (!EditorApplication.isPlaying)
{
GUI.enabled = true;
}
}
else
Expand Down Expand Up @@ -368,6 +362,21 @@ public override void OnInspectorGUI()
}
}

/// <inheritdoc/>
public override void OnInspectorGUI()
{
var networkManager = target as NetworkManager;
Initialize();
CheckNullProperties();
#if !MULTIPLAYER_TOOLS
DrawInstallMultiplayerToolsTip();
#endif
void SetExpanded(bool expanded) { networkManager.NetworkManagerExpanded = expanded; };
DrawFoldOutGroup<NetworkManager>(networkManager.GetType(), DisplayNetworkManagerProperties, networkManager.NetworkManagerExpanded, SetExpanded);
DisplayCallToActionButtons();
base.OnInspectorGUI();
}

private static void DrawInstallMultiplayerToolsTip()
{
const string getToolsText = "Access additional tools for multiplayer development by installing the Multiplayer Tools package in the Package Manager.";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
using Unity.Netcode.Components;
using UnityEditor;

namespace Unity.Netcode.Editor
{
[CustomEditor(typeof(NetworkRigidbodyBase), true)]
[CanEditMultipleObjects]
public class NetworkRigidbodyBaseEditor : NetcodeEditorBase<NetworkBehaviour>
{
private SerializedProperty m_UseRigidBodyForMotion;
private SerializedProperty m_AutoUpdateKinematicState;
private SerializedProperty m_AutoSetKinematicOnDespawn;


public override void OnEnable()
{
m_UseRigidBodyForMotion = serializedObject.FindProperty(nameof(NetworkRigidbodyBase.UseRigidBodyForMotion));
m_AutoUpdateKinematicState = serializedObject.FindProperty(nameof(NetworkRigidbodyBase.AutoUpdateKinematicState));
m_AutoSetKinematicOnDespawn = serializedObject.FindProperty(nameof(NetworkRigidbodyBase.AutoSetKinematicOnDespawn));

base.OnEnable();
}

private void DisplayNetworkRigidbodyProperties()
{
EditorGUILayout.PropertyField(m_UseRigidBodyForMotion);
EditorGUILayout.PropertyField(m_AutoUpdateKinematicState);
EditorGUILayout.PropertyField(m_AutoSetKinematicOnDespawn);
}

/// <inheritdoc/>
public override void OnInspectorGUI()
{
var networkRigidbodyBase = target as NetworkRigidbodyBase;
void SetExpanded(bool expanded) { networkRigidbodyBase.NetworkRigidbodyBaseExpanded = expanded; };
DrawFoldOutGroup<NetworkRigidbodyBase>(networkRigidbodyBase.GetType(), DisplayNetworkRigidbodyProperties, networkRigidbodyBase.NetworkRigidbodyBaseExpanded, SetExpanded);
base.OnInspectorGUI();
}
}
}
#endif

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 27 additions & 8 deletions com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ namespace Unity.Netcode.Editor
/// The <see cref="CustomEditor"/> for <see cref="NetworkTransform"/>
/// </summary>
[CustomEditor(typeof(NetworkTransform), true)]
public class NetworkTransformEditor : UnityEditor.Editor
[CanEditMultipleObjects]
public class NetworkTransformEditor : NetcodeEditorBase<NetworkBehaviour>
{
private SerializedProperty m_SwitchTransformSpaceWhenParented;
private SerializedProperty m_TickSyncChildren;
private SerializedProperty m_UseUnreliableDeltas;
private SerializedProperty m_SyncPositionXProperty;
private SerializedProperty m_SyncPositionYProperty;
Expand Down Expand Up @@ -39,8 +42,10 @@ public class NetworkTransformEditor : UnityEditor.Editor
private static GUIContent s_ScaleLabel = EditorGUIUtility.TrTextContent("Scale");

/// <inheritdoc/>
public virtual void OnEnable()
public override void OnEnable()
{
m_SwitchTransformSpaceWhenParented = serializedObject.FindProperty(nameof(NetworkTransform.SwitchTransformSpaceWhenParented));
m_TickSyncChildren = serializedObject.FindProperty(nameof(NetworkTransform.TickSyncChildren));
m_UseUnreliableDeltas = serializedObject.FindProperty(nameof(NetworkTransform.UseUnreliableDeltas));
m_SyncPositionXProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncPositionX));
m_SyncPositionYProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncPositionY));
Expand All @@ -61,10 +66,10 @@ public virtual void OnEnable()
m_UseHalfFloatPrecision = serializedObject.FindProperty(nameof(NetworkTransform.UseHalfFloatPrecision));
m_SlerpPosition = serializedObject.FindProperty(nameof(NetworkTransform.SlerpPosition));
m_AuthorityMode = serializedObject.FindProperty(nameof(NetworkTransform.AuthorityMode));
base.OnEnable();
}

/// <inheritdoc/>
public override void OnInspectorGUI()
private void DisplayNetworkTransformProperties()
{
var networkTransform = target as NetworkTransform;
EditorGUILayout.LabelField("Axis to Synchronize", EditorStyles.boldLabel);
Expand Down Expand Up @@ -141,9 +146,15 @@ public override void OnInspectorGUI()
EditorGUILayout.PropertyField(m_ScaleThresholdProperty);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Delivery", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_TickSyncChildren);
EditorGUILayout.PropertyField(m_UseUnreliableDeltas);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Configurations", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_SwitchTransformSpaceWhenParented);
if (m_SwitchTransformSpaceWhenParented.boolValue)
{
m_TickSyncChildren.boolValue = true;
}
EditorGUILayout.PropertyField(m_InLocalSpaceProperty);
if (!networkTransform.HideInterpolateValue)
{
Expand All @@ -163,23 +174,31 @@ public override void OnInspectorGUI()

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

#if COM_UNITY_MODULES_PHYSICS2D
if (go.TryGetComponent<Rigidbody2D>(out _) && go.TryGetComponent<NetworkRigidbody2D>(out _) == false)
if (networkTransform.TryGetComponent<Rigidbody2D>(out _) && networkTransform.TryGetComponent<NetworkRigidbody2D>(out _) == false)
{
EditorGUILayout.HelpBox("This GameObject contains a Rigidbody2D but no NetworkRigidbody2D.\n" +
"Add a NetworkRigidbody2D component to improve Rigidbody2D synchronization.", MessageType.Warning);
}
#endif // COM_UNITY_MODULES_PHYSICS2D
}


serializedObject.ApplyModifiedProperties();

/// <inheritdoc/>
public override void OnInspectorGUI()
{
var networkTransform = target as NetworkTransform;
void SetExpanded(bool expanded) { networkTransform.NetworkTransformExpanded = expanded; };
DrawFoldOutGroup<NetworkTransform>(networkTransform.GetType(), DisplayNetworkTransformProperties, networkTransform.NetworkTransformExpanded, SetExpanded);
base.OnInspectorGUI();
}
}
}
Loading
Loading