feat(session): snapshot getter for UserDataManager room user list

Extends the snapshot pattern to the room's user list. The React client
currently has many widgets each calling `getUserDataByIndex(idx)` in a
loop (chat, doorbell, room player list, infostand …) — every render
walks the underlying Map and rebuilds an array. With
`getRoomUserListSnapshot(): ReadonlyArray<IRoomUserData>` consumers can
memoize on the array reference and only rebuild when something actually
changed.

Invalidation fires on every state-changing path:
- updateUserData (add/replace)
- removeUserData (leave)
- updateFigure / updateName / updateMotto / updateNickIcon /
  updateCustomization / updateBackground / updateAchievementScore /
  updatePetLevel / updatePetBreedingStatus

The inner IRoomUserData objects keep their existing in-place mutation
semantics (deep-clone would be too expensive for 30+ avatars on every
single status push). Consumers should treat each entry as a
snapshot-at-time-of-read and not retain references across an
invalidation.

New event: NitroEventType.ROOM_USER_LIST_UPDATED. Interface and event
additions are backwards-compatible; no existing accessors changed.

Also tidied: `updatePetLevel` now uses the explicit `if(!userData)
return;` guard pattern matching the rest of the methods (was a one-line
inline conditional).
This commit is contained in:
simoleo89
2026-05-18 20:52:33 +02:00
parent a599e0cf89
commit 761d8ffe19
3 changed files with 62 additions and 3 deletions
@@ -23,4 +23,20 @@ export interface IUserDataManager
updatePetLevel(roomIndex: number, level: number): void;
updatePetBreedingStatus(roomIndex: number, canBreed: boolean, canHarvest: boolean, canRevive: boolean, hasBreedingPermission: boolean): void;
requestPetInfo(id: number): void;
/**
* Returns the current room's user list as a referentially-stable
* ReadonlyArray. The same array reference is returned across reads
* until any user is added, removed, or has a tracked field updated
* (figure / name / motto / nick icon / customization / background /
* achievement score / pet level / breeding status). Mutations
* dispatch `NitroEventType.ROOM_USER_LIST_UPDATED` to signal
* invalidation.
*
* The inner IRoomUserData objects keep the existing in-place
* mutation semantics — they are NOT deep-cloned. Treat them as
* snapshots-at-time-of-read; consumers should not retain individual
* entries across invalidations.
*/
getRoomUserListSnapshot(): ReadonlyArray<IRoomUserData>;
}