Files
youle_cocos/docs/superpowers/reports/2026-09-07-room-protocol-implementation.md

5.4 KiB

Room protocol implementation — 2026-09-07

Implemented Task 1 of the approved room-entry template plan. No server, SDK, Startup, UI, or serialized asset changes were made by this task. Existing dirty work was preserved; no commits were made.

Source evidence

  • docs/protocol/02-协议-agent路由.md, create_room / self_join_room: outbound agent route and exact identity, roomtype, IP and location fields.
  • projects/Game_Surface_3/js/00_Surface/09_Net.js:104-119: create request adds C_Player.ip / addr; response calls Desk.create_room, ends loading and calls the subgame hook.
  • projects/Game_Surface_3/js/00_Surface/07_Desk.js:456-536: create success does not consume players; sets local seat, resets isprepare, seats C_Player, then displays the room. Failure only displays the server error when requested.
  • 07_Desk.js:149-156: Desk.Init starts stage, needprepare and infinite at zero; create response overrides the latter two only when present. These defaults are owned by the create parser, not guessed downstream.
  • 06_Player.js:19,69,279-285: new/local player online state is zero and SetDeskInfo copies it. Created-room canonical self profile comes from the login player, with preparation reset.
  • 12_Logic.js:1024-1055: keypad join submits Number(RoomCode). Numeric roomcode is now preserved by the join request builder while existing string callers remain unchanged.

API and state

  • PlatformRuntime.createRoom({roomtype, location, ip}) delegates to PlatformCommands, requires authenticated lobby state and an open wire, sends exactly app/route/rpc plus agentid/playerid/gameid/roomtype/ip/location.
  • Reuses the existing defensive roomtype clone to reject non-JSON values without inspecting subgame array indices or rewriting rules.
  • Independent parseCreateRoomResponse accepts successful create data without players and retains raw data unchanged. PlatformStore.createRoom constructs canonical seats from GameEntry.resolveSeatCount, places the login player at the server seat, and never manufactures wire players or other raw fields.
  • Create denial retains state and reports ServerDenial.rpc='create_room'. Successful create opens the leased GameModule, publishes room.entered, and shows the room. The original create path has no deskinfo restoration; join/login restoration behavior is preserved.
  • Duplicate create success for the active room and duplicate join success during the active joined session do not reattach or restore a module. Login/switch/exit cleanup resets join deduplication.
  • Runtime join/create scene handoff checks that canonical room state is inside; denied lobby join cannot attempt to show an inactive module.

Verification

  • Red tests observed missing create command/session methods and duplicate join state/module replacement before implementation.
  • 180 tests passed: platform commands, runtime-session, runtime, and all protocol test files, using node --experimental-transform-types --test.
  • 37 platform-store tests passed separately.
  • node cocoscreator_projects/scripts/check-import-boundaries.mjs: OK.
  • New runtime end-to-end fixture verifies exact create RPC, denial with no module/scene, successful ten-seat entry, duplicate reply with one scene activation/module attachment, and module disposal on stop.
  • Framework tsc was attempted with cocoscreator_projects/node_modules/typescript/bin/tsc. No new protocol/platform implementation errors; the combined tree currently has pre-existing runtime test Array.at library errors and concurrent template UI/test type errors. Parent owns combined typecheck resolution.
  • Outputs: cocoscreator_projects/YouleNexus/temp/room-protocol-tests.txt and room-protocol-store-tests.txt.

Integration boundaries

Parent owns page waits, repeated submit prevention, timeout/disconnect/close cleanup and user error display. Runtime has no invented request correlation ID. Real server interoperability and Cocos visual acceptance were not performed by this task. Generic startup GameEntry validation already probes and disposes a module; tests distinguish that existing startup probe from actual room entry attachment.

Review follow-up: immutable resolver boundary

Confirmed the initial create-room path passed parsed.room.roomtype directly to the subgame seat resolver before canonical state construction. A resolver could mutate the inbound array or its nested objects, changing server data before commit.

RuntimeSession.handleCreateRoom now uses the existing cloneAndFreezeRoomtype rules before calling resolveSeatCount. The resolver receives a deeply immutable owned copy; raw response data remains untouched. The store still independently constructs canonical state using the original parsed response, with no fabricated input fields.

Two regressions attempted top-level and nested mutation. Both failed before the fix because no exception occurred. After the fix, both throw TypeError; the raw array and nested object remain unchanged and unfrozen, the prior store root remains identical, no module opens and no partial room state is committed. Re-reviewed create denial, invalid seat count, room command fields, duplicate response handling and scene ordering; existing targeted tests remain green.

Verification: 149 tests passed across runtime-session, runtime, commands and platform-store. Framework tsc reports only the previously communicated runtime Array.at and concurrent template-game test errors, with no error in this change. Parent edits preserved.