Repository navigation
feat: hybrid interop tests - #4176
NoelStephensUnity wants to merge 28 commits into
Conversation
CreateHybridPrefab takes an optional GhostMode. Predicted modes are applied after NetworkObjectBridge is added, because its editor OnValidate resets the supported ghost modes to interpolated. HybridPredictionTests: an owner-predicted hybrid prefab predicts and re-simulates on the owning client. HybridInteropTests combines N4E and NGO features on one hybrid prefab: - An NGO RPC sent from PredictionUpdate repeats for re-simulated ticks, and sends each tick once when gated on IsFirstTimeFullyPredictingTick. - Unified remote to NGO RPC to unified remote, and NGO RPC to unified remote to NGO RPC. - A NetworkVariable read during prediction is not tick-aligned, while a tick-stamped value applied from its stamp tick is consistent across re-simulation.
…on hybrid prefabs - A NetworkVariable written from PredictionUpdate moves backwards when older ticks re-simulate, and only moves forward when gated on IsFirstTimeFullyPredictingTick. - An NGO ownership change does not change the ghost's N4E owner.
- UnifiedBootstrap registers the worlds it created for other NetworkManagers again after each bootstrap, since every ClientServerBootstrap constructor clears N4E's ServerWorlds and ClientWorlds. Remote methods send through those lists, so with several NetworkManagers in one process server-to-client remotes were dropped. - NetworkObjectBridge defaults a GhostObject to interpolation only when the bridge is first added, instead of on every OnValidate, so prediction enabled on a hybrid prefab is kept. - NGO spawn ownership and ownership changes set the ghost's owner, so an owner-predicted ghost is predicted by its NGO owner. - NetworkManager shutdown disposes only its own world instead of every world in the process. NetworkObjectDontDestroyWithOwnerTests and NetworkSpawnManagerTests now run in hybrid prefab mode. NetworkShowThenClientDisconnects is ignored for hybrid prefabs: a scene migration update can reach a client before the object's ghost has spawned there.
|
Check the configuration's TOML syntax, permitted settings, and size limit. See the error below. Error message: Configuration content:# This is the configuration for the u-pr bot
# https://github.cds.internal.unity3d.com/unity/u-pr
# For configuration of this file:
# 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
|
There was a problem hiding this comment.
💡 Harness Review
The change adds hybrid prediction and interop coverage and keeps ghost ownership and world disposal scoped to each network manager, but the spawn callback order exposes an inconsistent owner state and two test assertions leave intended behavior unprotected.
Reviewed commit f6fee1d
🤖 Helpful? 👍/👎
- The ghost owner is now assigned right after SetupOnSpawn, so OnNetworkSpawn sees the same owner on the NetworkObject and its ghost. The interop test records the ghost owner in OnNetworkSpawn and asserts it. - NetworkVariableReadDuringPredictionIsNotTickAligned asserts that a re-simulated tick reads a different value than its first prediction, rather than counting reads before the stamp tick. - NetworkShowThenClientDisconnects is only ignored for UnifiedServer, the fixture where the scene migration failure occurs.
|
@u-pr please review again |
|
The changes addressing the previous review comments look good:
Summary of New Observations
🤖 Helpful? 👍/👎 |
…ation in the backwards-write test - UpdateGhostOwner leaves the ghost unowned if a host NetworkManager has no NetcodeWorld. - NetworkVariableWrittenFromPredictionUpdateMovesBackwards keeps writing until a backwards move has happened, instead of stopping after 20 changes, which could come before any re-simulation.
|
@u-pr please review again |
|
The latest changes in commit
Review Summary
Overall, the changes are clean, well-tested, and ready to go. 🤖 Helpful? 👍/👎 |
Codecov ReportAttention: Patch coverage is
@@ Coverage Diff @@
## develop-3.x.x #4176 +/- ##
=================================================
+ Coverage 78.19% 78.23% +0.04%
=================================================
Files 153 153
Lines 26272 26328 +56
=================================================
+ Hits 20544 20599 +55
- Misses 5728 5729 +1
Flags with carried forward coverage won't be shown. Click here to find out more.
|
…connects UnifiedNetcodeTransport.DisconnectLocalClient only requested the N4E disconnect. N4E reports it later, after NGO's shutdown has stopped listening, so the disconnecting client never received its ClientDisconnected event. It now notifies immediately, as UnityTransport does, and ignores N4E's later event. A server-initiated disconnect removes the connection before notifying, so the shutdown it triggers does not notify a second time. DisconnectTests and PeerDisconnectCallbackTests now run in hybrid prefab mode.
…ntegration tests The integration test hook that replaces GhostSpawnManager.RegisterGhostBridge also registered the server's own instance. On a dedicated server, which is never a connected client, that moved the instance into the DontDestroyOnLoad scene. The server then sent a scene migration for it to every client, and none of them had spawned it. The hook now skips the server, as the runtime does. NetworkShowThenClientDisconnects no longer needs to be ignored for UnifiedServer.
…brid spawns into their scene ObjectSceneChanged was sent to every connected client, including clients that did not observe the migrated NetworkObjects and had never spawned them, which logged "Trying to synchronize NetworkObjectId but it was not spawned". In client-server mode it is now only sent to clients that observe at least one migrated NetworkObject, and each client is only sent the NetworkObjects it observes. Distributed authority is unchanged. A hybrid prefab instance that is part of a client's initial synchronization can spawn after the synchronization has completed, once its ghost arrives. It missed the step that migrates synchronized NetworkObjects into their server-side scene, and stayed in the active scene. It now runs that step when it spawns.
…r's scene A client that starts observing a NetworkObject with NetworkShow after the NetworkObject migrated into another scene was never sent that migration, and instantiated the NetworkObject in its active scene. The client now moves a spawned NetworkObject into its server-side scene, as it already does for NetworkObjects that are part of its initial synchronization. Adds CHANGELOG entries for this and for scene migrations being sent to clients that do not observe the NetworkObject.
|
@u-pr please review again |
Review SummaryThe latest commits (
Findings
🤖 Helpful? 👍/👎 |
|
@u-pr please review again and look at my comments for your last two suggested fixes. |
Feedback on Previous SuggestionsYour explanations on both points are completely sound:
PR Review SummaryAll changes across the PR are in great shape:
🤖 Helpful? 👍/👎 |
…e test Owner persistence is now set per client on the server-side player object instead of on the player prefab, so the fixtures are only Host and UnifiedHost. The host-client shutdown check runs once after both clients disconnect; before, it ran after the first client and the second client was skipped on the ClientDisconnectsFromServer path.
N4E 7.1.0 (unity/unity PR 126612) renamed [Remote(Directionality)] to [RPC(SendDirection)], GhostObject.IsPredictedGhost to CanWriteState, and changed GhostBehaviour.PredictionUpdate(float) to PredictionUpdate(PredictionUpdateContext).
The execution order TODO is already handled by DefaultExecutionOrder(GhostObject.ExecutionOrder + 1).
…iable inside the prediction loop RPCs and NetworkVariables are not part of Netcode for Entities prediction: they are not rolled back or tick aligned, so a re-simulated tick sends or writes them again. Using them from inside the prediction loop is not supported. A hybrid instance now logs one warning per NetworkBehaviour when it sends an RPC or writes a NetworkVariable while its ghost is in the prediction loop. Replaces the HybridInteropTests cases that measured those unsupported patterns with tests for the warning, and that the same RPC and write made outside the prediction loop do not warn.
…Technologies/com.unity.netcode.gameobjects into feat/hybrid-interop-tests
Distributed authority still sent a scene migration to every client, so clients that did not observe a migrated NetworkObject logged "Trying to synchronize NetworkObjectId but it was not spawned", and a NetworkObject shown after it migrated spawned in the client's active scene. The owner now only sends a migration to the clients that observe a migrated NetworkObject, as in client-server mode. The CMB service's own copy still includes every migrated NetworkObject, and a migration the DAHost forwards is not filtered again. A NetworkObject a distributed authority client spawns when it is shown is moved into its owner's scene.
…gration Only the session owner sends the CMB service its own copy of a migration; a client that is not the session owner does not tell the service about objects only it observes.
EmandM
left a comment
There was a problem hiding this comment.
We did a live code review. This looks great!
Purpose of this PR
This PR adds 21 hybrid prefab test cases, fixes 9 issues the tests found (6 NGO issues in hybrid prefab mode, 2 NGO scene migration issues that affect every NGO project, and 1 test harness issue), and warns when a hybrid prefab instance uses NGO RPCs or NetworkVariables inside the N4E prediction loop, which is not supported. The results back the hybrid mode compatibility matrix (N4E prediction and unified remotes used with NGO RPCs, NetworkVariables and ownership).
PR Scope:
New tests (
Tests/Runtime/Unified,UnifiedHost/UnifiedServer):PredictionUpdateIsFirstTimeFullyPredictingTickor not. Logs a warning once perNetworkBehaviour(see below).Reading a NetworkVariable in
PredictionUpdate, including a tick-stamped value applied when the predicted tick reaches its stamp, is also not supported: NetworkVariables are not rolled back or tick aligned. Reads cannot be detected, so they do not warn.CreateHybridPrefabtakes an optionalGhostModeso tests can create predicted and owner-predicted hybrid prefabs.Prediction loop warning:
NetworkBehaviour, when it sends an RPC or writes a NetworkVariable while its ghost is in the N4E prediction loop (IsInPredictionLoop). It warns on clients, the server and the host. Non-hybrid instances only pay a bool check.Fixes:
UnifiedBootstrapre-registers the worlds it created for otherNetworkManagers. EveryClientServerBootstrapconstructor clears N4E'sServerWorldsandClientWorlds, and eachNetworkManagercreates its own bootstrap. Remote methods send through those lists, so with severalNetworkManagers in one process, server-to-client remotes were dropped.NetworkObjectBridgedefaults aGhostObjectto interpolation only when the bridge is first added (Reset). It no longer does it on everyOnValidate, which reverted prediction set in the inspector.GhostObject.OwnerNetworkId. Before this, an owner-predicted ghost was never given an owner, so no client predicted it.NetworkManagershutdown disposes only its own world instead of callingWorld.DisposeAllWorlds(). This means one peer shutting down no longer breaks the others.ClientDisconnectedevent.UnifiedNetcodeTransport.DisconnectLocalClientonly requested the N4E disconnect, which N4E reports after NGO's shutdown has stopped listening. It now notifies immediately, asUnityTransportdoes.NGO scene migration fixes (affect every NGO project, with CHANGELOG entries, and are also ported to
develop-2.0.0):SceneEventType.ObjectSceneChanged) was sent to every connected client, including clients that did not observe the migrated NetworkObject and logged "Trying to synchronize NetworkObjectId but it was not spawned". It is now only sent to the clients that observe at least one migrated NetworkObject, and each client is only sent the NetworkObjects it observes. In distributed authority mode the owner applies the same filter; the CMB service is still sent every migrated NetworkObject, since it keeps the session state, and a migration the DAHost forwards is not filtered again.NetworkShowafter it migrated into another scene, while hidden from that client, was instantiated in the client's active scene, since the client was never sent that migration. The client now moves the spawned NetworkObject into its server-side scene (its owner's scene in distributed authority mode), as it already does during its initial synchronization.Test harness fix:
DontDestroyOnLoadscene, and the server then sent every client a scene migration for an object none of them had spawned ("Trying to synchronize NetworkObjectId but it was not spawned",SceneEventData.cs:1302). The hook now skips the server, as the runtime does.NetworkObjectDontDestroyWithOwnerTests(6 cases) andNetworkSpawnManagerTests(4 cases) now run in hybrid prefab mode. Both failed before the shutdown fix.DisconnectTests(2 cases) andPeerDisconnectCallbackTests(12 cases) also run in hybrid prefab mode. Their client-initiated cases failed before the disconnect fix.DisconnectTestsis now only a disconnect test, with one fixture per host mode and a NetworkObject spawned while the clients disconnect. The owner persistence cases it duplicated are covered byNetworkObjectDontDestroyWithOwnerTests.New
NetworkObjectSceneMigrationObserverTests(4 tests,Host/DAHost/Server/UnifiedHost/UnifiedServer) cover both scene migration fixes and the late synchronization fix.The hybrid tests are adapted to the N4E 7.1.0 API renames (
[RPC(SendDirection)],PredictionUpdate(PredictionUpdateContext),GhostObject.CanWriteState).Out of this PR's scope:
PredictedPhysicsUpdateand prediction switching combined with NGO features (not covered yet). NGO RPCs and NetworkVariables fromGatherInputare not supported, by decision;GatherInputruns outside the prediction loop, so it does not warn.GhostObject.ParentReplicationis in N4E 7.1.0; NGO will defer parenting to it in a separate PR).InstantiateAndSpawnand hybrid player prefabs not selecting the world (resolved withGhostObject.DelaySpawning/Spawn()in a separate PR, in progress).Jira ticket
MTT-16222
Changelog
NetworkObjectinto another scene made the clients that did not observe it log "Trying to synchronize NetworkObjectId but it was not spawned". The scene migration is now only sent to the clients that observe theNetworkObject.NetworkObjectthat was moved into another scene while hidden from a client spawned in that client's active scene when it was shown withNetworkShow, instead of the scene it is in on the server.Documentation
Testing & QA (How your changes can be verified during release Playtest)
Headless PlayMode runs on 6000.7.0b1 with the unified job's scripting defines, filtered to the hybrid fixtures from #4172 plus the fixtures in this PR. Rows marked N4E 7.0.0 were run before the develop-3.x.x merge that moved this branch to N4E 7.1.0.
NetworkObjectSceneMigrationObserverTests,UNIFIED_TESTSunset (Host/DAHost/Server)DAHostfailed 3 of 4 before the distributed authority part of the fixes)NetworkObjectSceneMigrationObserverTests,UNIFIED_TESTS=trueUNIFIED_TESTSunset, all ofUnity.Netcode.RuntimeTestsNetworkVariableTestslocal-config cases as below)UNIFIED_TESTSunsetHybridInteropTests,UNIFIED_TESTS=trueHybridInteropTests, prediction loop check forced offHybridInteropTests,IsInPredictionLoopcondition removedUNIFIED_TESTS=trueUNIFIED_TESTSunset, all ofUnity.Netcode.RuntimeTestsNetworkVariableTests, which fails the same 96 cases before these changes, atd4fda26e8. It only fails with the unified scripting defines andUNIFIED_TESTSunset, a combination CI does not run)NetworkSceneManager*,NetworkObjectSceneMigrationTests, DontDestroyOnLoad, scene event tests),UNIFIED_TESTSunsetNetworkObjectSceneMigrationObserverTests,UNIFIED_TESTS=trueand unsetUNIFIED_TESTS=true, 3 runsNetworkObjectDontDestroyWithOwnerTests,UNIFIED_TESTS=true, 3 runsUNIFIED_TESTS=true, 3 runsUNIFIED_TESTSunsetThe
DisconnectTestscull and the removal ofHybridPredictionTestswere not rerun locally; CI covers them.Functional Testing
Manual testing :
Manual testing doneAutomated tests:
Covered by existing automated testsCovered by new automated testsDoes the change require QA team to:
Review automated tests?Execute manual tests?Provide feedback about the PR?Up-port
Not needed. Hybrid prefab mode only exists on
develop-3.x.x. The two NGO scene migration fixes are ported todevelop-2.0.0in #4185.Backports
Not needed.