You've already forked Nitro_Render_V3
mirror of
https://github.com/duckietm/Nitro_Render_V3.git
synced 2026-06-20 07:26:18 +00:00
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:
@@ -19,4 +19,13 @@ export interface IUserDataSnapshot
|
|||||||
isSystemShutdown: boolean;
|
isSystemShutdown: boolean;
|
||||||
uiFlags: number;
|
uiFlags: number;
|
||||||
tags: ReadonlyArray<string>;
|
tags: ReadonlyArray<string>;
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,22 @@ export class UserPermissionsParser implements IMessageParser
|
|||||||
private _clubLevel: number;
|
private _clubLevel: number;
|
||||||
private _securityLevel: number;
|
private _securityLevel: number;
|
||||||
private _isAmbassador: boolean;
|
private _isAmbassador: boolean;
|
||||||
|
private _rankId: number;
|
||||||
|
private _rankName: string;
|
||||||
|
private _rankBadge: string;
|
||||||
|
private _rankPrefix: string;
|
||||||
|
private _rankPrefixColor: string;
|
||||||
|
|
||||||
public flush(): boolean
|
public flush(): boolean
|
||||||
{
|
{
|
||||||
this._clubLevel = 0;
|
this._clubLevel = 0;
|
||||||
this._securityLevel = 0;
|
this._securityLevel = 0;
|
||||||
this._isAmbassador = false;
|
this._isAmbassador = false;
|
||||||
|
this._rankId = 0;
|
||||||
|
this._rankName = '';
|
||||||
|
this._rankBadge = '';
|
||||||
|
this._rankPrefix = '';
|
||||||
|
this._rankPrefixColor = '';
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -23,6 +33,18 @@ export class UserPermissionsParser implements IMessageParser
|
|||||||
this._securityLevel = wrapper.readInt();
|
this._securityLevel = wrapper.readInt();
|
||||||
this._isAmbassador = wrapper.readBoolean();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,4 +62,29 @@ export class UserPermissionsParser implements IMessageParser
|
|||||||
{
|
{
|
||||||
return this._isAmbassador;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ export class SessionDataManager implements ISessionDataManager
|
|||||||
private _clubLevel: number = 0;
|
private _clubLevel: number = 0;
|
||||||
private _securityLevel: number = 0;
|
private _securityLevel: number = 0;
|
||||||
private _isAmbassador: boolean = false;
|
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 _noobnessLevel: number = -1;
|
||||||
private _isEmailVerified: boolean = false;
|
private _isEmailVerified: boolean = false;
|
||||||
|
|
||||||
@@ -89,7 +94,12 @@ export class SessionDataManager implements ISessionDataManager
|
|||||||
isSystemOpen: this._systemOpen,
|
isSystemOpen: this._systemOpen,
|
||||||
isSystemShutdown: this._systemShutdown,
|
isSystemShutdown: this._systemShutdown,
|
||||||
uiFlags: this._uiFlags,
|
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;
|
return this._userDataSnapshot;
|
||||||
@@ -239,9 +249,16 @@ export class SessionDataManager implements ISessionDataManager
|
|||||||
{
|
{
|
||||||
if(!event || !event.connection) return;
|
if(!event || !event.connection) return;
|
||||||
|
|
||||||
this._clubLevel = event.getParser().clubLevel;
|
const parser = event.getParser();
|
||||||
this._securityLevel = event.getParser().securityLevel;
|
|
||||||
this._isAmbassador = event.getParser().isAmbassador;
|
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();
|
this.invalidateUserDataSnapshot();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user