diff --git a/packages/communication/src/NitroMessages.ts b/packages/communication/src/NitroMessages.ts index a1ad95f..3caca87 100644 --- a/packages/communication/src/NitroMessages.ts +++ b/packages/communication/src/NitroMessages.ts @@ -6,6 +6,7 @@ import { WiredMovementsEvent } from './messages'; import { ConfInvisStateMessageEvent } from './messages'; import { HanditemBlockStateMessageEvent } from './messages'; import { TranslationLanguagesEvent, TranslationLanguagesRequestComposer, TranslationResultEvent, TranslationTextRequestComposer } from './messages'; +import { YouTubeRoomBroadcastEvent, YouTubeRoomPlayComposer, YouTubeRoomSettingsComposer, YouTubeRoomSettingsEvent, YouTubeRoomWatchersEvent, YouTubeRoomWatchingComposer } from './messages'; export class NitroMessages implements IMessageConfiguration { private _events: Map; @@ -501,6 +502,9 @@ export class NitroMessages implements IMessageConfiguration this._events.set(IncomingHeader.HANDITEM_BLOCK_STATE, HanditemBlockStateMessageEvent); this._events.set(IncomingHeader.TRANSLATION_LANGUAGES, TranslationLanguagesEvent); this._events.set(IncomingHeader.TRANSLATION_RESULT, TranslationResultEvent); + this._events.set(IncomingHeader.YOUTUBE_ROOM_BROADCAST, YouTubeRoomBroadcastEvent); + this._events.set(IncomingHeader.YOUTUBE_ROOM_SETTINGS, YouTubeRoomSettingsEvent); + this._events.set(IncomingHeader.YOUTUBE_ROOM_WATCHERS, YouTubeRoomWatchersEvent); this._events.set(IncomingHeader.WIRED_REWARD, WiredRewardResultMessageEvent); this._events.set(IncomingHeader.WIRED_SAVE, WiredSaveSuccessEvent); this._events.set(IncomingHeader.WIRED_ERROR, WiredValidationErrorEvent); @@ -1248,6 +1252,9 @@ export class NitroMessages implements IMessageConfiguration this._composers.set(OutgoingHeader.PURCHASE_PREFIX, PurchasePrefixComposer); this._composers.set(OutgoingHeader.PURCHASE_CATALOG_PREFIX, PurchaseCatalogPrefixComposer); this._composers.set(OutgoingHeader.SET_DISPLAY_ORDER, SetDisplayOrderComposer); + this._composers.set(OutgoingHeader.YOUTUBE_ROOM_PLAY, YouTubeRoomPlayComposer); + this._composers.set(OutgoingHeader.YOUTUBE_ROOM_SETTINGS, YouTubeRoomSettingsComposer); + this._composers.set(OutgoingHeader.YOUTUBE_ROOM_WATCHING, YouTubeRoomWatchingComposer); } public get events(): Map diff --git a/packages/communication/src/messages/incoming/IncomingHeader.ts b/packages/communication/src/messages/incoming/IncomingHeader.ts index d87a735..70dbad3 100644 --- a/packages/communication/src/messages/incoming/IncomingHeader.ts +++ b/packages/communication/src/messages/incoming/IncomingHeader.ts @@ -498,4 +498,9 @@ export class IncomingHeader public static PREFIX_RECEIVED = 7002; public static ACTIVE_PREFIX_UPDATED = 7003; public static USER_NICK_ICONS = 7004; + + // YouTube Room Broadcast + public static YOUTUBE_ROOM_BROADCAST = 8001; + public static YOUTUBE_ROOM_WATCHERS = 8002; + public static YOUTUBE_ROOM_SETTINGS = 8003; } diff --git a/packages/communication/src/messages/incoming/room/index.ts b/packages/communication/src/messages/incoming/room/index.ts index 81b327b..0bab99d 100644 --- a/packages/communication/src/messages/incoming/room/index.ts +++ b/packages/communication/src/messages/incoming/room/index.ts @@ -13,3 +13,4 @@ export * from './pet'; export * from './session'; export * from './unit'; export * from './unit/chat'; +export * from './youtube'; diff --git a/packages/communication/src/messages/incoming/room/youtube/YouTubeRoomBroadcastEvent.ts b/packages/communication/src/messages/incoming/room/youtube/YouTubeRoomBroadcastEvent.ts new file mode 100644 index 0000000..aab2c9a --- /dev/null +++ b/packages/communication/src/messages/incoming/room/youtube/YouTubeRoomBroadcastEvent.ts @@ -0,0 +1,16 @@ +import { IMessageEvent } from '@nitrots/api'; +import { MessageEvent } from '@nitrots/events'; +import { YouTubeRoomBroadcastParser } from '../../../parser'; + +export class YouTubeRoomBroadcastEvent extends MessageEvent implements IMessageEvent +{ + constructor(callBack: Function) + { + super(callBack, YouTubeRoomBroadcastParser); + } + + public getParser(): YouTubeRoomBroadcastParser + { + return this.parser as YouTubeRoomBroadcastParser; + } +} diff --git a/packages/communication/src/messages/incoming/room/youtube/YouTubeRoomSettingsEvent.ts b/packages/communication/src/messages/incoming/room/youtube/YouTubeRoomSettingsEvent.ts new file mode 100644 index 0000000..fc704f9 --- /dev/null +++ b/packages/communication/src/messages/incoming/room/youtube/YouTubeRoomSettingsEvent.ts @@ -0,0 +1,16 @@ +import { IMessageEvent } from '@nitrots/api'; +import { MessageEvent } from '@nitrots/events'; +import { YouTubeRoomSettingsParser } from '../../../parser'; + +export class YouTubeRoomSettingsEvent extends MessageEvent implements IMessageEvent +{ + constructor(callBack: Function) + { + super(callBack, YouTubeRoomSettingsParser); + } + + public getParser(): YouTubeRoomSettingsParser + { + return this.parser as YouTubeRoomSettingsParser; + } +} diff --git a/packages/communication/src/messages/incoming/room/youtube/YouTubeRoomWatchersEvent.ts b/packages/communication/src/messages/incoming/room/youtube/YouTubeRoomWatchersEvent.ts new file mode 100644 index 0000000..eadc2e7 --- /dev/null +++ b/packages/communication/src/messages/incoming/room/youtube/YouTubeRoomWatchersEvent.ts @@ -0,0 +1,16 @@ +import { IMessageEvent } from '@nitrots/api'; +import { MessageEvent } from '@nitrots/events'; +import { YouTubeRoomWatchersParser } from '../../../parser'; + +export class YouTubeRoomWatchersEvent extends MessageEvent implements IMessageEvent +{ + constructor(callBack: Function) + { + super(callBack, YouTubeRoomWatchersParser); + } + + public getParser(): YouTubeRoomWatchersParser + { + return this.parser as YouTubeRoomWatchersParser; + } +} diff --git a/packages/communication/src/messages/incoming/room/youtube/index.ts b/packages/communication/src/messages/incoming/room/youtube/index.ts new file mode 100644 index 0000000..658dd87 --- /dev/null +++ b/packages/communication/src/messages/incoming/room/youtube/index.ts @@ -0,0 +1,3 @@ +export * from './YouTubeRoomBroadcastEvent'; +export * from './YouTubeRoomSettingsEvent'; +export * from './YouTubeRoomWatchersEvent'; diff --git a/packages/communication/src/messages/outgoing/OutgoingHeader.ts b/packages/communication/src/messages/outgoing/OutgoingHeader.ts index 52599f2..80dc117 100644 --- a/packages/communication/src/messages/outgoing/OutgoingHeader.ts +++ b/packages/communication/src/messages/outgoing/OutgoingHeader.ts @@ -517,4 +517,9 @@ export class OutgoingHeader public static SET_ACTIVE_NICK_ICON = 7017; public static PURCHASE_CATALOG_PREFIX = 7018; public static SET_DISPLAY_ORDER = 7019; + + // YouTube Room Broadcast + public static YOUTUBE_ROOM_PLAY = 8001; + public static YOUTUBE_ROOM_WATCHING = 8002; + public static YOUTUBE_ROOM_SETTINGS = 8003; } diff --git a/packages/communication/src/messages/outgoing/room/index.ts b/packages/communication/src/messages/outgoing/room/index.ts index 0067ee0..9e30ade 100644 --- a/packages/communication/src/messages/outgoing/room/index.ts +++ b/packages/communication/src/messages/outgoing/room/index.ts @@ -17,3 +17,4 @@ export * from './RedeemItemClothingComposer'; export * from './session'; export * from './unit'; export * from './unit/chat'; +export * from './youtube'; diff --git a/packages/communication/src/messages/outgoing/room/youtube/YouTubeRoomPlayComposer.ts b/packages/communication/src/messages/outgoing/room/youtube/YouTubeRoomPlayComposer.ts new file mode 100644 index 0000000..6ca7d33 --- /dev/null +++ b/packages/communication/src/messages/outgoing/room/youtube/YouTubeRoomPlayComposer.ts @@ -0,0 +1,14 @@ +import { IMessageComposer } from '@nitrots/api'; + +export class YouTubeRoomPlayComposer implements IMessageComposer +{ + private _data: any[]; + + constructor(videoId: string, playlist: string[]) + { + this._data = [videoId, playlist.length, ...playlist]; + } + + public getMessageArray() { return this._data; } + public dispose(): void {} +} diff --git a/packages/communication/src/messages/outgoing/room/youtube/YouTubeRoomSettingsComposer.ts b/packages/communication/src/messages/outgoing/room/youtube/YouTubeRoomSettingsComposer.ts new file mode 100644 index 0000000..a5fcfc0 --- /dev/null +++ b/packages/communication/src/messages/outgoing/room/youtube/YouTubeRoomSettingsComposer.ts @@ -0,0 +1,14 @@ +import { IMessageComposer } from '@nitrots/api'; + +export class YouTubeRoomSettingsComposer implements IMessageComposer +{ + private _data: any[]; + + constructor(enabled: boolean) + { + this._data = [enabled ? 1 : 0]; + } + + public getMessageArray() { return this._data; } + public dispose(): void {} +} diff --git a/packages/communication/src/messages/outgoing/room/youtube/YouTubeRoomWatchingComposer.ts b/packages/communication/src/messages/outgoing/room/youtube/YouTubeRoomWatchingComposer.ts new file mode 100644 index 0000000..b818591 --- /dev/null +++ b/packages/communication/src/messages/outgoing/room/youtube/YouTubeRoomWatchingComposer.ts @@ -0,0 +1,16 @@ +import { IMessageComposer } from '@nitrots/api'; + +export class YouTubeRoomWatchingComposer implements IMessageComposer +{ + private _data: any[]; + + constructor(watching: boolean) + { + // Send as int (0/1) instead of bare boolean to avoid + // serialization ambiguity in the Nitro wire protocol. + this._data = [watching ? 1 : 0]; + } + + public getMessageArray() { return this._data; } + public dispose(): void {} +} diff --git a/packages/communication/src/messages/outgoing/room/youtube/index.ts b/packages/communication/src/messages/outgoing/room/youtube/index.ts new file mode 100644 index 0000000..c1f24ca --- /dev/null +++ b/packages/communication/src/messages/outgoing/room/youtube/index.ts @@ -0,0 +1,3 @@ +export * from './YouTubeRoomPlayComposer'; +export * from './YouTubeRoomSettingsComposer'; +export * from './YouTubeRoomWatchingComposer'; diff --git a/packages/communication/src/messages/parser/inventory/badges/BadgeReceivedParser.ts b/packages/communication/src/messages/parser/inventory/badges/BadgeReceivedParser.ts index b4b6bcd..b63867e 100644 --- a/packages/communication/src/messages/parser/inventory/badges/BadgeReceivedParser.ts +++ b/packages/communication/src/messages/parser/inventory/badges/BadgeReceivedParser.ts @@ -1,14 +1,16 @@ -import { IMessageDataWrapper, IMessageParser } from '@nitrots/api'; +import { IMessageDataWrapper, IMessageParser } from '@nitrots/api'; export class BadgeReceivedParser implements IMessageParser { private _badgeId: number; private _badgeCode: string; + private _senderName: string; public flush(): boolean { this._badgeId = 0; this._badgeCode = null; + this._senderName = ''; return true; } @@ -19,6 +21,10 @@ export class BadgeReceivedParser implements IMessageParser this._badgeId = wrapper.readInt(); this._badgeCode = wrapper.readString(); + // Extra field appended by the Arcturus-Nitro fork: sender username for + // badges awarded by a staff member via the `:badge` command. Read + // defensively so older servers that don't send it still parse cleanly. + this._senderName = wrapper.bytesAvailable ? wrapper.readString() : ''; return true; } @@ -32,4 +38,9 @@ export class BadgeReceivedParser implements IMessageParser { return this._badgeCode; } + + public get senderName(): string + { + return this._senderName; + } } diff --git a/packages/communication/src/messages/parser/room/index.ts b/packages/communication/src/messages/parser/room/index.ts index 81b327b..0bab99d 100644 --- a/packages/communication/src/messages/parser/room/index.ts +++ b/packages/communication/src/messages/parser/room/index.ts @@ -13,3 +13,4 @@ export * from './pet'; export * from './session'; export * from './unit'; export * from './unit/chat'; +export * from './youtube'; diff --git a/packages/communication/src/messages/parser/room/youtube/YouTubeRoomBroadcastParser.ts b/packages/communication/src/messages/parser/room/youtube/YouTubeRoomBroadcastParser.ts new file mode 100644 index 0000000..87965fa --- /dev/null +++ b/packages/communication/src/messages/parser/room/youtube/YouTubeRoomBroadcastParser.ts @@ -0,0 +1,35 @@ +import { IMessageDataWrapper, IMessageParser } from '@nitrots/api'; + +export class YouTubeRoomBroadcastParser implements IMessageParser +{ + private _videoId: string; + private _senderName: string; + private _playlist: string[]; + + public flush(): boolean + { + this._videoId = ''; + this._senderName = ''; + this._playlist = []; + return true; + } + + public parse(wrapper: IMessageDataWrapper): boolean + { + if(!wrapper) return false; + + this._videoId = wrapper.readString(); + this._senderName = wrapper.readString(); + const count = wrapper.readInt(); + this._playlist = []; + for(let i = 0; i < count; i++) + { + this._playlist.push(wrapper.readString()); + } + return true; + } + + public get videoId(): string { return this._videoId; } + public get senderName(): string { return this._senderName; } + public get playlist(): string[] { return this._playlist; } +} diff --git a/packages/communication/src/messages/parser/room/youtube/YouTubeRoomSettingsParser.ts b/packages/communication/src/messages/parser/room/youtube/YouTubeRoomSettingsParser.ts new file mode 100644 index 0000000..53a90ab --- /dev/null +++ b/packages/communication/src/messages/parser/room/youtube/YouTubeRoomSettingsParser.ts @@ -0,0 +1,21 @@ +import { IMessageDataWrapper, IMessageParser } from '@nitrots/api'; + +export class YouTubeRoomSettingsParser implements IMessageParser +{ + private _youtubeEnabled: boolean; + + public flush(): boolean + { + this._youtubeEnabled = false; + return true; + } + + public parse(wrapper: IMessageDataWrapper): boolean + { + if(!wrapper) return false; + this._youtubeEnabled = wrapper.readInt() === 1; + return true; + } + + public get youtubeEnabled(): boolean { return this._youtubeEnabled; } +} diff --git a/packages/communication/src/messages/parser/room/youtube/YouTubeRoomWatchersParser.ts b/packages/communication/src/messages/parser/room/youtube/YouTubeRoomWatchersParser.ts new file mode 100644 index 0000000..716763c --- /dev/null +++ b/packages/communication/src/messages/parser/room/youtube/YouTubeRoomWatchersParser.ts @@ -0,0 +1,27 @@ +import { IMessageDataWrapper, IMessageParser } from '@nitrots/api'; + +export class YouTubeRoomWatchersParser implements IMessageParser +{ + private _watcherIds: number[]; + + public flush(): boolean + { + this._watcherIds = []; + return true; + } + + public parse(wrapper: IMessageDataWrapper): boolean + { + if(!wrapper) return false; + + const count = wrapper.readInt(); + this._watcherIds = []; + for(let i = 0; i < count; i++) + { + this._watcherIds.push(wrapper.readInt()); + } + return true; + } + + public get watcherIds(): number[] { return this._watcherIds; } +} diff --git a/packages/communication/src/messages/parser/room/youtube/index.ts b/packages/communication/src/messages/parser/room/youtube/index.ts new file mode 100644 index 0000000..00ee552 --- /dev/null +++ b/packages/communication/src/messages/parser/room/youtube/index.ts @@ -0,0 +1,3 @@ +export * from './YouTubeRoomBroadcastParser'; +export * from './YouTubeRoomSettingsParser'; +export * from './YouTubeRoomWatchersParser'; diff --git a/packages/room/src/RoomPreviewer.ts b/packages/room/src/RoomPreviewer.ts index 3f49af8..f6d70c7 100644 --- a/packages/room/src/RoomPreviewer.ts +++ b/packages/room/src/RoomPreviewer.ts @@ -239,6 +239,8 @@ export class RoomPreviewer if(this.isRoomEngineReady) { + if((this._currentPreviewObjectCategory === RoomObjectCategory.FLOOR) && (this._currentPreviewObjectType === classId) && (this._currentPreviewObjectData === (extra || ''))) return RoomPreviewer.PREVIEW_OBJECT_ID; + this.reset(false); this._currentPreviewObjectType = classId;