feat(session): rank metadata in UserPermissions snapshot

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.
This commit is contained in:
simoleo89
2026-05-19 18:37:57 +02:00
parent ce561bd5b3
commit 87e67d58df
3 changed files with 77 additions and 4 deletions
+21 -4
View File
@@ -32,6 +32,11 @@ export class SessionDataManager implements ISessionDataManager
private _clubLevel: number = 0;
private _securityLevel: number = 0;
private _isAmbassador: boolean = false;
private _rankId: number = 0;
private _rankName: string = '';
private _rankBadge: string = '';
private _rankPrefix: string = '';
private _rankPrefixColor: string = '';
private _noobnessLevel: number = -1;
private _isEmailVerified: boolean = false;
@@ -89,7 +94,12 @@ export class SessionDataManager implements ISessionDataManager
isSystemOpen: this._systemOpen,
isSystemShutdown: this._systemShutdown,
uiFlags: this._uiFlags,
tags: Object.freeze<string[]>([...this._tags]) as ReadonlyArray<string>
tags: Object.freeze<string[]>([...this._tags]) as ReadonlyArray<string>,
rankId: this._rankId,
rankName: this._rankName,
rankBadge: this._rankBadge,
rankPrefix: this._rankPrefix,
rankPrefixColor: this._rankPrefixColor
});
return this._userDataSnapshot;
@@ -239,9 +249,16 @@ export class SessionDataManager implements ISessionDataManager
{
if(!event || !event.connection) return;
this._clubLevel = event.getParser().clubLevel;
this._securityLevel = event.getParser().securityLevel;
this._isAmbassador = event.getParser().isAmbassador;
const parser = event.getParser();
this._clubLevel = parser.clubLevel;
this._securityLevel = parser.securityLevel;
this._isAmbassador = parser.isAmbassador;
this._rankId = parser.rankId;
this._rankName = parser.rankName;
this._rankBadge = parser.rankBadge;
this._rankPrefix = parser.rankPrefix;
this._rankPrefixColor = parser.rankPrefixColor;
this.invalidateUserDataSnapshot();
}