Skip to content

Commit ca1608f

Browse files
feat: hybrid NetcodeConfig defaults (#4144)
* feat: auto-configure NetcodeConfig for hybrid mode When Netcode for Entities is installed and a registered network prefab carries a GhostObject, the project's NetCodeConfig is now aligned with what NGO needs rather than leaving it to the user to discover. The two settings hybrid mode cannot run without (single world hosting, and automatic bootstrapping disabled since NetworkManager owns world creation) are corrected whenever they drift. The Netcode for Entities tick rates are driven from NetworkConfig.TickRate so that ghost transform updates land on the same interval as everything else. The snapshot, interpolation and transport values tuned against the 2000 instance stress test are applied once and then left alone, so a user's own edits survive; Project Settings > Multiplayer > Netcode for GameObjects can restore them. The config is never created here. Netcode for Entities already creates one unconditionally from its own InitializeOnLoadMethod, and creating a second lands the project in its multiple-config error path. Also: - UnifiedIsConfiguredCorrectly now validates EnableClientServerBootstrap and warns when the two tick rates diverge. Its two log messages were missing their string interpolation prefixes. - m_TempStreamSize returns to the Netcode for Entities default of 8192. GhostSendSystem takes max(TempStreamInitialSize, dataStream.Capacity), and capacity is DefaultSnapshotPacketSize, so 4192 had no effect. - Unity.Netcode.Editor.Tests gains the UNIFIED_NETCODE version define. Without it any hybrid editor test compiles away and reports zero cases rather than failing. - Adds a measurement fixture for sizing DefaultSnapshotPacketSize. It is marked Explicit so its 24 cases stay out of the suites. * style Some comment clean up. * fix and test Fixing some things u-pr caught and adding a test to validate the update. * refactor Refactoring when the NetcodeConfig default settings are written. Assuring that the NetcodeConfig tick rate is always the currently set tick rate when starting a session. * test Updating to use a more NGO like testing pattern. Some comment clean up is included. * update resolving concern over the .EndVertical(); * style removing white space. * chore: n4e 7.0.0 spellings, review feedback and snapshot size N4E 7.0.0 renamed NetCodeConfig to NetcodeConfig and moved its types into Unity.Netcode. Use the 7.0.0 spelling, aliased for 6.7.0 the way the rest of the unified code already is. The editor test assembly still declared UNIFIED_NETCODE as a versionDefine after #4158 made it project-level, so its unified block compiled while the runtime's did not. It also referenced Unity.NetCode by name alongside the GUID for the same assembly. Both removed, UNIFIED_NETCODE_7_0_0 added. The snapshot packet size drops from 15000 to 4096. A snapshot is sent unreliably, so losing any one of its fragments loses the whole snapshot: 4096 spans 3 datagrams at the 1400 byte MTU where 15000 spanned 11, and still caps ~840 ghosts at the measured 4.87 bytes each. The defaults version is bumped so a project that already recorded the marker picks the new value up. Review feedback: - The experimental opt-in is gone. N4E ships as a normal 3.0.0 release. - ResolveGlobalConfig's project scan is gone. N4E assigns NetcodeConfig.Global from an InitializeOnLoadMethod and delayCall runs after those complete, so there is nothing left for a scan to catch. - The apply log uses the contextual logger at Developer level. - UnifiedIsConfiguredCorrectly reports which setting is wrong rather than discarding the reason it already computed. * feat: hybrid NetcodeConfig values applied at session start Netcode for GameObjects no longer writes anything into the NetcodeConfig asset. NetworkManager writes the in-memory global config immediately before the world is created from it, and Netcode for Entities seeds its world singletons from that. Two values are driven, both measured rather than assumed: - The tick rates. NGO's own send queues are flushed by a system in N4E's SimulationSystemGroup, so a simulation rate below NetworkConfig.TickRate starves NGO's outbound traffic. N4E defaults to 60 and NGO to 30. - The snapshot packet size, behind the new NetworkConfig.AutoConfigureSnapshotSize. N4E's default of one MTU round-robins above roughly 230 GhostObjects: at 512 instances it holds a 13.51Hz effective update rate against a 30Hz tick, where 4096 holds 30.00Hz with no saturated snapshots. Below that count the cap is never reached, so it costs nothing. UnifiedBootstrap no longer delegates to base.Initialize. Entities selects the most derived ICustomBootstrap, so this type is the only one it instantiates under UNIFIED_NETCODE and N4E's own Initialize is never reached on its own. Calling it only gave N4E a chance to create worlds this bootstrap would then reject, which is why EnableClientServerBootstrap had to be configured at all. It no longer does. Removed with it: the editor applier, the Project Settings section, the applied-defaults version marker, and the interpolation, despawn reservation and transport queue values. Those were tuned against a 2000 instance stress test and are either inside N4E's own recommended ranges or inert below the snapshot cap. The FailValidation and ClientDoesNotRequest hybrid test cases are removed pending a separate fix: the server schedules its disconnect reason into N4E's outgoing RPC buffer and then tears the connection down in the same call, before RpcSystem transmits it. * test: move the connection approval latch fix out of this PR The polled disconnect reason check belongs with the fix for the defect it found, not with the NetcodeConfig changes. Only the removal of the FailValidation hybrid fixture stays here. * chore: verbosity pass Drops a stray blank line that was the only remaining change in NetcodeForGameObjectsProjectSettings, so that file leaves the diff. Trims the comments that carried mechanism or measurements the PR description already covers, keeping the reason each value or omission exists. * chore: clarify the AutoConfigureSnapshotSize tooltip --------- Co-authored-by: Unity Netcode CI <74025435+netcode-ci-service@users.noreply.github.com>
1 parent 6fbe8b5 commit ca1608f

14 files changed

Lines changed: 267 additions & 10 deletions

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Additional documentation and release notes are available at [Multiplayer Documen
1010

1111
### Added
1212

13+
- Added alignment of the Netcode for Entities tick rates with `NetworkConfig.TickRate` when a session carrying `GhostObject` prefabs is started, so `GhostObject` updates land on the same interval as the rest of Netcode for GameObjects. (#4144)
14+
- Added `NetworkConfig.AutoConfigureSnapshotSize`, enabled by default, which sets the Netcode for Entities snapshot packet size to 4096 bytes when a session carrying `GhostObject` prefabs is started. Netcode for Entities defaults to a single MTU, which updates `GhostObject`s well below the tick rate at the instance counts Netcode for GameObjects projects typically run. Disable it to manage the value yourself. (#4144)
15+
1316
### Changed
1417

1518
### Deprecated
@@ -22,6 +25,8 @@ Additional documentation and release notes are available at [Multiplayer Documen
2225
- Issue where a `NetworkObject` that was moved into another scene while hidden from a client spawned in that client's active scene when it was shown with `NetworkShow`, instead of the scene it is in on the server. (#4176)
2326
- Fixed issue where a prefab added to a `NetworkPrefabsList` while a session was running was registered more than once and logged a duplicate `GlobalObjectIdHash` error. (#4184)
2427
- Fixed an issue where mixed authority nested `NetworkTransform` instances could stop child/nested instances from updating because an authoritative `NetworkTransform` (root or otherwise) would remove the `NetworkObject` from the update group, preventing non-authoritative instances from updating their state on the authority side. (#4169)
28+
- Issue where the hybrid mode `NetcodeConfig` validation messages were not interpolated, so they reported placeholders instead of the setting that was wrong. (#4144)
29+
- Issue where a hybrid mode session failed to start unless `NetcodeConfig.EnableClientServerBootstrap` was set to `DisableAutomaticBootstrap`. Netcode for GameObjects creates the world itself and no longer needs that setting changed. (#4144)
2530

2631
### Security
2732

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public class NetworkManagerEditor : NetcodeEditorBase<NetworkManager>
3737
private SerializedProperty m_ProtocolVersionProperty;
3838
private SerializedProperty m_NetworkTransportProperty;
3939
private SerializedProperty m_TickRateProperty;
40+
#if UNIFIED_NETCODE
41+
private SerializedProperty m_AutoConfigureSnapshotSizeProperty;
42+
#endif
4043
#if MULTIPLAYER_SERVICES_SDK_INSTALLED
4144
private SerializedProperty m_AutoSpawnPlayerPrefabClientSide;
4245
private SerializedProperty m_NetworkTopologyProperty;
@@ -114,6 +117,9 @@ private void Initialize()
114117
m_ProtocolVersionProperty = m_NetworkConfigProperty.FindPropertyRelative("ProtocolVersion");
115118
m_NetworkTransportProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTransport");
116119
m_TickRateProperty = m_NetworkConfigProperty.FindPropertyRelative("TickRate");
120+
#if UNIFIED_NETCODE
121+
m_AutoConfigureSnapshotSizeProperty = m_NetworkConfigProperty.FindPropertyRelative(nameof(NetworkConfig.AutoConfigureSnapshotSize));
122+
#endif
117123
#if MULTIPLAYER_SERVICES_SDK_INSTALLED
118124
m_NetworkTopologyProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTopology");
119125
// Only display the auto spawn property when the distributed authority network topology is selected
@@ -157,6 +163,9 @@ private void CheckNullProperties()
157163
m_ProtocolVersionProperty = m_NetworkConfigProperty.FindPropertyRelative("ProtocolVersion");
158164
m_NetworkTransportProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTransport");
159165
m_TickRateProperty = m_NetworkConfigProperty.FindPropertyRelative("TickRate");
166+
#if UNIFIED_NETCODE
167+
m_AutoConfigureSnapshotSizeProperty = m_NetworkConfigProperty.FindPropertyRelative(nameof(NetworkConfig.AutoConfigureSnapshotSize));
168+
#endif
160169
#if MULTIPLAYER_SERVICES_SDK_INSTALLED
161170
m_NetworkTopologyProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTopology");
162171
// Only display the auto spawn property when the distributed authority network topology is selected
@@ -198,6 +207,12 @@ private void DisplayNetworkManagerProperties()
198207
EditorGUILayout.PropertyField(m_LogLevelProperty);
199208
EditorGUILayout.Space();
200209

210+
#if UNIFIED_NETCODE
211+
EditorGUILayout.LabelField("Hybrid Settings", EditorStyles.boldLabel);
212+
EditorGUILayout.PropertyField(m_AutoConfigureSnapshotSizeProperty);
213+
EditorGUILayout.Space();
214+
#endif
215+
201216
EditorGUILayout.LabelField("Network Settings", EditorStyles.boldLabel);
202217
#if MULTIPLAYER_SERVICES_SDK_INSTALLED
203218
EditorGUILayout.PropertyField(m_NetworkTopologyProperty);
@@ -221,6 +236,7 @@ private void DisplayNetworkManagerProperties()
221236
}
222237
}
223238
EditorGUILayout.PropertyField(m_TickRateProperty);
239+
224240
EditorGUILayout.PropertyField(m_SpawnTimeOutProperty);
225241
EditorGUILayout.PropertyField(m_ConnectionApprovalProperty);
226242
if (m_NetworkManager.NetworkConfig.ConnectionApproval)

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,9 @@ public override bool Initialize(string defaultWorldName)
6363
}
6464

6565
AutoConnectPort = Port;
66-
if (base.Initialize(defaultWorldName))
67-
{
68-
Debug.LogError($"[{nameof(UnifiedBootstrap)}] Auto-bootstrap is enabled!!! This will break the POC!");
69-
return true;
70-
}
66+
67+
// NetworkManager owns world creation here, so base.Initialize is deliberately not called: it would
68+
// let Netcode for Entities create worlds this bootstrap then has to reject.
7169

7270
if (networkManager != null)
7371
{
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#if UNIFIED_NETCODE
2+
#if !UNIFIED_NETCODE_7_0_0
3+
using NetcodeConfig = Unity.NetCode.NetCodeConfig;
4+
#endif
5+
6+
namespace Unity.Netcode
7+
{
8+
/// <summary>
9+
/// This handles applying two <see cref="NetcodeConfig"/> settings NGO requires and an optional recommended snapshot size when running in hybrid mode.
10+
/// </summary>
11+
/// <remarks>
12+
/// 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.
13+
/// </remarks>
14+
internal static class HybridNetcodeDefaults
15+
{
16+
// A hybrid ghost costs ~4.87 bytes per snapshot, so this carries ~840 of them at the full tick rate, which
17+
// covers the 200-1000 moving instances projects typically run. The default MTU size will round-robin at around ~230 instances.
18+
internal const int SnapshotPacketSize = 4096;
19+
20+
/// <summary>
21+
/// Assures N4E's tick rate matches NGO's <see cref="NetworkConfig.TickRate"/> setting.
22+
/// </summary>
23+
/// <remarks>
24+
/// Not cosmetic: NGO's own send queues are flushed by a system in N4E's SimulationSystemGroup, which steps at
25+
/// SimulationTickRate, so a rate below <see cref="NetworkConfig.TickRate"/> starves NGO's outbound traffic.
26+
/// </remarks>
27+
/// <param name="config">The configuration to determine if NGO's tick rate should be applied.</param>
28+
/// <param name="tickRate">The owning <see cref="NetworkManager"/>'s configured tick rate.</param>
29+
/// <returns>True if anything changed.</returns>
30+
internal static bool ApplyTickRate(NetcodeConfig config, uint tickRate)
31+
{
32+
var rate = (int)tickRate;
33+
if (config.ClientServerTickRate.SimulationTickRate == rate && config.ClientServerTickRate.NetworkTickRate == rate)
34+
{
35+
return false;
36+
}
37+
38+
// Both are written because you can set NetworkTickRate to 0 which N4E would then use SimulationTickRate.
39+
// Keeping both locked in at NGO's tick rate (runtime only) assures there can be no deviation.
40+
config.ClientServerTickRate.SimulationTickRate = rate;
41+
config.ClientServerTickRate.NetworkTickRate = rate;
42+
return true;
43+
}
44+
45+
/// <summary>
46+
/// Sets N4E's snapshot packet size to <see cref="SnapshotPacketSize"/>.
47+
/// </summary>
48+
/// <param name="config">The config to correct.</param>
49+
/// <returns>True if anything changed.</returns>
50+
internal static bool ApplySnapshotPacketSize(NetcodeConfig config)
51+
{
52+
if (config.GhostSendSystemData.DefaultSnapshotPacketSize == SnapshotPacketSize)
53+
{
54+
return false;
55+
}
56+
57+
config.GhostSendSystemData.DefaultSnapshotPacketSize = SnapshotPacketSize;
58+
return true;
59+
}
60+
61+
/// <summary>
62+
/// Determines if the NetcodeConfig about to be used to start a session meets the required settings.
63+
/// </summary>
64+
/// <param name="config">The config to check.</param>
65+
/// <param name="reason">Populated with a user-facing description of what is wrong.</param>
66+
/// <returns>True when <paramref name="config"/> is not configured correctly.</returns>
67+
internal static bool IsMissingRequired(NetcodeConfig config, out string reason)
68+
{
69+
if (config.HostWorldModeSelection != NetcodeConfig.HostWorldMode.SingleWorld)
70+
{
71+
reason = $"{nameof(NetcodeConfig.HostWorldModeSelection)} must be {nameof(NetcodeConfig.HostWorldMode.SingleWorld)} but is {config.HostWorldModeSelection}";
72+
return true;
73+
}
74+
75+
reason = null;
76+
return false;
77+
}
78+
}
79+
}
80+
#endif

‎com.unity.netcode.gameobjects/Runtime/Configuration/HybridNetcodeDefaults.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.

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ public class NetworkConfig
5252
[Tooltip("The tickrate. This value controls how often netcode runs user code and sends out data. The value is in 'ticks per seconds' which means a value of 50 will result in 50 ticks being executed per second or a fixed delta time of 0.02.")]
5353
public uint TickRate = 30;
5454

55+
#if UNIFIED_NETCODE
56+
/// <summary>
57+
/// Whether Netcode for GameObjects sets the Netcode for Entities snapshot packet size when a session
58+
/// carrying GhostObjects starts.
59+
/// </summary>
60+
/// <remarks>
61+
/// The default suits the 200-1000 moving instances most projects run. Netcode for Entities' own default is
62+
/// one MTU, which round-robins above roughly 230 GhostObjects and drops their update rate well below
63+
/// <see cref="TickRate"/>. Turn this off to keep whatever the NetcodeConfig asset specifies.
64+
/// </remarks>
65+
[Tooltip("When enabled, NGO will drive the N4E snapshot size setting for this project. The value defaults to 4096 bytes. This is a measured estimate for a project that uses the default tick rate of 30 and could have roughly 200-1000 spawned hybrid prefab instances.")]
66+
public bool AutoConfigureSnapshotSize = true;
67+
#endif
68+
5569
/// <summary>
5670
/// The amount of seconds for the server to wait for the connection approval handshake to complete before the client is disconnected.
5771
///

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,13 +1416,33 @@ private bool UnifiedIsConfiguredCorrectly()
14161416
Log.Error(new Context(LogLevel.Error, $"You must create a {nameof(NetcodeConfig)} and set it to a single world in order to run in hybrid mode!").AddTag("Unified"));
14171417
return false;
14181418
}
1419-
if (NetcodeConfig.Global.HostWorldModeSelection != NetcodeConfig.HostWorldMode.SingleWorld)
1419+
if (HybridNetcodeDefaults.IsMissingRequired(NetcodeConfig.Global, out var reason))
14201420
{
1421-
Log.Error(new Context(LogLevel.Error, $"You must configure {nameof(NetcodeConfig)} to only use a single world in order to run in hybrid mode!").AddTag("Unified"));
1421+
Log.Error(new Context(LogLevel.Error, $"The {nameof(NetcodeConfig)} cannot be used in hybrid mode: {reason}.").AddTag("Unified"));
14221422
return false;
14231423
}
14241424
return true;
14251425
}
1426+
1427+
/// <summary>
1428+
/// Invoked before creating the world for a hybrid mode session to assure the required NetcodeConfig settings are applied.
1429+
/// </summary>
1430+
/// <remarks>
1431+
/// Netcode for Entities copies the config into its world singletons once, at world creation, so this is the
1432+
/// point where it takes effect. This occurs during runtime to avoid modification of the NetcodeConfig asset.
1433+
/// </remarks>
1434+
private void UnifiedApplyNetcodeConfig()
1435+
{
1436+
if (HybridNetcodeDefaults.ApplyTickRate(NetcodeConfig.Global, NetworkConfig.TickRate))
1437+
{
1438+
Log.Info(new Context(LogLevel.Developer, $"The {nameof(NetcodeConfig)} tick rates have been set to {nameof(NetworkConfig)}.{nameof(NetworkConfig.TickRate)} ({NetworkConfig.TickRate}).").AddTag("Unified"));
1439+
}
1440+
1441+
if (NetworkConfig.AutoConfigureSnapshotSize && HybridNetcodeDefaults.ApplySnapshotPacketSize(NetcodeConfig.Global))
1442+
{
1443+
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"));
1444+
}
1445+
}
14261446
#endif
14271447

14281448
/// <summary>
@@ -1466,6 +1486,7 @@ public bool StartServer()
14661486
ShutdownInternal();
14671487
return false;
14681488
}
1489+
UnifiedApplyNetcodeConfig();
14691490
if (LogLevel <= LogLevel.Developer)
14701491
{
14711492
Log.Info(new Context(LogLevel.Developer, "Creating world: Default world"));
@@ -1545,6 +1566,7 @@ public bool StartClient()
15451566
ShutdownInternal();
15461567
return false;
15471568
}
1569+
UnifiedApplyNetcodeConfig();
15481570
Log.Info(new Context(LogLevel.Developer, "Creating world: Default world"));
15491571
InitializeNetcodeWorld();
15501572
}
@@ -1619,6 +1641,7 @@ public bool StartHost()
16191641
ShutdownInternal();
16201642
return false;
16211643
}
1644+
UnifiedApplyNetcodeConfig();
16221645
Log.Info(new Context(LogLevel.Developer, "Creating world: Default world"));
16231646
InitializeNetcodeWorld();
16241647
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#if UNIFIED_NETCODE
2+
using NUnit.Framework;
3+
#if !UNIFIED_NETCODE_7_0_0
4+
using NetcodeConfig = Unity.NetCode.NetCodeConfig;
5+
#endif
6+
using UnityEngine;
7+
8+
namespace Unity.Netcode.GameObjects.EditorTests
9+
{
10+
/// <summary>
11+
/// Validates the <see cref="NetcodeConfig"/> values NGO drives in hybrid mode.
12+
/// </summary>
13+
internal class HybridNetcodeDefaultsTests
14+
{
15+
// Stands in for a value the user chose. Far enough from SnapshotPacketSize that a partial apply cannot
16+
// look like a pass.
17+
private const int k_UserPacketSize = 9000;
18+
19+
private NetcodeConfig m_Config;
20+
21+
[SetUp]
22+
public void SetUp()
23+
{
24+
m_Config = ScriptableObject.CreateInstance<NetcodeConfig>();
25+
m_Config.Reset();
26+
}
27+
28+
[TearDown]
29+
public void TearDown()
30+
{
31+
Object.DestroyImmediate(m_Config);
32+
}
33+
34+
[TestCase(30u)]
35+
[TestCase(60u)]
36+
public void ApplyTickRateLocksSimulationAndNetworkRates(uint tickRate)
37+
{
38+
Assert.IsTrue(HybridNetcodeDefaults.ApplyTickRate(m_Config, tickRate), "The first apply should report a change.");
39+
Assert.AreEqual((int)tickRate, m_Config.ClientServerTickRate.SimulationTickRate, "SimulationTickRate should be the requested rate.");
40+
Assert.AreEqual((int)tickRate, m_Config.ClientServerTickRate.NetworkTickRate, "NetworkTickRate should track SimulationTickRate.");
41+
42+
Assert.IsFalse(HybridNetcodeDefaults.ApplyTickRate(m_Config, tickRate), "Re-applying the same rate should report no change.");
43+
}
44+
45+
[Test]
46+
public void ApplySnapshotPacketSizeOverridesTheNetcodeForEntitiesDefault()
47+
{
48+
// Zero is N4E's default and means one MTU, which round-robins well below the tick rate at the instance
49+
// counts NGO projects run.
50+
m_Config.GhostSendSystemData.DefaultSnapshotPacketSize = 0;
51+
52+
Assert.IsTrue(HybridNetcodeDefaults.ApplySnapshotPacketSize(m_Config), "The first apply should report a change.");
53+
Assert.AreEqual(HybridNetcodeDefaults.SnapshotPacketSize, m_Config.GhostSendSystemData.DefaultSnapshotPacketSize, "DefaultSnapshotPacketSize should be the NGO value.");
54+
55+
Assert.IsFalse(HybridNetcodeDefaults.ApplySnapshotPacketSize(m_Config), "Re-applying an unchanged config should report no change.");
56+
}
57+
58+
[Test]
59+
public void ApplySnapshotPacketSizeLeavesTheTickRatesAlone()
60+
{
61+
HybridNetcodeDefaults.ApplyTickRate(m_Config, 60);
62+
m_Config.GhostSendSystemData.DefaultSnapshotPacketSize = k_UserPacketSize;
63+
64+
HybridNetcodeDefaults.ApplySnapshotPacketSize(m_Config);
65+
Assert.AreEqual(60, m_Config.ClientServerTickRate.SimulationTickRate, "The snapshot size pass should leave SimulationTickRate alone.");
66+
Assert.AreEqual(60, m_Config.ClientServerTickRate.NetworkTickRate, "The snapshot size pass should leave NetworkTickRate alone.");
67+
}
68+
69+
[Test]
70+
public void IsMissingRequiredDetectsBinaryWorlds()
71+
{
72+
m_Config.HostWorldModeSelection = NetcodeConfig.HostWorldMode.SingleWorld;
73+
Assert.IsFalse(HybridNetcodeDefaults.IsMissingRequired(m_Config, out _), "A single world config should be valid for hybrid mode.");
74+
75+
m_Config.HostWorldModeSelection = NetcodeConfig.HostWorldMode.BinaryWorlds;
76+
Assert.IsTrue(HybridNetcodeDefaults.IsMissingRequired(m_Config, out var reason), "Binary worlds should be reported as invalid.");
77+
Assert.That(reason, Does.Contain(nameof(NetcodeConfig.HostWorldModeSelection)), "The reason should name the setting that is wrong.");
78+
}
79+
80+
/// <summary>
81+
/// NGO no longer requires the bootstrap setting, because <c>UnifiedBootstrap</c> never delegates to the
82+
/// Netcode for Entities bootstrap that reads it.
83+
/// </summary>
84+
[Test]
85+
public void AutomaticBootstrapIsNotRequiredToBeDisabled()
86+
{
87+
m_Config.HostWorldModeSelection = NetcodeConfig.HostWorldMode.SingleWorld;
88+
m_Config.EnableClientServerBootstrap = NetcodeConfig.AutomaticBootstrapSetting.EnableAutomaticBootstrap;
89+
90+
Assert.IsFalse(HybridNetcodeDefaults.IsMissingRequired(m_Config, out _), "Automatic bootstrapping should no longer block hybrid mode.");
91+
}
92+
93+
[Test]
94+
public void SnapshotPacketSizeIsOptOutThroughNetworkConfig()
95+
{
96+
Assert.IsTrue(new NetworkConfig().AutoConfigureSnapshotSize, "The snapshot size should be configured by default, with an opt out.");
97+
}
98+
}
99+
}
100+
#endif

‎com.unity.netcode.gameobjects/Tests/Editor/HybridNetcodeDefaultsTests.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.

‎com.unity.netcode.gameobjects/Tests/Editor/Unity.Netcode.Editor.Tests.asmdef‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
"expression": "",
3636
"define": "MULTIPLAYER_TOOLS"
3737
},
38+
{
39+
"name": "com.unity.netcode",
40+
"expression": "7.0.0",
41+
"define": "UNIFIED_NETCODE_7_0_0"
42+
},
3843
{
3944
"name": "Unity",
4045
"expression": "6000.1.0a1",

0 commit comments

Comments
 (0)