Skip to content

Commit 39a2448

Browse files
fix: NetworkAnimator does not update animator's parameters unless the animator's layer changes [MTT-3492] (#1946)
* fix Fix for animators that have one layer and handle most animation state changes via properties. * test and style Adding an integration test to validate the changes. Updated comments in NetworkAnimator. * style MTT-3492 Remove namespace references I was not using. * style only applying changes required for asmdef file. * update and test Removed the duplicate tracking for parameters. Added the ability to make it owner or server authoritative. Included triggers in this update. Added test for triggers. * style * update removing unused parameter state class * update and fix This updates the manual animation test so we can visually see NetworkAnimator working properly. This fixes the issue where late joining clients would not be updated to the NetworkAnimator's state. This fixes some test project asset related issues including to make sure we are always set to run in the background and have a target fps of 120. * update and fix This fixes the issue where it would sometimes not clean up/dispose the "cache" native array. This improves the client synchronization (as best for the current way that we write information). Manual Test Updates: This fixes an issue with scale as well as getting other players to join and distribute evenly. This fixes the issue with the prefab asset itself (scale issue impacted pulse). Increased send/receive buffer sizes (we send a lot of data for animations currently) * update Making CleanUp private. * fix This lost its parameters for some reason... * fix Missed adding the trigger state back. * test This verifies that late joining clients get synchronized to the current NetworkAnimator state. This also fixes the issue where stopping a client during an integration test always meant that you wanted to delete it. Now, you have the option to not destroy in the event you want to stop a client, do some stuff, and then reconnect the client. * test and style Minor tweak and additional check that the AnimatorTestHelper instances equals the TotalClient count (more of a sanity check). Added some comments and removed some LFs. * Test and Style I hooked up the TriggerTest to the wrong state. Fixed issue by creating a new state that is activated by the test trigger. Changing the warning to an actual error in TriggerTest (i.e. if that happens the test should fail). * Update This includes several adjustments to improve performance. -Parameters are now sent separately -New internal NetworkAnimatorStateChangeHandler that changes when: -It detects changes to the Animator -The server-side client forwarded RPC messages are processed here -Removed the OwnerAuthoritative public bool This also include integration test adjustments in order to be able to create and join a new client on the fly during a test. * fix This got test running locally in a stand alone testrunner build. Going to give this a shot in Yamato land. * wip Sorting out the issue with server-side owner late joining client synchronization. This version works with all tests ==but== the server-side owner late joining client portion... still trying to find this bug. * fix This reverts Triggers back to being set by an RPC (better to separate for now). This also fixes minor issues with a player joining right in the middle of a transition. This also fixes issue where trigger paths were not being set when transitioning (still could use more work). This fixes the issue with the NetworkAnimator failing on the late joining player test where the late joining player could join while an Animator is in the middle of a transition. * style * style * update This improves upon the synchronization of a late joining client when connected while an animation is in the middle of a transition (it doesn't fix the issue completely, but is closer to being synchronized with the source animation) * update Removing VerboseDebug information * Test Added a small profiling test to profile where we spend time. (sending RPCs) * update - optimize Optimizing how we send parameter updates. Now we only send the parameters that changed. This also avoids some smaller allocations by reusing a ClientRpcParams instance and a List<ulong> to hold the client ids to send to. * style updating a missed whitespace * update MTT-3492 MTT-2644 Updating what was fixed in the change log. * update Minor tweaks suggested by Fatih.
1 parent b9946cd commit 39a2448

37 files changed

+3632
-538
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ Additional documentation and release notes are available at [Multiplayer Documen
2525
- Fixed issues when multiple `ConnectionApprovalCallback`s were registered (#1972)
2626
- `FixedString` types can now be used in NetworkVariables and RPCs again without requiring a `ForceNetworkSerializeByMemcpy<>` wrapper (#1961)
2727
- Fixed endless dialog boxes when adding a `NetworkBehaviour` to a `NetworkManager` or vice-versa. (#1947)
28+
- Fixed `NetworkAnimator` issue where it was only synchronizing parameters if the layer or state changed or was transitioning between states. (#1946)
29+
- Fixed `NetworkAnimator` issue where when it did detect a parameter had changed it would send all parameters as opposed to only the parameters that changed. (#1946)
30+
- Fixed `NetworkAnimator` issue where it was not always disposing the `NativeArray` that is allocated when spawned. (#1946)
31+
- Fixed `NetworkAnimator` issue where it was not taking the animation speed or state speed multiplier into consideration. (#1946)
32+
- Fixed `NetworkAnimator` issue where it was not properly synchronizing late joining clients if they joined while `Animator` was transitioning between states. (#1946)
33+
- Fixed `NetworkAnimator` issue where the server was not relaying changes to non-owner clients when a client was the owner. (#1946)
2834

2935
## [1.0.0-pre.9] - 2022-05-10
3036

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

Lines changed: 575 additions & 98 deletions
Large diffs are not rendered by default.

com.unity.netcode.gameobjects/TestHelpers/Runtime/Components/ObjectNameIdentifier.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
namespace Unity.Netcode.TestHelpers.Runtime
23
{
34
public class ObjectNameIdentifier : NetworkBehaviour
@@ -13,6 +14,7 @@ public class ObjectNameIdentifier : NetworkBehaviour
1314
/// Keep a reference to the assigned NetworkObject
1415
/// <see cref="OnDestroy"/>
1516
/// </summary>
17+
[NonSerialized]
1618
private NetworkObject m_NetworkObject;
1719
private string m_OriginalName;
1820

com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public abstract class NetcodeIntegrationTest
2222
/// determine how clients will load scenes
2323
/// </summary>
2424
internal static bool IsRunning { get; private set; }
25-
protected static TimeoutHelper s_GlobalTimeoutHelper = new TimeoutHelper(4.0f);
25+
protected static TimeoutHelper s_GlobalTimeoutHelper = new TimeoutHelper(8.0f);
2626
protected static WaitForSeconds s_DefaultWaitForTick = new WaitForSeconds(1.0f / k_DefaultTickRate);
2727

2828
/// <summary>
@@ -80,9 +80,11 @@ public static void DeregisterNetworkObject(ulong localClientId, ulong networkObj
8080
}
8181
}
8282

83-
protected int TotalClients => m_UseHost ? NumberOfClients + 1 : NumberOfClients;
83+
protected int TotalClients => m_UseHost ? m_NumberOfClients + 1 : m_NumberOfClients;
8484

8585
protected const uint k_DefaultTickRate = 30;
86+
87+
private int m_NumberOfClients;
8688
protected abstract int NumberOfClients { get; }
8789

8890
/// <summary>
@@ -125,7 +127,7 @@ public enum HostOrServer
125127

126128
private NetworkManagerInstatiationMode m_NetworkManagerInstatiationMode;
127129

128-
protected bool m_EnableVerboseDebug { get; private set; }
130+
protected bool m_EnableVerboseDebug { get; set; }
129131

130132
/// <summary>
131133
/// Used to display the various integration test
@@ -171,6 +173,8 @@ protected virtual void OnOneTimeSetup()
171173
[OneTimeSetUp]
172174
public void OneTimeSetup()
173175
{
176+
Application.runInBackground = true;
177+
m_NumberOfClients = NumberOfClients;
174178
IsRunning = true;
175179
m_EnableVerboseDebug = OnSetVerboseDebug();
176180
IntegrationTestSceneHandler.VerboseDebugMode = m_EnableVerboseDebug;
@@ -255,6 +259,59 @@ protected void CreateServerAndClients()
255259
CreateServerAndClients(NumberOfClients);
256260
}
257261

262+
protected virtual void OnNewClientCreated(NetworkManager networkManager)
263+
{
264+
265+
}
266+
267+
protected virtual void OnNewClientStartedAndConnected(NetworkManager networkManager)
268+
{
269+
270+
}
271+
272+
private void AddRemoveNetworkManager(NetworkManager networkManager, bool addNetworkManager)
273+
{
274+
var clientNetworkManagersList = new List<NetworkManager>(m_ClientNetworkManagers);
275+
if (addNetworkManager)
276+
{
277+
clientNetworkManagersList.Add(networkManager);
278+
}
279+
else
280+
{
281+
clientNetworkManagersList.Remove(networkManager);
282+
}
283+
m_ClientNetworkManagers = clientNetworkManagersList.ToArray();
284+
m_NumberOfClients = clientNetworkManagersList.Count;
285+
}
286+
287+
protected IEnumerator CreateAndStartNewClient()
288+
{
289+
var networkManager = NetcodeIntegrationTestHelpers.CreateNewClient(m_ClientNetworkManagers.Length);
290+
networkManager.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
291+
OnNewClientCreated(networkManager);
292+
293+
NetcodeIntegrationTestHelpers.StartOneClient(networkManager);
294+
AddRemoveNetworkManager(networkManager, true);
295+
// Wait for the new client to connect
296+
yield return WaitForClientsConnectedOrTimeOut();
297+
if (s_GlobalTimeoutHelper.TimedOut)
298+
{
299+
AddRemoveNetworkManager(networkManager, false);
300+
Object.Destroy(networkManager.gameObject);
301+
}
302+
AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for the new client to be connected!");
303+
ClientNetworkManagerPostStart(networkManager);
304+
VerboseDebug($"[{networkManager.name}] Created and connected!");
305+
OnNewClientCreated(networkManager);
306+
}
307+
308+
protected IEnumerator StopOneClient(NetworkManager networkManager, bool destroy = false)
309+
{
310+
NetcodeIntegrationTestHelpers.StopOneClient(networkManager, destroy);
311+
AddRemoveNetworkManager(networkManager, false);
312+
yield return WaitForConditionOrTimeOut(() => !networkManager.IsConnectedClient);
313+
}
314+
258315
/// <summary>
259316
/// Creates the server and clients
260317
/// </summary>
@@ -322,30 +379,35 @@ protected virtual IEnumerator OnServerAndClientsConnected()
322379
yield return null;
323380
}
324381

382+
private void ClientNetworkManagerPostStart(NetworkManager networkManager)
383+
{
384+
networkManager.name = $"NetworkManager - Client - {networkManager.LocalClientId}";
385+
Assert.NotNull(networkManager.LocalClient.PlayerObject, $"{nameof(StartServerAndClients)} detected that client {networkManager.LocalClientId} does not have an assigned player NetworkObject!");
386+
387+
// Get all player instances for the current client NetworkManager instance
388+
var clientPlayerClones = Object.FindObjectsOfType<NetworkObject>().Where((c) => c.IsPlayerObject && c.OwnerClientId == networkManager.LocalClientId);
389+
// Add this player instance to each client player entry
390+
foreach (var playerNetworkObject in clientPlayerClones)
391+
{
392+
// When the server is not the host this needs to be done
393+
if (!m_PlayerNetworkObjects.ContainsKey(playerNetworkObject.NetworkManager.LocalClientId))
394+
{
395+
m_PlayerNetworkObjects.Add(playerNetworkObject.NetworkManager.LocalClientId, new Dictionary<ulong, NetworkObject>());
396+
}
397+
if (!m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].ContainsKey(networkManager.LocalClientId))
398+
{
399+
m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].Add(networkManager.LocalClientId, playerNetworkObject);
400+
}
401+
}
402+
}
403+
325404
protected void ClientNetworkManagerPostStartInit()
326405
{
327406
// Creates a dictionary for all player instances client and server relative
328407
// This provides a simpler way to get a specific player instance relative to a client instance
329408
foreach (var networkManager in m_ClientNetworkManagers)
330409
{
331-
networkManager.name = $"NetworkManager - Client - {networkManager.LocalClientId}";
332-
Assert.NotNull(networkManager.LocalClient.PlayerObject, $"{nameof(StartServerAndClients)} detected that client {networkManager.LocalClientId} does not have an assigned player NetworkObject!");
333-
334-
// Get all player instances for the current client NetworkManager instance
335-
var clientPlayerClones = Object.FindObjectsOfType<NetworkObject>().Where((c) => c.IsPlayerObject && c.OwnerClientId == networkManager.LocalClientId);
336-
// Add this player instance to each client player entry
337-
foreach (var playerNetworkObject in clientPlayerClones)
338-
{
339-
// When the server is not the host this needs to be done
340-
if (!m_PlayerNetworkObjects.ContainsKey(playerNetworkObject.NetworkManager.LocalClientId))
341-
{
342-
m_PlayerNetworkObjects.Add(playerNetworkObject.NetworkManager.LocalClientId, new Dictionary<ulong, NetworkObject>());
343-
}
344-
if (!m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].ContainsKey(networkManager.LocalClientId))
345-
{
346-
m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].Add(networkManager.LocalClientId, playerNetworkObject);
347-
}
348-
}
410+
ClientNetworkManagerPostStart(networkManager);
349411
}
350412
}
351413

com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTestHelpers.cs

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -169,17 +169,10 @@ public static void RegisterHandlers(NetworkManager networkManager, bool serverSi
169169
}
170170
}
171171

172-
public static NetworkManager CreateServer()
172+
private static void AddUnityTransport(NetworkManager networkManager)
173173
{
174-
// Create gameObject
175-
var go = new GameObject("NetworkManager - Server");
176-
177-
// Create networkManager component
178-
var server = go.AddComponent<NetworkManager>();
179-
NetworkManagerInstances.Insert(0, server);
180-
181174
// Create transport
182-
var unityTransport = go.AddComponent<UnityTransport>();
175+
var unityTransport = networkManager.gameObject.AddComponent<UnityTransport>();
183176
// We need to increase this buffer size for tests that spawn a bunch of things
184177
unityTransport.MaxPayloadSize = 256000;
185178
unityTransport.MaxSendQueueSize = 1024 * 1024;
@@ -189,11 +182,22 @@ public static NetworkManager CreateServer()
189182
unityTransport.ConnectTimeoutMS = 500;
190183

191184
// Set the NetworkConfig
192-
server.NetworkConfig = new NetworkConfig()
185+
networkManager.NetworkConfig = new NetworkConfig()
193186
{
194187
// Set transport
195188
NetworkTransport = unityTransport
196189
};
190+
}
191+
192+
public static NetworkManager CreateServer()
193+
{
194+
// Create gameObject
195+
var go = new GameObject("NetworkManager - Server");
196+
197+
// Create networkManager component
198+
var server = go.AddComponent<NetworkManager>();
199+
NetworkManagerInstances.Insert(0, server);
200+
AddUnityTransport(server);
197201
return server;
198202
}
199203

@@ -227,6 +231,17 @@ public static bool Create(int clientCount, out NetworkManager server, out Networ
227231
return true;
228232
}
229233

234+
internal static NetworkManager CreateNewClient(int identifier)
235+
{
236+
// Create gameObject
237+
var go = new GameObject("NetworkManager - Client - " + identifier);
238+
// Create networkManager component
239+
var networkManager = go.AddComponent<NetworkManager>();
240+
AddUnityTransport(networkManager);
241+
return networkManager;
242+
}
243+
244+
230245
/// <summary>
231246
/// Used to add a client to the already existing list of clients
232247
/// </summary>
@@ -235,23 +250,10 @@ public static bool Create(int clientCount, out NetworkManager server, out Networ
235250
public static bool CreateNewClients(int clientCount, out NetworkManager[] clients)
236251
{
237252
clients = new NetworkManager[clientCount];
238-
var activeSceneName = SceneManager.GetActiveScene().name;
239253
for (int i = 0; i < clientCount; i++)
240254
{
241-
// Create gameObject
242-
var go = new GameObject("NetworkManager - Client - " + i);
243255
// Create networkManager component
244-
clients[i] = go.AddComponent<NetworkManager>();
245-
246-
// Create transport
247-
var unityTransport = go.AddComponent<UnityTransport>();
248-
249-
// Set the NetworkConfig
250-
clients[i].NetworkConfig = new NetworkConfig()
251-
{
252-
// Set transport
253-
NetworkTransport = unityTransport
254-
};
256+
clients[i] = CreateNewClient(i);
255257
}
256258

257259
NetworkManagerInstances.AddRange(clients);
@@ -262,12 +264,15 @@ public static bool CreateNewClients(int clientCount, out NetworkManager[] client
262264
/// Stops one single client and makes sure to cleanup any static variables in this helper
263265
/// </summary>
264266
/// <param name="clientToStop"></param>
265-
public static void StopOneClient(NetworkManager clientToStop)
267+
public static void StopOneClient(NetworkManager clientToStop, bool destroy = true)
266268
{
267269
clientToStop.Shutdown();
268270
s_Hooks.Remove(clientToStop);
269-
Object.Destroy(clientToStop.gameObject);
270-
NetworkManagerInstances.Remove(clientToStop);
271+
if (destroy)
272+
{
273+
Object.Destroy(clientToStop.gameObject);
274+
NetworkManagerInstances.Remove(clientToStop);
275+
}
271276
}
272277

273278
/// <summary>
@@ -279,6 +284,10 @@ public static void StartOneClient(NetworkManager clientToStart)
279284
clientToStart.StartClient();
280285
s_Hooks[clientToStart] = new MultiInstanceHooks();
281286
clientToStart.MessagingSystem.Hook(s_Hooks[clientToStart]);
287+
if (!NetworkManagerInstances.Contains(clientToStart))
288+
{
289+
NetworkManagerInstances.Add(clientToStart);
290+
}
282291
// if set, then invoke this for the client
283292
RegisterHandlers(clientToStart);
284293
}
@@ -469,8 +478,11 @@ public static void MakeNetworkObjectTestPrefab(NetworkObject networkObject, uint
469478
// this feature only works with NetcodeIntegrationTest derived classes
470479
if (IsNetcodeIntegrationTestRunning)
471480
{
472-
// Add the object identifier component
473-
networkObject.gameObject.AddComponent<ObjectNameIdentifier>();
481+
if (networkObject.GetComponent<ObjectNameIdentifier>() == null && networkObject.GetComponentInChildren<ObjectNameIdentifier>() == null)
482+
{
483+
// Add the object identifier component
484+
networkObject.gameObject.AddComponent<ObjectNameIdentifier>();
485+
}
474486
}
475487
}
476488

testproject/Assets/AddressableAssetsData/AddressableAssetSettings.asset

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,32 @@ MonoBehaviour:
1313
m_Name: AddressableAssetSettings
1414
m_EditorClassIdentifier:
1515
m_DefaultGroup: 93aa504d1b753cb41a8a779ae63f5795
16+
m_CachedHash:
17+
serializedVersion: 2
18+
Hash: 00000000000000000000000000000000
1619
m_OptimizeCatalogSize: 0
1720
m_BuildRemoteCatalog: 0
1821
m_BundleLocalCatalog: 0
22+
m_CatalogRequestsTimeout: 0
1923
m_DisableCatalogUpdateOnStart: 0
2024
m_IgnoreUnsupportedFilesInBuild: 0
2125
m_UniqueBundleIds: 0
26+
m_NonRecursiveBuilding: 1
27+
m_CCDEnabled: 0
2228
m_maxConcurrentWebRequests: 500
2329
m_ContiguousBundles: 0
30+
m_StripUnityVersionFromBundleBuild: 0
31+
m_DisableVisibleSubAssetRepresentations: 0
32+
m_ShaderBundleNaming: 0
33+
m_ShaderBundleCustomNaming:
34+
m_MonoScriptBundleNaming: 0
35+
m_MonoScriptBundleCustomNaming:
2436
m_RemoteCatalogBuildPath:
2537
m_Id: eaae5cc67c56cfe4299363a742a284b3
2638
m_RemoteCatalogLoadPath:
2739
m_Id: 2a3d80e942fdbfe49a979d4a22bbe893
40+
m_ContentStateBuildPath:
41+
m_BuildAddressablesWithPlayerBuild: 2
2842
m_overridePlayerVersion:
2943
m_GroupAssets:
3044
- {fileID: 11400000, guid: 783a7ba7cfd87084388760e6c08547b4, type: 2}

testproject/Assets/References/Scene/NetworkAnimatorEnhancements.asset

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ MonoBehaviour:
1414
m_EditorClassIdentifier:
1515
SceneToReference: {fileID: 102900000, guid: f88da8bb8d07e11418eaad6524d5cc12, type: 3}
1616
m_IncludedScenes: []
17-
m_DisplayName: NetworkAnimator
17+
m_DisplayName: NetworkAnimator Test
1818
m_ReferencedScenes:
19-
- NetworkTransformEnhancementsScene
19+
- NetworkAnimatorEnhancement

testproject/Assets/Scripts/MenuManagement/MainMenuManager.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,22 @@
22
using UnityEngine;
33
using UnityEngine.SceneManagement;
44
using UnityEngine.UI;
5+
#if UNITY_EDITOR
6+
using UnityEditor;
7+
#endif
58

69
/// <summary>
710
/// Main Menu Manager only accepts types of MenuReference
811
/// </summary>
912
public class MainMenuManager : MenuManager<MenuReference>
1013
{
11-
14+
#if UNITY_EDITOR
15+
[InitializeOnEnterPlayMode]
16+
public static void OnEnterPlaymodeInEditor(EnterPlayModeOptions options)
17+
{
18+
Initialize();
19+
}
20+
#endif
1221
}
1322

1423

@@ -37,8 +46,16 @@ public class MenuManager<T> : MonoBehaviour where T : ISceneReference
3746
protected Dictionary<string, T> m_SceneMenuReferencesByDisplayName = new Dictionary<string, T>();
3847

3948

49+
protected static void Initialize()
50+
{
51+
Application.runInBackground = true;
52+
Application.targetFrameRate = 60;
53+
}
54+
55+
4056
private void Awake()
4157
{
58+
Initialize();
4259
Screen.SetResolution(HorizontalResolution, VerticalResolution, false);
4360
}
4461

0 commit comments

Comments
 (0)