diff --git a/packages/api/src/nitro/session/IUserDataSnapshot.ts b/packages/api/src/nitro/session/IUserDataSnapshot.ts index 84c971f..9d7a24f 100644 --- a/packages/api/src/nitro/session/IUserDataSnapshot.ts +++ b/packages/api/src/nitro/session/IUserDataSnapshot.ts @@ -19,4 +19,13 @@ export interface IUserDataSnapshot isSystemShutdown: boolean; uiFlags: number; tags: ReadonlyArray; + // Rank metadata mirrored from `permission_ranks` (Arcturus emulator + // ≥ 4.2.10 ships these via `UserPermissionsComposer`). Older + // emulators leave them at the defaults (rankId=0, empty strings) + // because the renderer-side parser short-circuits on bytesAvailable. + rankId: number; + rankName: string; + rankBadge: string; + rankPrefix: string; + rankPrefixColor: string; } diff --git a/packages/communication/src/messages/parser/user/access/UserPermissionsParser.ts b/packages/communication/src/messages/parser/user/access/UserPermissionsParser.ts index 4f40f45..20d5fb6 100644 --- a/packages/communication/src/messages/parser/user/access/UserPermissionsParser.ts +++ b/packages/communication/src/messages/parser/user/access/UserPermissionsParser.ts @@ -5,12 +5,22 @@ export class UserPermissionsParser implements IMessageParser private _clubLevel: number; private _securityLevel: number; private _isAmbassador: boolean; + private _rankId: number; + private _rankName: string; + private _rankBadge: string; + private _rankPrefix: string; + private _rankPrefixColor: string; public flush(): boolean { this._clubLevel = 0; this._securityLevel = 0; this._isAmbassador = false; + this._rankId = 0; + this._rankName = ''; + this._rankBadge = ''; + this._rankPrefix = ''; + this._rankPrefixColor = ''; return true; } @@ -23,6 +33,18 @@ export class UserPermissionsParser implements IMessageParser this._securityLevel = wrapper.readInt(); this._isAmbassador = wrapper.readBoolean(); + // Optional trailing block (Arcturus-Morningstar-Extended ≥ 4.2.10): + // rank metadata appended in a backward-compatible way. Older + // emulators don't write these bytes so we keep the defaults + // from flush(). + if(!wrapper.bytesAvailable) return true; + + this._rankId = wrapper.readInt(); + this._rankName = wrapper.readString(); + this._rankBadge = wrapper.readString(); + this._rankPrefix = wrapper.readString(); + this._rankPrefixColor = wrapper.readString(); + return true; } @@ -40,4 +62,29 @@ export class UserPermissionsParser implements IMessageParser { return this._isAmbassador; } + + public get rankId(): number + { + return this._rankId; + } + + public get rankName(): string + { + return this._rankName; + } + + public get rankBadge(): string + { + return this._rankBadge; + } + + public get rankPrefix(): string + { + return this._rankPrefix; + } + + public get rankPrefixColor(): string + { + return this._rankPrefixColor; + } } diff --git a/packages/session/src/SessionDataManager.ts b/packages/session/src/SessionDataManager.ts index c2f15e9..c6c8b9b 100644 --- a/packages/session/src/SessionDataManager.ts +++ b/packages/session/src/SessionDataManager.ts @@ -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([...this._tags]) as ReadonlyArray + tags: Object.freeze([...this._tags]) as ReadonlyArray, + 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(); }