feat(communication): add housekeeping find-user-by-name packet pair

TS counterparts to Arcturus' new HK packet pair. Adds
HousekeepingFindUserByNameComposer (OutgoingHeader 9100) and
HousekeepingUserDetailEvent (IncomingHeader 9200) with a parser that
wraps an optional HousekeepingUserDetailData. The data class follows
the flat optional-trailing-field pattern (isMuted / isTradeLocked
read under bytesAvailable guards) so the renderer stays compatible
with a server that hasn't surfaced those manager APIs offline yet.

The parser exposes `found: boolean` and `user: HousekeepingUserDetailData | null`
so a callsite that gets a "user not found" reply can branch without
having to read into an unpopulated data object — the composer writes
`appendBoolean(false)` and stops, the parser sees the false and leaves
`user` null.

Headers 9100..9199 / 9200..9299 reserved for the rest of the HK
packet surface. Composer + event registered in NitroMessages alongside
the existing YouTube-room overrides. `yarn compile:fast` clean, vitest
138/138 green.
This commit is contained in:
simoleo89
2026-05-24 10:39:20 +02:00
committed by simoleo89
parent 081e06b208
commit ec7e122e74
13 changed files with 148 additions and 0 deletions
@@ -7,6 +7,7 @@ import { ConfInvisStateMessageEvent } from './messages';
import { HanditemBlockStateMessageEvent } from './messages';
import { TranslationLanguagesEvent, TranslationLanguagesRequestComposer, TranslationResultEvent, TranslationTextRequestComposer } from './messages';
import { YouTubeRoomBroadcastEvent, YouTubeRoomPlayComposer, YouTubeRoomSettingsComposer, YouTubeRoomSettingsEvent, YouTubeRoomWatchersEvent, YouTubeRoomWatchingComposer } from './messages';
import { HousekeepingFindUserByNameComposer, HousekeepingUserDetailEvent } from './messages';
export class NitroMessages implements IMessageConfiguration
{
private _events: Map<number, Function>;
@@ -505,6 +506,9 @@ export class NitroMessages implements IMessageConfiguration
this._events.set(IncomingHeader.YOUTUBE_ROOM_BROADCAST, YouTubeRoomBroadcastEvent);
this._events.set(IncomingHeader.YOUTUBE_ROOM_SETTINGS, YouTubeRoomSettingsEvent);
this._events.set(IncomingHeader.YOUTUBE_ROOM_WATCHERS, YouTubeRoomWatchersEvent);
// Housekeeping (in-client admin panel)
this._events.set(IncomingHeader.HOUSEKEEPING_USER_DETAIL, HousekeepingUserDetailEvent);
this._events.set(IncomingHeader.WIRED_REWARD, WiredRewardResultMessageEvent);
this._events.set(IncomingHeader.WIRED_SAVE, WiredSaveSuccessEvent);
this._events.set(IncomingHeader.WIRED_ERROR, WiredValidationErrorEvent);
@@ -1255,6 +1259,9 @@ export class NitroMessages implements IMessageConfiguration
this._composers.set(OutgoingHeader.YOUTUBE_ROOM_PLAY, YouTubeRoomPlayComposer);
this._composers.set(OutgoingHeader.YOUTUBE_ROOM_SETTINGS, YouTubeRoomSettingsComposer);
this._composers.set(OutgoingHeader.YOUTUBE_ROOM_WATCHING, YouTubeRoomWatchingComposer);
// Housekeeping (in-client admin panel)
this._composers.set(OutgoingHeader.HOUSEKEEPING_FIND_USER_BY_NAME, HousekeepingFindUserByNameComposer);
}
public get events(): Map<number, Function>
@@ -503,4 +503,7 @@ export class IncomingHeader
public static YOUTUBE_ROOM_BROADCAST = 8001;
public static YOUTUBE_ROOM_WATCHERS = 8002;
public static YOUTUBE_ROOM_SETTINGS = 8003;
// Housekeeping (in-client admin panel) — IDs 9200..9299 reserved
public static HOUSEKEEPING_USER_DETAIL = 9200;
}
@@ -0,0 +1,16 @@
import { IMessageEvent } from '@nitrots/api';
import { MessageEvent } from '@nitrots/events';
import { HousekeepingUserDetailParser } from '../../parser';
export class HousekeepingUserDetailEvent extends MessageEvent implements IMessageEvent
{
constructor(callBack: Function)
{
super(callBack, HousekeepingUserDetailParser);
}
public getParser(): HousekeepingUserDetailParser
{
return this.parser as HousekeepingUserDetailParser;
}
}
@@ -0,0 +1 @@
export * from './HousekeepingUserDetailEvent';
@@ -24,6 +24,7 @@ export * from './group';
export * from './groupforums';
export * from './handshake';
export * from './help';
export * from './housekeeping';
export * from './inventory';
export * from './inventory/achievements';
export * from './inventory/avatareffect';
@@ -522,4 +522,7 @@ export class OutgoingHeader
public static YOUTUBE_ROOM_PLAY = 8001;
public static YOUTUBE_ROOM_WATCHING = 8002;
public static YOUTUBE_ROOM_SETTINGS = 8003;
// Housekeeping (in-client admin panel) — IDs 9100..9199 reserved
public static HOUSEKEEPING_FIND_USER_BY_NAME = 9100;
}
@@ -0,0 +1,21 @@
import { IMessageComposer } from '@nitrots/api';
export class HousekeepingFindUserByNameComposer implements IMessageComposer<ConstructorParameters<typeof HousekeepingFindUserByNameComposer>>
{
private _data: ConstructorParameters<typeof HousekeepingFindUserByNameComposer>;
constructor(username: string)
{
this._data = [username];
}
public getMessageArray()
{
return this._data;
}
public dispose(): void
{
return;
}
}
@@ -0,0 +1 @@
export * from './HousekeepingFindUserByNameComposer';
@@ -21,6 +21,7 @@ export * from './group';
export * from './groupforums';
export * from './handshake';
export * from './help';
export * from './housekeeping';
export * from './inventory';
export * from './inventory/avatareffect';
export * from './inventory/badges';
@@ -0,0 +1,61 @@
import { IMessageDataWrapper } from '@nitrots/api';
export class HousekeepingUserDetailData
{
private _id: number = 0;
private _username: string = '';
private _motto: string = '';
private _figure: string = '';
private _rank: number = 0;
private _rankName: string = '';
private _online: boolean = false;
private _lastOnlineAt: number = 0;
private _creditsBalance: number = 0;
private _ducketsBalance: number = 0;
private _diamondsBalance: number = 0;
private _email: string = '';
private _ipLast: string = '';
private _isBanned: boolean = false;
private _isMuted: boolean = false;
private _isTradeLocked: boolean = false;
constructor(wrapper: IMessageDataWrapper)
{
if(!wrapper) throw new Error('invalid_wrapper');
this._id = wrapper.readInt();
this._username = wrapper.readString();
this._motto = wrapper.readString();
this._figure = wrapper.readString();
this._rank = wrapper.readInt();
this._rankName = wrapper.readString();
this._online = wrapper.readBoolean();
this._lastOnlineAt = wrapper.readInt();
this._creditsBalance = wrapper.readInt();
this._ducketsBalance = wrapper.readInt();
this._diamondsBalance = wrapper.readInt();
this._email = wrapper.readString();
this._ipLast = wrapper.readString();
this._isBanned = wrapper.readBoolean();
if(wrapper.bytesAvailable) this._isMuted = wrapper.readBoolean();
if(wrapper.bytesAvailable) this._isTradeLocked = wrapper.readBoolean();
}
public get id(): number { return this._id; }
public get username(): string { return this._username; }
public get motto(): string { return this._motto; }
public get figure(): string { return this._figure; }
public get rank(): number { return this._rank; }
public get rankName(): string { return this._rankName; }
public get online(): boolean { return this._online; }
public get lastOnlineAt(): number { return this._lastOnlineAt; }
public get creditsBalance(): number { return this._creditsBalance; }
public get ducketsBalance(): number { return this._ducketsBalance; }
public get diamondsBalance(): number { return this._diamondsBalance; }
public get email(): string { return this._email; }
public get ipLast(): string { return this._ipLast; }
public get isBanned(): boolean { return this._isBanned; }
public get isMuted(): boolean { return this._isMuted; }
public get isTradeLocked(): boolean { return this._isTradeLocked; }
}
@@ -0,0 +1,30 @@
import { IMessageDataWrapper, IMessageParser } from '@nitrots/api';
import { HousekeepingUserDetailData } from './HousekeepingUserDetailData';
export class HousekeepingUserDetailParser implements IMessageParser
{
private _found: boolean = false;
private _user: HousekeepingUserDetailData | null = null;
public flush(): boolean
{
this._found = false;
this._user = null;
return true;
}
public parse(wrapper: IMessageDataWrapper): boolean
{
if(!wrapper) return false;
this._found = wrapper.readBoolean();
if(this._found) this._user = new HousekeepingUserDetailData(wrapper);
return true;
}
public get found(): boolean { return this._found; }
public get user(): HousekeepingUserDetailData | null { return this._user; }
}
@@ -0,0 +1,2 @@
export * from './HousekeepingUserDetailData';
export * from './HousekeepingUserDetailParser';
@@ -24,6 +24,7 @@ export * from './group/utils';
export * from './groupforums';
export * from './handshake';
export * from './help';
export * from './housekeeping';
export * from './inventory';
export * from './inventory/achievements';
export * from './inventory/avatareffect';