Skip to content

Commit 6c4d6c2

Browse files
Merge develop-3.x.x into fix/hybrid-prefab-component-removal
2 parents f8e8e75 + 212a491 commit 6c4d6c2

8 files changed

Lines changed: 143 additions & 5 deletions

File tree

‎com.unity.netcode.gameobjects/CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
1515

1616
### Changed
1717

18+
- A hybrid mode session now disables `NetcodeConfig.AutomaticStateReplication` at runtime, as Netcode for GameObjects puts each connection in game once the client has synchronized. (#4209)
1819
- Renamed the Editor assembly definition files to match their assembly names. Assembly names and GUIDs are unchanged. (#4187)
1920

2021
### Deprecated
@@ -24,6 +25,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
2425
### Fixed
2526

2627
- Issue where a client promoted to session owner could throw an exception when synchronizing a newly joining client. (#4214)
28+
- Issue where `NetworkManager.OnNetCodeDisconnect` was not invoked when a connection closed during a hybrid mode session, only when the session shut down. (#4209)
2729
- Issue where a rejected parent change, for example one made by a client without parenting authority, restored the `NetworkObject`'s parent but left it at the moved position when the change was made with `worldPositionStays` disabled. The original position, rotation and scale are now restored. (#4202)
2830
- Issue where a client's clock kept alternating between running slightly fast and slightly slow on every frame, even after it had synchronized with the server. Interpolated objects juddered (a periodic motion artifact caused by mismatched frame rates): they moved in uneven steps instead of smoothly. Barely noticeable at the default `NetworkTimeSystem.AdjustmentRatio`, and clearly visible at higher values. (#4195)
2931
- Issue where the IL post-processor could not resolve core library types, such as `Guid` and `List<T>`, in assemblies compiled against .NET reference assemblies, for example when targeting .NET 10. Those split the core library across `System.Runtime`, `System.Collections` and other assemblies. (#4188)

‎com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,15 @@ protected override void OnUpdate()
5555
var networkManager = m_HybridNetworkManagerQuery.GetSingleton<HybridNetworkManager>().NetworkManager.Value;
5656
// A missing NetworkManager counts as shutting down: the world outlives it if ShutdownInternal throws before disposing the world.
5757
var isShuttingDown = !networkManager || networkManager.ShutdownInProgress || !networkManager.IsListening;
58-
foreach (var (networkId, connectionState, entity) in SystemAPI.Query<NetworkId, ConnectionState>().WithNone<NetworkStreamConnection>().WithEntityAccess())
58+
// A destroyed connection keeps only its cleanup components, so the NetworkId comes from ConnectionState.
59+
foreach (var (connectionState, entity) in SystemAPI.Query<ConnectionState>().WithNone<NetworkStreamConnection>().WithEntityAccess())
5960
{
6061
commandBuffer.RemoveComponent<ConnectionState>(entity);
6162
m_TempConnections.Add(new NetcodeConnection
6263
{
6364
World = World,
6465
Entity = entity,
65-
NetworkId = networkId.Value
66+
NetworkId = connectionState.NetworkId
6667
});
6768
}
6869

@@ -99,7 +100,7 @@ protected override void OnUpdate()
99100
{
100101
// Set the connection in-game
101102
commandBuffer.AddComponent<NetworkStreamInGame>(entry.Value.Entity);
102-
commandBuffer.AddComponent(entry.Value.Entity, default(ConnectionState));
103+
commandBuffer.AddComponent(entry.Value.Entity, new ConnectionState { NetworkId = entry.Value.NetworkId });
103104
NetworkManager.OnNetCodeConnect?.Invoke(entry.Value);
104105
m_TempConnections.Add(entry.Value);
105106
}

‎com.unity.netcode.gameobjects/Runtime/Configuration/HybridNetcodeDefaults.cs‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace Unity.Netcode
44
{
55
/// <summary>
6-
/// This handles applying two <see cref="NetcodeConfig"/> settings NGO requires and an optional recommended snapshot size when running in hybrid mode.
6+
/// This handles applying the <see cref="NetcodeConfig"/> settings NGO requires and an optional recommended snapshot size when running in hybrid mode.
77
/// </summary>
88
/// <remarks>
99
/// This intentionally does not modify the <see cref="NetcodeConfig"/> asset to preserve the default settings and/or any user adjustments other than the ones required.
@@ -55,6 +55,26 @@ internal static bool ApplySnapshotPacketSize(NetcodeConfig config)
5555
return true;
5656
}
5757

58+
/// <summary>
59+
/// Assures N4E leaves putting connections in game to NGO.
60+
/// </summary>
61+
/// <remarks>
62+
/// <see cref="Components.UnifiedUpdateConnections"/> raises the connect events for connections not yet in game,
63+
/// and a client only goes in game once NGO has synchronized it, so it receives no ghosts prior to that.
64+
/// </remarks>
65+
/// <param name="config">The config to correct.</param>
66+
/// <returns>True if anything changed.</returns>
67+
internal static bool ApplyManualStateReplication(NetcodeConfig config)
68+
{
69+
if (!config.AutomaticStateReplication)
70+
{
71+
return false;
72+
}
73+
74+
config.AutomaticStateReplication = false;
75+
return true;
76+
}
77+
5878
/// <summary>
5979
/// Determines if the NetcodeConfig about to be used to start a session meets the required settings.
6080
/// </summary>

‎com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ private bool AddPrefabRegistration(NetworkPrefab networkPrefab)
429429
if (networkPrefab.HasGhost)
430430
{
431431
// Registering a hybrid prefab mid-session would switch NetworkManager into hybrid mode and stop its send queue.
432-
if (m_GhostPrefabRejection != null)
432+
if (!string.IsNullOrEmpty(m_GhostPrefabRejection))
433433
{
434434
Debug.LogError($"{m_GhostPrefabRejection} {networkPrefab.GetDebugName()} was not added.");
435435
return false;

‎com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,11 @@ private void UnifiedApplyNetcodeConfig()
14471447
Log.Info(new Context(LogLevel.Developer, $"The {nameof(NetcodeConfig)} tick rates have been set to {nameof(NetworkConfig)}.{nameof(NetworkConfig.TickRate)} ({NetworkConfig.TickRate}).").AddTag("Unified"));
14481448
}
14491449

1450+
if (HybridNetcodeDefaults.ApplyManualStateReplication(NetcodeConfig.Global))
1451+
{
1452+
Log.Info(new Context(LogLevel.Developer, $"The {nameof(NetcodeConfig)}.{nameof(NetcodeConfig.AutomaticStateReplication)} has been disabled, as NGO puts connections in game once synchronized.").AddTag("Unified"));
1453+
}
1454+
14501455
if (NetworkConfig.AutoConfigureSnapshotSize && HybridNetcodeDefaults.ApplySnapshotPacketSize(NetcodeConfig.Global))
14511456
{
14521457
Log.Info(new Context(LogLevel.Developer, $"The {nameof(NetcodeConfig)} snapshot packet size has been set to {HybridNetcodeDefaults.SnapshotPacketSize}. Disable {nameof(NetworkConfig)}.{nameof(NetworkConfig.AutoConfigureSnapshotSize)} to manage it yourself.").AddTag("Unified"));

‎com.unity.netcode.gameobjects/Tests/Editor/HybridNetcodeDefaultsTests.cs‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ public void ApplySnapshotPacketSizeLeavesTheTickRatesAlone()
6363
Assert.AreEqual(60, m_Config.ClientServerTickRate.NetworkTickRate, "The snapshot size pass should leave NetworkTickRate alone.");
6464
}
6565

66+
[Test]
67+
public void ApplyManualStateReplicationDisablesAutomaticStateReplication()
68+
{
69+
m_Config.AutomaticStateReplication = true;
70+
71+
Assert.IsTrue(HybridNetcodeDefaults.ApplyManualStateReplication(m_Config), "The first apply should report a change.");
72+
Assert.IsFalse(m_Config.AutomaticStateReplication, "NGO should own putting connections in game.");
73+
74+
Assert.IsFalse(HybridNetcodeDefaults.ApplyManualStateReplication(m_Config), "Re-applying an unchanged config should report no change.");
75+
}
76+
6677
[Test]
6778
public void IsMissingRequiredDetectsBinaryWorlds()
6879
{
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#if UNIFIED_NETCODE
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using NUnit.Framework;
5+
using Unity.Netcode.Components;
6+
using Unity.Netcode.TestHelpers.Runtime;
7+
using UnityEngine.TestTools;
8+
9+
namespace Unity.Netcode.RuntimeTests
10+
{
11+
/// <summary>
12+
/// Validates <see cref="NetworkManager.OnNetCodeConnect"/> and <see cref="NetworkManager.OnNetCodeDisconnect"/> fire
13+
/// for each connection, and that a client only goes in game once NGO has synchronized it.
14+
/// </summary>
15+
[TestFixture(HostOrServer.UnifiedHost)]
16+
[TestFixture(HostOrServer.UnifiedServer)]
17+
internal class HybridConnectionEventsTests : NetcodeIntegrationTest
18+
{
19+
protected override int NumberOfClients => 1;
20+
21+
private readonly List<int> m_ServerConnects = new List<int>();
22+
private readonly List<int> m_ServerDisconnects = new List<int>();
23+
private int m_ClientConnects;
24+
private bool m_ClientSynchronizedOnConnect;
25+
26+
public HybridConnectionEventsTests(HostOrServer hostOrServer) : base(hostOrServer) { }
27+
28+
protected override bool UseUnifiedTests()
29+
{
30+
return true;
31+
}
32+
33+
protected override void OnServerAndClientsCreated()
34+
{
35+
// No world is created for a session without ghost prefabs.
36+
CreateHybridPrefab("ConnectionEventsPrefab");
37+
m_ServerConnects.Clear();
38+
m_ServerDisconnects.Clear();
39+
m_ClientConnects = 0;
40+
m_ClientSynchronizedOnConnect = false;
41+
NetworkManager.OnNetCodeConnect += OnNetCodeConnect;
42+
NetworkManager.OnNetCodeDisconnect += OnNetCodeDisconnect;
43+
base.OnServerAndClientsCreated();
44+
}
45+
46+
protected override IEnumerator OnTearDown()
47+
{
48+
NetworkManager.OnNetCodeConnect -= OnNetCodeConnect;
49+
NetworkManager.OnNetCodeDisconnect -= OnNetCodeDisconnect;
50+
return base.OnTearDown();
51+
}
52+
53+
private void OnNetCodeConnect(NetcodeConnection connection)
54+
{
55+
if (connection.IsServer)
56+
{
57+
m_ServerConnects.Add(connection.NetworkId);
58+
return;
59+
}
60+
m_ClientConnects++;
61+
m_ClientSynchronizedOnConnect = m_ClientNetworkManagers[0].IsConnectedClient;
62+
}
63+
64+
private void OnNetCodeDisconnect(NetcodeConnection connection)
65+
{
66+
if (connection.IsServer)
67+
{
68+
m_ServerDisconnects.Add(connection.NetworkId);
69+
}
70+
}
71+
72+
[UnityTest]
73+
public IEnumerator ConnectFiresOnceSynchronized()
74+
{
75+
var clientNetworkId = m_ClientNetworkManagers[0].NetcodeWorld.LocalConnection.NetworkId.Value;
76+
yield return WaitForConditionOrTimeOut(() => m_ClientConnects > 0 && m_ServerConnects.Contains(clientNetworkId));
77+
AssertOnTimeout($"Connect events missing! Client connects: {m_ClientConnects}, server saw the client: {m_ServerConnects.Contains(clientNetworkId)}");
78+
79+
Assert.AreEqual(1, m_ClientConnects, "The client connection should only be reported once.");
80+
Assert.IsTrue(m_ClientSynchronizedOnConnect, "The client went in game prior to NGO synchronizing it.");
81+
}
82+
83+
[UnityTest]
84+
public IEnumerator ServerReportsClientDisconnect()
85+
{
86+
var clientNetworkId = m_ClientNetworkManagers[0].NetcodeWorld.LocalConnection.NetworkId.Value;
87+
yield return WaitForConditionOrTimeOut(() => m_ServerConnects.Contains(clientNetworkId));
88+
AssertOnTimeout("The server never reported the client connection!");
89+
90+
yield return StopOneClient(m_ClientNetworkManagers[0]);
91+
yield return WaitForConditionOrTimeOut(() => m_ServerDisconnects.Contains(clientNetworkId));
92+
AssertOnTimeout("The server never reported the client disconnect!");
93+
Assert.IsTrue(m_ServerNetworkManager.IsListening, "The disconnect should be reported while the session is still running.");
94+
}
95+
}
96+
}
97+
#endif

‎com.unity.netcode.gameobjects/Tests/Runtime/Unified/HybridConnectionEventsTests.cs.meta‎

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)