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
Merge branch 'main' into chat-prefix
This commit is contained in:
@@ -35,9 +35,9 @@ export interface IRoomCreator
|
|||||||
updateRoomObjectFloorHeight(roomId: number, objectId: number, height: number): boolean;
|
updateRoomObjectFloorHeight(roomId: number, objectId: number, height: number): boolean;
|
||||||
updateRoomObjectFloorExpiration(roomId: number, objectId: number, expires: number): boolean;
|
updateRoomObjectFloorExpiration(roomId: number, objectId: number, expires: number): boolean;
|
||||||
updateRoomObjectWallExpiration(roomId: number, objectId: number, expires: number): boolean;
|
updateRoomObjectWallExpiration(roomId: number, objectId: number, expires: number): boolean;
|
||||||
rollRoomObjectFloor(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D): void;
|
rollRoomObjectFloor(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D, duration?: number, direction?: IVector3D): void;
|
||||||
addRoomObjectUser(roomId: number, objectId: number, location: IVector3D, direction: IVector3D, headDirection: number, type: number, figure: string): boolean;
|
addRoomObjectUser(roomId: number, objectId: number, location: IVector3D, direction: IVector3D, headDirection: number, type: number, figure: string): boolean;
|
||||||
updateRoomObjectUserLocation(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D, canStandUp?: boolean, baseY?: number, direction?: IVector3D, headDirection?: number, skipLocationFix?: boolean): boolean;
|
updateRoomObjectUserLocation(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D, canStandUp?: boolean, baseY?: number, direction?: IVector3D, headDirection?: number, skipLocationFix?: boolean, isSlide?: boolean, duration?: number): boolean;
|
||||||
updateRoomObjectUserAction(roomId: number, objectId: number, action: string, value: number, parameter?: string): boolean;
|
updateRoomObjectUserAction(roomId: number, objectId: number, action: string, value: number, parameter?: string): boolean;
|
||||||
updateRoomObjectUserFigure(roomId: number, objectId: number, figure: string, gender?: string, subType?: string, isRiding?: boolean): boolean;
|
updateRoomObjectUserFigure(roomId: number, objectId: number, figure: string, gender?: string, subType?: string, isRiding?: boolean): boolean;
|
||||||
updateRoomObjectUserFlatControl(roomId: number, objectId: number, level: string): boolean;
|
updateRoomObjectUserFlatControl(roomId: number, objectId: number, level: string): boolean;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export interface IRoomEngine
|
|||||||
getFurnitureWallIcon(typeId: number, listener: IGetImageListener, extras?: string): IImageResult;
|
getFurnitureWallIcon(typeId: number, listener: IGetImageListener, extras?: string): IImageResult;
|
||||||
updateRoomObjectWallLocation(roomId: number, objectId: number, location: IVector3D): boolean;
|
updateRoomObjectWallLocation(roomId: number, objectId: number, location: IVector3D): boolean;
|
||||||
addRoomObjectUser(roomId: number, objectId: number, location: IVector3D, direction: IVector3D, headDirection: number, type: number, figure: string): boolean;
|
addRoomObjectUser(roomId: number, objectId: number, location: IVector3D, direction: IVector3D, headDirection: number, type: number, figure: string): boolean;
|
||||||
updateRoomObjectUserLocation(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D, canStandUp?: boolean, baseY?: number, direction?: IVector3D, headDirection?: number, skipLocationFix?: boolean): boolean;
|
updateRoomObjectUserLocation(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D, canStandUp?: boolean, baseY?: number, direction?: IVector3D, headDirection?: number, skipLocationFix?: boolean, isSlide?: boolean, duration?: number): boolean;
|
||||||
addFurnitureFloor(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number): boolean;
|
addFurnitureFloor(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number): boolean;
|
||||||
addFurnitureFloorByTypeName(roomId: number, id: number, typeName: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number): boolean;
|
addFurnitureFloorByTypeName(roomId: number, id: number, typeName: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number): boolean;
|
||||||
addFurnitureWall(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, extra: string, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, realRoomObject?: boolean): boolean;
|
addFurnitureWall(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, extra: string, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, realRoomObject?: boolean): boolean;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -11,19 +11,13 @@ export class SocketConnection implements IConnection
|
|||||||
private _codec: ICodec = new EvaWireFormat();
|
private _codec: ICodec = new EvaWireFormat();
|
||||||
private _dataBuffer: ArrayBuffer = null;
|
private _dataBuffer: ArrayBuffer = null;
|
||||||
private _isReady: boolean = false;
|
private _isReady: boolean = false;
|
||||||
|
|
||||||
private _pendingClientMessages: IMessageComposer<unknown[]>[] = [];
|
private _pendingClientMessages: IMessageComposer<unknown[]>[] = [];
|
||||||
private _pendingServerMessages: IMessageDataWrapper[] = [];
|
private _pendingServerMessages: IMessageDataWrapper[] = [];
|
||||||
|
|
||||||
private _isAuthenticated: boolean = false;
|
private _isAuthenticated: boolean = false;
|
||||||
|
|
||||||
// Store callbacks for cleanup
|
|
||||||
private _onOpenCallback: (event: Event) => void = null;
|
private _onOpenCallback: (event: Event) => void = null;
|
||||||
private _onCloseCallback: (event: Event) => void = null;
|
private _onCloseCallback: (event: Event) => void = null;
|
||||||
private _onErrorCallback: (event: Event) => void = null;
|
private _onErrorCallback: (event: Event) => void = null;
|
||||||
private _onMessageCallback: (event: MessageEvent) => void = null;
|
private _onMessageCallback: (event: MessageEvent) => void = null;
|
||||||
|
|
||||||
// Reconnection state
|
|
||||||
private _socketUrl: string = null;
|
private _socketUrl: string = null;
|
||||||
private _reconnectAttempt: number = 0;
|
private _reconnectAttempt: number = 0;
|
||||||
private _reconnectTimer: ReturnType<typeof setTimeout> = null;
|
private _reconnectTimer: ReturnType<typeof setTimeout> = null;
|
||||||
@@ -51,8 +45,6 @@ export class SocketConnection implements IConnection
|
|||||||
|
|
||||||
this._socket = new WebSocket(socketUrl);
|
this._socket = new WebSocket(socketUrl);
|
||||||
this._socket.binaryType = 'arraybuffer';
|
this._socket.binaryType = 'arraybuffer';
|
||||||
|
|
||||||
// Store callbacks for cleanup
|
|
||||||
this._onOpenCallback = () => this.onSocketOpened();
|
this._onOpenCallback = () => this.onSocketOpened();
|
||||||
this._onCloseCallback = (event: Event) => this.onSocketClosed(event as CloseEvent);
|
this._onCloseCallback = (event: Event) => this.onSocketClosed(event as CloseEvent);
|
||||||
this._onErrorCallback = () => this.onSocketError();
|
this._onErrorCallback = () => this.onSocketError();
|
||||||
@@ -72,8 +64,6 @@ export class SocketConnection implements IConnection
|
|||||||
{
|
{
|
||||||
if(this._isReconnecting)
|
if(this._isReconnecting)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[SocketConnection] Reconnected successfully after ' + this._reconnectAttempt + ' attempt(s)');
|
|
||||||
|
|
||||||
this._reconnectAttempt = 0;
|
this._reconnectAttempt = 0;
|
||||||
this._isReconnecting = false;
|
this._isReconnecting = false;
|
||||||
|
|
||||||
@@ -99,8 +89,6 @@ export class SocketConnection implements IConnection
|
|||||||
|
|
||||||
if(code === 1000 || code === 1001)
|
if(code === 1000 || code === 1001)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[SocketConnection] Server closed cleanly (code ' + code + ') - not reconnecting');
|
|
||||||
|
|
||||||
this._isAuthenticated = false;
|
this._isAuthenticated = false;
|
||||||
this._isReady = false;
|
this._isReady = false;
|
||||||
|
|
||||||
@@ -122,7 +110,6 @@ export class SocketConnection implements IConnection
|
|||||||
{
|
{
|
||||||
if(this._isReconnecting)
|
if(this._isReconnecting)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[SocketConnection] Reconnect attempt ' + this._reconnectAttempt + ' failed');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,8 +123,6 @@ export class SocketConnection implements IConnection
|
|||||||
{
|
{
|
||||||
if(this._reconnectAttempt >= SocketConnection.MAX_RECONNECT_ATTEMPTS)
|
if(this._reconnectAttempt >= SocketConnection.MAX_RECONNECT_ATTEMPTS)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[SocketConnection] Max reconnect attempts reached (' + SocketConnection.MAX_RECONNECT_ATTEMPTS + ')');
|
|
||||||
|
|
||||||
this._isReconnecting = false;
|
this._isReconnecting = false;
|
||||||
this._wasAuthenticated = false;
|
this._wasAuthenticated = false;
|
||||||
|
|
||||||
@@ -160,8 +145,6 @@ export class SocketConnection implements IConnection
|
|||||||
SocketConnection.MAX_RECONNECT_DELAY_MS
|
SocketConnection.MAX_RECONNECT_DELAY_MS
|
||||||
);
|
);
|
||||||
|
|
||||||
NitroLogger.log('[SocketConnection] Reconnecting in ' + Math.round(delay) + 'ms (attempt ' + this._reconnectAttempt + '/' + SocketConnection.MAX_RECONNECT_ATTEMPTS + ')');
|
|
||||||
|
|
||||||
GetEventDispatcher().dispatchEvent(new ReconnectEvent(
|
GetEventDispatcher().dispatchEvent(new ReconnectEvent(
|
||||||
NitroEventType.SOCKET_RECONNECTING,
|
NitroEventType.SOCKET_RECONNECTING,
|
||||||
this._reconnectAttempt,
|
this._reconnectAttempt,
|
||||||
@@ -189,7 +172,7 @@ export class SocketConnection implements IConnection
|
|||||||
|
|
||||||
if(this._socket.readyState === WebSocket.OPEN || this._socket.readyState === WebSocket.CONNECTING)
|
if(this._socket.readyState === WebSocket.OPEN || this._socket.readyState === WebSocket.CONNECTING)
|
||||||
{
|
{
|
||||||
try { this._socket.close(); } catch(e) { /* ignore */ }
|
try { this._socket.close(); } catch(e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._socket = null;
|
this._socket = null;
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ export class IncomingHeader
|
|||||||
public static ROOM_RIGHTS_LIST_REMOVE = 1327;
|
public static ROOM_RIGHTS_LIST_REMOVE = 1327;
|
||||||
public static ROOM_RIGHTS_OWNER = 339;
|
public static ROOM_RIGHTS_OWNER = 339;
|
||||||
public static ROOM_ROLLING = 3207;
|
public static ROOM_ROLLING = 3207;
|
||||||
|
public static WIRED_MOVEMENTS = 3999;
|
||||||
public static ROOM_SCORE = 482;
|
public static ROOM_SCORE = 482;
|
||||||
public static ROOM_SETTINGS = 1498;
|
public static ROOM_SETTINGS = 1498;
|
||||||
public static ROOM_SETTINGS_CHAT = 1191;
|
public static ROOM_SETTINGS_CHAT = 1191;
|
||||||
@@ -475,6 +476,9 @@ export class IncomingHeader
|
|||||||
public static WEEKLY_GAME2_LEADERBOARD = 2196;
|
public static WEEKLY_GAME2_LEADERBOARD = 2196;
|
||||||
public static RENTABLE_FURNI_RENT_OR_BUYOUT_OFFER = 35;
|
public static RENTABLE_FURNI_RENT_OR_BUYOUT_OFFER = 35;
|
||||||
public static HANDSHAKE_IDENTITY_ACCOUNT = 3523;
|
public static HANDSHAKE_IDENTITY_ACCOUNT = 3523;
|
||||||
|
|
||||||
|
// Catalog Admin
|
||||||
|
public static CATALOG_ADMIN_RESULT = 10059;
|
||||||
|
|
||||||
// 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 { CatalogAdminResultMessageParser } from '../../parser';
|
||||||
|
|
||||||
|
export class CatalogAdminResultEvent extends MessageEvent implements IMessageEvent
|
||||||
|
{
|
||||||
|
constructor(callBack: Function)
|
||||||
|
{
|
||||||
|
super(callBack, CatalogAdminResultMessageParser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParser(): CatalogAdminResultMessageParser
|
||||||
|
{
|
||||||
|
return this.parser as CatalogAdminResultMessageParser;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './BonusRareInfoMessageEvent';
|
export * from './BonusRareInfoMessageEvent';
|
||||||
|
export * from './CatalogAdminResultEvent';
|
||||||
export * from './BuildersClubFurniCountMessageEvent';
|
export * from './BuildersClubFurniCountMessageEvent';
|
||||||
export * from './BuildersClubSubscriptionStatusMessageEvent';
|
export * from './BuildersClubSubscriptionStatusMessageEvent';
|
||||||
export * from './BundleDiscountRulesetMessageEvent';
|
export * from './BundleDiscountRulesetMessageEvent';
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { IMessageEvent } from '@nitrots/api';
|
||||||
|
import { MessageEvent } from '@nitrots/events';
|
||||||
|
import { WiredMovementsParser } from '../../../parser';
|
||||||
|
|
||||||
|
export class WiredMovementsEvent extends MessageEvent implements IMessageEvent
|
||||||
|
{
|
||||||
|
constructor(callBack: Function)
|
||||||
|
{
|
||||||
|
super(callBack, WiredMovementsParser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParser(): WiredMovementsParser
|
||||||
|
{
|
||||||
|
return this.parser as WiredMovementsParser;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './FavoriteMembershipUpdateMessageEvent';
|
export * from './FavoriteMembershipUpdateMessageEvent';
|
||||||
export * from './ObjectsDataUpdateEvent';
|
export * from './ObjectsDataUpdateEvent';
|
||||||
export * from './ObjectsRollingEvent';
|
export * from './ObjectsRollingEvent';
|
||||||
|
export * from './WiredMovementsEvent';
|
||||||
|
|||||||
@@ -475,6 +475,17 @@ export class OutgoingHeader
|
|||||||
public static RENTABLE_GET_RENT_OR_BUYOUT_OFFER = 2518;
|
public static RENTABLE_GET_RENT_OR_BUYOUT_OFFER = 2518;
|
||||||
|
|
||||||
public static FURNITURE_PICKUP_ALL = 10017;
|
public static FURNITURE_PICKUP_ALL = 10017;
|
||||||
|
|
||||||
|
public static CATALOG_ADMIN_SAVE_PAGE = 10050;
|
||||||
|
public static CATALOG_ADMIN_CREATE_PAGE = 10051;
|
||||||
|
public static CATALOG_ADMIN_DELETE_PAGE = 10052;
|
||||||
|
public static CATALOG_ADMIN_SAVE_OFFER = 10053;
|
||||||
|
public static CATALOG_ADMIN_CREATE_OFFER = 10054;
|
||||||
|
public static CATALOG_ADMIN_DELETE_OFFER = 10055;
|
||||||
|
public static CATALOG_ADMIN_MOVE_OFFER = 10056;
|
||||||
|
public static CATALOG_ADMIN_MOVE_PAGE = 10057;
|
||||||
|
public static CATALOG_ADMIN_PUBLISH = 10058;
|
||||||
|
|
||||||
public static DELETE_ITEM = 10018;
|
public static DELETE_ITEM = 10018;
|
||||||
public static DELETE_PET = 10030;
|
public static DELETE_PET = 10030;
|
||||||
public static DELETE_BADGE = 10031;
|
public static DELETE_BADGE = 10031;
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
import { IMessageComposer } from '@nitrots/api';
|
||||||
|
|
||||||
|
export class CatalogAdminCreateOfferComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminCreateOfferComposer>>
|
||||||
|
{
|
||||||
|
private _data: ConstructorParameters<typeof CatalogAdminCreateOfferComposer>;
|
||||||
|
|
||||||
|
constructor(pageId: number, itemId: number, catalogName: string, costCredits: number, costPoints: number, pointsType: number, amount: number, clubOnly: number, extradata: string, haveOffer: boolean, offerIdGroup: number, limitedStack: number, orderNumber: number)
|
||||||
|
{
|
||||||
|
this._data = [ pageId, itemId, catalogName, costCredits, costPoints, pointsType, amount, clubOnly, extradata, haveOffer, offerIdGroup, limitedStack, orderNumber ];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void
|
||||||
|
{
|
||||||
|
this._data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessageArray()
|
||||||
|
{
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
import { IMessageComposer } from '@nitrots/api';
|
||||||
|
|
||||||
|
export class CatalogAdminCreatePageComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminCreatePageComposer>>
|
||||||
|
{
|
||||||
|
private _data: ConstructorParameters<typeof CatalogAdminCreatePageComposer>;
|
||||||
|
|
||||||
|
constructor(caption: string, caption2: string, layout: string, iconType: number, minRank: number, visible: boolean, enabled: boolean, orderNum: number, parentId: number)
|
||||||
|
{
|
||||||
|
this._data = [ caption, caption2, layout, iconType, minRank, visible, enabled, orderNum, parentId ];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void
|
||||||
|
{
|
||||||
|
this._data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessageArray()
|
||||||
|
{
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
import { IMessageComposer } from '@nitrots/api';
|
||||||
|
|
||||||
|
export class CatalogAdminDeleteOfferComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminDeleteOfferComposer>>
|
||||||
|
{
|
||||||
|
private _data: ConstructorParameters<typeof CatalogAdminDeleteOfferComposer>;
|
||||||
|
|
||||||
|
constructor(offerId: number)
|
||||||
|
{
|
||||||
|
this._data = [ offerId ];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void
|
||||||
|
{
|
||||||
|
this._data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessageArray()
|
||||||
|
{
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
import { IMessageComposer } from '@nitrots/api';
|
||||||
|
|
||||||
|
export class CatalogAdminDeletePageComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminDeletePageComposer>>
|
||||||
|
{
|
||||||
|
private _data: ConstructorParameters<typeof CatalogAdminDeletePageComposer>;
|
||||||
|
|
||||||
|
constructor(pageId: number)
|
||||||
|
{
|
||||||
|
this._data = [ pageId ];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void
|
||||||
|
{
|
||||||
|
this._data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessageArray()
|
||||||
|
{
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { IMessageComposer } from '@nitrots/api';
|
||||||
|
|
||||||
|
export class CatalogAdminMoveOfferComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminMoveOfferComposer>>
|
||||||
|
{
|
||||||
|
private _data: ConstructorParameters<typeof CatalogAdminMoveOfferComposer>;
|
||||||
|
|
||||||
|
constructor(offerId: number, orderNumber: number)
|
||||||
|
{
|
||||||
|
this._data = [ offerId, orderNumber ];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void
|
||||||
|
{
|
||||||
|
this._data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessageArray()
|
||||||
|
{
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { IMessageComposer } from '@nitrots/api';
|
||||||
|
|
||||||
|
export class CatalogAdminMovePageComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminMovePageComposer>>
|
||||||
|
{
|
||||||
|
private _data: ConstructorParameters<typeof CatalogAdminMovePageComposer>;
|
||||||
|
|
||||||
|
constructor(pageId: number, newParentId: number, newIndex: number)
|
||||||
|
{
|
||||||
|
this._data = [ pageId, newParentId, newIndex ];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void
|
||||||
|
{
|
||||||
|
this._data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessageArray()
|
||||||
|
{
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { IMessageComposer } from '@nitrots/api';
|
||||||
|
|
||||||
|
export class CatalogAdminPublishComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminPublishComposer>>
|
||||||
|
{
|
||||||
|
private _data: ConstructorParameters<typeof CatalogAdminPublishComposer>;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
this._data = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void
|
||||||
|
{
|
||||||
|
this._data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessageArray()
|
||||||
|
{
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { IMessageComposer } from '@nitrots/api';
|
||||||
|
|
||||||
|
export class CatalogAdminSaveOfferComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminSaveOfferComposer>>
|
||||||
|
{
|
||||||
|
private _data: ConstructorParameters<typeof CatalogAdminSaveOfferComposer>;
|
||||||
|
|
||||||
|
constructor(offerId: number, pageId: number, itemId: number, catalogName: string, costCredits: number, costPoints: number, pointsType: number, amount: number, clubOnly: number, extradata: string, haveOffer: boolean, offerIdGroup: number, limitedStack: number, orderNumber: number)
|
||||||
|
{
|
||||||
|
this._data = [ offerId, pageId, itemId, catalogName, costCredits, costPoints, pointsType, amount, clubOnly, extradata, haveOffer, offerIdGroup, limitedStack, orderNumber ];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void
|
||||||
|
{
|
||||||
|
this._data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessageArray()
|
||||||
|
{
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { IMessageComposer } from '@nitrots/api';
|
||||||
|
|
||||||
|
export class CatalogAdminSavePageComposer implements IMessageComposer<ConstructorParameters<typeof CatalogAdminSavePageComposer>>
|
||||||
|
{
|
||||||
|
private _data: ConstructorParameters<typeof CatalogAdminSavePageComposer>;
|
||||||
|
|
||||||
|
constructor(pageId: number, caption: string, caption2: string, layout: string, iconType: number, minRank: number, visible: boolean, enabled: boolean, orderNum: number, parentId: number, headline: string, teaser: string, textDetails: string)
|
||||||
|
{
|
||||||
|
this._data = [ pageId, caption, caption2, layout, iconType, minRank, visible, enabled, orderNum, parentId, headline, teaser, textDetails ];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void
|
||||||
|
{
|
||||||
|
this._data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessageArray()
|
||||||
|
{
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,24 @@
|
|||||||
export * from './BuildersClubPlaceRoomItemMessageComposer';
|
export * from './BuildersClubPlaceRoomItemMessageComposer';
|
||||||
|
export * from './CatalogAdminCreateOfferComposer';
|
||||||
|
export * from './CatalogAdminCreatePageComposer';
|
||||||
|
export * from './CatalogAdminDeleteOfferComposer';
|
||||||
|
export * from './CatalogAdminDeletePageComposer';
|
||||||
|
export * from './CatalogAdminMoveOfferComposer';
|
||||||
|
export * from './CatalogAdminMovePageComposer';
|
||||||
|
export * from './CatalogAdminPublishComposer';
|
||||||
|
export * from './CatalogAdminSaveOfferComposer';
|
||||||
|
export * from './CatalogAdminSavePageComposer';
|
||||||
export * from './BuildersClubPlaceWallItemMessageComposer';
|
export * from './BuildersClubPlaceWallItemMessageComposer';
|
||||||
export * from './BuildersClubQueryFurniCountMessageComposer';
|
export * from './BuildersClubQueryFurniCountMessageComposer';
|
||||||
|
export * from './CatalogAdminCreateOfferComposer';
|
||||||
|
export * from './CatalogAdminCreatePageComposer';
|
||||||
|
export * from './CatalogAdminDeleteOfferComposer';
|
||||||
|
export * from './CatalogAdminDeletePageComposer';
|
||||||
|
export * from './CatalogAdminMoveOfferComposer';
|
||||||
|
export * from './CatalogAdminMovePageComposer';
|
||||||
|
export * from './CatalogAdminPublishComposer';
|
||||||
|
export * from './CatalogAdminSaveOfferComposer';
|
||||||
|
export * from './CatalogAdminSavePageComposer';
|
||||||
export * from './GetBonusRareInfoMessageComposer';
|
export * from './GetBonusRareInfoMessageComposer';
|
||||||
export * from './GetBundleDiscountRulesetComposer';
|
export * from './GetBundleDiscountRulesetComposer';
|
||||||
export * from './GetCatalogIndexComposer';
|
export * from './GetCatalogIndexComposer';
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { IMessageDataWrapper, IMessageParser } from '@nitrots/api';
|
||||||
|
|
||||||
|
export class CatalogAdminResultMessageParser implements IMessageParser
|
||||||
|
{
|
||||||
|
private _success: boolean;
|
||||||
|
private _message: string;
|
||||||
|
|
||||||
|
public flush(): boolean
|
||||||
|
{
|
||||||
|
this._success = false;
|
||||||
|
this._message = '';
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public parse(wrapper: IMessageDataWrapper): boolean
|
||||||
|
{
|
||||||
|
if(!wrapper) return false;
|
||||||
|
|
||||||
|
this._success = wrapper.readBoolean();
|
||||||
|
this._message = wrapper.readString();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get success(): boolean
|
||||||
|
{
|
||||||
|
return this._success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get message(): string
|
||||||
|
{
|
||||||
|
return this._message;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ export class CatalogLocalizationData
|
|||||||
this._images = [];
|
this._images = [];
|
||||||
this._texts = [];
|
this._texts = [];
|
||||||
|
|
||||||
let totalImages = wrapper.readInt();
|
let totalImages = Math.min(wrapper.readInt(), 100);
|
||||||
|
|
||||||
while(totalImages > 0)
|
while(totalImages > 0)
|
||||||
{
|
{
|
||||||
@@ -19,7 +19,7 @@ export class CatalogLocalizationData
|
|||||||
totalImages--;
|
totalImages--;
|
||||||
}
|
}
|
||||||
|
|
||||||
let totalTexts = wrapper.readInt();
|
let totalTexts = Math.min(wrapper.readInt(), 100);
|
||||||
|
|
||||||
while(totalTexts > 0)
|
while(totalTexts > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class CatalogPageMessageOfferData
|
|||||||
|
|
||||||
this._products = [];
|
this._products = [];
|
||||||
|
|
||||||
let totalProducts = wrapper.readInt();
|
let totalProducts = Math.min(wrapper.readInt(), 200);
|
||||||
|
|
||||||
while(totalProducts > 0)
|
while(totalProducts > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export class CatalogPageMessageParser implements IMessageParser
|
|||||||
this._layoutCode = wrapper.readString();
|
this._layoutCode = wrapper.readString();
|
||||||
this._localization = new CatalogLocalizationData(wrapper);
|
this._localization = new CatalogLocalizationData(wrapper);
|
||||||
|
|
||||||
let totalOffers = wrapper.readInt();
|
let totalOffers = Math.min(wrapper.readInt(), 1000);
|
||||||
|
|
||||||
while(totalOffers > 0)
|
while(totalOffers > 0)
|
||||||
{
|
{
|
||||||
@@ -51,7 +51,7 @@ export class CatalogPageMessageParser implements IMessageParser
|
|||||||
|
|
||||||
if(wrapper.bytesAvailable)
|
if(wrapper.bytesAvailable)
|
||||||
{
|
{
|
||||||
let totalFrontPageItems = wrapper.readInt();
|
let totalFrontPageItems = Math.min(wrapper.readInt(), 100);
|
||||||
|
|
||||||
while(totalFrontPageItems > 0)
|
while(totalFrontPageItems > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ export class NodeData
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly MAX_OFFERS: number = 1000;
|
||||||
|
private static readonly MAX_CHILDREN: number = 500;
|
||||||
|
private static _parseDepth: number = 0;
|
||||||
|
private static readonly MAX_DEPTH: number = 20;
|
||||||
|
|
||||||
public parse(wrapper: IMessageDataWrapper): boolean
|
public parse(wrapper: IMessageDataWrapper): boolean
|
||||||
{
|
{
|
||||||
if(!wrapper) return false;
|
if(!wrapper) return false;
|
||||||
@@ -41,7 +46,7 @@ export class NodeData
|
|||||||
this._pageName = wrapper.readString();
|
this._pageName = wrapper.readString();
|
||||||
this._localization = wrapper.readString();
|
this._localization = wrapper.readString();
|
||||||
|
|
||||||
let totalOffers = wrapper.readInt();
|
let totalOffers = Math.min(wrapper.readInt(), NodeData.MAX_OFFERS);
|
||||||
|
|
||||||
while(totalOffers > 0)
|
while(totalOffers > 0)
|
||||||
{
|
{
|
||||||
@@ -50,7 +55,15 @@ export class NodeData
|
|||||||
totalOffers--;
|
totalOffers--;
|
||||||
}
|
}
|
||||||
|
|
||||||
let totalChildren = wrapper.readInt();
|
let totalChildren = Math.min(wrapper.readInt(), NodeData.MAX_CHILDREN);
|
||||||
|
|
||||||
|
NodeData._parseDepth++;
|
||||||
|
|
||||||
|
if(NodeData._parseDepth > NodeData.MAX_DEPTH)
|
||||||
|
{
|
||||||
|
NodeData._parseDepth--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
while(totalChildren > 0)
|
while(totalChildren > 0)
|
||||||
{
|
{
|
||||||
@@ -59,6 +72,8 @@ export class NodeData
|
|||||||
totalChildren--;
|
totalChildren--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeData._parseDepth--;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export * from './BuildersClubFurniCountMessageParser';
|
|||||||
export * from './BuildersClubSubscriptionStatusMessageParser';
|
export * from './BuildersClubSubscriptionStatusMessageParser';
|
||||||
export * from './BundleDiscountRuleset';
|
export * from './BundleDiscountRuleset';
|
||||||
export * from './BundleDiscountRulesetMessageParser';
|
export * from './BundleDiscountRulesetMessageParser';
|
||||||
|
export * from './CatalogAdminResultMessageParser';
|
||||||
export * from './CatalogIndexMessageParser';
|
export * from './CatalogIndexMessageParser';
|
||||||
export * from './CatalogLocalizationData';
|
export * from './CatalogLocalizationData';
|
||||||
export * from './CatalogPageExpirationParser';
|
export * from './CatalogPageExpirationParser';
|
||||||
|
|||||||
@@ -0,0 +1,240 @@
|
|||||||
|
import { IMessageDataWrapper, IMessageParser, ObjectRolling } from '@nitrots/api';
|
||||||
|
import { Vector3d } from '@nitrots/utils';
|
||||||
|
|
||||||
|
function parseLocaleFloat(value: string): number
|
||||||
|
{
|
||||||
|
if(!value) return 0;
|
||||||
|
|
||||||
|
return parseFloat(value.replace(',', '.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDirection(value: number): number
|
||||||
|
{
|
||||||
|
return ((((value % 8) + 8) % 8) * 45);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WiredUserMovementData extends ObjectRolling
|
||||||
|
{
|
||||||
|
constructor(id: number, location: Vector3d, targetLocation: Vector3d, movementType: string, private _bodyDirection: number, private _headDirection: number, private _duration: number)
|
||||||
|
{
|
||||||
|
super(id, location, targetLocation, movementType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get bodyDirection(): number
|
||||||
|
{
|
||||||
|
return this._bodyDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get headDirection(): number
|
||||||
|
{
|
||||||
|
return this._headDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get duration(): number
|
||||||
|
{
|
||||||
|
return this._duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WiredFurniMovementData extends ObjectRolling
|
||||||
|
{
|
||||||
|
constructor(id: number, location: Vector3d, targetLocation: Vector3d, private _rotation: number, private _duration: number)
|
||||||
|
{
|
||||||
|
super(id, location, targetLocation, ObjectRolling.SLIDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get rotation(): number
|
||||||
|
{
|
||||||
|
return this._rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get duration(): number
|
||||||
|
{
|
||||||
|
return this._duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WiredWallItemMovementData
|
||||||
|
{
|
||||||
|
constructor(private _id: number, private _enabled: boolean, private _values: number[])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): number
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get enabled(): boolean
|
||||||
|
{
|
||||||
|
return this._enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get values(): number[]
|
||||||
|
{
|
||||||
|
return this._values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WiredUserDirectionUpdateData
|
||||||
|
{
|
||||||
|
constructor(private _id: number, private _headDirection: number, private _bodyDirection: number)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): number
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get headDirection(): number
|
||||||
|
{
|
||||||
|
return this._headDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get bodyDirection(): number
|
||||||
|
{
|
||||||
|
return this._bodyDirection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WiredMovementsParser implements IMessageParser
|
||||||
|
{
|
||||||
|
private _furniMovements: WiredFurniMovementData[];
|
||||||
|
private _userMovements: WiredUserMovementData[];
|
||||||
|
private _wallItemMovements: WiredWallItemMovementData[];
|
||||||
|
private _userDirectionUpdates: WiredUserDirectionUpdateData[];
|
||||||
|
|
||||||
|
public flush(): boolean
|
||||||
|
{
|
||||||
|
this._furniMovements = [];
|
||||||
|
this._userMovements = [];
|
||||||
|
this._wallItemMovements = [];
|
||||||
|
this._userDirectionUpdates = [];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public parse(wrapper: IMessageDataWrapper): boolean
|
||||||
|
{
|
||||||
|
if(!wrapper) return false;
|
||||||
|
|
||||||
|
let totalMovements = wrapper.readInt();
|
||||||
|
|
||||||
|
while(totalMovements > 0)
|
||||||
|
{
|
||||||
|
const type = wrapper.readInt();
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
const fromX = wrapper.readInt();
|
||||||
|
const fromY = wrapper.readInt();
|
||||||
|
const toX = wrapper.readInt();
|
||||||
|
const toY = wrapper.readInt();
|
||||||
|
const fromZ = parseLocaleFloat(wrapper.readString());
|
||||||
|
const toZ = parseLocaleFloat(wrapper.readString());
|
||||||
|
const id = wrapper.readInt();
|
||||||
|
const animationType = wrapper.readInt();
|
||||||
|
const bodyDirection = parseDirection(wrapper.readInt());
|
||||||
|
const headDirection = parseDirection(wrapper.readInt());
|
||||||
|
const duration = wrapper.readInt();
|
||||||
|
const movementType = (animationType === 0) ? ObjectRolling.MOVE : ObjectRolling.SLIDE;
|
||||||
|
|
||||||
|
this._userMovements.push(new WiredUserMovementData(
|
||||||
|
id,
|
||||||
|
new Vector3d(fromX, fromY, fromZ),
|
||||||
|
new Vector3d(toX, toY, toZ),
|
||||||
|
movementType,
|
||||||
|
bodyDirection,
|
||||||
|
headDirection,
|
||||||
|
duration));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
const fromX = wrapper.readInt();
|
||||||
|
const fromY = wrapper.readInt();
|
||||||
|
const toX = wrapper.readInt();
|
||||||
|
const toY = wrapper.readInt();
|
||||||
|
const fromZ = parseLocaleFloat(wrapper.readString());
|
||||||
|
const toZ = parseLocaleFloat(wrapper.readString());
|
||||||
|
const id = wrapper.readInt();
|
||||||
|
const rotation = wrapper.readInt();
|
||||||
|
const duration = wrapper.readInt();
|
||||||
|
|
||||||
|
this._furniMovements.push(new WiredFurniMovementData(
|
||||||
|
id,
|
||||||
|
new Vector3d(fromX, fromY, fromZ),
|
||||||
|
new Vector3d(toX, toY, toZ),
|
||||||
|
rotation,
|
||||||
|
duration));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
const id = wrapper.readInt();
|
||||||
|
const enabled = wrapper.readBoolean();
|
||||||
|
const values: number[] = [];
|
||||||
|
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
while(index < 9)
|
||||||
|
{
|
||||||
|
values.push(wrapper.readInt());
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._wallItemMovements.push(new WiredWallItemMovementData(id, enabled, values));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
const id = wrapper.readInt();
|
||||||
|
const headDirection = parseDirection(wrapper.readInt());
|
||||||
|
const bodyDirection = parseDirection(wrapper.readInt());
|
||||||
|
|
||||||
|
this._userDirectionUpdates.push(new WiredUserDirectionUpdateData(id, headDirection, bodyDirection));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalMovements--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get itemMovements(): WiredFurniMovementData[]
|
||||||
|
{
|
||||||
|
return this._furniMovements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get unitMovements(): WiredUserMovementData[]
|
||||||
|
{
|
||||||
|
return this._userMovements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get furniMovements(): WiredFurniMovementData[]
|
||||||
|
{
|
||||||
|
return this._furniMovements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get userMovements(): WiredUserMovementData[]
|
||||||
|
{
|
||||||
|
return this._userMovements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get wallItemMovements(): WiredWallItemMovementData[]
|
||||||
|
{
|
||||||
|
return this._wallItemMovements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get userDirectionUpdates(): WiredUserDirectionUpdateData[]
|
||||||
|
{
|
||||||
|
return this._userDirectionUpdates;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,3 +3,4 @@ export * from './FavoriteMembershipUpdateMessageParser';
|
|||||||
export * from './ObjectData';
|
export * from './ObjectData';
|
||||||
export * from './ObjectsDataUpdateParser';
|
export * from './ObjectsDataUpdateParser';
|
||||||
export * from './ObjectsRollingParser';
|
export * from './ObjectsRollingParser';
|
||||||
|
export * from './WiredMovementsParser';
|
||||||
|
|||||||
@@ -52,11 +52,9 @@ export class EventDispatcher implements IEventDispatcher
|
|||||||
{
|
{
|
||||||
if(!event) return false;
|
if(!event) return false;
|
||||||
|
|
||||||
// Debug: log SOCKET_ events to trace reconnection flow
|
|
||||||
if(event.type && event.type.startsWith('SOCKET_'))
|
if(event.type && event.type.startsWith('SOCKET_'))
|
||||||
{
|
{
|
||||||
const listenerCount = this._listeners.get(event.type)?.length ?? 0;
|
const listenerCount = this._listeners.get(event.type)?.length ?? 0;
|
||||||
console.log('[EventDispatcher] Dispatching ' + event.type + ' (listeners: ' + listenerCount + ')');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NitroLogger.events('Dispatched Event', event.type);
|
NitroLogger.events('Dispatched Event', event.type);
|
||||||
|
|||||||
@@ -1816,13 +1816,13 @@ export class RoomEngine implements IRoomEngine, IRoomCreator, IRoomEngineService
|
|||||||
if(roomOwnObject && roomOwnObject.logic && maskUpdate) roomOwnObject.logic.processUpdateMessage(maskUpdate);
|
if(roomOwnObject && roomOwnObject.logic && maskUpdate) roomOwnObject.logic.processUpdateMessage(maskUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public rollRoomObjectFloor(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D): void
|
public rollRoomObjectFloor(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D, duration: number = ObjectMoveUpdateMessage.DEFAULT_DURATION, direction: IVector3D = null): void
|
||||||
{
|
{
|
||||||
const object = this.getRoomObjectFloor(roomId, objectId);
|
const object = this.getRoomObjectFloor(roomId, objectId);
|
||||||
|
|
||||||
if(!object) return;
|
if(!object) return;
|
||||||
|
|
||||||
object.processUpdateMessage(new ObjectMoveUpdateMessage(location, targetLocation, null, !!targetLocation));
|
object.processUpdateMessage(new ObjectMoveUpdateMessage(location, targetLocation, direction, !!targetLocation, duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateRoomObjectWallLocation(roomId: number, objectId: number, location: IVector3D): boolean
|
public updateRoomObjectWallLocation(roomId: number, objectId: number, location: IVector3D): boolean
|
||||||
@@ -1884,7 +1884,7 @@ export class RoomEngine implements IRoomEngine, IRoomCreator, IRoomEngineService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateRoomObjectUserLocation(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D, canStandUp: boolean = false, baseY: number = 0, direction: IVector3D = null, headDirection: number = NaN, skipLocationFix: boolean = false): boolean
|
public updateRoomObjectUserLocation(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D, canStandUp: boolean = false, baseY: number = 0, direction: IVector3D = null, headDirection: number = NaN, skipLocationFix: boolean = false, isSlide: boolean = false, duration: number = ObjectMoveUpdateMessage.DEFAULT_DURATION): boolean
|
||||||
{
|
{
|
||||||
const object = this.getRoomObjectUser(roomId, objectId);
|
const object = this.getRoomObjectUser(roomId, objectId);
|
||||||
|
|
||||||
@@ -1899,11 +1899,11 @@ export class RoomEngine implements IRoomEngine, IRoomCreator, IRoomEngineService
|
|||||||
const fixedLoc = skipLocationFix ? location : this.fixedUserLocation(roomId, location);
|
const fixedLoc = skipLocationFix ? location : this.fixedUserLocation(roomId, location);
|
||||||
const fixedTarget = skipLocationFix ? targetLocation : this.fixedUserLocation(roomId, targetLocation);
|
const fixedTarget = skipLocationFix ? targetLocation : this.fixedUserLocation(roomId, targetLocation);
|
||||||
|
|
||||||
object.processUpdateMessage(new ObjectAvatarUpdateMessage(fixedLoc, fixedTarget, direction, headDirection, canStandUp, baseY));
|
object.processUpdateMessage(new ObjectAvatarUpdateMessage(fixedLoc, fixedTarget, direction, headDirection, canStandUp, baseY, isSlide, duration));
|
||||||
|
|
||||||
const roomSession = this._roomSessionManager.getSession(roomId);
|
const roomSession = this._roomSessionManager.getSession(roomId);
|
||||||
|
|
||||||
if(roomSession && (roomSession.ownRoomIndex === objectId))
|
if(roomSession && (roomSession.ownRoomIndex === objectId) && targetLocation)
|
||||||
{
|
{
|
||||||
GetEventDispatcher().dispatchEvent(new RoomToObjectOwnAvatarMoveEvent(RoomToObjectOwnAvatarMoveEvent.ROAME_MOVE_TO, targetLocation));
|
GetEventDispatcher().dispatchEvent(new RoomToObjectOwnAvatarMoveEvent(RoomToObjectOwnAvatarMoveEvent.ROAME_MOVE_TO, targetLocation));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { AvatarGuideStatus, IConnection, IMessageEvent, IRoomCreator, IVector3D, LegacyDataType, ObjectRolling, PetType, RoomObjectType, RoomObjectUserType, RoomObjectVariable } from '@nitrots/api';
|
import { AvatarGuideStatus, IConnection, IMessageEvent, IRoomCreator, IVector3D, LegacyDataType, ObjectRolling, PetType, RoomObjectType, RoomObjectUserType, RoomObjectVariable } from '@nitrots/api';
|
||||||
import { AreaHideMessageEvent, DiceValueMessageEvent, FloorHeightMapEvent, FurnitureAliasesComposer, FurnitureAliasesEvent, FurnitureDataEvent, FurnitureFloorAddEvent, FurnitureFloorDataParser, FurnitureFloorEvent, FurnitureFloorRemoveEvent, FurnitureFloorUpdateEvent, FurnitureWallAddEvent, FurnitureWallDataParser, FurnitureWallEvent, FurnitureWallRemoveEvent, FurnitureWallUpdateEvent, GetCommunication, GetRoomEntryDataMessageComposer, GuideSessionEndedMessageEvent, GuideSessionErrorMessageEvent, GuideSessionStartedMessageEvent, IgnoreResultEvent, ItemDataUpdateMessageEvent, ObjectsDataUpdateEvent, ObjectsRollingEvent, OneWayDoorStatusMessageEvent, PetExperienceEvent, PetFigureUpdateEvent, RoomEntryTileMessageEvent, RoomEntryTileMessageParser, RoomHeightMapEvent, RoomHeightMapUpdateEvent, RoomPaintEvent, RoomReadyMessageEvent, RoomUnitChatEvent, RoomUnitChatShoutEvent, RoomUnitChatWhisperEvent, RoomUnitDanceEvent, RoomUnitEffectEvent, RoomUnitEvent, RoomUnitExpressionEvent, RoomUnitHandItemEvent, RoomUnitIdleEvent, RoomUnitInfoEvent, RoomUnitNumberEvent, RoomUnitRemoveEvent, RoomUnitStatusEvent, RoomUnitTypingEvent, RoomVisualizationSettingsEvent, UserInfoEvent, YouArePlayingGameEvent } from '@nitrots/communication';
|
import { AreaHideMessageEvent, DiceValueMessageEvent, FloorHeightMapEvent, FurnitureAliasesComposer, FurnitureAliasesEvent, FurnitureDataEvent, FurnitureFloorAddEvent, FurnitureFloorDataParser, FurnitureFloorEvent, FurnitureFloorRemoveEvent, FurnitureFloorUpdateEvent, FurnitureWallAddEvent, FurnitureWallDataParser, FurnitureWallEvent, FurnitureWallRemoveEvent, FurnitureWallUpdateEvent, GetCommunication, GetRoomEntryDataMessageComposer, GuideSessionEndedMessageEvent, GuideSessionErrorMessageEvent, GuideSessionStartedMessageEvent, IgnoreResultEvent, ItemDataUpdateMessageEvent, ObjectsDataUpdateEvent, ObjectsRollingEvent, OneWayDoorStatusMessageEvent, PetExperienceEvent, PetFigureUpdateEvent, RoomEntryTileMessageEvent, RoomEntryTileMessageParser, RoomHeightMapEvent, RoomHeightMapUpdateEvent, RoomPaintEvent, RoomReadyMessageEvent, RoomUnitChatEvent, RoomUnitChatShoutEvent, RoomUnitChatWhisperEvent, RoomUnitDanceEvent, RoomUnitEffectEvent, RoomUnitEvent, RoomUnitExpressionEvent, RoomUnitHandItemEvent, RoomUnitIdleEvent, RoomUnitInfoEvent, RoomUnitNumberEvent, RoomUnitRemoveEvent, RoomUnitStatusEvent, RoomUnitStatusMessage, RoomUnitTypingEvent, RoomVisualizationSettingsEvent, UserInfoEvent, WiredMovementsEvent, WiredUserDirectionUpdateData, WiredUserMovementData, YouArePlayingGameEvent } from '@nitrots/communication';
|
||||||
import { GetRoomSessionManager, GetSessionDataManager } from '@nitrots/session';
|
import { GetRoomSessionManager, GetSessionDataManager } from '@nitrots/session';
|
||||||
import { Vector3d } from '@nitrots/utils';
|
import { Vector3d } from '@nitrots/utils';
|
||||||
import { GetRoomEngine } from './GetRoomEngine';
|
import { GetRoomEngine } from './GetRoomEngine';
|
||||||
@@ -9,11 +9,15 @@ import { FurnitureStackingHeightMap, LegacyWallGeometry } from './utils';
|
|||||||
|
|
||||||
export class RoomMessageHandler
|
export class RoomMessageHandler
|
||||||
{
|
{
|
||||||
|
private static WIRED_MOVEMENT_STATUS_GRACE = 250;
|
||||||
|
private static WIRED_MOVEMENT_Z_EPSILON = 0.01;
|
||||||
|
|
||||||
private _connection: IConnection = null;
|
private _connection: IConnection = null;
|
||||||
private _roomEngine: IRoomCreator = null;
|
private _roomEngine: IRoomCreator = null;
|
||||||
private _planeParser = new RoomPlaneParser();
|
private _planeParser = new RoomPlaneParser();
|
||||||
private _latestEntryTileEvent: RoomEntryTileMessageEvent = null;
|
private _latestEntryTileEvent: RoomEntryTileMessageEvent = null;
|
||||||
private _messageEvents: IMessageEvent[] = [];
|
private _messageEvents: IMessageEvent[] = [];
|
||||||
|
private _activeWiredUserMovements = new Map<number, { expiresAt: number, targetX: number, targetY: number, targetZ: number }>();
|
||||||
|
|
||||||
private _currentRoomId: number = 0;
|
private _currentRoomId: number = 0;
|
||||||
private _ownUserId: number = 0;
|
private _ownUserId: number = 0;
|
||||||
@@ -38,6 +42,7 @@ export class RoomMessageHandler
|
|||||||
new RoomVisualizationSettingsEvent(this.onRoomThicknessEvent.bind(this)),
|
new RoomVisualizationSettingsEvent(this.onRoomThicknessEvent.bind(this)),
|
||||||
new RoomEntryTileMessageEvent(this.onRoomDoorEvent.bind(this)),
|
new RoomEntryTileMessageEvent(this.onRoomDoorEvent.bind(this)),
|
||||||
new ObjectsRollingEvent(this.onRoomRollingEvent.bind(this)),
|
new ObjectsRollingEvent(this.onRoomRollingEvent.bind(this)),
|
||||||
|
new WiredMovementsEvent(this.onWiredMovementsEvent.bind(this)),
|
||||||
new ObjectsDataUpdateEvent(this.onObjectsDataUpdateEvent.bind(this)),
|
new ObjectsDataUpdateEvent(this.onObjectsDataUpdateEvent.bind(this)),
|
||||||
new FurnitureAliasesEvent(this.onFurnitureAliasesEvent.bind(this)),
|
new FurnitureAliasesEvent(this.onFurnitureAliasesEvent.bind(this)),
|
||||||
new FurnitureFloorAddEvent(this.onFurnitureFloorAddEvent.bind(this)),
|
new FurnitureFloorAddEvent(this.onFurnitureFloorAddEvent.bind(this)),
|
||||||
@@ -98,6 +103,7 @@ export class RoomMessageHandler
|
|||||||
this._connection = null;
|
this._connection = null;
|
||||||
this._roomEngine = null;
|
this._roomEngine = null;
|
||||||
this._latestEntryTileEvent = null;
|
this._latestEntryTileEvent = null;
|
||||||
|
this._activeWiredUserMovements.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setRoomId(id: number): void
|
public setRoomId(id: number): void
|
||||||
@@ -109,12 +115,14 @@ export class RoomMessageHandler
|
|||||||
|
|
||||||
this._currentRoomId = id;
|
this._currentRoomId = id;
|
||||||
this._latestEntryTileEvent = null;
|
this._latestEntryTileEvent = null;
|
||||||
|
this._activeWiredUserMovements.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public clearRoomId(): void
|
public clearRoomId(): void
|
||||||
{
|
{
|
||||||
this._currentRoomId = 0;
|
this._currentRoomId = 0;
|
||||||
this._latestEntryTileEvent = null;
|
this._latestEntryTileEvent = null;
|
||||||
|
this._activeWiredUserMovements.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private onUserInfoEvent(event: UserInfoEvent): void
|
private onUserInfoEvent(event: UserInfoEvent): void
|
||||||
@@ -378,27 +386,158 @@ export class RoomMessageHandler
|
|||||||
|
|
||||||
if(unitRollData)
|
if(unitRollData)
|
||||||
{
|
{
|
||||||
this._roomEngine.updateRoomObjectUserLocation(this._currentRoomId, unitRollData.id, unitRollData.location, unitRollData.targetLocation, false, 0, null, NaN, true);
|
this.applyRollingUnitMovement(unitRollData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const object = this._roomEngine.getRoomObjectUser(this._currentRoomId, unitRollData.id);
|
private onWiredMovementsEvent(event: WiredMovementsEvent): void
|
||||||
|
{
|
||||||
|
if(!(event instanceof WiredMovementsEvent) || !event.connection || !this._roomEngine) return;
|
||||||
|
|
||||||
if(object && object.type !== RoomObjectUserType.MONSTER_PLANT)
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(!parser) return;
|
||||||
|
|
||||||
|
if(parser.furniMovements?.length)
|
||||||
|
{
|
||||||
|
for(const movement of parser.furniMovements)
|
||||||
{
|
{
|
||||||
let posture = 'std';
|
if(!movement) continue;
|
||||||
|
|
||||||
switch(unitRollData.movementType)
|
this._roomEngine.rollRoomObjectFloor(
|
||||||
{
|
this._currentRoomId,
|
||||||
case ObjectRolling.MOVE:
|
movement.id,
|
||||||
posture = 'mv';
|
movement.location,
|
||||||
break;
|
movement.targetLocation,
|
||||||
case ObjectRolling.SLIDE:
|
movement.duration,
|
||||||
posture = 'std';
|
new Vector3d(movement.rotation));
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._roomEngine.updateRoomObjectUserPosture(this._currentRoomId, unitRollData.id, posture);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(parser.userMovements?.length)
|
||||||
|
{
|
||||||
|
for(const movement of parser.userMovements)
|
||||||
|
{
|
||||||
|
if(!movement) continue;
|
||||||
|
|
||||||
|
this.applyWiredUserMovement(movement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(parser.userDirectionUpdates?.length)
|
||||||
|
{
|
||||||
|
for(const update of parser.userDirectionUpdates)
|
||||||
|
{
|
||||||
|
if(!update) continue;
|
||||||
|
|
||||||
|
this.applyWiredUserDirectionUpdate(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyRollingUnitMovement(movement: ObjectRolling): void
|
||||||
|
{
|
||||||
|
this._roomEngine.updateRoomObjectUserLocation(this._currentRoomId, movement.id, movement.location, movement.targetLocation, false, 0, null, NaN, true);
|
||||||
|
|
||||||
|
const object = this._roomEngine.getRoomObjectUser(this._currentRoomId, movement.id);
|
||||||
|
|
||||||
|
if(object && object.type !== RoomObjectUserType.MONSTER_PLANT)
|
||||||
|
{
|
||||||
|
const posture = (movement.movementType === ObjectRolling.MOVE) ? 'mv' : 'std';
|
||||||
|
|
||||||
|
this._roomEngine.updateRoomObjectUserPosture(this._currentRoomId, movement.id, posture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyWiredUserMovement(movement: WiredUserMovementData): void
|
||||||
|
{
|
||||||
|
const isSlide = (movement.movementType === ObjectRolling.SLIDE);
|
||||||
|
this.trackWiredUserMovement(movement);
|
||||||
|
|
||||||
|
this._roomEngine.updateRoomObjectUserLocation(
|
||||||
|
this._currentRoomId,
|
||||||
|
movement.id,
|
||||||
|
movement.location,
|
||||||
|
movement.targetLocation,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
new Vector3d(movement.bodyDirection),
|
||||||
|
movement.headDirection,
|
||||||
|
true,
|
||||||
|
isSlide,
|
||||||
|
movement.duration);
|
||||||
|
|
||||||
|
const object = this._roomEngine.getRoomObjectUser(this._currentRoomId, movement.id);
|
||||||
|
|
||||||
|
if(object && object.type !== RoomObjectUserType.MONSTER_PLANT)
|
||||||
|
{
|
||||||
|
const posture = (movement.movementType === ObjectRolling.MOVE) ? 'mv' : 'std';
|
||||||
|
|
||||||
|
this._roomEngine.updateRoomObjectUserPosture(this._currentRoomId, movement.id, posture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private trackWiredUserMovement(movement: WiredUserMovementData): void
|
||||||
|
{
|
||||||
|
this._activeWiredUserMovements.set(movement.id, {
|
||||||
|
expiresAt: Date.now() + Math.max(movement.duration, 1) + RoomMessageHandler.WIRED_MOVEMENT_STATUS_GRACE,
|
||||||
|
targetX: movement.targetLocation.x,
|
||||||
|
targetY: movement.targetLocation.y,
|
||||||
|
targetZ: movement.targetLocation.z
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private shouldSuppressWiredStatusLocation(status: RoomUnitStatusMessage): boolean
|
||||||
|
{
|
||||||
|
const activeMovement = this._activeWiredUserMovements.get(status.id);
|
||||||
|
|
||||||
|
if(!activeMovement) return false;
|
||||||
|
|
||||||
|
if(activeMovement.expiresAt <= Date.now())
|
||||||
|
{
|
||||||
|
this._activeWiredUserMovements.delete(status.id);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.shouldReleaseWiredStatusLocation(status, activeMovement))
|
||||||
|
{
|
||||||
|
this._activeWiredUserMovements.delete(status.id);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private shouldReleaseWiredStatusLocation(status: RoomUnitStatusMessage, activeMovement: { expiresAt: number, targetX: number, targetY: number, targetZ: number }): boolean
|
||||||
|
{
|
||||||
|
if(!status.didMove) return false;
|
||||||
|
|
||||||
|
return !this.matchesWiredMovementTarget(status.targetX, status.targetY, status.targetZ, activeMovement);
|
||||||
|
}
|
||||||
|
|
||||||
|
private matchesWiredMovementTarget(x: number, y: number, z: number, activeMovement: { expiresAt: number, targetX: number, targetY: number, targetZ: number }): boolean
|
||||||
|
{
|
||||||
|
if(!activeMovement) return false;
|
||||||
|
|
||||||
|
return ((x === activeMovement.targetX)
|
||||||
|
&& (y === activeMovement.targetY)
|
||||||
|
&& (Math.abs(z - activeMovement.targetZ) <= RoomMessageHandler.WIRED_MOVEMENT_Z_EPSILON));
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyWiredUserDirectionUpdate(update: WiredUserDirectionUpdateData): void
|
||||||
|
{
|
||||||
|
this._roomEngine.updateRoomObjectUserLocation(
|
||||||
|
this._currentRoomId,
|
||||||
|
update.id,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
new Vector3d(update.bodyDirection),
|
||||||
|
update.headDirection,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onObjectsDataUpdateEvent(event: ObjectsDataUpdateEvent): void
|
private onObjectsDataUpdateEvent(event: ObjectsDataUpdateEvent): void
|
||||||
@@ -734,7 +873,11 @@ export class RoomMessageHandler
|
|||||||
|
|
||||||
if(status.didMove) goal = new Vector3d(status.targetX, status.targetY, status.targetZ);
|
if(status.didMove) goal = new Vector3d(status.targetX, status.targetY, status.targetZ);
|
||||||
|
|
||||||
this._roomEngine.updateRoomObjectUserLocation(this._currentRoomId, status.id, location, goal, status.canStandUp, height, direction, status.headDirection);
|
if(!this.shouldSuppressWiredStatusLocation(status))
|
||||||
|
{
|
||||||
|
this._roomEngine.updateRoomObjectUserLocation(this._currentRoomId, status.id, location, goal, status.canStandUp, height, direction, status.headDirection);
|
||||||
|
}
|
||||||
|
|
||||||
this._roomEngine.updateRoomObjectUserFlatControl(this._currentRoomId, status.id, null);
|
this._roomEngine.updateRoomObjectUserFlatControl(this._currentRoomId, status.id, null);
|
||||||
|
|
||||||
// Save own user's position for reconnection
|
// Save own user's position for reconnection
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ export class ObjectAvatarUpdateMessage extends ObjectMoveUpdateMessage
|
|||||||
private _canStandUp: boolean;
|
private _canStandUp: boolean;
|
||||||
private _baseY: number;
|
private _baseY: number;
|
||||||
|
|
||||||
constructor(location: IVector3D, targetLocation: IVector3D, direction: IVector3D, headDirection: number, canStandUp: boolean, baseY: number)
|
constructor(location: IVector3D, targetLocation: IVector3D, direction: IVector3D, headDirection: number, canStandUp: boolean, baseY: number, isSlide: boolean = false, duration: number = ObjectMoveUpdateMessage.DEFAULT_DURATION)
|
||||||
{
|
{
|
||||||
super(location, targetLocation, direction);
|
super(location, targetLocation, direction, isSlide, duration);
|
||||||
|
|
||||||
this._headDirection = headDirection;
|
this._headDirection = headDirection;
|
||||||
this._canStandUp = canStandUp;
|
this._canStandUp = canStandUp;
|
||||||
|
|||||||
@@ -3,15 +3,19 @@ import { RoomObjectUpdateMessage } from './RoomObjectUpdateMessage';
|
|||||||
|
|
||||||
export class ObjectMoveUpdateMessage extends RoomObjectUpdateMessage
|
export class ObjectMoveUpdateMessage extends RoomObjectUpdateMessage
|
||||||
{
|
{
|
||||||
|
public static DEFAULT_DURATION: number = 500;
|
||||||
|
|
||||||
private _targetLocation: IVector3D;
|
private _targetLocation: IVector3D;
|
||||||
private _isSlide: boolean;
|
private _isSlide: boolean;
|
||||||
|
private _duration: number;
|
||||||
|
|
||||||
constructor(location: IVector3D, targetLocation: IVector3D, direction: IVector3D, isSlide: boolean = false)
|
constructor(location: IVector3D, targetLocation: IVector3D, direction: IVector3D, isSlide: boolean = false, duration: number = ObjectMoveUpdateMessage.DEFAULT_DURATION)
|
||||||
{
|
{
|
||||||
super(location, direction);
|
super(location, direction);
|
||||||
|
|
||||||
this._targetLocation = targetLocation;
|
this._targetLocation = targetLocation;
|
||||||
this._isSlide = isSlide;
|
this._isSlide = isSlide;
|
||||||
|
this._duration = duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get targetLocation(): IVector3D
|
public get targetLocation(): IVector3D
|
||||||
@@ -25,4 +29,9 @@ export class ObjectMoveUpdateMessage extends RoomObjectUpdateMessage
|
|||||||
{
|
{
|
||||||
return this._isSlide;
|
return this._isSlide;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get duration(): number
|
||||||
|
{
|
||||||
|
return this._duration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ export class MovingObjectLogic extends RoomObjectLogicBase
|
|||||||
if(!message || !this.object || !message.location) return;
|
if(!message || !this.object || !message.location) return;
|
||||||
|
|
||||||
this._changeTime = this._lastUpdateTime;
|
this._changeTime = this._lastUpdateTime;
|
||||||
|
this.updateInterval = message.duration;
|
||||||
|
|
||||||
this._locationDelta.assign(message.targetLocation);
|
this._locationDelta.assign(message.targetLocation);
|
||||||
this._locationDelta.subtract(this._location);
|
this._locationDelta.subtract(this._location);
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export class FurniturePushableLogic extends FurnitureMultiStateLogic
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isMoveMessage && message.isSlide) this.updateInterval = MovingObjectLogic.DEFAULT_UPDATE_INTERVAL;
|
if(isMoveMessage && message.isSlide) this.updateInterval = message.duration;
|
||||||
|
|
||||||
super.processUpdateMessage(message);
|
super.processUpdateMessage(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ export class RoomAreaSelectionManager implements IRoomAreaSelectionManager
|
|||||||
private _callback: (rootX: number, rootY: number, width: number, height: number) => void;
|
private _callback: (rootX: number, rootY: number, width: number, height: number) => void;
|
||||||
private _highlightType: string = RoomAreaSelectionManager.HIGHLIGHT_BRIGHTEN;
|
private _highlightType: string = RoomAreaSelectionManager.HIGHLIGHT_BRIGHTEN;
|
||||||
|
|
||||||
|
private resetHighlightBounds(): void
|
||||||
|
{
|
||||||
|
this._highlightRootX = 0;
|
||||||
|
this._highlightRootY = 0;
|
||||||
|
this._highlightWidth = 0;
|
||||||
|
this._highlightHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(roomEngine: IRoomEngine)
|
constructor(roomEngine: IRoomEngine)
|
||||||
{
|
{
|
||||||
this._roomEngine = roomEngine;
|
this._roomEngine = roomEngine;
|
||||||
@@ -191,6 +199,7 @@ export class RoomAreaSelectionManager implements IRoomAreaSelectionManager
|
|||||||
if(this._state === RoomAreaSelectionManager.NOT_ACTIVE) return;
|
if(this._state === RoomAreaSelectionManager.NOT_ACTIVE) return;
|
||||||
|
|
||||||
this.clearHighlightSilent();
|
this.clearHighlightSilent();
|
||||||
|
this.resetHighlightBounds();
|
||||||
|
|
||||||
this._state = RoomAreaSelectionManager.NOT_SELECTING_AREA;
|
this._state = RoomAreaSelectionManager.NOT_SELECTING_AREA;
|
||||||
|
|
||||||
@@ -233,6 +242,7 @@ export class RoomAreaSelectionManager implements IRoomAreaSelectionManager
|
|||||||
|
|
||||||
this._callback = callback;
|
this._callback = callback;
|
||||||
this._highlightType = highlightType;
|
this._highlightType = highlightType;
|
||||||
|
this.resetHighlightBounds();
|
||||||
|
|
||||||
for(const roomObject of this.getAllFurniture())
|
for(const roomObject of this.getAllFurniture())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
private _sessionStarting: boolean = false;
|
private _sessionStarting: boolean = false;
|
||||||
private _viewerSession: IRoomSession = null;
|
private _viewerSession: IRoomSession = null;
|
||||||
|
|
||||||
// Reconnection state tracking
|
|
||||||
private _lastRoomId: number = -1;
|
private _lastRoomId: number = -1;
|
||||||
private _lastRoomPassword: string = null;
|
private _lastRoomPassword: string = null;
|
||||||
private _isReconnecting: boolean = false;
|
private _isReconnecting: boolean = false;
|
||||||
@@ -34,9 +33,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
this.createHandlers();
|
this.createHandlers();
|
||||||
this.processPendingSession();
|
this.processPendingSession();
|
||||||
this.setupReconnectListener();
|
this.setupReconnectListener();
|
||||||
|
|
||||||
// Check if there's a persisted room from a network disconnect (Vite page reload).
|
|
||||||
// sessionStorage survives same-tab reloads but is cleared on browser close.
|
|
||||||
this.checkPersistedRoom();
|
this.checkPersistedRoom();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,19 +48,12 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
if(isNaN(roomId) || roomId <= 0) return;
|
if(isNaN(roomId) || roomId <= 0) return;
|
||||||
|
|
||||||
NitroLogger.log('[RoomSessionManager] Found persisted room ' + roomId + ' - setting guard for page-reload restore');
|
|
||||||
|
|
||||||
// Pre-load memory state so attemptRoomReEntry and tryRestoreSession can use it
|
|
||||||
this._lastRoomId = roomId;
|
this._lastRoomId = roomId;
|
||||||
this._lastRoomPassword = sessionStorage.getItem(STORAGE_KEY_ROOM_PASSWORD) || null;
|
this._lastRoomPassword = sessionStorage.getItem(STORAGE_KEY_ROOM_PASSWORD) || null;
|
||||||
|
|
||||||
// Enable guard to block DesktopViewEvent until we enter the stored room
|
|
||||||
this._isReconnecting = true;
|
this._isReconnecting = true;
|
||||||
}
|
}
|
||||||
catch(e)
|
catch(e){}
|
||||||
{
|
|
||||||
// sessionStorage not available
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private createHandlers(): void
|
private createHandlers(): void
|
||||||
@@ -90,56 +79,31 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
private setupReconnectListener(): void
|
private setupReconnectListener(): void
|
||||||
{
|
{
|
||||||
console.log('[RoomSessionManager] setupReconnectListener() - registering event listeners');
|
|
||||||
|
|
||||||
// Mark reconnecting state early so DesktopViewEvent / home room redirects
|
|
||||||
// don't clear the tracked room before we can re-enter it
|
|
||||||
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_RECONNECTING, () =>
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_RECONNECTING, () =>
|
||||||
{
|
{
|
||||||
// Cancel any pending room ID clear from removeSession().
|
|
||||||
// The server sends DesktopViewEvent before closing the socket, which
|
|
||||||
// schedules a delayed clear. We need to preserve the room ID for re-entry.
|
|
||||||
this.cancelRoomIdClear();
|
this.cancelRoomIdClear();
|
||||||
|
|
||||||
// Re-persist room to sessionStorage (it was cleared in removeSession)
|
|
||||||
if(this._lastRoomId > 0)
|
if(this._lastRoomId > 0)
|
||||||
{
|
{
|
||||||
this.persistRoom(this._lastRoomId, this._lastRoomPassword);
|
this.persistRoom(this._lastRoomId, this._lastRoomPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[RoomSessionManager] SOCKET_RECONNECTING fired! lastRoomId=' + this._lastRoomId);
|
|
||||||
this._isReconnecting = true;
|
this._isReconnecting = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// SOCKET_RECONNECTED: the WebSocket is open but NOT yet authenticated.
|
|
||||||
// We set up a fallback timer here in case the server doesn't send
|
|
||||||
// AuthenticatedEvent (e.g. SSO ticket consumed).
|
|
||||||
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_RECONNECTED, () =>
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_RECONNECTED, () =>
|
||||||
{
|
{
|
||||||
console.log('[RoomSessionManager] SOCKET_RECONNECTED fired! lastRoomId=' + this._lastRoomId);
|
|
||||||
|
|
||||||
// Fallback: if REAUTHENTICATED doesn't fire within 5 seconds,
|
|
||||||
// try to re-enter the room anyway (the connection might still work)
|
|
||||||
this.clearGuardTimer();
|
this.clearGuardTimer();
|
||||||
this._reconnectGuardTimer = setTimeout(() =>
|
this._reconnectGuardTimer = setTimeout(() =>
|
||||||
{
|
{
|
||||||
this._reconnectGuardTimer = null;
|
this._reconnectGuardTimer = null;
|
||||||
|
|
||||||
if(!this._isReconnecting) return;
|
if(!this._isReconnecting) return;
|
||||||
|
|
||||||
NitroLogger.log('[RoomSessionManager] REAUTHENTICATED timeout - attempting fallback room re-entry for room ' + this._lastRoomId);
|
|
||||||
this.attemptRoomReEntry();
|
this.attemptRoomReEntry();
|
||||||
}, 5000);
|
}, 5000);
|
||||||
});
|
});
|
||||||
|
|
||||||
// REAUTHENTICATED: SSO handshake completed, connection is ready to send messages
|
|
||||||
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_REAUTHENTICATED, () =>
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_REAUTHENTICATED, () =>
|
||||||
{
|
{
|
||||||
console.log('[RoomSessionManager] SOCKET_REAUTHENTICATED fired! lastRoomId=' + this._lastRoomId);
|
|
||||||
|
|
||||||
// Snapshot the saved position BEFORE re-entering (re-entry overwrites sessionStorage)
|
|
||||||
this.snapshotSavedPosition();
|
this.snapshotSavedPosition();
|
||||||
|
|
||||||
this.clearGuardTimer();
|
this.clearGuardTimer();
|
||||||
this.attemptRoomReEntry();
|
this.attemptRoomReEntry();
|
||||||
});
|
});
|
||||||
@@ -155,11 +119,8 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
this.clearPersistedPosition();
|
this.clearPersistedPosition();
|
||||||
});
|
});
|
||||||
|
|
||||||
// When the socket is permanently closed (server shutdown, max retries),
|
|
||||||
// clear the persisted room so the next page load uses normal navigation
|
|
||||||
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_CLOSED, () =>
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_CLOSED, () =>
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] SOCKET_CLOSED - clearing persisted room');
|
|
||||||
this.clearGuardTimer();
|
this.clearGuardTimer();
|
||||||
this._isReconnecting = false;
|
this._isReconnecting = false;
|
||||||
this._lastRoomId = -1;
|
this._lastRoomId = -1;
|
||||||
@@ -209,30 +170,17 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
if(roomId <= 0)
|
if(roomId <= 0)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] No room to re-enter (lastRoomId=' + roomId + '), dropping guard');
|
|
||||||
this._isReconnecting = false;
|
this._isReconnecting = false;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we already have a session for this room (seamless reconnection).
|
|
||||||
// The server-side SessionResumeManager kept the habbo alive in the room
|
|
||||||
// during the grace period. The client's room view is still rendered behind
|
|
||||||
// the reconnection overlay. Instead of tearing it down and rebuilding,
|
|
||||||
// just drop the guard so the room view "unfreezes" in place.
|
|
||||||
const existingSession = this.getSession(roomId);
|
const existingSession = this.getSession(roomId);
|
||||||
|
|
||||||
if(existingSession)
|
if(existingSession)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] Existing session found for room ' + roomId + ' — sending room enter request');
|
|
||||||
|
|
||||||
// Re-send room enter request to the server with saved spawn coordinates.
|
|
||||||
// The server will place the habbo directly at the saved position
|
|
||||||
// instead of the door tile, providing a seamless reconnection experience.
|
|
||||||
GetCommunication().connection.send(new RoomEnterComposer(roomId, password, this._savedPosX, this._savedPosY));
|
GetCommunication().connection.send(new RoomEnterComposer(roomId, password, this._savedPosX, this._savedPosY));
|
||||||
|
|
||||||
// Keep the guard up briefly to absorb any stray server-side redirects
|
|
||||||
// (DesktopViewEvent, etc.) from the login packet sequence, then drop it.
|
|
||||||
this.clearGuardTimer();
|
this.clearGuardTimer();
|
||||||
this._reconnectGuardTimer = setTimeout(() =>
|
this._reconnectGuardTimer = setTimeout(() =>
|
||||||
{
|
{
|
||||||
@@ -240,7 +188,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
if(this._isReconnecting)
|
if(this._isReconnecting)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] Session resume guard timeout - dropping guard');
|
|
||||||
this._isReconnecting = false;
|
this._isReconnecting = false;
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
@@ -248,21 +195,9 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NitroLogger.log('[RoomSessionManager] Re-entering room ' + roomId);
|
|
||||||
|
|
||||||
// No existing session — full room entry (e.g. page reload restore)
|
|
||||||
this._sessions.clear();
|
this._sessions.clear();
|
||||||
this._viewerSession = null;
|
this._viewerSession = null;
|
||||||
|
|
||||||
// Send the room enter request with saved spawn coordinates. The server
|
|
||||||
// will place the habbo at the saved position instead of the door tile.
|
|
||||||
this.createSession(roomId, password, this._savedPosX, this._savedPosY);
|
this.createSession(roomId, password, this._savedPosX, this._savedPosY);
|
||||||
|
|
||||||
// Keep the guard up for a generous window to absorb any DesktopViewEvent
|
|
||||||
// or other server-side redirects that arrive after authentication.
|
|
||||||
// The guard drops when:
|
|
||||||
// 1. RS_CONNECTED/RS_READY fires (positive room entry confirmation), OR
|
|
||||||
// 2. This safety timeout expires (10 seconds)
|
|
||||||
this.clearGuardTimer();
|
this.clearGuardTimer();
|
||||||
this._reconnectGuardTimer = setTimeout(() =>
|
this._reconnectGuardTimer = setTimeout(() =>
|
||||||
{
|
{
|
||||||
@@ -270,19 +205,11 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
if(this._isReconnecting)
|
if(this._isReconnecting)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] Guard timeout (10s) - dropping guard');
|
|
||||||
this._isReconnecting = false;
|
this._isReconnecting = false;
|
||||||
}
|
}
|
||||||
}, 10000);
|
}, 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called on page load (from MainView). Checks sessionStorage for a
|
|
||||||
* persisted room ID from a network disconnect and enters it instead
|
|
||||||
* of following the normal home room / hotel view flow.
|
|
||||||
*
|
|
||||||
* Returns true if a room restore was initiated.
|
|
||||||
*/
|
|
||||||
public tryRestoreSession(): boolean
|
public tryRestoreSession(): boolean
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -297,7 +224,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
const password = sessionStorage.getItem(STORAGE_KEY_ROOM_PASSWORD) || null;
|
const password = sessionStorage.getItem(STORAGE_KEY_ROOM_PASSWORD) || null;
|
||||||
|
|
||||||
// Read saved position for page-reload restore
|
|
||||||
let spawnX = -1;
|
let spawnX = -1;
|
||||||
let spawnY = -1;
|
let spawnY = -1;
|
||||||
|
|
||||||
@@ -314,17 +240,10 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
if(isNaN(spawnX) || isNaN(spawnY)) { spawnX = -1; spawnY = -1; }
|
if(isNaN(spawnX) || isNaN(spawnY)) { spawnX = -1; spawnY = -1; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(e) { /* ignore */ }
|
catch(e) {}
|
||||||
|
|
||||||
NitroLogger.log('[RoomSessionManager] Restoring session for room ' + roomId + ' from sessionStorage (spawn: ' + spawnX + ', ' + spawnY + ')');
|
|
||||||
|
|
||||||
// Set the guard so DesktopViewEvent from the server's login sequence
|
|
||||||
// doesn't kick us to hotel view before we enter the room
|
|
||||||
this._isReconnecting = true;
|
this._isReconnecting = true;
|
||||||
|
|
||||||
this.createSession(roomId, password, spawnX, spawnY);
|
this.createSession(roomId, password, spawnX, spawnY);
|
||||||
|
|
||||||
// Drop the guard when room entry succeeds or after timeout
|
|
||||||
this.clearGuardTimer();
|
this.clearGuardTimer();
|
||||||
this._reconnectGuardTimer = setTimeout(() =>
|
this._reconnectGuardTimer = setTimeout(() =>
|
||||||
{
|
{
|
||||||
@@ -332,7 +251,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
if(this._isReconnecting)
|
if(this._isReconnecting)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] Restore guard timeout (10s) - dropping guard');
|
|
||||||
this._isReconnecting = false;
|
this._isReconnecting = false;
|
||||||
}
|
}
|
||||||
}, 10000);
|
}, 10000);
|
||||||
@@ -367,10 +285,7 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
this.clearPersistedRoom();
|
this.clearPersistedRoom();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(e)
|
catch(e) {}
|
||||||
{
|
|
||||||
// sessionStorage not available (private browsing, etc.) - fail silently
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private clearPersistedRoom(): void
|
private clearPersistedRoom(): void
|
||||||
@@ -379,14 +294,8 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
{
|
{
|
||||||
sessionStorage.removeItem(STORAGE_KEY_ROOM_ID);
|
sessionStorage.removeItem(STORAGE_KEY_ROOM_ID);
|
||||||
sessionStorage.removeItem(STORAGE_KEY_ROOM_PASSWORD);
|
sessionStorage.removeItem(STORAGE_KEY_ROOM_PASSWORD);
|
||||||
// Note: position keys (POS_X, POS_Y) are NOT cleared here.
|
|
||||||
// They persist across the disconnect→reconnect cycle and are
|
|
||||||
// sent to the server as spawn coordinates during re-entry.
|
|
||||||
}
|
|
||||||
catch(e)
|
|
||||||
{
|
|
||||||
// ignore
|
|
||||||
}
|
}
|
||||||
|
catch(e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
private clearPersistedPosition(): void
|
private clearPersistedPosition(): void
|
||||||
@@ -396,10 +305,7 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
sessionStorage.removeItem(STORAGE_KEY_POS_X);
|
sessionStorage.removeItem(STORAGE_KEY_POS_X);
|
||||||
sessionStorage.removeItem(STORAGE_KEY_POS_Y);
|
sessionStorage.removeItem(STORAGE_KEY_POS_Y);
|
||||||
}
|
}
|
||||||
catch(e)
|
catch(e) {}
|
||||||
{
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private snapshotSavedPosition(): void
|
private snapshotSavedPosition(): void
|
||||||
@@ -414,7 +320,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
this._savedPosX = parseInt(posX, 10);
|
this._savedPosX = parseInt(posX, 10);
|
||||||
this._savedPosY = parseInt(posY, 10);
|
this._savedPosY = parseInt(posY, 10);
|
||||||
|
|
||||||
NitroLogger.log('[RoomSessionManager] Snapshot saved position (' + this._savedPosX + ', ' + this._savedPosY + ')');
|
|
||||||
}
|
}
|
||||||
catch(e)
|
catch(e)
|
||||||
{
|
{
|
||||||
@@ -476,8 +381,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
GetEventDispatcher().dispatchEvent(new RoomSessionEvent(RoomSessionEvent.CREATED, roomSession));
|
GetEventDispatcher().dispatchEvent(new RoomSessionEvent(RoomSessionEvent.CREATED, roomSession));
|
||||||
|
|
||||||
this._viewerSession = roomSession;
|
this._viewerSession = roomSession;
|
||||||
|
|
||||||
// Track room for reconnection (memory + sessionStorage)
|
|
||||||
this._lastRoomId = roomSession.roomId;
|
this._lastRoomId = roomSession.roomId;
|
||||||
this._lastRoomPassword = roomSession.password;
|
this._lastRoomPassword = roomSession.password;
|
||||||
this.persistRoom(roomSession.roomId, roomSession.password);
|
this.persistRoom(roomSession.roomId, roomSession.password);
|
||||||
@@ -513,13 +416,8 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
if(!session) return;
|
if(!session) return;
|
||||||
|
|
||||||
// During reconnection, block BOTH the session map deletion AND the ENDED event.
|
|
||||||
// This preserves the session so attemptRoomReEntry can find it, and prevents
|
|
||||||
// the UI from flashing hotel view during the reconnection flow.
|
|
||||||
if(this._isReconnecting)
|
if(this._isReconnecting)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] removeSession fully blocked by reconnect guard (room=' + id + ', openLandingView=' + openLandingView + ')');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,11 +425,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
if(openLandingView)
|
if(openLandingView)
|
||||||
{
|
{
|
||||||
// Don't clear _lastRoomId immediately. During server shutdown the server
|
|
||||||
// sends DesktopViewEvent (which triggers removeSession) BEFORE closing the
|
|
||||||
// socket. If we clear the room ID now, the SOCKET_RECONNECTING handler
|
|
||||||
// won't know which room to re-enter. Instead, delay the clear so that
|
|
||||||
// SOCKET_RECONNECTING can cancel it and preserve the room info.
|
|
||||||
this.clearPersistedRoom();
|
this.clearPersistedRoom();
|
||||||
this.scheduleRoomIdClear();
|
this.scheduleRoomIdClear();
|
||||||
}
|
}
|
||||||
@@ -545,43 +438,19 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
if(!session)
|
if(!session)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] sessionUpdate(' + type + ') - no session found for id ' + id);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case RoomSessionHandler.RS_CONNECTED:
|
case RoomSessionHandler.RS_CONNECTED:
|
||||||
NitroLogger.log('[RoomSessionManager] RS_CONNECTED for room ' + id);
|
|
||||||
|
|
||||||
// Positive signal: we successfully entered the room.
|
|
||||||
// Do NOT drop the guard yet — the server's login sequence may still
|
|
||||||
// send a DesktopViewEvent that arrives after this. Keep the guard up
|
|
||||||
// and let RS_READY (or the existing timeout) handle the final drop.
|
|
||||||
if(this._isReconnecting)
|
|
||||||
{
|
|
||||||
NitroLogger.log('[RoomSessionManager] Room entry confirmed - guard stays up until RS_READY');
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case RoomSessionHandler.RS_READY:
|
case RoomSessionHandler.RS_READY:
|
||||||
NitroLogger.log('[RoomSessionManager] RS_READY for room ' + id);
|
|
||||||
|
|
||||||
// Room is fully loaded. Keep the guard up for a short grace period
|
|
||||||
// to absorb any late DesktopViewEvent from the server's login sequence,
|
|
||||||
// then drop it. This prevents a race where the login sequence's
|
|
||||||
// DesktopViewEvent arrives after the room entry confirmation.
|
|
||||||
if(this._isReconnecting)
|
if(this._isReconnecting)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] Room ready confirmed - dropping guard in 3s');
|
if(this._savedPosX >= 0 && this._savedPosY >= 0)
|
||||||
|
|
||||||
// If we have saved spawn coordinates, send a walk command so the
|
|
||||||
// avatar moves to their previous position. This handles the EMU-restart
|
|
||||||
// case where the server has no ghost session and spawns at the door.
|
|
||||||
if(this._savedPosX >= 0 && this._savedPosY >= 0)
|
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] Walking to saved position (' + this._savedPosX + ', ' + this._savedPosY + ')');
|
|
||||||
GetCommunication().connection.send(new RoomUnitWalkComposer(this._savedPosX, this._savedPosY));
|
GetCommunication().connection.send(new RoomUnitWalkComposer(this._savedPosX, this._savedPosY));
|
||||||
this._savedPosX = -1;
|
this._savedPosX = -1;
|
||||||
this._savedPosY = -1;
|
this._savedPosY = -1;
|
||||||
@@ -594,18 +463,14 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
if(this._isReconnecting)
|
if(this._isReconnecting)
|
||||||
{
|
{
|
||||||
NitroLogger.log('[RoomSessionManager] Post-ready grace period elapsed - dropping guard');
|
this._isReconnecting = false;
|
||||||
this._isReconnecting = false;
|
|
||||||
}
|
}
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case RoomSessionHandler.RS_DISCONNECTED:
|
case RoomSessionHandler.RS_DISCONNECTED:
|
||||||
NitroLogger.log('[RoomSessionManager] RS_DISCONNECTED for room ' + id + ' (isReconnecting=' + this._isReconnecting + ')');
|
|
||||||
|
|
||||||
// During reconnection, don't process server-side disconnects
|
|
||||||
// (DesktopViewEvent / home room redirect) - we'll re-enter the room
|
|
||||||
if(this._isReconnecting) return;
|
if(this._isReconnecting) return;
|
||||||
|
|
||||||
this.removeSession(id);
|
this.removeSession(id);
|
||||||
@@ -625,7 +490,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
this._sessions.set(this.getRoomId(toRoomId), existing);
|
this._sessions.set(this.getRoomId(toRoomId), existing);
|
||||||
|
|
||||||
// Update tracked room
|
|
||||||
this._lastRoomId = toRoomId;
|
this._lastRoomId = toRoomId;
|
||||||
this.persistRoom(toRoomId, existing.password);
|
this.persistRoom(toRoomId, existing.password);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user