From a7797698bfff28260df6504e758900fdbea92f46 Mon Sep 17 00:00:00 2001 From: Emma Date: Thu, 15 Oct 2026 17:23:23 -0400 Subject: [PATCH 01/14] fix: Yamato jobs not testing built player --- .yamato/cmb-service-standalone-tests.yml | 3 +- .yamato/console-standalone-test.yml | 3 +- .yamato/desktop-standalone-tests.yml | 5 +- .yamato/mobile-standalone-test.yml | 7 +- Tools/CI/service.cmb/run_cmb_service.sh | 4 +- testproject/Assets/NetCodeConfig.asset | 82 +++++++++++++++++++ testproject/Assets/NetCodeConfig.asset.meta | 8 ++ .../NetCodeClientAndServerSettings.asset | 35 ++++++++ 8 files changed, 133 insertions(+), 14 deletions(-) create mode 100644 testproject/Assets/NetCodeConfig.asset create mode 100644 testproject/Assets/NetCodeConfig.asset.meta create mode 100644 testproject/ProjectSettings/NetCodeClientAndServerSettings.asset diff --git a/.yamato/cmb-service-standalone-tests.yml b/.yamato/cmb-service-standalone-tests.yml index 64685fa1c0..c555ab03b2 100644 --- a/.yamato/cmb-service-standalone-tests.yml +++ b/.yamato/cmb-service-standalone-tests.yml @@ -61,8 +61,7 @@ cmb_service_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }} # run_cmb_service.sh builds and starts a release version of the full CMB service (along with the limited echo server) - ./Tools/CI/service.cmb/run_cmb_service.sh -e $ECHO_SERVER_PORT -s $CMB_SERVICE_PORT -l artifacts - - unity-downloader-cli --fast --wait -u {{ editor }} -c Editor {% if backend == "il2cpp" %} -c il2cpp {% endif %}{% if backend == "coreclr" %}{% unless coreclr_runtime_editors contains editor %} -c {{ platform.coreclr_component }} {% endunless %}{% endif %} --arch {{ platform.architecture }} - - UnifiedTestRunner --suite=playmode --player-load-path=build/players --artifacts-path=test-results --testproject={{ project.path }} --editor-location=.Editor --playergraphicsapi=Null --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --clean-library-on-rerun --timeout={{ test_timeout }} + - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --scripting-backend={{ backend }} --player-load-path=build/players --artifacts-path=test-results --testproject={{ project.path }} --playergraphicsapi=Null --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} artifacts: logs: paths: diff --git a/.yamato/console-standalone-test.yml b/.yamato/console-standalone-test.yml index 8a19417478..8fce76b789 100644 --- a/.yamato/console-standalone-test.yml +++ b/.yamato/console-standalone-test.yml @@ -88,8 +88,7 @@ console_standalone_test_{{ project.name }}_{{ platform.name }}_{{ editor }}: model: {{ platform.model }} # This is set only in platforms where we want non-default model to use (more information in project.metafile) {% endif %} commands: - - unity-downloader-cli --fast --wait -u {{ editor }} -c Editor -c il2cpp -c {{ platform.name }} --arch {{ platform.architecture }} - - UnifiedTestRunner --suite=playmode --testproject={{ project.path }} --editor-location=.Editor --artifacts-path=test-results --player-load-path=build/players --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --clean-library-on-rerun --timeout={{ test_timeout }} + - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --scripting-backend=il2cpp --testproject={{ project.path }} --artifacts-path=test-results --player-load-path=build/players --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} variables: # PS4 related SCE_ORBIS_SDK_DIR: 'C:\Users\bokken\SCE\ps4_sdk_12_00' diff --git a/.yamato/desktop-standalone-tests.yml b/.yamato/desktop-standalone-tests.yml index 12b98c4e27..68bd5c2e74 100644 --- a/.yamato/desktop-standalone-tests.yml +++ b/.yamato/desktop-standalone-tests.yml @@ -49,7 +49,7 @@ desktop_standalone_build_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{ {% endif %} commands: - unity-downloader-cli --fast --wait -u {{ editor }} -c Editor {% if backend == "il2cpp" %} -c il2cpp {% endif %}{% if backend == "coreclr" %}{% unless coreclr_runtime_editors contains editor %} -c {{ platform.coreclr_component }} {% endunless %}{% endif %} --arch {{ platform.architecture }} - - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --editor-location=.Editor --testproject={{ project.path }} --scripting-backend={{ backend }} --testfilter="Unity.Netcode.RuntimeTests.*" --player-save-path=build/players --artifacts-path=artifacts --extra-editor-arg=-batchmode --extra-editor-arg=-nographics --reruncount=1 --clean-library-on-rerun --build-only --timeout={{ test_timeout }} + - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --editor-location=.Editor --testproject={{ project.path }} --scripting-backend={{ backend }} --testfilter="Unity.Netcode.RuntimeTests.*;TestProject.RuntimeTests.*" --player-save-path=build/players --artifacts-path=artifacts --extra-editor-arg=-batchmode --extra-editor-arg=-nographics --reruncount=1 --clean-library-on-rerun --build-only --timeout={{ test_timeout }} artifacts: players: paths: @@ -90,8 +90,7 @@ desktop_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{ {% endif %} commands: - - unity-downloader-cli --fast --wait -u {{ editor }} -c Editor {% if backend == "il2cpp" %} -c il2cpp {% endif %}{% if backend == "coreclr" %}{% unless coreclr_runtime_editors contains editor %} -c {{ platform.coreclr_component }} {% endunless %}{% endif %} --arch {{ platform.architecture }} - - UnifiedTestRunner --suite=playmode --player-load-path=build/players --artifacts-path=test-results --testproject={{ project.path }} --editor-location=.Editor --playergraphicsapi=Null --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --clean-library-on-rerun --timeout={{ test_timeout }} + - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --scripting-backend={{ backend }} --player-load-path=build/players --artifacts-path=test-results --testproject={{ project.path }} --playergraphicsapi=Null --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} artifacts: logs: paths: diff --git a/.yamato/mobile-standalone-test.yml b/.yamato/mobile-standalone-test.yml index 1c61148c8c..178bc25adb 100644 --- a/.yamato/mobile-standalone-test.yml +++ b/.yamato/mobile-standalone-test.yml @@ -82,9 +82,6 @@ mobile_standalone_test_{{ project.name }}_{{ platform.name }}_{{ editor }}: model: {{ platform.model }} # This is set only in platforms where we want non-default model to use (more information in project.metafile) {% endif %} commands: - # Installing editor. We still need the editor to run tests on standalone build and for that the Editor is required - - unity-downloader-cli --fast --wait -u {{ editor }} -c Editor -c il2cpp {% if platform.base == "mac" %} -c ios {% else %} -c android {% endif %} --arch {{ platform.architecture }} - {% if platform.standalone == "Android" %} # Download standalone UnityTestRunner and ADB setup - command: wget http://artifactory-slo.bf.unity3d.com/artifactory/mobile-generic/android/ADBKeys.zip!/adbkey.pub -O %USERPROFILE%/.android/adbkey.pub @@ -97,11 +94,11 @@ mobile_standalone_test_{{ project.name }}_{{ platform.name }}_{{ editor }}: # Run tests for Android devices - | set ANDROID_DEVICE_CONNECTION=%BOKKEN_DEVICE_IP% - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --artifacts-path=test-results --player-load-path=build/players --testproject={{ project.path }} --editor-location=.Editor --player-connection-ip=%BOKKEN_HOST_IP% --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --clean-library-on-rerun --timeout={{ test_timeout }} + UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --artifacts-path=test-results --player-load-path=build/players --testproject={{ project.path }} --player-connection-ip=%BOKKEN_HOST_IP% --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} {% else %} # Run tests for non-Android devices - - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --artifacts-path=test-results --player-load-path=build/players --testproject={{ project.path }} --editor-location=.Editor --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --clean-library-on-rerun --timeout={{ test_timeout }} --device-id=%BOKKEN_DEVICE_ID% + - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --artifacts-path=test-results --player-load-path=build/players --testproject={{ project.path }} --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} --device-id=%BOKKEN_DEVICE_ID% {% endif %} artifacts: logs: diff --git a/Tools/CI/service.cmb/run_cmb_service.sh b/Tools/CI/service.cmb/run_cmb_service.sh index 8dd26df88a..05fe686538 100755 --- a/Tools/CI/service.cmb/run_cmb_service.sh +++ b/Tools/CI/service.cmb/run_cmb_service.sh @@ -171,8 +171,8 @@ cargo build --release --locked # The infinite loop is required as the service will exit each time all connected clients disconnect. # This means the service will exit after each test. The infinite loop will immediately restart the service each time it exits. logMessage "Running service integration tests..." -echo "comb-server -l error --metrics-port 5000 standalone --port $service_port -t 60m --unity-version $unity_version" +echo "comb-server -l warn -l ngo::session=info -l comb_server::session=info --metrics-port 5000 standalone --port $service_port -t 60m --unity-version $unity_version" while :; do - ./target/release/comb-server -l error --metrics-port 5000 standalone --port $service_port -t 60m --unity-version $unity_version; + ./target/release/comb-server -l warn -l ngo::session=info -l comb_server::session=info --metrics-port 5000 standalone --port $service_port -t 60m --unity-version $unity_version; done & # <- use & to run the entire loop in the background diff --git a/testproject/Assets/NetCodeConfig.asset b/testproject/Assets/NetCodeConfig.asset new file mode 100644 index 0000000000..4f87186053 --- /dev/null +++ b/testproject/Assets/NetCodeConfig.asset @@ -0,0 +1,82 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: abd30ee0214cf6a45b2d76765a4615b1, type: 3} + m_Name: NetCodeConfig + m_EditorClassIdentifier: Unity.NetCode::Unity.NetCode.NetCodeConfig + IsGlobalConfig: 1 + EnableClientServerBootstrap: 0 + HostWorldModeSelection: 1 + ClientServerTickRate: + SimulationTickRate: 30 + PredictedFixedStepSimulationTickRatio: 1 + NetworkTickRate: 30 + MaxSimulationStepsPerFrame: 1 + MaxSimulationStepBatchSize: 4 + TargetFrameRateMode: 0 + m_SendSnapshotsForCatchUpTicks: 0 + SnapshotAckMaskCapacity: 4096 + m_ClampPartialTicksThreshold: 5 + HandshakeApprovalTimeoutMS: 5000 + ClientTickRate: + InterpolationTimeNetTicks: 0 + InterpolationTimeMS: 50 + MaxExtrapolationTimeSimTicks: 20 + ForcedInputLatencyTicks: 0 + MaxPredictAheadTimeMS: 500 + NumAdditionalClientPredictedGhostLifetimeTicks: 0 + DefaultClassificationAllowableTickPeriod: 5 + TargetCommandSlack: 2 + NumAdditionalCommandsToSend: 2 + MaxPredictionStepBatchSizeRepeatedTick: 0 + MaxPredictionStepBatchSizeFirstTimeTick: 0 + AlwaysRollbackAllPredictedGhosts: 0 + PredictionLoopUpdateMode: 0 + InterpolationDelayJitterScale: 1.25 + InterpolationDelayMaxDeltaTicksFraction: 0.15 + InterpolationDelayCorrectionFraction: 0.1 + InterpolationTimeScaleMin: 0.9 + InterpolationTimeScaleMax: 1.33 + CommandAgeCorrectionFraction: 0.1 + PredictionTimeScaleMin: 0.9 + PredictionTimeScaleMax: 1.1 + GhostSendSystemData: + DefaultSnapshotPacketSize: 15000 + PercentReservedForDespawnMessages: 0.2 + MinSendImportance: 0 + MinDistanceScaledSendImportance: 0 + MaxIterateChunks: 0 + MaxSendChunks: 0 + MaxSendEntities: 0 + m_ForceSingleBaseline: 0 + m_ForcePreSerialize: 0 + m_KeepSnapshotHistoryOnStructuralChange: 1 + m_EnablePerComponentProfiling: 0 + CleanupConnectionStatePerTick: 1 + m_FirstSendImportanceMultiplier: 1 + m_IrrelevantImportanceDownScale: 1 + m_TempStreamSize: 8192 + m_UseCustomSerializer: 0 + ConnectTimeoutMS: 1000 + MaxConnectAttempts: 60 + DisconnectTimeoutMS: 30000 + HeartbeatTimeoutMS: 500 + ReconnectionTimeoutMS: 2000 + ClientSendQueueCapacity: 128 + ClientReceiveQueueCapacity: 128 + ServerSendQueueCapacity: 512 + ServerReceiveQueueCapacity: 512 + MaxMessageSize: 1400 + TracingConfig: + TracingMemoryLimitMb: 2048 + FuzzyFactor: 0.0001 + IgnoreDTDiffs: 0 + IgnorePartialTicks: 0 diff --git a/testproject/Assets/NetCodeConfig.asset.meta b/testproject/Assets/NetCodeConfig.asset.meta new file mode 100644 index 0000000000..222ccfadf4 --- /dev/null +++ b/testproject/Assets/NetCodeConfig.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c547acbddd81d32a0ba5e62ddfc4f4e3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/ProjectSettings/NetCodeClientAndServerSettings.asset b/testproject/ProjectSettings/NetCodeClientAndServerSettings.asset new file mode 100644 index 0000000000..9994ae3ddb --- /dev/null +++ b/testproject/ProjectSettings/NetCodeClientAndServerSettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 53 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4111970df3904877aade1a474116e5c2, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.Hybrid.NetCodeClientAndServerSettings + FilterSettings: + ExcludedBakingSystemAssemblies: [] + AdditionalScriptingDefines: [] + GlobalNetcodeConfig: {fileID: 11400000, guid: c547acbddd81d32a0ba5e62ddfc4f4e3, type: 2} + CurrentImportanceSuggestions: + - MinValue: 1 + MaxValue: 4 + Name: Low Importance + Tooltip: For cosmetic (i.e. visual-only) ghosts like glass bottles, signs, beach-balls, and cones etc. Typically Static. + - MinValue: 5 + MaxValue: 40 + Name: Medium Importance + Tooltip: For common gameplay-affecting ghosts like trees, doors, explosive barrels, dropped loot etc. Typically Static. + - MinValue: 50 + MaxValue: 250 + Name: High Importance + Tooltip: For per-player and objective-critical ghosts like Player Character Controllers and CTF flags etc. Typically for Dynamic i.e. Predicted ghosts. UsePreSerialization is likely a good fit. + - MinValue: 1000 + MaxValue: 0 + Name: Critical Importance + Tooltip: For gameplay critical singletons like the one keeping the current score, or the one denoting whether or not the current round has started etc. Choose UsePreSerialization, and use sparingly. From 240eba529d33ba8bc2f0a4fca38addaaaa47d436 Mon Sep 17 00:00:00 2001 From: Emma Date: Thu, 15 Oct 2026 20:50:26 -0400 Subject: [PATCH 02/14] Next round of fixes --- .yamato/console-standalone-test.yml | 12 +++- .yamato/desktop-standalone-tests.yml | 2 +- .../IntegrationTestSceneHandler.cs | 3 +- .../TestHelpers/NetcodeIntegrationTest.cs | 69 +++++++++++++++++-- .../NetcodeIntegrationTestHelpers.cs | 19 ++++- 5 files changed, 92 insertions(+), 13 deletions(-) diff --git a/.yamato/console-standalone-test.yml b/.yamato/console-standalone-test.yml index 8fce76b789..ae083bd7ce 100644 --- a/.yamato/console-standalone-test.yml +++ b/.yamato/console-standalone-test.yml @@ -88,7 +88,17 @@ console_standalone_test_{{ project.name }}_{{ platform.name }}_{{ editor }}: model: {{ platform.model }} # This is set only in platforms where we want non-default model to use (more information in project.metafile) {% endif %} commands: - - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --scripting-backend=il2cpp --testproject={{ project.path }} --artifacts-path=test-results --player-load-path=build/players --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} + # Console players connect back to UTR's player connection listener on this VM, so the firewall must allow it + - command: gsudo NetSh Advfirewall set allprofiles state off + # Register the Bokken devkit with the platform's target tools so UTR can deploy and run the prebuilt player +{% if platform.name == "ps5" %} + - command: gsudo prospero-ctrl target add %BOKKEN_DEVICE_IP% +{% elsif platform.name == "ps4" %} + - command: orbis-ctrl add %BOKKEN_DEVICE_IP% +{% else %} + - command: '"%GameDK%/bin/xbconnect" /WS %BOKKEN_DEVICE_IP%' +{% endif %} + - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --scripting-backend=il2cpp --testproject={{ project.path }} --artifacts-path=test-results --player-load-path=build/players --player-connection-ip=%BOKKEN_HOST_IP% --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} variables: # PS4 related SCE_ORBIS_SDK_DIR: 'C:\Users\bokken\SCE\ps4_sdk_12_00' diff --git a/.yamato/desktop-standalone-tests.yml b/.yamato/desktop-standalone-tests.yml index 68bd5c2e74..1f01d51a68 100644 --- a/.yamato/desktop-standalone-tests.yml +++ b/.yamato/desktop-standalone-tests.yml @@ -49,7 +49,7 @@ desktop_standalone_build_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{ {% endif %} commands: - unity-downloader-cli --fast --wait -u {{ editor }} -c Editor {% if backend == "il2cpp" %} -c il2cpp {% endif %}{% if backend == "coreclr" %}{% unless coreclr_runtime_editors contains editor %} -c {{ platform.coreclr_component }} {% endunless %}{% endif %} --arch {{ platform.architecture }} - - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --editor-location=.Editor --testproject={{ project.path }} --scripting-backend={{ backend }} --testfilter="Unity.Netcode.RuntimeTests.*;TestProject.RuntimeTests.*" --player-save-path=build/players --artifacts-path=artifacts --extra-editor-arg=-batchmode --extra-editor-arg=-nographics --reruncount=1 --clean-library-on-rerun --build-only --timeout={{ test_timeout }} + - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --editor-location=.Editor --testproject={{ project.path }} --scripting-backend={{ backend }} --testfilter="Unity.Netcode.RuntimeTests.*;TestProject.RuntimeTests.*" --playergraphicsapi=Null --player-save-path=build/players --artifacts-path=artifacts --extra-editor-arg=-batchmode --extra-editor-arg=-nographics --reruncount=1 --clean-library-on-rerun --build-only --timeout={{ test_timeout }} artifacts: players: paths: diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs index 209caf300b..22d37621d4 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/IntegrationTestSceneHandler.cs @@ -372,7 +372,8 @@ private bool ExcludeSceneFromSynchronizationCheck(Scene scene) public void ClearSceneTracking(NetworkManager networkManager) { - SceneNameToSceneHandles.Clear(); + // Only clear the calling NetworkManager's tracking, other NetworkManagers may still be tracking their own scenes + SceneNameToSceneHandles.Remove(networkManager); } public void StopTrackingScene(NetworkSceneHandle handle, string name, NetworkManager networkManager) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs index e62bb13471..5e40f2f8ef 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs @@ -831,6 +831,8 @@ public IEnumerator SetUp() // In addition to setting the number of clients in the OneTimeSetup, we need to re-apply the number of clients for each unique test // in the event that a previous test stopped a client. m_NumberOfClients = NumberOfClients; + // Clear any time out state left by a previous test so it cannot fail this test's assertions + s_GlobalTimeoutHelper.TimedOut = false; VerboseDebugLog.Clear(); VerboseDebug($"Entering {nameof(SetUp)}"); NetcodeLogAssert = new NetcodeLogAssert(); @@ -1261,7 +1263,7 @@ protected void CreateAndStartNewClientWithTimeTravel() // Wait for the new client to connect var connected = WaitForClientsConnectedOrTimeOutWithTimeTravel(); - AssertOnTimeout($"{nameof(CreateAndStartNewClientWithTimeTravel)} timed out waiting for all clients to be connected!\n {m_InternalErrorLog}"); + Assert.IsTrue(connected, $"{nameof(CreateAndStartNewClientWithTimeTravel)} timed out waiting for all clients to be connected!\n {m_InternalErrorLog}"); OnNewClientStartedAndConnected(networkManager); if (!connected) @@ -1644,9 +1646,9 @@ protected void StartServerAndClientsWithTimeTravel() if (!m_BypassConnectionTimeout) { // Wait for all clients to connect - WaitForClientsConnectedOrTimeOutWithTimeTravel(); + var connected = WaitForClientsConnectedOrTimeOutWithTimeTravel(); - AssertOnTimeout($"{nameof(StartServerAndClients)} timed out waiting for all clients to be connected!\n {m_InternalErrorLog}"); + Assert.IsTrue(connected, $"{nameof(StartServerAndClients)} timed out waiting for all clients to be connected!\n {m_InternalErrorLog}"); if (m_UseHost || authorityManager.IsHost) { @@ -1669,8 +1671,8 @@ protected void StartServerAndClientsWithTimeTravel() { foreach (var networkManager in m_NetworkManagers) { - WaitForConditionOrTimeOutWithTimeTravel(() => AllPlayerObjectClonesSpawned(networkManager)); - AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for all sessions to spawn Client-{networkManager.LocalClientId}'s player object!"); + var spawned = WaitForConditionOrTimeOutWithTimeTravel(() => AllPlayerObjectClonesSpawned(networkManager)); + Assert.IsTrue(spawned, $"{nameof(CreateAndStartNewClient)} timed out waiting for all sessions to spawn Client-{networkManager.LocalClientId}'s player object!"); } } @@ -1771,7 +1773,7 @@ protected void ShutdownAndCleanUp() } catch (Exception e) { - throw e; + Debug.LogException(e); } finally { @@ -1909,6 +1911,9 @@ public IEnumerator TearDown() { ShutdownAndCleanUp(); } + + // Wait until all the scene from this test are unloaded before starting the next test. + yield return WaitForRemainingScenesUnloaded(); } if (m_EnableTimeTravel) @@ -2975,22 +2980,72 @@ protected void AssertOnTimeout(string timeOutErrorMessage, TimeoutHelper assigne } + private const float k_SceneUnloadTimeout = 5.0f; + private readonly List m_PendingSceneUnloads = new List(); + private void UnloadRemainingScenes() { // Unload any remaining scenes loaded but the test runner scene // Note: Some tests only unload the server-side instance, and this // just assures no currently loaded scenes will impact the next test + Scene testRunnerScene = default; for (int i = 0; i < SceneManager.sceneCount; i++) { var scene = SceneManager.GetSceneAt(i); - if (!scene.IsValid() || !scene.isLoaded || scene.name.Contains(NetcodeIntegrationTestHelpers.FirstPartOfTestRunnerSceneName) || !OnCanSceneCleanUpUnload(scene)) + if (scene.name.Contains(NetcodeIntegrationTestHelpers.FirstPartOfTestRunnerSceneName)) { + testRunnerScene = scene; + continue; + } + if (!scene.IsValid() || !scene.isLoaded || !OnCanSceneCleanUpUnload(scene)) { continue; } VerboseDebug($"Unloading scene {scene.name}-{scene.handle}"); var asyncOperation = SceneManager.UnloadSceneAsync(scene); + if (asyncOperation != null) + { + m_PendingSceneUnloads.Add(asyncOperation); + } + } + + // Ensure the test runner scene is reset to be the active scene. + if (testRunnerScene.IsValid()) + { + if (SceneManager.GetActiveScene() != testRunnerScene) + { + SceneManager.SetActiveScene(testRunnerScene); + } + + } + } + + /// + /// Waits (in real time) for all scenes left over by the test to finish unloading. + /// Scenes that finish loading after tear down started are also unloaded. + /// + private IEnumerator WaitForRemainingScenesUnloaded() + { + var timeOut = Time.realtimeSinceStartup + k_SceneUnloadTimeout; + while (true) + { + // Pick up any scenes that finished loading after the clean up started + UnloadRemainingScenes(); + + if (m_PendingSceneUnloads.All(c => c.isDone)) + { + break; + } + + if (Time.realtimeSinceStartup >= timeOut) + { + Debug.LogWarning($"[{nameof(WaitForRemainingScenesUnloaded)}] Timed out waiting for scenes to unload!"); + break; + } + yield return null; } + + m_PendingSceneUnloads.Clear(); } private StringBuilder m_WaitForLog = new StringBuilder(); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs index 4be45b5927..87e46c2529 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs @@ -478,16 +478,29 @@ public static void Destroy() try { - // Shutdown the server which forces clients to disconnect + NetworkManager sessionAuthority = null; + // Shutdown clients first foreach (var networkManager in NetworkManagerInstances) { - if (networkManager != null && networkManager.IsListening) + if (networkManager.LocalClient.IsSessionOwner || networkManager.IsServer) { - networkManager?.Shutdown(); + sessionAuthority = networkManager; + } + else + { + networkManager.Shutdown(); s_Hooks.Remove(networkManager); } } + // Shutdown the server/session owner last + // This avoids session owner election when running CMB tests + if (sessionAuthority != null) + { + sessionAuthority.Shutdown(); + s_Hooks.Remove(sessionAuthority); + } + // Destroy the network manager instances foreach (var networkManager in NetworkManagerInstances) { From 98846f0925071014d66c69273307e8a493f48c01 Mon Sep 17 00:00:00 2001 From: Emma Date: Thu, 15 Oct 2026 20:54:28 -0400 Subject: [PATCH 03/14] Set addressables to build on players --- .../Assets/AddressableAssetsData/AddressableAssetSettings.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testproject/Assets/AddressableAssetsData/AddressableAssetSettings.asset b/testproject/Assets/AddressableAssetsData/AddressableAssetSettings.asset index 4723ebbbb4..bd96beed5a 100644 --- a/testproject/Assets/AddressableAssetsData/AddressableAssetSettings.asset +++ b/testproject/Assets/AddressableAssetsData/AddressableAssetSettings.asset @@ -70,7 +70,7 @@ MonoBehaviour: m_ContentStateBuildPathProfileVariableName: m_CustomContentStateBuildPath: m_ContentStateBuildPath: - m_BuildAddressablesWithPlayerBuild: 2 + m_BuildAddressablesWithPlayerBuild: 1 m_overridePlayerVersion: m_GroupAssets: - {fileID: 11400000, guid: 783a7ba7cfd87084388760e6c08547b4, type: 2} From 701debd9276076292c6de5d007ca227e994cb788 Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 09:47:12 -0400 Subject: [PATCH 04/14] dotnet-fix --- .../Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs index 5e40f2f8ef..ef63e7b332 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs @@ -2992,7 +2992,8 @@ private void UnloadRemainingScenes() for (int i = 0; i < SceneManager.sceneCount; i++) { var scene = SceneManager.GetSceneAt(i); - if (scene.name.Contains(NetcodeIntegrationTestHelpers.FirstPartOfTestRunnerSceneName)) { + if (scene.name.Contains(NetcodeIntegrationTestHelpers.FirstPartOfTestRunnerSceneName)) + { testRunnerScene = scene; continue; } From 0007b82661170c00e01edb56cc269495e24157be Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 10:21:06 -0400 Subject: [PATCH 05/14] Fix console tests --- .../NetworkTransformOrderOfOperations.cs | 1 + .../Runtime/NetworkVariable/NetworkVariableTests.cs | 9 +-------- .../Runtime/Transports/UnityTransportConnectionTests.cs | 1 + 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformOrderOfOperations.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformOrderOfOperations.cs index 20630f0803..2f128459ec 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformOrderOfOperations.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformOrderOfOperations.cs @@ -24,6 +24,7 @@ namespace Unity.Netcode.RuntimeTests [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.Server)] + [UnityPlatform(exclude = new[] { RuntimePlatform.PS4 })] // Ignored test tracked in MTT-16494 internal class NetworkTransformOrderOfOperations : IntegrationTestWithApproximation { #region Configuration, Properties, and Overrides diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs index a545d88fa8..2345207692 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs @@ -1881,7 +1881,6 @@ public string ArrayStr(NativeArray arr) where T : unmanaged [Test] [UnityPlatform(exclude = new[] { RuntimePlatform.Android, RuntimePlatform.IPhonePlayer })] // Ignored test tracked in MTT-11343 - [Repeat(5)] public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeArrayNetworkVariables_ValuesAreSerializedCorrectly( [Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), @@ -2343,7 +2342,6 @@ public string DictionaryStr(Dictionary list) [Test] [UnityPlatform(exclude = new[] { RuntimePlatform.Android, RuntimePlatform.IPhonePlayer })] // Ignored test tracked in MTT-11343 - [Repeat(5)] public void WhenSerializingAndDeserializingVeryLargeListNetworkVariables_ValuesAreSerializedCorrectly( [Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), @@ -2538,7 +2536,6 @@ public void WhenSerializingAndDeserializingVeryLargeListNetworkVariables_ValuesA [Test] [UnityPlatform(exclude = new[] { RuntimePlatform.Android, RuntimePlatform.IPhonePlayer })] // Ignored test tracked in MTT-11343 - [Repeat(5)] public void WhenSerializingAndDeserializingVeryLargeHashSetNetworkVariables_ValuesAreSerializedCorrectly( [Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), @@ -2701,8 +2698,7 @@ public void WhenSerializingAndDeserializingVeryLargeHashSetNetworkVariables_Valu } [Test] - [UnityPlatform(exclude = new[] { RuntimePlatform.Android, RuntimePlatform.IPhonePlayer })] // Ignored test tracked in MTT-11343 - [Repeat(5)] + [UnityPlatform(exclude = new[] { RuntimePlatform.Android, RuntimePlatform.IPhonePlayer, RuntimePlatform.PS4, RuntimePlatform.PS5 })] // Ignored test tracked in MTT-11343, MTT-16494 public void WhenSerializingAndDeserializingVeryLargeDictionaryNetworkVariables_ValuesAreSerializedCorrectly( [Values(typeof(byte), typeof(ulong), typeof(Vector2), typeof(HashMapKeyClass))] Type keyType, @@ -3844,7 +3840,6 @@ public string NativeHashMapStr(NativeHashMap list) } [Test] - [Repeat(5)] public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeListNetworkVariables_ValuesAreSerializedCorrectly( [Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), @@ -4035,7 +4030,6 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeListNetworkVa } [Test] - [Repeat(5)] public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeHashSetNetworkVariables_ValuesAreSerializedCorrectly( [Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), @@ -4195,7 +4189,6 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeHashSetNetwor } [Test] - [Repeat(5)] public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeHashMapNetworkVariables_ValuesAreSerializedCorrectly( [Values(typeof(byte), typeof(ulong), typeof(Vector2), typeof(HashMapKeyStruct))] Type keyType, diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs index fc83715898..68c5c81276 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs @@ -134,6 +134,7 @@ public IEnumerator ConnectSingleClient_WebSocket_IPAddressAndPath() #if HOSTNAME_RESOLUTION_AVAILABLE // Check connection with a single client (hostname). [UnityTest] + [UnityPlatform(exclude = new[] { RuntimePlatform.PS4, RuntimePlatform.PS5 })] // Ignored test tracked in MTT-16494 public IEnumerator ConnectSingleClient_Hostname() { InitializeTransport(out m_Server, out m_ServerEvents); From 2ef41bdfb78bcdff41cae157765d386d2946ecc2 Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 11:51:44 -0400 Subject: [PATCH 06/14] Try again to remove graphics from desktop players --- .yamato/cmb-service-standalone-tests.yml | 2 +- .yamato/desktop-standalone-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.yamato/cmb-service-standalone-tests.yml b/.yamato/cmb-service-standalone-tests.yml index c555ab03b2..5bb8951228 100644 --- a/.yamato/cmb-service-standalone-tests.yml +++ b/.yamato/cmb-service-standalone-tests.yml @@ -61,7 +61,7 @@ cmb_service_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }} # run_cmb_service.sh builds and starts a release version of the full CMB service (along with the limited echo server) - ./Tools/CI/service.cmb/run_cmb_service.sh -e $ECHO_SERVER_PORT -s $CMB_SERVICE_PORT -l artifacts - - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --scripting-backend={{ backend }} --player-load-path=build/players --artifacts-path=test-results --testproject={{ project.path }} --playergraphicsapi=Null --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} + - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --scripting-backend={{ backend }} --player-load-path=build/players --artifacts-path=test-results --testproject={{ project.path }} --extra-player-arg=-batchmode --extra-player-arg=-nographics --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} artifacts: logs: paths: diff --git a/.yamato/desktop-standalone-tests.yml b/.yamato/desktop-standalone-tests.yml index 1f01d51a68..d42318982b 100644 --- a/.yamato/desktop-standalone-tests.yml +++ b/.yamato/desktop-standalone-tests.yml @@ -90,7 +90,7 @@ desktop_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{ {% endif %} commands: - - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --scripting-backend={{ backend }} --player-load-path=build/players --artifacts-path=test-results --testproject={{ project.path }} --playergraphicsapi=Null --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} + - UnifiedTestRunner --suite=playmode --platform={{ platform.standalone }} --scripting-backend={{ backend }} --player-load-path=build/players --artifacts-path=test-results --testproject={{ project.path }} --extra-player-arg=-batchmode --extra-player-arg=-nographics --fail-on-assert --rerun-strategy=Test --retry={{ num_test_retries }} --timeout={{ test_timeout }} artifacts: logs: paths: From 099649222f978dd5194494fee7b013406f353f50 Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 11:54:10 -0400 Subject: [PATCH 07/14] Fix DA NetworkObjectDeserializationFailure test --- .../TestHelpers/Components/ObjectNameIdentifier.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs index e33b6ea313..4c228518ff 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs @@ -81,17 +81,11 @@ protected void DeRegisterNetworkObject() } /// - public override void OnLostOwnership() - { - DeRegisterNetworkObject(); - RegisterAndLabelNetworkObject(); - } - - /// - public override void OnGainedOwnership() + protected override void OnOwnershipChanged(ulong previous, ulong current) { DeRegisterNetworkObject(); RegisterAndLabelNetworkObject(); + base.OnOwnershipChanged(previous, current); } /// From 196e4ecc3f885d00eb9ab5a6aafbba9bfa3c942a Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 13:14:02 -0400 Subject: [PATCH 08/14] Remove the temporarily added N4E settings --- testproject/Assets/NetCodeConfig.asset | 82 ------------------- testproject/Assets/NetCodeConfig.asset.meta | 8 -- .../NetCodeClientAndServerSettings.asset | 35 -------- 3 files changed, 125 deletions(-) delete mode 100644 testproject/Assets/NetCodeConfig.asset delete mode 100644 testproject/Assets/NetCodeConfig.asset.meta delete mode 100644 testproject/ProjectSettings/NetCodeClientAndServerSettings.asset diff --git a/testproject/Assets/NetCodeConfig.asset b/testproject/Assets/NetCodeConfig.asset deleted file mode 100644 index 4f87186053..0000000000 --- a/testproject/Assets/NetCodeConfig.asset +++ /dev/null @@ -1,82 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: abd30ee0214cf6a45b2d76765a4615b1, type: 3} - m_Name: NetCodeConfig - m_EditorClassIdentifier: Unity.NetCode::Unity.NetCode.NetCodeConfig - IsGlobalConfig: 1 - EnableClientServerBootstrap: 0 - HostWorldModeSelection: 1 - ClientServerTickRate: - SimulationTickRate: 30 - PredictedFixedStepSimulationTickRatio: 1 - NetworkTickRate: 30 - MaxSimulationStepsPerFrame: 1 - MaxSimulationStepBatchSize: 4 - TargetFrameRateMode: 0 - m_SendSnapshotsForCatchUpTicks: 0 - SnapshotAckMaskCapacity: 4096 - m_ClampPartialTicksThreshold: 5 - HandshakeApprovalTimeoutMS: 5000 - ClientTickRate: - InterpolationTimeNetTicks: 0 - InterpolationTimeMS: 50 - MaxExtrapolationTimeSimTicks: 20 - ForcedInputLatencyTicks: 0 - MaxPredictAheadTimeMS: 500 - NumAdditionalClientPredictedGhostLifetimeTicks: 0 - DefaultClassificationAllowableTickPeriod: 5 - TargetCommandSlack: 2 - NumAdditionalCommandsToSend: 2 - MaxPredictionStepBatchSizeRepeatedTick: 0 - MaxPredictionStepBatchSizeFirstTimeTick: 0 - AlwaysRollbackAllPredictedGhosts: 0 - PredictionLoopUpdateMode: 0 - InterpolationDelayJitterScale: 1.25 - InterpolationDelayMaxDeltaTicksFraction: 0.15 - InterpolationDelayCorrectionFraction: 0.1 - InterpolationTimeScaleMin: 0.9 - InterpolationTimeScaleMax: 1.33 - CommandAgeCorrectionFraction: 0.1 - PredictionTimeScaleMin: 0.9 - PredictionTimeScaleMax: 1.1 - GhostSendSystemData: - DefaultSnapshotPacketSize: 15000 - PercentReservedForDespawnMessages: 0.2 - MinSendImportance: 0 - MinDistanceScaledSendImportance: 0 - MaxIterateChunks: 0 - MaxSendChunks: 0 - MaxSendEntities: 0 - m_ForceSingleBaseline: 0 - m_ForcePreSerialize: 0 - m_KeepSnapshotHistoryOnStructuralChange: 1 - m_EnablePerComponentProfiling: 0 - CleanupConnectionStatePerTick: 1 - m_FirstSendImportanceMultiplier: 1 - m_IrrelevantImportanceDownScale: 1 - m_TempStreamSize: 8192 - m_UseCustomSerializer: 0 - ConnectTimeoutMS: 1000 - MaxConnectAttempts: 60 - DisconnectTimeoutMS: 30000 - HeartbeatTimeoutMS: 500 - ReconnectionTimeoutMS: 2000 - ClientSendQueueCapacity: 128 - ClientReceiveQueueCapacity: 128 - ServerSendQueueCapacity: 512 - ServerReceiveQueueCapacity: 512 - MaxMessageSize: 1400 - TracingConfig: - TracingMemoryLimitMb: 2048 - FuzzyFactor: 0.0001 - IgnoreDTDiffs: 0 - IgnorePartialTicks: 0 diff --git a/testproject/Assets/NetCodeConfig.asset.meta b/testproject/Assets/NetCodeConfig.asset.meta deleted file mode 100644 index 222ccfadf4..0000000000 --- a/testproject/Assets/NetCodeConfig.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c547acbddd81d32a0ba5e62ddfc4f4e3 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/ProjectSettings/NetCodeClientAndServerSettings.asset b/testproject/ProjectSettings/NetCodeClientAndServerSettings.asset deleted file mode 100644 index 9994ae3ddb..0000000000 --- a/testproject/ProjectSettings/NetCodeClientAndServerSettings.asset +++ /dev/null @@ -1,35 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &1 -MonoBehaviour: - m_ObjectHideFlags: 53 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4111970df3904877aade1a474116e5c2, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.Hybrid.NetCodeClientAndServerSettings - FilterSettings: - ExcludedBakingSystemAssemblies: [] - AdditionalScriptingDefines: [] - GlobalNetcodeConfig: {fileID: 11400000, guid: c547acbddd81d32a0ba5e62ddfc4f4e3, type: 2} - CurrentImportanceSuggestions: - - MinValue: 1 - MaxValue: 4 - Name: Low Importance - Tooltip: For cosmetic (i.e. visual-only) ghosts like glass bottles, signs, beach-balls, and cones etc. Typically Static. - - MinValue: 5 - MaxValue: 40 - Name: Medium Importance - Tooltip: For common gameplay-affecting ghosts like trees, doors, explosive barrels, dropped loot etc. Typically Static. - - MinValue: 50 - MaxValue: 250 - Name: High Importance - Tooltip: For per-player and objective-critical ghosts like Player Character Controllers and CTF flags etc. Typically for Dynamic i.e. Predicted ghosts. UsePreSerialization is likely a good fit. - - MinValue: 1000 - MaxValue: 0 - Name: Critical Importance - Tooltip: For gameplay critical singletons like the one keeping the current score, or the one denoting whether or not the current round has started etc. Choose UsePreSerialization, and use sparingly. From a7ebbea690de85cc6f99c6f9722a55ba6e3a64bf Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 13:14:21 -0400 Subject: [PATCH 09/14] Fix the test failures --- .../Runtime/NetworkVariable/NetworkVariableTraitsTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTraitsTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTraitsTests.cs index 110e9ecba3..a11d4c5a7b 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTraitsTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTraitsTests.cs @@ -107,7 +107,7 @@ public IEnumerator WhenNewValueIsLessThanThresholdButMaxTimeHasPassed_VariableIs var authorityComponent = GetAuthorityComponent(); authorityComponent.TheVariable.CheckExceedsDirtinessThreshold = (in float value, in float newValue) => Mathf.Abs(newValue - value) >= 0.1; authorityComponent.TheVariable.SetUpdateTraits(new NetworkVariableUpdateTraits { MaxSecondsBetweenUpdates = 1.0f }); - authorityComponent.TheVariable.LastUpdateSent = authorityComponent.NetworkManager.NetworkTimeSystem.LocalTime; + authorityComponent.TheVariable.UpdateLastSentTime(); var timeoutHelper = new TimeoutHelper(0.62f); var newValue = 0.05f; @@ -127,7 +127,7 @@ public IEnumerator WhenNewValueIsGreaterThanThresholdButMinTimeHasNotPassed_Vari var authorityComponent = GetAuthorityComponent(); authorityComponent.TheVariable.CheckExceedsDirtinessThreshold = (in float value, in float newValue) => Mathf.Abs(newValue - value) >= 0.1; authorityComponent.TheVariable.SetUpdateTraits(new NetworkVariableUpdateTraits { MinSecondsBetweenUpdates = 1 }); - authorityComponent.TheVariable.LastUpdateSent = authorityComponent.NetworkManager.NetworkTimeSystem.LocalTime; + authorityComponent.TheVariable.UpdateLastSentTime(); var timeoutHelper = new TimeoutHelper(0.62f); var newValue = 0.15f; @@ -146,7 +146,7 @@ public IEnumerator WhenNoThresholdIsSetButMinTimeHasNotPassed_VariableIsNotSeria { var authorityComponent = GetAuthorityComponent(); authorityComponent.TheVariable.SetUpdateTraits(new NetworkVariableUpdateTraits { MinSecondsBetweenUpdates = 1 }); - authorityComponent.TheVariable.LastUpdateSent = authorityComponent.NetworkManager.NetworkTimeSystem.LocalTime; + authorityComponent.TheVariable.UpdateLastSentTime(); var timeoutHelper = new TimeoutHelper(0.62f); var newValue = 0.15f; @@ -170,7 +170,7 @@ public IEnumerator WhenNonTraitsIsDirtyButTraitsIsNotReadyToSend() { var authorityComponent = GetAuthorityComponent(); authorityComponent.TheVariable.SetUpdateTraits(new NetworkVariableUpdateTraits { MinSecondsBetweenUpdates = 1 }); - authorityComponent.TheVariable.LastUpdateSent = authorityComponent.NetworkManager.NetworkTimeSystem.LocalTime; + authorityComponent.TheVariable.UpdateLastSentTime(); var timeoutHelper = new TimeoutHelper(0.62f); var firstValue = 0.15f; From 60935fca9d1b3c79e995f1729d8db8edaa7f56d7 Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 13:29:08 -0400 Subject: [PATCH 10/14] Remove fix that was more a symptom than a cause (keep it simple) --- .../NetcodeIntegrationTestHelpers.cs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs index 87e46c2529..4be45b5927 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs @@ -478,29 +478,16 @@ public static void Destroy() try { - NetworkManager sessionAuthority = null; - // Shutdown clients first + // Shutdown the server which forces clients to disconnect foreach (var networkManager in NetworkManagerInstances) { - if (networkManager.LocalClient.IsSessionOwner || networkManager.IsServer) + if (networkManager != null && networkManager.IsListening) { - sessionAuthority = networkManager; - } - else - { - networkManager.Shutdown(); + networkManager?.Shutdown(); s_Hooks.Remove(networkManager); } } - // Shutdown the server/session owner last - // This avoids session owner election when running CMB tests - if (sessionAuthority != null) - { - sessionAuthority.Shutdown(); - s_Hooks.Remove(sessionAuthority); - } - // Destroy the network manager instances foreach (var networkManager in NetworkManagerInstances) { From 0fa8a08713366ec0d48d4497576244e3ae14a48d Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 14:11:21 -0400 Subject: [PATCH 11/14] Match the deregistration to the registration logic --- .../Components/ObjectNameIdentifier.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs index 4c228518ff..4df4cdd352 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs @@ -9,7 +9,7 @@ namespace Unity.Netcode.TestHelpers.Runtime /// public class ObjectNameIdentifier : NetworkBehaviour { - private ulong m_CurrentOwner; + private ulong m_RegisteredLocalClientId; private ulong m_CurrentNetworkObjectId; private bool m_IsRegistered; @@ -45,18 +45,18 @@ protected void RegisterAndLabelNetworkObject() // This is required otherwise it will try to continue to update the NetworkBehaviour even if // it has been destroyed. m_NetworkObject = NetworkObject; - m_CurrentOwner = OwnerClientId; + m_RegisteredLocalClientId = NetworkManager.LocalClientId; m_CurrentNetworkObjectId = NetworkObjectId; var serverOrClient = IsServer ? "Server" : "Client"; if (NetworkObject.IsPlayerObject) { - gameObject.name = NetworkManager.LocalClientId == OwnerClientId ? $"{m_OriginalName}-{k_TagInfoStart}{OwnerClientId}{k_TagInfoStop}-Local{m_OriginalName}" : - $"{m_OriginalName}-{k_TagInfoStart}{OwnerClientId}{k_TagInfoStop}- On{serverOrClient}{k_TagInfoStart}{NetworkManager.LocalClientId}{k_TagInfoStop}"; + gameObject.name = m_RegisteredLocalClientId == OwnerClientId ? $"{m_OriginalName}-{k_TagInfoStart}{OwnerClientId}{k_TagInfoStop}-Local{m_OriginalName}" : + $"{m_OriginalName}-{k_TagInfoStart}{OwnerClientId}{k_TagInfoStop}- On{serverOrClient}{k_TagInfoStart}{m_RegisteredLocalClientId}{k_TagInfoStop}"; } else { - gameObject.name = $"{m_OriginalName}{k_TagInfoStart}{NetworkObjectId}{k_TagInfoStop}-On{serverOrClient}{k_TagInfoStart}{NetworkManager.LocalClientId}{k_TagInfoStop}"; + gameObject.name = $"{m_OriginalName}{k_TagInfoStart}{NetworkObjectId}{k_TagInfoStop}-On{serverOrClient}{k_TagInfoStart}{m_RegisteredLocalClientId}{k_TagInfoStop}"; } // Don't add the player objects to the global list of NetworkObjects @@ -75,17 +75,23 @@ protected void DeRegisterNetworkObject() { if (m_IsRegistered) { - NetcodeIntegrationTest.DeregisterNetworkObject(m_CurrentOwner, m_CurrentNetworkObjectId); + NetcodeIntegrationTest.DeregisterNetworkObject(m_RegisteredLocalClientId, m_CurrentNetworkObjectId); m_IsRegistered = false; } } /// - protected override void OnOwnershipChanged(ulong previous, ulong current) + public override void OnLostOwnership() + { + DeRegisterNetworkObject(); + RegisterAndLabelNetworkObject(); + } + + /// + public override void OnGainedOwnership() { DeRegisterNetworkObject(); RegisterAndLabelNetworkObject(); - base.OnOwnershipChanged(previous, current); } /// From f47f747a1a525c340b1adb7fe6b0b3638fbda4b1 Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 14:12:00 -0400 Subject: [PATCH 12/14] Don't finish cleaning up if any scene is still loading --- .../TestHelpers/NetcodeIntegrationTest.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs index ef63e7b332..5da91ddde0 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs @@ -2983,12 +2983,14 @@ protected void AssertOnTimeout(string timeOutErrorMessage, TimeoutHelper assigne private const float k_SceneUnloadTimeout = 5.0f; private readonly List m_PendingSceneUnloads = new List(); - private void UnloadRemainingScenes() + /// true if any scene (other than the test runner scene) is still loading and could not be unloaded yet + private bool UnloadRemainingScenes() { // Unload any remaining scenes loaded but the test runner scene // Note: Some tests only unload the server-side instance, and this // just assures no currently loaded scenes will impact the next test Scene testRunnerScene = default; + var sceneStillLoading = false; for (int i = 0; i < SceneManager.sceneCount; i++) { var scene = SceneManager.GetSceneAt(i); @@ -2997,7 +2999,13 @@ private void UnloadRemainingScenes() testRunnerScene = scene; continue; } - if (!scene.IsValid() || !scene.isLoaded || !OnCanSceneCleanUpUnload(scene)) + if (scene.IsValid() && !scene.isLoaded) + { + // Can't unload a scene that is still loading + sceneStillLoading = true; + continue; + } + if (!scene.IsValid() || !OnCanSceneCleanUpUnload(scene)) { continue; } @@ -3019,6 +3027,8 @@ private void UnloadRemainingScenes() } } + + return sceneStillLoading; } /// @@ -3031,9 +3041,10 @@ private IEnumerator WaitForRemainingScenesUnloaded() while (true) { // Pick up any scenes that finished loading after the clean up started - UnloadRemainingScenes(); + var sceneStillLoading = UnloadRemainingScenes(); - if (m_PendingSceneUnloads.All(c => c.isDone)) + // Keep waiting while a scene is still loading so it can be unloaded once it finishes loading + if (!sceneStillLoading && m_PendingSceneUnloads.All(c => c.isDone)) { break; } From 241459e54731c4bf520830361a97fb753a90a30c Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 14:12:14 -0400 Subject: [PATCH 13/14] Fix the U-PR config --- .pr_agent.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/.pr_agent.toml b/.pr_agent.toml index 71d8783c0c..9a8dba21cd 100644 --- a/.pr_agent.toml +++ b/.pr_agent.toml @@ -4,6 +4,5 @@ # https://developer.portal.internal.unity.com/catalog/default/component/u-pr/docs/configuration/automatic_runs/ [github_app] -handle_pr_actions = ['opened', 'ready_for_review'] # PR events that auto-run pr_commands pr_commands = ["/harness-review"] # what runs on those events reviewer_commands = ["/harness-review"] # what runs when @u-pr is added as reviewer From 6639ab26b106e92e7b400ebf4466dadfb5df63e6 Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 16 Oct 2026 15:54:11 -0400 Subject: [PATCH 14/14] Fix IL2CPP player tests --- .../Tests/Runtime/NetworkVariable/NetworkVariableTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs index 2345207692..2d76f87a3c 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkVariableTests.cs @@ -1940,7 +1940,7 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeArrayNetworkV } else if (testType == typeof(bool)) { - (var original, var original2, var changed, var changed2) = GetArarys(RandGenBytes); + (var original, var original2, var changed, var changed2) = GetArarys((rand) => rand.Next(2) == 1); TestValueTypeNativeArray(original, changed); TestValueTypeNativeArray(original2, changed2); } @@ -4033,7 +4033,7 @@ public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeListNetworkVa public void WhenSerializingAndDeserializingVeryLargeValueTypeNativeHashSetNetworkVariables_ValuesAreSerializedCorrectly( [Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), - typeof(long), typeof(ulong), typeof(bool), typeof(char), typeof(float), typeof(double), + typeof(long), typeof(ulong), typeof(char), typeof(float), typeof(double), typeof(Vector2), typeof(Vector3), typeof(Vector2Int), typeof(Vector3Int), typeof(Vector4), typeof(Quaternion), typeof(Pose), typeof(HashableNetworkVariableTestStruct), typeof(FixedString32Bytes))] Type testType)