You've already forked Nitro_Render_V3
mirror of
https://github.com/duckietm/Nitro_Render_V3.git
synced 2026-06-19 15:06:20 +00:00
docs(CLAUDE.md): document new snapshot getters + flat bytesAvailable pattern
Add the four 2026-05-18 snapshot additions (IgnoredUsers, GroupInformation, UserDataManager room list, SoundManager volumes) to the snapshot-getter table with their invalidation events, plus the 3-step checklist for adding new ones. Also document the flat bytesAvailable early-return pattern as the canonical shape for optional-trailing-field parsers (replaces the brittle nested if-chain). Note the SoundManager volume-diff bug fix landed alongside.
This commit is contained in:
@@ -58,26 +58,35 @@ unsubscriber, no need to juggle callback identity. Implemented in
|
|||||||
Equivalent for packet streams. Implemented in
|
Equivalent for packet streams. Implemented in
|
||||||
`packages/communication/src/CommunicationManager.ts`.
|
`packages/communication/src/CommunicationManager.ts`.
|
||||||
|
|
||||||
### Snapshot getters on `SessionDataManager` + `RoomSessionManager`
|
### Snapshot getters (referentially stable, lazy-frozen, invalidated on mutation)
|
||||||
|
|
||||||
```ts
|
Pattern: `getXxxSnapshot()` returns a frozen value cached internally;
|
||||||
getUserDataSnapshot(): Readonly<IUserDataSnapshot>
|
mutators call `invalidateXxxSnapshot()` which drops the cache AND
|
||||||
getActiveRoomSessionSnapshot(): Readonly<IRoomSessionSnapshot> | null
|
dispatches an invalidation event. The React side reads via
|
||||||
```
|
`useSyncExternalStore`.
|
||||||
|
|
||||||
Returns **referentially-stable** values: the same object reference is
|
| Manager | Getter | Invalidation event |
|
||||||
returned across reads until invalidated. Invalidation happens via the
|
|---|---|---|
|
||||||
new event types `NitroEventType.SESSION_DATA_UPDATED` and
|
| `SessionDataManager` | `getUserDataSnapshot(): Readonly<IUserDataSnapshot>` | `SESSION_DATA_UPDATED` |
|
||||||
`NitroEventType.ROOM_SESSION_UPDATED`.
|
| `RoomSessionManager` | `getActiveRoomSessionSnapshot(): Readonly<IRoomSessionSnapshot> \| null` | `ROOM_SESSION_UPDATED` |
|
||||||
|
| `IgnoredUsersManager` | `getIgnoredUsersSnapshot(): ReadonlyArray<string>` | `IGNORED_USERS_UPDATED` |
|
||||||
|
| `GroupInformationManager` | `getGroupBadgesSnapshot(): ReadonlyMap<number, string>` | `GROUP_BADGES_UPDATED` (only on real changes — no-op refresh stays quiet) |
|
||||||
|
| `UserDataManager` | `getRoomUserListSnapshot(): ReadonlyArray<IRoomUserData>` | `ROOM_USER_LIST_UPDATED` (inner IRoomUserData kept mutable — don't deep-clone) |
|
||||||
|
| `SoundManager` | `getVolumesSnapshot(): Readonly<ISoundVolumesSnapshot>` | `SOUND_VOLUMES_UPDATED` (only when a volume actually changes) |
|
||||||
|
|
||||||
When you mutate any field that the snapshot exposes, call the private
|
Snapshot interface contracts live under `packages/api/src/nitro/session/`
|
||||||
`invalidateUserDataSnapshot()` / `invalidateRoomSessionSnapshot()` —
|
and `packages/api/src/nitro/sound/`. When adding a new snapshot, the
|
||||||
that drops the cached snapshot and dispatches the invalidation event.
|
checklist is:
|
||||||
The React side rebuilds via `useSyncExternalStore`.
|
1. Define the `Ixxx Snapshot` interface in `packages/api/src/nitro/...`
|
||||||
|
and export it from the matching `index.ts`.
|
||||||
|
2. Add a `XXX_UPDATED` member to `packages/events/src/NitroEventType.ts`.
|
||||||
|
3. Add `getXxxSnapshot()` to the interface AND impl; cache + invalidate
|
||||||
|
on every mutation path (don't forget batch operations like queue
|
||||||
|
truncation — invalidate AFTER the full batch, not mid-way).
|
||||||
|
|
||||||
The interface contracts live in:
|
Adding snapshots here is the preferred way to unblock new React
|
||||||
- `packages/api/src/nitro/session/IUserDataSnapshot.ts`
|
widgets — prefer it over exposing raw event-listener APIs on the
|
||||||
- `packages/api/src/nitro/session/IRoomSessionSnapshot.ts`
|
client side.
|
||||||
|
|
||||||
## Recent renderer changes (`feat/react19-event-bus`)
|
## Recent renderer changes (`feat/react19-event-bus`)
|
||||||
|
|
||||||
@@ -139,6 +148,38 @@ unchanged.
|
|||||||
`WiredUserVariablesRequestComposer`) annotate the return type
|
`WiredUserVariablesRequestComposer`) annotate the return type
|
||||||
`(): []` explicitly so `IMessageComposer<[]>` lines up.
|
`(): []` explicitly so `IMessageComposer<[]>` lines up.
|
||||||
|
|
||||||
|
### Optional-trailing-field parsers: flat early-return chain
|
||||||
|
|
||||||
|
Parsers that read "one tier of optional trailing fields per emulator
|
||||||
|
release" (UserProfileParser, GetGuestRoomResultMessageParser,
|
||||||
|
RoomSettingsDataParser, ModeratorUserInfoData, UserSubscriptionParser
|
||||||
|
…) all use a flat chain:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
if(!wrapper.bytesAvailable) return true;
|
||||||
|
// block N reads
|
||||||
|
if(!wrapper.bytesAvailable) return true;
|
||||||
|
// block N+1 reads
|
||||||
|
…
|
||||||
|
```
|
||||||
|
|
||||||
|
Defaults come from `flush()`. When the next emulator release ships a
|
||||||
|
new trailing block, append `if(!wrapper.bytesAvailable) return true;`
|
||||||
|
+ the new reads. Do NOT nest with `if(wrapper.bytesAvailable) { … }`
|
||||||
|
— the nested form re-indents the whole chain on every new tier and
|
||||||
|
is the historical source of brittle reads.
|
||||||
|
|
||||||
|
### Bug fix: `SoundManager` volume diff comparison
|
||||||
|
|
||||||
|
`onEvent(SETTINGS_UPDATED)` cached `volumeFurniUpdated` /
|
||||||
|
`volumeTraxUpdated` by comparing `castedEvent.volumeFurni` (percent,
|
||||||
|
e.g. 75) against `this._volumeFurni` (fraction, e.g. 0.75) — so the
|
||||||
|
change check almost always reported "updated" for a real settings push
|
||||||
|
and only reported "unchanged" if the percent matched the fraction by
|
||||||
|
coincidence (0 / 100 only). Fixed: divide first, compare divided
|
||||||
|
values, then write. Also tracks `volumeSystemUpdated` for the new
|
||||||
|
`SOUND_VOLUMES_UPDATED` snapshot invalidation.
|
||||||
|
|
||||||
### Bug fix: `PetBreedingMessageParser.bytesAvailable < 12`
|
### Bug fix: `PetBreedingMessageParser.bytesAvailable < 12`
|
||||||
|
|
||||||
`bytesAvailable` is a boolean (the wrapper just answers "is there
|
`bytesAvailable` is a boolean (the wrapper just answers "is there
|
||||||
|
|||||||
Reference in New Issue
Block a user