fix: Maintain LocalPlayer-related data on all scenes#8837
Conversation
…e lifecycle - Local Player is propagated on Initialize from the scene world so it's available on `onStart` - Local Player data updated in every scene even if it's not current
|
Windows and Mac build successful in Unity Cloud! You can find a link to the downloadable artifact below. |
This comment has been minimized.
This comment has been minimized.
|
PR #8837, run #26182654059 Builds: Windows change, Windows baseline, macOS change, macOS baseline Framework 13 i7
|
|
🔍 Claude reviewed this PR and found no blocking issues, but assessed it as complex — human DEV review is still required before merging. |
This comment has been minimized.
This comment has been minimized.
| { | ||
| bool newSceneIsValid = scenesCache.TryGetByParcel(characterTransform.Transform.ParcelPosition(), out ISceneFacade currentScene) | ||
| && currentScene.SceneStateProvider.State == SceneState.Running | ||
| && currentScene.SceneStateProvider.State.Value() is SceneState.Running or SceneState.Starting |
There was a problem hiding this comment.
Failing tests not updated for this behavior change.
SceneState.Starting is now accepted as valid for assignment, but two pre-existing tests assert the opposite behavior and are not updated by this PR:
-
NotAssignPlayerWhenSceneIsStarting(lines 293–313) — assertsAssignedToScene = falsewhen the scene isStarting, but this code will now set it totrue. BothisMainPlayer = trueandisMainPlayer = falsevariants fail. -
AssignPlayerWhenSceneTransitionsFromStartingToRunning(lines 315–346) — the firstUpdate()tick (scene stillStarting) now assigns the player, soAssert.IsFalse(playerCRDTEntity.AssignedToScene)at line 334 fails.
These tests need to be updated to cover the new semantics. For NotAssignPlayerWhenSceneIsStarting, the test should be renamed and updated to verify that the player is assigned when the scene is Starting. For AssignPlayerWhenSceneTransitionsFromStartingToRunning, the intermediate assertion after the first tick should be removed or changed to IsTrue.
…cene-init' into feat/seed-local-player-crdt-on-scene-init
This comment has been minimized.
This comment has been minimized.
|
PR #8837, run #26220267637 Builds: Windows change, Windows baseline, macOS change, macOS baseline Framework 13 i7
|
This comment has been minimized.
This comment has been minimized.
| { | ||
| // Local player: PersistentEntities.Player has PlayerSceneCRDTEntity removed, not destroyed | ||
| Assert.IsFalse(scene1World.Has<DeleteEntityIntention>(playerCRDTEntity.SceneWorldEntity)); | ||
| Assert.IsFalse(scene1World.Has<PlayerSceneCRDTEntity>(playerCRDTEntity.SceneWorldEntity)); |
There was a problem hiding this comment.
BLOCKING — test assertion contradicts current implementation.
Commit ea34e551 removed the World.Remove<PlayerSceneCRDTEntity> call from RemovePlayerFromScene for the local player:
// Local Player is never removed from the scene world
if (crdtEntity.Id == SpecialEntitiesID.PLAYER_ENTITY)
return;With that early return, PlayerSceneCRDTEntity is never removed from PersistentEntities.Player when the local player leaves a scene. The assertion below will therefore always fail (component is still present):
Assert.IsFalse(scene1World.Has<PlayerSceneCRDTEntity>(playerCRDTEntity.SceneWorldEntity)); // FAILSPer the PR's stated intent ("user-related data will be available for the scene even if it's not current"), the expected behavior is now that the component persists. Fix: change to Assert.IsTrue and update the comment on line 154 accordingly.
| { | ||
| // Local player: old scene's persistent player loses PlayerSceneCRDTEntity (not destroyed) | ||
| Assert.IsFalse(scene1Facade.EcsExecutor.World.Has<DeleteEntityIntention>(scene1Entity)); | ||
| Assert.IsFalse(scene1Facade.EcsExecutor.World.Has<PlayerSceneCRDTEntity>(scene1Entity)); |
There was a problem hiding this comment.
BLOCKING — same issue as line 157. RemovePlayerFromScene returns early for local player without removing PlayerSceneCRDTEntity, so scene1Entity (which is scene1Facade.PersistentEntities.Player) still has the component after the player moves to scene2. Assert.IsFalse will fail. Change to Assert.IsTrue and update the comment on line 200 to say the persistent entity retains PlayerSceneCRDTEntity.
|
PR #8837, run #26226730238 Builds: Windows change, Windows baseline, macOS change, macOS baseline Framework 13 i7
|
There was a problem hiding this comment.
✔️ PR reviewed and approved by QA on both platforms following instructions playing both happy and un-happy path
Regressions for this ticket had been performed in order to verify that the normal flow is working as expected:
- [✔️ ] Backpack and wearables in world
- [✔️ ] Emotes in world and in backpack
- [ ✔️] Teleport with map/coordinates/Jump In
- [✔️ ] Chat and multiplayer
- [ ✔️] Profile card
- [ ✔️] Skybox
- [ ✔️] Settings
In order to re-create this one :
- Open the index of a scene folder
- Copy the text and erase the other one inside index
- Save the new text
- npm i on the src code
- npm run start
- check that when enteering to the scene the console mentions the name and wallet of the user
Evidence:
20260522-0824-01.1221605.mp4
Fix test assertions for local player PlayerSceneCRDTEntity persistence Local player PlayerSceneCRDTEntity now persists on the persistent entity after leaving a scene, matching the RemovePlayerFromScene early-return behavior from ea34e55. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> @
|
Claude finished @mikhail-dcl's task in 4m 7s —— View job PR Review (Re-review after sync)
Root-cause checkPASS. Previous blocking issue 1 — RESOLVED ✅Commit
Previous blocking issue 2 — RESOLVED ✅Commit
Both match the new intended behavior: the persistent player entity retains No new blocking issuesThe full current diff is clean:
Non-blocking observations (unchanged from previous review)
REVIEW_RESULT: PASS ✅ |
|
PR #8837, run #26280529239 Builds: Windows change, Windows baseline, macOS change, macOS baseline Framework 13 i7
|
Fixes decentraland/creator-hub#264
Problem
SDKProfileis propagated to the scene with 1 frame delay, making the following code failonStart:Solution
Make the whole set of Avatar-related components available on the systems'
Initializewhich is called before the scen starts. It's right the same flow seen inWriteMainPlayerTransformSystemSensitive changes
TransformComponentwas available for the player entity right away whereasPlayerIdentityData,AvatarBaseandAvatarEquippedDatawere not available until the player steps on the current sceneP.S. Behavior for remote peers has not changed.
How to QA