From 6a07afb02246dadd8256506c42f1a5911b0e6c22 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Sun, 16 Aug 2026 15:02:07 -0500 Subject: [PATCH 1/6] update - ci Adding an additional unified hybrid spawning test pass. --- .yamato/_run-all.yml | 15 ++++++++ .yamato/_triggers.yml | 24 ++++++++++++ .yamato/project.metafile | 36 ++++++++++++++++++ .yamato/unified-tests.yml | 78 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 .yamato/unified-tests.yml diff --git a/.yamato/_run-all.yml b/.yamato/_run-all.yml index 6cc1709b16..d0af1a4d4f 100644 --- a/.yamato/_run-all.yml +++ b/.yamato/_run-all.yml @@ -368,6 +368,21 @@ run_all_project_tests_console_standalone_default: {% endfor -%} +# Runs all unified (NGO + N4E) tests +# These run on their own pinned editor (unified_editors) rather than the validation_editors, because +# they need an editor that bundles a com.unity.netcode with the unified API. See unified-tests.yml. +run_all_unified_tests: + name: Run All Unified Tests + dependencies: +{% for project in projects.default -%} +{% for platform in unified_test_platforms -%} +{% for editor in unified_editors.default -%} + - .yamato/unified-tests.yml#unified_test_{{ project.name }}_{{ platform.name }}_{{ editor }} +{% endfor -%} +{% endfor -%} +{% endfor -%} + + # Runs all CMB service tests run_all_project_tests_cmb_service: name: Run All CMB Service Tests diff --git a/.yamato/_triggers.yml b/.yamato/_triggers.yml index ac4356cd7a..5d8ca30e88 100644 --- a/.yamato/_triggers.yml +++ b/.yamato/_triggers.yml @@ -90,6 +90,13 @@ pr_code_changes_checks: # Note that our daily tests will anyway run both test configurations in "minimal supported" and "trunk" configurations - .yamato/desktop-standalone-tests.yml#desktop_standalone_test_testproject_ubuntu_il2cpp_{{ pinnedTrunk }} - .yamato/cmb-service-standalone-tests.yml#cmb_service_standalone_test_testproject_ubuntu_il2cpp_{{ pinnedTrunk }} + + # Run the unified (NGO + N4E) tests. Unlike every other job here this one runs on a pinned Unity + # alpha (unified_editors in project.metafile) rather than a supported editor, because it needs an + # editor that bundles a com.unity.netcode with the unified API. Expect it to need a pin bump + # whenever N4E lands breaking changes in trunk. See .yamato/unified-tests.yml. + - .yamato/_run-all.yml#run_all_unified_tests + # Run code coverage test (PRs use the pinned "safe" trunk) - .yamato/code-coverage.yml#code_coverage_project_test_testproject_ubuntu_{{ pinnedTrunk }} triggers: @@ -120,6 +127,21 @@ pr_code_changes_checks: +# Unified (NGO + N4E) validation, on demand. +# The unified tests run automatically as part of pr_code_changes_checks and develop_nightly (same as +# the CMB service tests do). This job only exists so they can also be kicked off by commenting +# "/ci unified", for PRs that pr_code_changes_checks does not cover (drafts, doc-only changes, or +# branches targeting something other than develop / develop-3.x.x / release). +unified_pr_checks: + name: Unified (NGO + N4E) checks [on demand] + dependencies: + - .yamato/_run-all.yml#run_all_unified_tests + triggers: + expression: |- + pull_request.comment eq "unified" + cancel_old_ci: true + + # Run all tests on nightly basis. # Same subset as pull_request_trigger with addition of mobile/desktop/console tests and webgl builds # Those tests are all running on trunk and the default editor (since it's daily and running all of them would add a lot of overhead) @@ -156,6 +178,8 @@ develop_nightly: # Run Runtime tests against cmb service on trunk and default editors - .yamato/_run-all.yml#run_all_project_tests_cmb_service_trunk - .yamato/_run-all.yml#run_all_project_tests_cmb_service_default + # Run the unified (NGO + N4E) tests on their own pinned editor (see .yamato/unified-tests.yml) + - .yamato/_run-all.yml#run_all_unified_tests # Build player for webgl platform on trunk and default editors - .yamato/project-updated-dependencies-test.yml#updated-dependencies_testproject_NGO_ubuntu_trunk - .yamato/project-updated-dependencies-test.yml#updated-dependencies_testproject_NGO_win_{{ validation_editors.default }} diff --git a/.yamato/project.metafile b/.yamato/project.metafile index f1e5c5c924..38ff5ed3d7 100644 --- a/.yamato/project.metafile +++ b/.yamato/project.metafile @@ -190,6 +190,42 @@ validation_editors: pinnedTrunk: 5fe7931aab8c4fff9274e15ef0800125c68b8d6a +# UNIFIED (NGO + N4E) CONFIGURATION--------------------------------------------------------------------- +# The unified test job validates NGO running against Netcode for Entities (N4E) through the unified API. +# It is deliberately kept separate from every other job in this repo because it needs an editor that +# bundles com.unity.netcode with the unified API, and that editor is NOT one of the validation_editors. +# +# WHY THIS IS PINNED TO 6000.7.0a5 (and not 6000.7.0a2): +# UnifiedNetcodeTransport is compiled behind "#if UNIFIED_NETCODE && OUT_OF_BAND_RPC" and needs the +# N4E out-of-band RPC API (IOutOfBandRpcCommand / OutgoingOutOfBandRpcDataStreamBuffer). +# Both 6000.7.0a2 and 6000.7.0a5 bundle com.unity.netcode 6.7.0, but that API only landed in the a5 +# snapshot. On a2 the unified transport does not compile, so the unified tests cannot run there. +# Bump this pin (and unified_netcode_version below) together whenever the required N4E API moves. +# +# An explicit alpha version is used instead of a trunk revision hash because published alphas are +# already immutable, so there is nothing to pin against. +unified_editors: + default: + - 6000.7.0a5 + +# Version of com.unity.netcode (N4E) bundled with unified_editors.default. +# It resolves as a "builtin" package out of the editor install, so it must match the editor exactly. +unified_netcode_version: 6.7.0 + +# The unified job runs in Editor context only, so a single fast platform is enough. +unified_test_platforms: + - name: ubuntu + type: Unity::VM + image: package-ci/ubuntu-22.04:v4.87.0 + flavor: b1.large + +# Restricts the unified job to unified-only tests so nothing else runs on the alpha editor. +# The pattern matches on the NUnit full test name, which covers both the dedicated unified fixtures +# (UnifiedNetworkTransformTest) and any shared fixture parameterized with +# HostOrServer.UnifiedHost / HostOrServer.UnifiedServer, e.g. "NetworkTransformTests(UnifiedHost,...)". +unified_test_filter: "*Unified*" + + # Scripting backends used by Standalone RunTimeTests--------------------------------------------------- scripting_backends: diff --git a/.yamato/unified-tests.yml b/.yamato/unified-tests.yml new file mode 100644 index 0000000000..9e4e6b315e --- /dev/null +++ b/.yamato/unified-tests.yml @@ -0,0 +1,78 @@ +{% metadata_file .yamato/project.metafile %} # All configuration that is used to create different configurations (used in for loops) is taken from this file. +--- + +# DESCRIPTION-------------------------------------------------------------------------- + # This job validates NGO running against Netcode for Entities (N4E) through the unified API. + # A "hybrid prefab" is an NGO prefab (NetworkObject at the root) that also carries a GhostObject. + # When one or more hybrid prefabs are in the NetworkManager's prefab list, NGO hands transform + # synchronization to N4E's snapshot system and tunnels its own batched messages over + # UnifiedNetcodeTransport (N4E's out-of-band RPC) instead of using a NetworkTransport such as UTP. + # UnifiedNetworkTransformTest is the validation test that this path works end to end. + +# WHY THIS JOB IS SEPARATE FROM EVERY OTHER JOB------------------------------------------ + # 1. It needs an editor that bundles a com.unity.netcode with the unified API. That editor + # (unified_editors.default in project.metafile) is not one of the validation_editors, and NGO + # still has to keep building and testing against editors that have no unified API at all. + # 2. It needs com.unity.netcode in the testproject so that the UNIFIED_NETCODE define is set + # (see the versionDefines in Unity.Netcode.Runtime.asmdef). The committed + # testproject/Packages/manifest.json deliberately does NOT reference it, so this job swaps in + # testproject/Packages/manifest-unified.json instead. + # 3. It is wired into pr_code_changes_checks and develop_nightly the same way the CMB service tests + # are, so it runs automatically on PRs targeting develop / develop-3.x.x / release. Be aware that + # this makes an unsupported alpha editor part of the PR gate: when N4E lands breaking changes in + # trunk this job goes red and the pin has to be bumped to unblock PRs. + # _triggers.yml also has unified_pr_checks, so it can be kicked off with "/ci unified" on PRs + # that pr_code_changes_checks does not cover. + +# CONFIGURATION STRUCTURE-------------------------------------------------------------- + # Jobs are generated using nested loops: + # 1. For all unified test platforms (currently Ubuntu only, see project.metafile) + # 2. For all unified editors (currently a single pinned alpha, see project.metafile) + +# TECHNICAL CONSIDERATIONS--------------------------------------------------------------- + # This job runs in Editor context only (no player builds required), like project-tests.yml. + # Only playmode is run: every unified test is an integration test and there are no unified EditMode tests. + # The run is restricted to unified tests via unified_test_filter so that nothing else is exercised + # on the alpha editor. Non-unified tests are covered by the regular jobs on the supported editors. + # packages-lock.json is removed because the committed lock was resolved against a much older editor + # and its builtin package versions do not exist in the unified editor. + +# QUALITY CONSIDERATIONS-------------------------------------------------------------------- + # TODO: the manifest swap means testproject/Packages/manifest-unified.json has to be kept in sync + # with manifest.json by hand. Revisit once N4E is a hard dependency of NGO and one manifest + # can cover both cases. + # TODO: unified_test_filter is a test-name pattern. Replacing it with an NUnit category (for + # example [Category("Unified")]) would be less fragile once more fixtures gain unified variants. + +#------------------------------------------------------------------------------------ + +{% for project in projects.default -%} +{% for platform in unified_test_platforms -%} +{% for editor in unified_editors.default -%} +unified_test_{{ project.name }}_{{ platform.name }}_{{ editor }}: + name : Unified Test - NGO {{ project.name }} [{{ platform.name }}, {{ editor }}] + agent: + type: {{ platform.type }} + image: {{ platform.image }} + flavor: {{ platform.flavor }} +{% if platform.model %} + model: {{ platform.model }} # This is set only in platforms where we want non-default model to use (more information in project.metafile) +{% endif %} + commands: + # Swap in the manifest that pulls in com.unity.netcode (N4E). This is what causes UNIFIED_NETCODE + # to be defined and therefore what makes the unified tests compile at all. + - cp {{ project.path }}/Packages/manifest-unified.json {{ project.path }}/Packages/manifest.json + # The committed lock was resolved against a supported editor, not the unified alpha. + - rm -f {{ project.path }}/Packages/packages-lock.json + + - unity-downloader-cli --fast --wait -u {{ editor }} -c Editor # Installing basic editor for tests execution + - UnifiedTestRunner --testproject={{ project.path }} --suite=playmode --artifacts-path=test-results --editor-location=.Editor --testfilter="{{ unified_test_filter }}" --rerun-strategy=Test --retry={{ num_test_retries }} --clean-library-on-rerun --timeout={{ test_timeout }} + artifacts: + logs: + paths: + - "test-results/**/*" + dependencies: + - .yamato/_run-all.yml#run_quick_checks # initial checks to perform fast validation of common errors +{% endfor -%} +{% endfor -%} +{% endfor -%} From b0c8a3caa76a8fb2b6d457016b2911be971bafda Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Sun, 16 Aug 2026 15:11:43 -0500 Subject: [PATCH 2/6] fix Fixed: - Issue with NetworkObject throwing an exception during hybrid integration test. - Issue with setting the active world prior to spawning a hybrid prefab during integration tests. - Issue with UnifiedNetcodeUpdateSystem not overriding the OnCreate method along with checks for a valid NetworkManager and/or transport within OnUpdate. - Issues (minor) with the original UnifiedNetworkTransformTest. - Adjustments to the NetcodeIntegrationTest that assures the correct active world is assigned when spawning. --- .../Runtime/Core/NetworkObject.cs | 11 +++++ .../Unified/UnifiedNetcodeTransport.cs | 22 ++++++++-- .../UnifiedNetworkTransformTest.cs | 40 +++++++++++-------- .../TestHelpers/NetcodeIntegrationTest.cs | 22 +++++++--- 4 files changed, 70 insertions(+), 25 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 306cbf4572..94364a217a 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -3968,6 +3968,17 @@ private void Start() private void InitGhost() { + // Note: If hybrid prefabs are created prior to any NetworkManager instances, + // then the next line throws and exception. This avoids that issue. + // We might come up with some global way to verify if we are running integration + // tests and add additional logic within to determine if we should log an error + // or not. + if (NetworkManager == null) + { + return; + } + + if (!NetworkManager.IsListening) { if (NetworkManager.LogLevel == LogLevel.Developer) diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs index bdaebdc3ca..785c959da9 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs @@ -124,10 +124,18 @@ public void OnUpdate(ref SystemState state) [UpdateBefore(typeof(RpcSystem))] internal partial class UnifiedNetcodeUpdateSystem : SystemBase { - public void OnCreate(ref SystemState state) + // Note: this must be the parameterless ComponentSystemBase.OnCreate override, not the + // ISystem-style OnCreate(ref SystemState). With the ISystem signature this is just a new + // method that Entities never calls, so neither RequireForUpdate takes effect and OnUpdate + // runs from the very first world tick - which is before StartClient/StartServer have + // assigned Transport and NetworkManager below, and therefore a NullReferenceException. + // CreateSingleWorldHost calls AppendWorldToCurrentPlayerLoop, so the world can tick in the + // window between world creation and the transport being started. + protected override void OnCreate() { - state.RequireForUpdate(); - state.RequireForUpdate(); + RequireForUpdate(); + RequireForUpdate(); + base.OnCreate(); } public UnifiedNetcodeTransport Transport; @@ -155,6 +163,14 @@ public void SendRpc(TransportRpc rpc, Entity connectionEntity) protected override void OnUpdate() { + // Belt and braces alongside the RequireForUpdate gating in OnCreate: these are only + // assigned once the transport is started but the world can already be in the player loop + // before that happens. Exit early under this scenario. + if (NetworkManager == null || Transport == null) + { + return; + } + NetworkManager.MessageManager.ProcessSendQueues(); using var commandBuffer = new EntityCommandBuffer(Allocator.Temp); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/UnifiedNetworkTransformTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/UnifiedNetworkTransformTest.cs index b5fd31ae71..fc128ae31f 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/UnifiedNetworkTransformTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/UnifiedNetworkTransformTest.cs @@ -1,5 +1,6 @@ #if UNIFIED_NETCODE using System.Collections; +using System.Text; using NUnit.Framework; using Unity.Netcode.Components; using Unity.Netcode.TestHelpers.Runtime; @@ -52,38 +53,45 @@ protected override IEnumerator OnSetup() return base.OnSetup(); } + private bool ValidatePosition(StringBuilder errorLog) + { + var authorityPosition = m_AuthorityInstanceTransform.position; + foreach (var client in m_ClientNetworkManagers) + { + var instancePosition = client.SpawnManager.SpawnedObjects[m_Instance.NetworkObjectId].transform.position; + if (!Approximately(authorityPosition, instancePosition)) + { + errorLog.AppendLine($"[Client-{client.LocalClientId}] Clone instance position {GetVector3Values(instancePosition)} " + + $"does not equal the authority's {GetVector3Values(authorityPosition)}"); + } + } + return errorLog.Length == 0; + } + + private Transform m_AuthorityInstanceTransform; + [UnityTest] public IEnumerator BasicMovementTest() { var authority = GetAuthorityNetworkManager(); m_Instance = SpawnObject(m_Prefab, m_ServerNetworkManager).GetComponent(); - - // Wait 5 seconds so we will dump any deferred messages if it failed on clients - // when checking to see if it spawned or not on the clients next. - // Enable this to debug deferred - //yield return new WaitForSeconds(5); + m_AuthorityInstanceTransform = m_Instance.transform; yield return WaitForSpawnedOnAllOrTimeOut(m_Instance); AssertOnTimeout($"Failed to spawn {m_Instance.name} on all clients!"); VerboseDebug("All clients spawned instance!"); + yield return WaitForConditionOrTimeOut(ValidatePosition); + AssertOnTimeout($"A client failed to synchronize the position on the initial spawn!"); + var originalPos = authority.LocalClient.PlayerObject.transform.position; var newPos = originalPos + new Vector3(1, 1, 1); m_Instance.transform.position = newPos; - foreach (var client in m_ClientNetworkManagers) - { - Assert.IsTrue(Approximately(originalPos, s_GlobalNetworkObjects[client.LocalClientId][m_Instance.NetworkObjectId].transform.position)); - } - - yield return new WaitForSeconds(1); - - foreach (var client in m_ClientNetworkManagers) - { - Assert.IsTrue(Approximately(newPos, s_GlobalNetworkObjects[client.LocalClientId][m_Instance.NetworkObjectId].transform.position)); - } + yield return WaitForConditionOrTimeOut(ValidatePosition); + AssertOnTimeout($"A client failed to synchronize the changed position: {GetVector3Values(newPos)}!"); VerboseDebug("Test Passed!"); } } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs index 51d91eea3d..8cfd641c33 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs @@ -2436,13 +2436,9 @@ protected GameObject CreateHybridPrefab(string baseName, bool moveToDDOL = true) // - Then set it back to active. gameObject.SetActive(false); var adapter = gameObject.AddComponent(); - // Mark the reference as post processing to avoid registering this instance automatically. - GhostPrefabReference.s_IsPostProcessing = true; - adapter.prefabReference = ScriptableObject.CreateInstance(); - adapter.prefabReference.name = "GhostPrefabReference"; - adapter.prefabReference.Prefab = gameObject; - GhostPrefabReference.s_IsPostProcessing = false; + // Initialize it as a prefab + adapter.InitializeAsPrefab(); // TODO: This might be part of the CreateHybridPrefab parameters // For now, just use normal interpolation until we get integration @@ -2610,6 +2606,20 @@ protected void SpawnObjectInstance(NetworkObject networkObjectToSpawn, NetworkMa private GameObject SpawnObject(NetworkObject prefabNetworkObject, NetworkManager owner, bool destroyWithScene = false, bool isPlayerObject = false) { Assert.IsTrue(prefabNetworkObject.GlobalObjectIdHash > 0, $"{nameof(GameObject)} {prefabNetworkObject.name} has a {nameof(NetworkObject.GlobalObjectIdHash)} value of 0! Make sure to make it a valid prefab before trying to spawn!"); +#if UNIFIED_NETCODE + // This has to happen *before* Instantiate, not after. The hybrid prefab is active, so the clone's + // GhostObject.Awake runs synchronously inside Object.Instantiate below. The clone is not a prefab + // (its prefabReference.Prefab points at the prefab, not at itself), so Awake acquires an entity + // reference, which resolves the world to spawn into from the Netcode.Instance.m_ActiveWorld singleton. + // N4E's rate managers reassign that singleton on every world update, so by the time a test body runs + // it points at whichever world updated last - typically a client world - and the spawn is rejected with + // "You can only spawn a ghost on a server or during prediction on a client." + // TODO-FixMe: NetCode.Netcode.Instance is a singleton and might cause issues assigning this. + if (prefabNetworkObject.HasGhost) + { + NetCode.Netcode.Instance.m_ActiveWorld = m_ServerNetworkManager.NetcodeWorld; + } +#endif var newInstance = Object.Instantiate(prefabNetworkObject.gameObject); var networkObjectToSpawn = newInstance.GetComponent(); SpawnObjectInstance(networkObjectToSpawn, owner, destroyWithScene, isPlayerObject); From 75472691461420f45c20d1600a6d3baeb1865c6b Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Sun, 16 Aug 2026 15:13:18 -0500 Subject: [PATCH 3/6] update Adding the modified NetcodeConfig specific to NGO. Adding the unified manifest file for running unified tests. --- testproject/Assets/NetCodeConfig.asset | 28 ++++++---- testproject/Packages/manifest-unified.json | 61 ++++++++++++++++++++++ 2 files changed, 78 insertions(+), 11 deletions(-) create mode 100644 testproject/Packages/manifest-unified.json diff --git a/testproject/Assets/NetCodeConfig.asset b/testproject/Assets/NetCodeConfig.asset index f6b1280970..8988bbd48c 100644 --- a/testproject/Assets/NetCodeConfig.asset +++ b/testproject/Assets/NetCodeConfig.asset @@ -18,7 +18,7 @@ MonoBehaviour: ClientServerTickRate: SimulationTickRate: 30 PredictedFixedStepSimulationTickRatio: 1 - NetworkTickRate: 0 + NetworkTickRate: 30 MaxSimulationStepsPerFrame: 1 MaxSimulationStepBatchSize: 4 TargetFrameRateMode: 0 @@ -27,8 +27,8 @@ MonoBehaviour: m_ClampPartialTicksThreshold: 5 HandshakeApprovalTimeoutMS: 5000 ClientTickRate: - InterpolationTimeNetTicks: 2 - InterpolationTimeMS: 0 + InterpolationTimeNetTicks: 0 + InterpolationTimeMS: 50 MaxExtrapolationTimeSimTicks: 20 ForcedInputLatencyTicks: 0 MaxPredictAheadTimeMS: 500 @@ -38,18 +38,19 @@ MonoBehaviour: NumAdditionalCommandsToSend: 2 MaxPredictionStepBatchSizeRepeatedTick: 0 MaxPredictionStepBatchSizeFirstTimeTick: 0 + AlwaysRollbackAllPredictedGhosts: 0 PredictionLoopUpdateMode: 0 InterpolationDelayJitterScale: 1.25 - InterpolationDelayMaxDeltaTicksFraction: 0.1 + InterpolationDelayMaxDeltaTicksFraction: 0.15 InterpolationDelayCorrectionFraction: 0.1 - InterpolationTimeScaleMin: 0.85 - InterpolationTimeScaleMax: 1.1 + InterpolationTimeScaleMin: 0.9 + InterpolationTimeScaleMax: 1.33 CommandAgeCorrectionFraction: 0.1 PredictionTimeScaleMin: 0.9 PredictionTimeScaleMax: 1.1 GhostSendSystemData: - DefaultSnapshotPacketSize: 0 - PercentReservedForDespawnMessages: 0.33 + DefaultSnapshotPacketSize: 15000 + PercentReservedForDespawnMessages: 0.2 MinSendImportance: 0 MinDistanceScaledSendImportance: 0 MaxIterateChunks: 0 @@ -62,15 +63,20 @@ MonoBehaviour: CleanupConnectionStatePerTick: 1 m_FirstSendImportanceMultiplier: 1 m_IrrelevantImportanceDownScale: 1 - m_TempStreamSize: 8192 + m_TempStreamSize: 4192 m_UseCustomSerializer: 0 ConnectTimeoutMS: 1000 MaxConnectAttempts: 60 DisconnectTimeoutMS: 30000 HeartbeatTimeoutMS: 500 ReconnectionTimeoutMS: 2000 - ClientSendQueueCapacity: 64 - ClientReceiveQueueCapacity: 64 + ClientSendQueueCapacity: 128 + ClientReceiveQueueCapacity: 128 ServerSendQueueCapacity: 512 ServerReceiveQueueCapacity: 512 MaxMessageSize: 1400 + TracingConfig: + TracingMemoryLimitMb: 2048 + FuzzyFactor: 0.0001 + IgnoreDTDiffs: 0 + IgnorePartialTicks: 0 diff --git a/testproject/Packages/manifest-unified.json b/testproject/Packages/manifest-unified.json new file mode 100644 index 0000000000..faaad41358 --- /dev/null +++ b/testproject/Packages/manifest-unified.json @@ -0,0 +1,61 @@ +{ + "disableProjectUpdate": false, + "dependencies": { + "com.unity.addressables": "4.0.1", + "com.unity.ai.navigation": "2.0.14", + "com.unity.collab-proxy": "2.13.6", + "com.unity.ide.rider": "3.0.40", + "com.unity.ide.visualstudio": "2.0.26", + "com.unity.mathematics": "1.4.0", + "com.unity.multiplayer.tools": "2.2.10", + "com.unity.netcode": "6.7.0", + "com.unity.netcode.gameobjects": "file:../../com.unity.netcode.gameobjects", + "com.unity.package-validation-suite": "0.49.0-preview", + "com.unity.services.authentication": "3.7.3", + "com.unity.services.multiplayer": "2.3.0", + "com.unity.test-framework": "1.8.0", + "com.unity.test-framework.performance": "6.6.0", + "com.unity.timeline": "6.7.0", + "com.unity.ugui": "2.7.0", + "com.unity.modules.accessibility": "1.0.0", + "com.unity.modules.adaptiveperformance": "1.0.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.physicscore2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.smartstrings": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tetgen": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.timelinefoundation": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vectorgraphics": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + }, + "testables": [ + "com.unity.netcode.gameobjects" + ] +} From 319d7eb4470c0a72fa8cd34f8a490a988ba7efdf Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Sun, 16 Aug 2026 15:18:36 -0500 Subject: [PATCH 4/6] update Unified specific settings --- .../EntitiesClientSettings.asset | 16 +++++++++ .../NetCodeClientAndServerSettings.asset | 35 +++++++++++++++++++ .../NetCodeServerSettings.asset | 17 +++++++++ 3 files changed, 68 insertions(+) create mode 100644 testproject/ProjectSettings/EntitiesClientSettings.asset create mode 100644 testproject/ProjectSettings/NetCodeClientAndServerSettings.asset create mode 100644 testproject/ProjectSettings/NetCodeServerSettings.asset diff --git a/testproject/ProjectSettings/EntitiesClientSettings.asset b/testproject/ProjectSettings/EntitiesClientSettings.asset new file mode 100644 index 0000000000..baf6668fde --- /dev/null +++ b/testproject/ProjectSettings/EntitiesClientSettings.asset @@ -0,0 +1,16 @@ +%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: e2ea235c1fcfe29488ed97c467a0da53, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.Entities.Build::Unity.Entities.Build.EntitiesClientSettings + FilterSettings: + ExcludedBakingSystemAssemblies: [] diff --git a/testproject/ProjectSettings/NetCodeClientAndServerSettings.asset b/testproject/ProjectSettings/NetCodeClientAndServerSettings.asset new file mode 100644 index 0000000000..09eae04db5 --- /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. diff --git a/testproject/ProjectSettings/NetCodeServerSettings.asset b/testproject/ProjectSettings/NetCodeServerSettings.asset new file mode 100644 index 0000000000..a53b8eef71 --- /dev/null +++ b/testproject/ProjectSettings/NetCodeServerSettings.asset @@ -0,0 +1,17 @@ +%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: 70bae3f5df04479cba47f4cd56a60d53, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.Hybrid.NetCodeServerSettings + FilterSettings: + ExcludedBakingSystemAssemblies: [] + AdditionalScriptingDefines: [] From 9e8b6bb2ac03ea2d7704b0445999a8bb605c1563 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Sun, 16 Aug 2026 15:51:04 -0500 Subject: [PATCH 5/6] fix Formatting of the unified test filter. --- .yamato/project.metafile | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.yamato/project.metafile b/.yamato/project.metafile index 38ff5ed3d7..eb6c88d70b 100644 --- a/.yamato/project.metafile +++ b/.yamato/project.metafile @@ -220,10 +220,17 @@ unified_test_platforms: flavor: b1.large # Restricts the unified job to unified-only tests so nothing else runs on the alpha editor. -# The pattern matches on the NUnit full test name, which covers both the dedicated unified fixtures -# (UnifiedNetworkTransformTest) and any shared fixture parameterized with -# HostOrServer.UnifiedHost / HostOrServer.UnifiedServer, e.g. "NetworkTransformTests(UnifiedHost,...)". -unified_test_filter: "*Unified*" +# +# This is a REGULAR EXPRESSION, not a glob. UTR passes it to the editor as -testFilter, which ends up +# in UnityEngine.TestRunner's FullNameFilter -> NUnit ValueMatchFilter -> new Regex(pattern).IsMatch(). +# A glob-style "*Unified*" throws "Quantifier {x,y} following nothing" and fails the whole run. +# The other jobs' "Unity.Netcode.RuntimeTests.*" works because it is also a valid regex - it just +# happens to read like a glob. +# +# The match is against the NUnit *full* test name, which includes fixture arguments. That covers both +# the dedicated unified fixtures (UnifiedNetworkTransformTest) and any shared fixture parameterized +# with HostOrServer.UnifiedHost / UnifiedServer, e.g. "NetworkTransformTests(UnifiedHost,...)". +unified_test_filter: ".*Unified.*" # Scripting backends used by Standalone RunTimeTests--------------------------------------------------- From 93a7d715770fbeaabce1b0bab4e063ec5d0c6d90 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Sun, 16 Aug 2026 16:45:36 -0500 Subject: [PATCH 6/6] update One more time... just running the UnifiedNetworkTransformTest for this phase. A more integrated one will be coming in the next PR for this effort. --- .yamato/project.metafile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.yamato/project.metafile b/.yamato/project.metafile index eb6c88d70b..1117c4badf 100644 --- a/.yamato/project.metafile +++ b/.yamato/project.metafile @@ -227,10 +227,16 @@ unified_test_platforms: # The other jobs' "Unity.Netcode.RuntimeTests.*" works because it is also a valid regex - it just # happens to read like a glob. # -# The match is against the NUnit *full* test name, which includes fixture arguments. That covers both -# the dedicated unified fixtures (UnifiedNetworkTransformTest) and any shared fixture parameterized -# with HostOrServer.UnifiedHost / UnifiedServer, e.g. "NetworkTransformTests(UnifiedHost,...)". -unified_test_filter: ".*Unified.*" +# The match is against the NUnit *full* test name, which includes both fixture and method arguments. +# +# DO NOT widen this to ".*Unified.*". "Unified" appearing in a test name does NOT mean that test was +# deliberately converted to run against hybrid prefabs. HostOrServer gained UnifiedServer/UnifiedHost +# members under UNIFIED_NETCODE, and NUnit expands a bare [Values] on an enum parameter (and +# enum-typed fixture constructors) to every member. So with N4E installed, much of the existing suite +# silently grows unified cases - e.g. NetworkVariableTests(Default).AllNetworkVariableTypes(UnifiedHost), +# which nobody wrote. ".*Unified.*" selected 138 tests, 84 of which failed, against the 1 test this +# job exists to validate. Deciding which of those should pass, and how they opt in, is Goal-2. +unified_test_filter: ".*UnifiedNetworkTransformTest.*" # Scripting backends used by Standalone RunTimeTests---------------------------------------------------