Merge pull request #92 from duckietm/Dev

Dev
This commit is contained in:
DuckieTM
2026-06-05 21:19:46 +02:00
committed by GitHub
20 changed files with 269 additions and 29 deletions
+1 -1
View File
@@ -37,7 +37,7 @@
"json5": "^2.2.3", "json5": "^2.2.3",
"pako": "^2.1.0", "pako": "^2.1.0",
"pixi-filters": "^6.1.5", "pixi-filters": "^6.1.5",
"pixi.js": "^8.18.1" "pixi.js": "^8.19.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.13.0", "@eslint/js": "^9.13.0",
@@ -9,6 +9,7 @@ export interface ISessionDataManager
{ {
init(): Promise<void>; init(): Promise<void>;
getAllFurnitureData(): IFurnitureData[]; getAllFurnitureData(): IFurnitureData[];
mergeFurnitureDataFromUrl(url: string): Promise<IFurnitureData[]>;
applyFurnitureDataOverrides(url: string): Promise<void>; applyFurnitureDataOverrides(url: string): Promise<void>;
clearFurnitureDataOverrides(): void; clearFurnitureDataOverrides(): void;
getFloorItemData(id: number): IFurnitureData; getFloorItemData(id: number): IFurnitureData;
File diff suppressed because one or more lines are too long
@@ -496,6 +496,8 @@ export class IncomingHeader
// Catalog Admin // Catalog Admin
public static CATALOG_ADMIN_RESULT = 10059; public static CATALOG_ADMIN_RESULT = 10059;
public static CATALOG_ADMIN_OFFER_DETAILS = 10062;
public static CATALOG_ADMIN_PAGE_DETAILS = 10063;
// Custom Prefixes // Custom Prefixes
public static USER_PREFIXES = 7001; public static USER_PREFIXES = 7001;
@@ -0,0 +1,16 @@
import { IMessageEvent } from '@nitrots/api';
import { MessageEvent } from '@nitrots/events';
import { CatalogAdminOfferDetailsMessageParser } from '../../parser';
export class CatalogAdminOfferDetailsEvent extends MessageEvent implements IMessageEvent
{
constructor(callBack: Function)
{
super(callBack, CatalogAdminOfferDetailsMessageParser);
}
public getParser(): CatalogAdminOfferDetailsMessageParser
{
return this.parser as CatalogAdminOfferDetailsMessageParser;
}
}
@@ -0,0 +1,16 @@
import { IMessageEvent } from '@nitrots/api';
import { MessageEvent } from '@nitrots/events';
import { CatalogAdminPageDetailsMessageParser } from '../../parser';
export class CatalogAdminPageDetailsEvent extends MessageEvent implements IMessageEvent
{
constructor(callBack: Function)
{
super(callBack, CatalogAdminPageDetailsMessageParser);
}
public getParser(): CatalogAdminPageDetailsMessageParser
{
return this.parser as CatalogAdminPageDetailsMessageParser;
}
}
@@ -1,4 +1,6 @@
export * from './BonusRareInfoMessageEvent'; export * from './BonusRareInfoMessageEvent';
export * from './CatalogAdminOfferDetailsEvent';
export * from './CatalogAdminPageDetailsEvent';
export * from './CatalogAdminResultEvent'; export * from './CatalogAdminResultEvent';
export * from './BuildersClubFurniCountMessageEvent'; export * from './BuildersClubFurniCountMessageEvent';
export * from './BuildersClubSubscriptionStatusMessageEvent'; export * from './BuildersClubSubscriptionStatusMessageEvent';
@@ -507,6 +507,8 @@ export class OutgoingHeader
public static CATALOG_ADMIN_MOVE_OFFER = 10056; public static CATALOG_ADMIN_MOVE_OFFER = 10056;
public static CATALOG_ADMIN_MOVE_PAGE = 10057; public static CATALOG_ADMIN_MOVE_PAGE = 10057;
public static CATALOG_ADMIN_PUBLISH = 10058; public static CATALOG_ADMIN_PUBLISH = 10058;
public static CATALOG_ADMIN_LOAD_OFFER = 10062;
public static CATALOG_ADMIN_LOAD_PAGE = 10063;
public static DELETE_ITEM = 10018; public static DELETE_ITEM = 10018;
public static DELETE_PET = 10030; public static DELETE_PET = 10030;
@@ -0,0 +1,21 @@
import { IMessageComposer } from '@nitrots/api';
export class CatalogAdminLoadOfferComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminLoadOfferComposer>>
{
private _data: ConstructorParameters<typeof CatalogAdminLoadOfferComposer>;
constructor(offerId: number, catalogMode: string = 'NORMAL')
{
this._data = [ offerId, catalogMode ];
}
dispose(): void
{
this._data = null;
}
public getMessageArray()
{
return this._data;
}
}
@@ -0,0 +1,21 @@
import { IMessageComposer } from '@nitrots/api';
export class CatalogAdminLoadPageComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminLoadPageComposer>>
{
private _data: ConstructorParameters<typeof CatalogAdminLoadPageComposer>;
constructor(pageId: number, catalogMode: string = 'NORMAL')
{
this._data = [ pageId, catalogMode ];
}
dispose(): void
{
this._data = null;
}
public getMessageArray()
{
return this._data;
}
}
@@ -3,6 +3,8 @@ export * from './CatalogAdminCreateOfferComposer';
export * from './CatalogAdminCreatePageComposer'; export * from './CatalogAdminCreatePageComposer';
export * from './CatalogAdminDeleteOfferComposer'; export * from './CatalogAdminDeleteOfferComposer';
export * from './CatalogAdminDeletePageComposer'; export * from './CatalogAdminDeletePageComposer';
export * from './CatalogAdminLoadOfferComposer';
export * from './CatalogAdminLoadPageComposer';
export * from './CatalogAdminMoveOfferComposer'; export * from './CatalogAdminMoveOfferComposer';
export * from './CatalogAdminMovePageComposer'; export * from './CatalogAdminMovePageComposer';
export * from './CatalogAdminPublishComposer'; export * from './CatalogAdminPublishComposer';
@@ -14,6 +16,8 @@ export * from './CatalogAdminCreateOfferComposer';
export * from './CatalogAdminCreatePageComposer'; export * from './CatalogAdminCreatePageComposer';
export * from './CatalogAdminDeleteOfferComposer'; export * from './CatalogAdminDeleteOfferComposer';
export * from './CatalogAdminDeletePageComposer'; export * from './CatalogAdminDeletePageComposer';
export * from './CatalogAdminLoadOfferComposer';
export * from './CatalogAdminLoadPageComposer';
export * from './CatalogAdminMoveOfferComposer'; export * from './CatalogAdminMoveOfferComposer';
export * from './CatalogAdminMovePageComposer'; export * from './CatalogAdminMovePageComposer';
export * from './CatalogAdminPublishComposer'; export * from './CatalogAdminPublishComposer';
@@ -0,0 +1,51 @@
import { IMessageDataWrapper, IMessageParser } from '@nitrots/api';
export class CatalogAdminOfferDetailsMessageParser implements IMessageParser
{
private _offerId: number;
private _offerIdGroup: number;
private _limitedStack: number;
private _orderNumber: number;
public flush(): boolean
{
this._offerId = -1;
this._offerIdGroup = 0;
this._limitedStack = 0;
this._orderNumber = 0;
return true;
}
public parse(wrapper: IMessageDataWrapper): boolean
{
if(!wrapper) return false;
this._offerId = wrapper.readInt();
this._offerIdGroup = wrapper.readInt();
this._limitedStack = wrapper.readInt();
this._orderNumber = wrapper.readInt();
return true;
}
public get offerId(): number
{
return this._offerId;
}
public get offerIdGroup(): number
{
return this._offerIdGroup;
}
public get limitedStack(): number
{
return this._limitedStack;
}
public get orderNumber(): number
{
return this._orderNumber;
}
}
@@ -0,0 +1,48 @@
import { IMessageDataWrapper, IMessageParser } from '@nitrots/api';
export class CatalogAdminPageDetailsMessageParser implements IMessageParser
{
private _pageId: number;
private _caption: string;
private _captionSave: string;
private _minRank: number;
private _orderNum: number;
private _visible: boolean;
private _enabled: boolean;
public flush(): boolean
{
this._pageId = -1;
this._caption = '';
this._captionSave = '';
this._minRank = 1;
this._orderNum = 0;
this._visible = true;
this._enabled = true;
return true;
}
public parse(wrapper: IMessageDataWrapper): boolean
{
if(!wrapper) return false;
this._pageId = wrapper.readInt();
this._caption = wrapper.readString();
this._captionSave = wrapper.readString();
this._minRank = wrapper.readInt();
this._orderNum = wrapper.readInt();
this._visible = wrapper.readBoolean();
this._enabled = wrapper.readBoolean();
return true;
}
public get pageId(): number { return this._pageId; }
public get caption(): string { return this._caption; }
public get captionSave(): string { return this._captionSave; }
public get minRank(): number { return this._minRank; }
public get orderNum(): number { return this._orderNum; }
public get visible(): boolean { return this._visible; }
public get enabled(): boolean { return this._enabled; }
}
@@ -3,6 +3,8 @@ export * from './BuildersClubFurniCountMessageParser';
export * from './BuildersClubSubscriptionStatusMessageParser'; export * from './BuildersClubSubscriptionStatusMessageParser';
export * from './BundleDiscountRuleset'; export * from './BundleDiscountRuleset';
export * from './BundleDiscountRulesetMessageParser'; export * from './BundleDiscountRulesetMessageParser';
export * from './CatalogAdminOfferDetailsMessageParser';
export * from './CatalogAdminPageDetailsMessageParser';
export * from './CatalogAdminResultMessageParser'; export * from './CatalogAdminResultMessageParser';
export * from './CatalogIndexMessageParser'; export * from './CatalogIndexMessageParser';
export * from './CatalogLocalizationData'; export * from './CatalogLocalizationData';
@@ -5,6 +5,7 @@ export class MentionListItem
private _mentionId: number; private _mentionId: number;
private _senderId: number; private _senderId: number;
private _senderUsername: string; private _senderUsername: string;
private _senderFigure: string;
private _roomId: number; private _roomId: number;
private _roomName: string; private _roomName: string;
private _message: string; private _message: string;
@@ -17,6 +18,10 @@ export class MentionListItem
this._mentionId = wrapper.readInt(); this._mentionId = wrapper.readInt();
this._senderId = wrapper.readInt(); this._senderId = wrapper.readInt();
this._senderUsername = wrapper.readString(); this._senderUsername = wrapper.readString();
// Wire order: sender_figure sits between username and roomId. The
// server composer writes it unconditionally; an empty string is
// produced for legacy rows where the column wasn't loaded.
this._senderFigure = wrapper.readString();
this._roomId = wrapper.readInt(); this._roomId = wrapper.readInt();
this._roomName = wrapper.readString(); this._roomName = wrapper.readString();
this._message = wrapper.readString(); this._message = wrapper.readString();
@@ -28,6 +33,7 @@ export class MentionListItem
public get mentionId(): number { return this._mentionId; } public get mentionId(): number { return this._mentionId; }
public get senderId(): number { return this._senderId; } public get senderId(): number { return this._senderId; }
public get senderUsername(): string { return this._senderUsername; } public get senderUsername(): string { return this._senderUsername; }
public get senderFigure(): string { return this._senderFigure; }
public get roomId(): number { return this._roomId; } public get roomId(): number { return this._roomId; }
public get roomName(): string { return this._roomName; } public get roomName(): string { return this._roomName; }
public get message(): string { return this._message; } public get message(): string { return this._message; }
@@ -23,7 +23,7 @@ describe('MentionReceivedParser', () =>
it('parses a single mention without read flag', () => it('parses a single mention without read flag', () =>
{ {
const w = new BinaryWriter(); const w = new BinaryWriter();
w.writeInt(7); w.writeInt(42); w.writeString('Bob'); w.writeInt(99); w.writeInt(7); w.writeInt(42); w.writeString('Bob'); w.writeString('hd-180-2.ch-210-66'); w.writeInt(99);
w.writeString('My Room'); w.writeString('ciao @me'); w.writeInt(0); w.writeInt(1717000000); w.writeString('My Room'); w.writeString('ciao @me'); w.writeInt(0); w.writeInt(1717000000);
const parser = new MentionReceivedParser(); const parser = new MentionReceivedParser();
parser.flush(); parser.flush();
@@ -32,6 +32,7 @@ describe('MentionReceivedParser', () =>
expect(m.mentionId).toBe(7); expect(m.mentionId).toBe(7);
expect(m.senderId).toBe(42); expect(m.senderId).toBe(42);
expect(m.senderUsername).toBe('Bob'); expect(m.senderUsername).toBe('Bob');
expect(m.senderFigure).toBe('hd-180-2.ch-210-66');
expect(m.roomId).toBe(99); expect(m.roomId).toBe(99);
expect(m.roomName).toBe('My Room'); expect(m.roomName).toBe('My Room');
expect(m.message).toBe('ciao @me'); expect(m.message).toBe('ciao @me');
@@ -46,7 +47,8 @@ describe('MentionsListParser', () =>
it('parses a count-prefixed list with read flags', () => it('parses a count-prefixed list with read flags', () =>
{ {
const w = new BinaryWriter(); const w = new BinaryWriter();
w.writeInt(1); w.writeInt(3); w.writeInt(42); w.writeString('Bob'); w.writeInt(99); w.writeInt(1);
w.writeInt(3); w.writeInt(42); w.writeString('Bob'); w.writeString('hd-180-2.ch-210-66'); w.writeInt(99);
w.writeString('My Room'); w.writeString('@all festa'); w.writeInt(1); w.writeInt(1717000000); w.writeByte(1); w.writeString('My Room'); w.writeString('@all festa'); w.writeInt(1); w.writeInt(1717000000); w.writeByte(1);
const parser = new MentionsListParser(); const parser = new MentionsListParser();
parser.flush(); parser.flush();
@@ -54,6 +56,7 @@ describe('MentionsListParser', () =>
expect(parser.mentions).toHaveLength(1); expect(parser.mentions).toHaveLength(1);
expect(parser.mentions[0].mentionId).toBe(3); expect(parser.mentions[0].mentionId).toBe(3);
expect(parser.mentions[0].senderUsername).toBe('Bob'); expect(parser.mentions[0].senderUsername).toBe('Bob');
expect(parser.mentions[0].senderFigure).toBe('hd-180-2.ch-210-66');
expect(parser.mentions[0].read).toBe(true); expect(parser.mentions[0].read).toBe(true);
expect(parser.mentions[0].mentionType).toBe(1); expect(parser.mentions[0].mentionType).toBe(1);
expect(parser.mentions[0].message).toBe('@all festa'); expect(parser.mentions[0].message).toBe('@all festa');
+5 -4
View File
@@ -136,10 +136,6 @@ export class RoomPreviewer
public updatePreviewModel(model: string, wallHeight: number, scale: boolean = true): void public updatePreviewModel(model: string, wallHeight: number, scale: boolean = true): void
{ {
// Defensive: dispose() nulls _planeParser, and React 19
// StrictMode dev double-mount can leave a stale reference
// briefly pointing at a disposed instance. Bail rather
// than crashing with "cannot read property reset of null".
if(!this._planeParser) return; if(!this._planeParser) return;
const parser = new FloorHeightMapMessageParser(); const parser = new FloorHeightMapMessageParser();
@@ -394,6 +390,11 @@ export class RoomPreviewer
} }
} }
public setAutomaticStateChange(enabled: boolean): void
{
this._automaticStateChange = enabled;
}
public changeRoomObjectDirection(): void public changeRoomObjectDirection(): void
{ {
if(this.isRoomEngineReady) if(this.isRoomEngineReady)
@@ -1,5 +1,5 @@
import { AlphaTolerance, IGraphicAsset, IObjectVisualizationData, IRoomGeometry, IRoomObjectSprite, RoomObjectVariable, RoomObjectVisualizationType } from '@nitrots/api'; import { AlphaTolerance, IGraphicAsset, IObjectVisualizationData, IRoomGeometry, IRoomObjectSprite, RoomObjectVariable, RoomObjectVisualizationType } from '@nitrots/api';
import { BlackToAlphaFilter, ChooserSelectionFilter } from '@nitrots/utils'; import { ChooserSelectionFilter } from '@nitrots/utils';
import { BLEND_MODES, Filter, Texture } from 'pixi.js'; import { BLEND_MODES, Filter, Texture } from 'pixi.js';
import { RoomObjectSpriteVisualization } from '../RoomObjectSpriteVisualization'; import { RoomObjectSpriteVisualization } from '../RoomObjectSpriteVisualization';
import { ColorData, LayerData } from '../data'; import { ColorData, LayerData } from '../data';
@@ -8,7 +8,6 @@ import { FurnitureVisualizationData } from './FurnitureVisualizationData';
export class FurnitureVisualization extends RoomObjectSpriteVisualization export class FurnitureVisualization extends RoomObjectSpriteVisualization
{ {
protected static DEPTH_MULTIPLIER: number = Math.sqrt(0.5); protected static DEPTH_MULTIPLIER: number = Math.sqrt(0.5);
private static _blackToAlphaFilter: BlackToAlphaFilter = null;
public static TYPE: string = RoomObjectVisualizationType.FURNITURE_STATIC; public static TYPE: string = RoomObjectVisualizationType.FURNITURE_STATIC;
@@ -340,20 +339,7 @@ export class FurnitureVisualization extends RoomObjectSpriteVisualization
const chooserFilters = (sprite.filters || []).filter(f => f instanceof ChooserSelectionFilter); const chooserFilters = (sprite.filters || []).filter(f => f instanceof ChooserSelectionFilter);
if(sprite.blendMode === 'add' && !this.isBackgroundColorBlack()) sprite.filters = chooserFilters.length > 0 ? [...this._filters, ...chooserFilters] : this._filters;
{
if(!FurnitureVisualization._blackToAlphaFilter) FurnitureVisualization._blackToAlphaFilter = new BlackToAlphaFilter();
sprite.filters = chooserFilters.length > 0
? [FurnitureVisualization._blackToAlphaFilter, ...chooserFilters]
: [FurnitureVisualization._blackToAlphaFilter];
}
else
{
sprite.filters = chooserFilters.length > 0
? [...this._filters, ...chooserFilters]
: this._filters;
}
} }
else else
{ {
@@ -224,6 +224,21 @@ export class SessionDataManager implements ISessionDataManager
]; ];
} }
// Mergia a runtime un chunk furnidata (es. custom/imported.json5) nelle Map
// esistenti, SENZA reload del client. Ritorna gli entry aggiunti cosi il
// chiamante puo' aggiornare anche il RoomContentLoader. Fa comparire i furni
// appena importati nel catalogo in tempo reale.
public async mergeFurnitureDataFromUrl(url: string): Promise<IFurnitureData[]>
{
if(!url || !url.length) return [];
const added = await this._furnitureData.mergeFromUrl(url);
if(added && added.length) GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SESSION_DATA_UPDATED));
return added;
}
public async applyFurnitureDataOverrides(url: string): Promise<void> public async applyFurnitureDataOverrides(url: string): Promise<void>
{ {
if(!url || !url.length) if(!url || !url.length)
@@ -37,9 +37,38 @@ export class FurnitureDataLoader
if(responseData.wallitemtypes) this.parseWallItems(responseData.wallitemtypes); if(responseData.wallitemtypes) this.parseWallItems(responseData.wallitemtypes);
} }
private parseFloorItems(data: any): void // Ri-carica un singolo chunk furnidata (es. custom/imported.json5) e
// mergia i suoi entry nelle Map esistenti. Ritorna gli entry aggiunti/aggiornati
// cosi il chiamante puo' aggiornare anche il RoomContentLoader senza reload.
public async mergeFromUrl(url: string): Promise<IFurnitureData[]>
{ {
if(!data || !data.furnitype) return; if(!url || !url.length) return [];
let responseData: any;
try
{
responseData = await loadGamedata(url);
}
catch(err)
{
return [];
}
const added: IFurnitureData[] = [];
if(responseData.roomitemtypes) added.push(...this.parseFloorItems(responseData.roomitemtypes));
if(responseData.wallitemtypes) added.push(...this.parseWallItems(responseData.wallitemtypes));
return added;
}
private parseFloorItems(data: any): IFurnitureData[]
{
const added: IFurnitureData[] = [];
if(!data || !data.furnitype) return added;
for(const furniture of data.furnitype) for(const furniture of data.furnitype)
{ {
@@ -76,13 +105,19 @@ export class FurnitureDataLoader
this._floorItems.set(furnitureData.id, furnitureData); this._floorItems.set(furnitureData.id, furnitureData);
added.push(furnitureData);
this.updateLocalizations(furnitureData); this.updateLocalizations(furnitureData);
} }
return added;
} }
private parseWallItems(data: any): void private parseWallItems(data: any): IFurnitureData[]
{ {
if(!data || !data.furnitype) return; const added: IFurnitureData[] = [];
if(!data || !data.furnitype) return added;
for(const furniture of data.furnitype) for(const furniture of data.furnitype)
{ {
@@ -93,8 +128,12 @@ export class FurnitureDataLoader
this._wallItems.set(furnitureData.id, furnitureData); this._wallItems.set(furnitureData.id, furnitureData);
added.push(furnitureData);
this.updateLocalizations(furnitureData); this.updateLocalizations(furnitureData);
} }
return added;
} }
private updateLocalizations(furniture: FurnitureData): void private updateLocalizations(furniture: FurnitureData): void