From 1d6c102fd663757a5a91425fd73d119f566f4a5d Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Thu, 4 Jun 2026 22:01:08 +0200 Subject: [PATCH] feat(session): apply FurnitureDataReload delta + reload-hint (separate path) --- packages/session/src/SessionDataManager.ts | 23 +++++++++- .../src/__tests__/applyFurnidataDelta.test.ts | 36 ++++++++++++++++ .../src/furniture/applyFurnidataDelta.ts | 43 +++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 packages/session/src/__tests__/applyFurnidataDelta.test.ts create mode 100644 packages/session/src/furniture/applyFurnidataDelta.ts diff --git a/packages/session/src/SessionDataManager.ts b/packages/session/src/SessionDataManager.ts index f78c7bb..687f3ea 100644 --- a/packages/session/src/SessionDataManager.ts +++ b/packages/session/src/SessionDataManager.ts @@ -1,5 +1,7 @@ import { IFurnitureData, IGroupInformationManager, IMessageComposer, IMessageEvent, IProductData, ISessionDataManager, IUserDataSnapshot, NoobnessLevelEnum, SecurityLevel } from '@nitrots/api'; -import { AccountSafetyLockStatusChangeMessageEvent, AccountSafetyLockStatusChangeParser, AvailabilityStatusMessageEvent, ChangeUserNameResultMessageEvent, EmailStatusResultEvent, FigureUpdateEvent, GetCommunication, GetUserTagsComposer, InClientLinkEvent, MysteryBoxKeysEvent, NoobnessLevelMessageEvent, PetRespectComposer, PetScratchFailedMessageEvent, RoomReadyMessageEvent, RoomUnitChatComposer, UserInfoEvent, UserNameChangeMessageEvent, UserPermissionsEvent, UserRespectComposer, UserTagsMessageEvent } from '@nitrots/communication'; +import { AccountSafetyLockStatusChangeMessageEvent, AccountSafetyLockStatusChangeParser, AvailabilityStatusMessageEvent, ChangeUserNameResultMessageEvent, EmailStatusResultEvent, FigureUpdateEvent, FurnitureDataReloadEvent, GetCommunication, GetUserTagsComposer, InClientLinkEvent, MysteryBoxKeysEvent, NoobnessLevelMessageEvent, PetRespectComposer, PetScratchFailedMessageEvent, RoomReadyMessageEvent, RoomUnitChatComposer, UserInfoEvent, UserNameChangeMessageEvent, UserPermissionsEvent, UserRespectComposer, UserTagsMessageEvent } from '@nitrots/communication'; +import type { FurnidataDeltaEntry } from '@nitrots/communication'; +import { applyFurnidataDeltaTo } from './furniture/applyFurnidataDelta'; import { GetConfiguration } from '@nitrots/configuration'; import { GetLocalizationManager } from '@nitrots/localization'; import { GetEventDispatcher, MysteryBoxKeysUpdateEvent, NitroEvent, NitroEventType, NitroSettingsEvent, SessionDataPreferencesEvent, UserNameUpdateEvent } from '@nitrots/events'; @@ -171,7 +173,13 @@ export class SessionDataManager implements ISessionDataManager GetCommunication().registerMessageEvent(new MysteryBoxKeysEvent(this.onMysteryBoxKeysEvent.bind(this))), GetCommunication().registerMessageEvent(new NoobnessLevelMessageEvent(this.onNoobnessLevelMessageEvent.bind(this))), GetCommunication().registerMessageEvent(new AccountSafetyLockStatusChangeMessageEvent(this.onAccountSafetyLockStatusChangeMessageEvent.bind(this))), - GetCommunication().registerMessageEvent(new EmailStatusResultEvent(this.onEmailStatus.bind(this))) + GetCommunication().registerMessageEvent(new EmailStatusResultEvent(this.onEmailStatus.bind(this))), + GetCommunication().registerMessageEvent(new FurnitureDataReloadEvent((event: FurnitureDataReloadEvent) => + { + const parser = event.getParser(); + if(parser.mode === 1) { void this.applyFurnidataReloadHint(); } + else { this.applyFurnidataDelta(parser.entries); } + })) ); // Store event dispatcher callback for cleanup @@ -564,6 +572,17 @@ export class SessionDataManager implements ISessionDataManager } } + public applyFurnidataDelta(entries: FurnidataDeltaEntry[]): void + { + applyFurnidataDeltaTo(entries, this._floorItems as any, this._wallItems as any, GetLocalizationManager(), (typeof window !== 'undefined') ? window : { dispatchEvent: () => {} } as any); + } + + public async applyFurnidataReloadHint(): Promise + { + await this._furnitureData.init(); + if(typeof window !== 'undefined') window.dispatchEvent(new CustomEvent('nitro-localization-updated')); + } + public getBadgeUrl(name: string): string { return this._badgeImageManager.getBadgeUrl(name); diff --git a/packages/session/src/__tests__/applyFurnidataDelta.test.ts b/packages/session/src/__tests__/applyFurnidataDelta.test.ts new file mode 100644 index 0000000..25f4ada --- /dev/null +++ b/packages/session/src/__tests__/applyFurnidataDelta.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it, vi, beforeEach } from 'vitest'; +import { applyFurnidataDeltaTo } from '../furniture/applyFurnidataDelta'; + +describe('applyFurnidataDeltaTo', () => { + const setValue = vi.fn(); + beforeEach(() => setValue.mockClear()); + + it('patches floor FurnitureData name/desc + localization keys, dispatches window event', () => { + const floor: any = { _localizedName: 'Old', _description: 'Old desc' }; + const floorItems = new Map([[ 5, floor ]]); + const dispatched: string[] = []; + const win: any = { dispatchEvent: (e: any) => dispatched.push(e.type) }; + + applyFurnidataDeltaTo( + [ { type: 'S', id: 5, classname: 'chair', name: 'New', description: 'New desc' } ], + floorItems, new Map(), { setValue }, win + ); + + expect(floor._localizedName).toBe('New'); + expect(floor._description).toBe('New desc'); + expect(setValue).toHaveBeenCalledWith('roomItem.name.5', 'New'); + expect(setValue).toHaveBeenCalledWith('roomItem.desc.5', 'New desc'); + expect(dispatched).toContain('nitro-localization-updated'); + }); + + it('patches wall items by id', () => { + const wall: any = { _localizedName: 'W', _description: '' }; + const wallItems = new Map([[ 9, wall ]]); + applyFurnidataDeltaTo( + [ { type: 'I', id: 9, classname: 'poster', name: 'WallNew', description: 'd' } ], + new Map(), wallItems, { setValue }, { dispatchEvent: () => {} } + ); + expect(wall._localizedName).toBe('WallNew'); + expect(setValue).toHaveBeenCalledWith('wallItem.name.9', 'WallNew'); + }); +}); diff --git a/packages/session/src/furniture/applyFurnidataDelta.ts b/packages/session/src/furniture/applyFurnidataDelta.ts new file mode 100644 index 0000000..86b2c07 --- /dev/null +++ b/packages/session/src/furniture/applyFurnidataDelta.ts @@ -0,0 +1,43 @@ +import type { FurnidataDeltaEntry } from '@nitrots/communication'; + +/** + * Pure, testable furnidata-delta patcher. Mutates the FurnitureData objects in + * the given maps (by id) and the localization keys, then dispatches the + * `nitro-localization-updated` window event so subscribed React surfaces refresh. + */ +export function applyFurnidataDeltaTo( + entries: FurnidataDeltaEntry[], + floorItems: Map, + wallItems: Map, + localization: { setValue: (key: string, value: string) => void }, + win: { dispatchEvent: (event: any) => void } +): void +{ + if(!entries || !entries.length) return; + + for(const e of entries) + { + if(e.type === 'I') + { + const wall = wallItems.get(e.id); + if(wall) { wall._localizedName = e.name; wall._description = e.description; } + localization.setValue('wallItem.name.' + e.id, e.name); + localization.setValue('wallItem.desc.' + e.id, e.description); + } + else + { + const floor = floorItems.get(e.id); + if(floor) { floor._localizedName = e.name; floor._description = e.description; } + localization.setValue('roomItem.name.' + e.id, e.name); + localization.setValue('roomItem.desc.' + e.id, e.description); + } + } + + if(win && typeof win.dispatchEvent === 'function') + { + const evt = (typeof CustomEvent !== 'undefined') + ? new CustomEvent('nitro-localization-updated') + : { type: 'nitro-localization-updated' } as any; + win.dispatchEvent(evt); + } +}