Add SessionDataManager.mergeFurnitureDataFromUrl() + FurnitureDataLoader.mergeFromUrl()
to merge a single furnidata chunk (e.g. a custom tier) into the live floor/wall maps at
runtime, returning the added entries so callers can also refresh the RoomContentLoader.
Lets newly added furniture appear without a full client reload.
Drop the separate UserPermissionsMapEvent / UserPermissionsMapParser
and the IncomingHeader.USER_PERMISSIONS_MAP = 10070 registration —
the resolved permission map now rides on the existing
UserPermissionsEvent as a third optional trailing block, after the
rank metadata one. Same wire data, one fewer packet, one fewer
event registration, one fewer handler.
Wire layout (UserPermissionsEvent / header 411):
int clubLevel
int securityLevel
bool isAmbassador
--- rank metadata (Arcturus ≥ 4.2.10) ---
int rankId
string rankName
string rankBadge
string rankPrefix
string rankPrefixColor
--- resolved permission map (Arcturus ≥ 4.2.10) ---
int count
loop: string permission_key + int value (1=ALLOWED, 2=ROOM_OWNER)
Both trailing blocks are guarded by `bytesAvailable` in
UserPermissionsParser so older emulators that don't append them
still parse cleanly.
SessionDataManager.onUserPermissionsEvent is now the single handler:
- updates clubLevel/securityLevel/isAmbassador/rank* AND _permissions;
- invalidates BOTH the user-data snapshot and the permissions
snapshot (dispatching the two distinct
NitroEventType.SESSION_DATA_UPDATED / USER_PERMISSIONS_UPDATED
events).
The two distinct invalidation events stay so React consumers can
subscribe granularly — useHasPermission(key) only triggers on a real
permission map flip, not on every session-data bump.
Companion Arcturus change (feat/react19-emu-update) folds
UserPermissionsMapComposer into UserPermissionsComposer and removes
the second sendResponse in HabboManager.setRank +
SecureLoginEvent.
Verification: yarn compile:fast clean, vitest 138/138.
Adds the wire pipeline for `Outgoing.UserPermissionsMapComposer = 10070`
shipped by Arcturus-Morningstar-Extended ≥ 4.2.10. The composer sends
the resolved `permission_definitions` map for the current user
(filtered to ALLOWED / ROOM_OWNER entries) at login and after every
`HabboManager.setRank` — so a runtime promote/demote re-derives every
React-side permission gate.
- NitroEventType.USER_PERMISSIONS_UPDATED — new invalidation event.
- IncomingHeader.USER_PERMISSIONS_MAP = 10070.
- UserPermissionsMapParser reads `int count + (string key, int value)*`.
- UserPermissionsMapEvent + NitroMessages registration.
- SessionDataManager._permissions Map + getPermissionsSnapshot()
referentially-stable per the snapshot convention. New handler
onUserPermissionsMapEvent copies the parser map into the manager
(so the parser's mutable reference doesn't leak) and invalidates.
- ISessionDataManager.getPermissionsSnapshot() — public contract.
React-side consumers ship in the companion commit on
feat/react19-modernization. The wire is backward-compatible: older
emulators never send the packet, the snapshot stays empty Map, and
all useHasPermission(key) gates return false (mod-only UI hidden by
default = safe).
Verification: tsgo clean, vitest 138/138.
Extend the `UserPermissionsEvent` parser and `IUserDataSnapshot` with
rank metadata mirrored from the Arcturus `permission_ranks` table:
rankId, rankName, rankBadge, rankPrefix, rankPrefixColor.
The new fields are appended to the wire payload AFTER the existing
[clubLevel, securityLevel, isAmbassador] triple. The parser guards
the trailing block with `if(!wrapper.bytesAvailable) return true;`
so older emulators (that don't write the extension) keep working —
the snapshot just exposes the defaults (rankId=0, empty strings) in
that case.
`SessionDataManager.onUserPermissionsEvent` stores the values; the
snapshot builder includes them; existing
`invalidateUserDataSnapshot()` semantics flow through unchanged, so
a runtime promote/demote (via `HabboManager.setRank` →
`UserPermissionsComposer`) auto-flips the React-side
`useUserRank()` / `useHasRankLevel()` / `useIsRank()` consumers in
the Nitro-V3 client.
Companion changes:
- Arcturus-Morningstar-Extended:
`UserPermissionsComposer.composeInternal()` now appends the 5
extra fields (pending operator commit; see
../Arcturus-Morningstar-Extended/Emulator/src/main/java/
com/eu/habbo/messages/outgoing/users/UserPermissionsComposer.java).
- Nitro-V3:
`useSessionSnapshots.ts` exposes the new family
(useUserRank / useHasRankLevel / useIsRank), replacing the
SecurityLevel-based wrappers (useIsModerator etc.) that hardcoded
the renderer enum names — those don't match the operator's
`permission_ranks.rank_name` column.
Verification: tsgo clean, vitest 138/138.