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
🆕 Disconnection handler, when you got disconnected you automatic go back to the room
This commit is contained in:
@@ -5,6 +5,7 @@ import { IMessageEvent } from './IMessageEvent';
|
|||||||
export interface IConnection
|
export interface IConnection
|
||||||
{
|
{
|
||||||
init(socketUrl: string): void;
|
init(socketUrl: string): void;
|
||||||
|
dispose(): void;
|
||||||
ready(): void;
|
ready(): void;
|
||||||
authenticated(): void;
|
authenticated(): void;
|
||||||
send(...composers: IMessageComposer<unknown[]>[]): void;
|
send(...composers: IMessageComposer<unknown[]>[]): void;
|
||||||
|
|||||||
@@ -7,5 +7,6 @@ export interface IRoomSessionManager
|
|||||||
createSession(roomId: number, password?: string): boolean;
|
createSession(roomId: number, password?: string): boolean;
|
||||||
startSession(session: IRoomSession): boolean;
|
startSession(session: IRoomSession): boolean;
|
||||||
removeSession(id: number, openLandingView?: boolean): void;
|
removeSession(id: number, openLandingView?: boolean): void;
|
||||||
|
tryRestoreSession(): boolean;
|
||||||
viewerSession: IRoomSession;
|
viewerSession: IRoomSession;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ICommunicationManager, IConnection, IMessageConfiguration, IMessageEvent } from '@nitrots/api';
|
import { ICommunicationManager, IConnection, IMessageConfiguration, IMessageEvent } from '@nitrots/api';
|
||||||
import { GetConfiguration } from '@nitrots/configuration';
|
import { GetConfiguration } from '@nitrots/configuration';
|
||||||
import { GetEventDispatcher, NitroEventType } from '@nitrots/events';
|
import { GetEventDispatcher, NitroEvent, NitroEventType } from '@nitrots/events';
|
||||||
import { GetTickerTime } from '@nitrots/utils';
|
import { GetTickerTime, NitroLogger } from '@nitrots/utils';
|
||||||
import { NitroMessages } from './NitroMessages';
|
import { NitroMessages } from './NitroMessages';
|
||||||
import { SocketConnection } from './SocketConnection';
|
import { SocketConnection } from './SocketConnection';
|
||||||
import { AuthenticatedEvent, ClientHelloMessageComposer, ClientPingEvent, InfoRetrieveMessageComposer, PongMessageComposer, SSOTicketMessageComposer, UniqueIDMessageComposer } from './messages';
|
import { AuthenticatedEvent, ClientHelloMessageComposer, ClientPingEvent, InfoRetrieveMessageComposer, PongMessageComposer, SSOTicketMessageComposer, UniqueIDMessageComposer } from './messages';
|
||||||
@@ -17,6 +17,10 @@ export class CommunicationManager implements ICommunicationManager
|
|||||||
private _socketClosedCallback: () => void = null;
|
private _socketClosedCallback: () => void = null;
|
||||||
private _socketOpenedCallback: () => void = null;
|
private _socketOpenedCallback: () => void = null;
|
||||||
private _socketErrorCallback: () => void = null;
|
private _socketErrorCallback: () => void = null;
|
||||||
|
private _socketReconnectedCallback: () => void = null;
|
||||||
|
|
||||||
|
private _machineId: string = null;
|
||||||
|
private _initResolved: boolean = false;
|
||||||
|
|
||||||
private getGpu(): string {
|
private getGpu(): string {
|
||||||
const e = document.createElement('canvas');
|
const e = document.createElement('canvas');
|
||||||
@@ -85,6 +89,15 @@ export class CommunicationManager implements ICommunicationManager
|
|||||||
return uniqueId == null ? 'FAILED' : `IID-${uniqueId}`;
|
return uniqueId == null ? 'FAILED' : `IID-${uniqueId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sendHandshake(): void
|
||||||
|
{
|
||||||
|
if(!this._machineId) this._machineId = this.generateMachineID();
|
||||||
|
|
||||||
|
this._connection.send(new ClientHelloMessageComposer(null, null, null, null));
|
||||||
|
this._connection.send(new SSOTicketMessageComposer(GetConfiguration().getValue('sso.ticket', null), GetTickerTime()));
|
||||||
|
this._connection.send(new UniqueIDMessageComposer(this._machineId, '', ''));
|
||||||
|
}
|
||||||
|
|
||||||
constructor()
|
constructor()
|
||||||
{
|
{
|
||||||
this._connection.registerMessages(this._messages);
|
this._connection.registerMessages(this._messages);
|
||||||
@@ -99,6 +112,17 @@ export class CommunicationManager implements ICommunicationManager
|
|||||||
};
|
};
|
||||||
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_CLOSED, this._socketClosedCallback);
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_CLOSED, this._socketClosedCallback);
|
||||||
|
|
||||||
|
// Handle reconnection - re-authenticate when socket reconnects
|
||||||
|
this._socketReconnectedCallback = () =>
|
||||||
|
{
|
||||||
|
NitroLogger.log('[CommunicationManager] Socket reconnected, re-authenticating...');
|
||||||
|
|
||||||
|
if(GetConfiguration().getValue<boolean>('system.pong.manually', false)) this.startPong();
|
||||||
|
|
||||||
|
this.sendHandshake();
|
||||||
|
};
|
||||||
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_RECONNECTED, this._socketReconnectedCallback);
|
||||||
|
|
||||||
return new Promise((resolve, reject) =>
|
return new Promise((resolve, reject) =>
|
||||||
{
|
{
|
||||||
// Store callback for cleanup
|
// Store callback for cleanup
|
||||||
@@ -106,18 +130,14 @@ export class CommunicationManager implements ICommunicationManager
|
|||||||
{
|
{
|
||||||
if(GetConfiguration().getValue<boolean>('system.pong.manually', false)) this.startPong();
|
if(GetConfiguration().getValue<boolean>('system.pong.manually', false)) this.startPong();
|
||||||
|
|
||||||
const machineId = this.generateMachineID();
|
this.sendHandshake();
|
||||||
|
|
||||||
this._connection.send(new ClientHelloMessageComposer(null, null, null, null));
|
|
||||||
this._connection.send(new SSOTicketMessageComposer(GetConfiguration().getValue('sso.ticket', null), GetTickerTime()));
|
|
||||||
this._connection.send(new UniqueIDMessageComposer(machineId, '', ''));
|
|
||||||
};
|
};
|
||||||
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_OPENED, this._socketOpenedCallback);
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_OPENED, this._socketOpenedCallback);
|
||||||
|
|
||||||
// Store callback for cleanup
|
// Store callback for cleanup
|
||||||
this._socketErrorCallback = () =>
|
this._socketErrorCallback = () =>
|
||||||
{
|
{
|
||||||
reject();
|
if(!this._initResolved) reject();
|
||||||
};
|
};
|
||||||
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_ERROR, this._socketErrorCallback);
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_ERROR, this._socketErrorCallback);
|
||||||
|
|
||||||
@@ -125,11 +145,30 @@ export class CommunicationManager implements ICommunicationManager
|
|||||||
const pingEvent = new ClientPingEvent((event: ClientPingEvent) => this.sendPong());
|
const pingEvent = new ClientPingEvent((event: ClientPingEvent) => this.sendPong());
|
||||||
const authEvent = new AuthenticatedEvent((event: AuthenticatedEvent) =>
|
const authEvent = new AuthenticatedEvent((event: AuthenticatedEvent) =>
|
||||||
{
|
{
|
||||||
|
const isReconnect = this._initResolved;
|
||||||
|
|
||||||
|
NitroLogger.log('[CommunicationManager] AuthenticatedEvent received (isReconnect=' + isReconnect + ')');
|
||||||
|
|
||||||
this._connection.authenticated();
|
this._connection.authenticated();
|
||||||
|
|
||||||
|
if(!this._initResolved)
|
||||||
|
{
|
||||||
|
this._initResolved = true;
|
||||||
resolve();
|
resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isReconnect)
|
||||||
|
{
|
||||||
|
this._connection.ready();
|
||||||
|
}
|
||||||
|
|
||||||
event.connection.send(new InfoRetrieveMessageComposer());
|
event.connection.send(new InfoRetrieveMessageComposer());
|
||||||
|
|
||||||
|
if(isReconnect)
|
||||||
|
{
|
||||||
|
NitroLogger.log('[CommunicationManager] Dispatching SOCKET_REAUTHENTICATED');
|
||||||
|
GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_REAUTHENTICATED));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this._messageEvents.push(pingEvent, authEvent);
|
this._messageEvents.push(pingEvent, authEvent);
|
||||||
@@ -164,6 +203,12 @@ export class CommunicationManager implements ICommunicationManager
|
|||||||
this._socketErrorCallback = null;
|
this._socketErrorCallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this._socketReconnectedCallback)
|
||||||
|
{
|
||||||
|
GetEventDispatcher().removeEventListener(NitroEventType.SOCKET_RECONNECTED, this._socketReconnectedCallback);
|
||||||
|
this._socketReconnectedCallback = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove message events
|
// Remove message events
|
||||||
for(const event of this._messageEvents)
|
for(const event of this._messageEvents)
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
|||||||
import { ICodec, IConnection, IMessageComposer, IMessageConfiguration, IMessageDataWrapper, IMessageEvent, WebSocketEventEnum } from '@nitrots/api';
|
import { ICodec, IConnection, IMessageComposer, IMessageConfiguration, IMessageDataWrapper, IMessageEvent, WebSocketEventEnum } from '@nitrots/api';
|
||||||
import { GetEventDispatcher, NitroEvent, NitroEventType } from '@nitrots/events';
|
import { GetEventDispatcher, NitroEvent, NitroEventType, ReconnectEvent } from '@nitrots/events';
|
||||||
import { NitroLogger } from '@nitrots/utils';
|
import { NitroLogger } from '@nitrots/utils';
|
||||||
import { EvaWireFormat } from './codec';
|
import { EvaWireFormat } from './codec';
|
||||||
import { MessageClassManager } from './messages';
|
import { MessageClassManager } from './messages';
|
||||||
@@ -23,19 +23,39 @@ export class SocketConnection implements IConnection
|
|||||||
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 _reconnectAttempt: number = 0;
|
||||||
|
private _reconnectTimer: ReturnType<typeof setTimeout> = null;
|
||||||
|
private _isReconnecting: boolean = false;
|
||||||
|
private _intentionalClose: boolean = false;
|
||||||
|
private _wasAuthenticated: boolean = false;
|
||||||
|
|
||||||
|
public static readonly MAX_RECONNECT_ATTEMPTS: number = 7;
|
||||||
|
public static readonly BASE_RECONNECT_DELAY_MS: number = 1000;
|
||||||
|
public static readonly MAX_RECONNECT_DELAY_MS: number = 30000;
|
||||||
|
|
||||||
public init(socketUrl: string): void
|
public init(socketUrl: string): void
|
||||||
{
|
{
|
||||||
if(!socketUrl || !socketUrl.length) return;
|
if(!socketUrl || !socketUrl.length) return;
|
||||||
|
|
||||||
|
this._socketUrl = socketUrl;
|
||||||
|
this._intentionalClose = false;
|
||||||
|
|
||||||
|
this.createSocket(socketUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createSocket(socketUrl: string): void
|
||||||
|
{
|
||||||
this._dataBuffer = new ArrayBuffer(0);
|
this._dataBuffer = new ArrayBuffer(0);
|
||||||
|
|
||||||
this._socket = new WebSocket(socketUrl);
|
this._socket = new WebSocket(socketUrl);
|
||||||
this._socket.binaryType = 'arraybuffer';
|
this._socket.binaryType = 'arraybuffer';
|
||||||
|
|
||||||
// Store callbacks for cleanup
|
// Store callbacks for cleanup
|
||||||
this._onOpenCallback = () => GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_OPENED));
|
this._onOpenCallback = () => this.onSocketOpened();
|
||||||
this._onCloseCallback = () => GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_CLOSED));
|
this._onCloseCallback = (event: Event) => this.onSocketClosed(event as CloseEvent);
|
||||||
this._onErrorCallback = () => GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_ERROR));
|
this._onErrorCallback = () => this.onSocketError();
|
||||||
this._onMessageCallback = (event: MessageEvent) =>
|
this._onMessageCallback = (event: MessageEvent) =>
|
||||||
{
|
{
|
||||||
this._dataBuffer = this.concatArrayBuffers(this._dataBuffer, event.data);
|
this._dataBuffer = this.concatArrayBuffers(this._dataBuffer, event.data);
|
||||||
@@ -48,29 +68,152 @@ export class SocketConnection implements IConnection
|
|||||||
this._socket.addEventListener(WebSocketEventEnum.CONNECTION_MESSAGE, this._onMessageCallback);
|
this._socket.addEventListener(WebSocketEventEnum.CONNECTION_MESSAGE, this._onMessageCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void
|
private onSocketOpened(): void
|
||||||
{
|
{
|
||||||
if(this._socket)
|
if(this._isReconnecting)
|
||||||
{
|
{
|
||||||
// Remove all event listeners
|
NitroLogger.log('[SocketConnection] Reconnected successfully after ' + this._reconnectAttempt + ' attempt(s)');
|
||||||
|
|
||||||
|
this._reconnectAttempt = 0;
|
||||||
|
this._isReconnecting = false;
|
||||||
|
|
||||||
|
GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_RECONNECTED));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_OPENED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onSocketClosed(event: CloseEvent): void
|
||||||
|
{
|
||||||
|
NitroLogger.log('[SocketConnection] Socket closed, code: ' + (event?.code ?? 'unknown') + ', reason: ' + (event?.reason || 'none'));
|
||||||
|
|
||||||
|
if(this._intentionalClose)
|
||||||
|
{
|
||||||
|
GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_CLOSED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const code = event?.code ?? 0;
|
||||||
|
|
||||||
|
if(code === 1000 || code === 1001)
|
||||||
|
{
|
||||||
|
NitroLogger.log('[SocketConnection] Server closed cleanly (code ' + code + ') - not reconnecting');
|
||||||
|
|
||||||
|
this._isAuthenticated = false;
|
||||||
|
this._isReady = false;
|
||||||
|
|
||||||
|
GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_CLOSED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._isAuthenticated) this._wasAuthenticated = true;
|
||||||
|
|
||||||
|
this._isAuthenticated = false;
|
||||||
|
this._isReady = false;
|
||||||
|
this._pendingClientMessages = [];
|
||||||
|
this._pendingServerMessages = [];
|
||||||
|
|
||||||
|
this.attemptReconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private onSocketError(): void
|
||||||
|
{
|
||||||
|
if(this._isReconnecting)
|
||||||
|
{
|
||||||
|
NitroLogger.log('[SocketConnection] Reconnect attempt ' + this._reconnectAttempt + ' failed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this._wasAuthenticated && !this._isAuthenticated)
|
||||||
|
{
|
||||||
|
GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_ERROR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private attemptReconnect(): void
|
||||||
|
{
|
||||||
|
if(this._reconnectAttempt >= SocketConnection.MAX_RECONNECT_ATTEMPTS)
|
||||||
|
{
|
||||||
|
NitroLogger.log('[SocketConnection] Max reconnect attempts reached (' + SocketConnection.MAX_RECONNECT_ATTEMPTS + ')');
|
||||||
|
|
||||||
|
this._isReconnecting = false;
|
||||||
|
this._wasAuthenticated = false;
|
||||||
|
|
||||||
|
GetEventDispatcher().dispatchEvent(new ReconnectEvent(
|
||||||
|
NitroEventType.SOCKET_RECONNECT_FAILED,
|
||||||
|
this._reconnectAttempt,
|
||||||
|
SocketConnection.MAX_RECONNECT_ATTEMPTS
|
||||||
|
));
|
||||||
|
|
||||||
|
GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_CLOSED));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isReconnecting = true;
|
||||||
|
this._reconnectAttempt++;
|
||||||
|
|
||||||
|
const delay = Math.min(
|
||||||
|
SocketConnection.BASE_RECONNECT_DELAY_MS * Math.pow(2, this._reconnectAttempt - 1) + Math.random() * 1000,
|
||||||
|
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(
|
||||||
|
NitroEventType.SOCKET_RECONNECTING,
|
||||||
|
this._reconnectAttempt,
|
||||||
|
SocketConnection.MAX_RECONNECT_ATTEMPTS
|
||||||
|
));
|
||||||
|
|
||||||
|
this._reconnectTimer = setTimeout(() =>
|
||||||
|
{
|
||||||
|
this._reconnectTimer = null;
|
||||||
|
|
||||||
|
this.cleanupSocket();
|
||||||
|
|
||||||
|
this.createSocket(this._socketUrl);
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
private cleanupSocket(): void
|
||||||
|
{
|
||||||
|
if(!this._socket) return;
|
||||||
|
|
||||||
if(this._onOpenCallback) this._socket.removeEventListener(WebSocketEventEnum.CONNECTION_OPENED, this._onOpenCallback);
|
if(this._onOpenCallback) this._socket.removeEventListener(WebSocketEventEnum.CONNECTION_OPENED, this._onOpenCallback);
|
||||||
if(this._onCloseCallback) this._socket.removeEventListener(WebSocketEventEnum.CONNECTION_CLOSED, this._onCloseCallback);
|
if(this._onCloseCallback) this._socket.removeEventListener(WebSocketEventEnum.CONNECTION_CLOSED, this._onCloseCallback);
|
||||||
if(this._onErrorCallback) this._socket.removeEventListener(WebSocketEventEnum.CONNECTION_ERROR, this._onErrorCallback);
|
if(this._onErrorCallback) this._socket.removeEventListener(WebSocketEventEnum.CONNECTION_ERROR, this._onErrorCallback);
|
||||||
if(this._onMessageCallback) this._socket.removeEventListener(WebSocketEventEnum.CONNECTION_MESSAGE, this._onMessageCallback);
|
if(this._onMessageCallback) this._socket.removeEventListener(WebSocketEventEnum.CONNECTION_MESSAGE, this._onMessageCallback);
|
||||||
|
|
||||||
// Close socket if still open
|
|
||||||
if(this._socket.readyState === WebSocket.OPEN || this._socket.readyState === WebSocket.CONNECTING)
|
if(this._socket.readyState === WebSocket.OPEN || this._socket.readyState === WebSocket.CONNECTING)
|
||||||
{
|
{
|
||||||
this._socket.close();
|
try { this._socket.close(); } catch(e) { /* ignore */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
this._socket = null;
|
this._socket = null;
|
||||||
}
|
|
||||||
|
|
||||||
this._onOpenCallback = null;
|
this._onOpenCallback = null;
|
||||||
this._onCloseCallback = null;
|
this._onCloseCallback = null;
|
||||||
this._onErrorCallback = null;
|
this._onErrorCallback = null;
|
||||||
this._onMessageCallback = null;
|
this._onMessageCallback = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
this._intentionalClose = true;
|
||||||
|
|
||||||
|
if(this._reconnectTimer)
|
||||||
|
{
|
||||||
|
clearTimeout(this._reconnectTimer);
|
||||||
|
this._reconnectTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isReconnecting = false;
|
||||||
|
this._reconnectAttempt = 0;
|
||||||
|
this._wasAuthenticated = false;
|
||||||
|
|
||||||
|
this.cleanupSocket();
|
||||||
|
|
||||||
this._pendingClientMessages = [];
|
this._pendingClientMessages = [];
|
||||||
this._pendingServerMessages = [];
|
this._pendingServerMessages = [];
|
||||||
@@ -142,7 +285,7 @@ export class SocketConnection implements IConnection
|
|||||||
|
|
||||||
private write(buffer: ArrayBuffer): void
|
private write(buffer: ArrayBuffer): void
|
||||||
{
|
{
|
||||||
if(this._socket.readyState !== WebSocket.OPEN) return;
|
if(!this._socket || this._socket.readyState !== WebSocket.OPEN) return;
|
||||||
|
|
||||||
this._socket.send(buffer);
|
this._socket.send(buffer);
|
||||||
}
|
}
|
||||||
@@ -286,6 +429,16 @@ export class SocketConnection implements IConnection
|
|||||||
return this._isAuthenticated;
|
return this._isAuthenticated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get isReconnecting(): boolean
|
||||||
|
{
|
||||||
|
return this._isReconnecting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get wasAuthenticated(): boolean
|
||||||
|
{
|
||||||
|
return this._wasAuthenticated;
|
||||||
|
}
|
||||||
|
|
||||||
public get dataBuffer(): ArrayBuffer
|
public get dataBuffer(): ArrayBuffer
|
||||||
{
|
{
|
||||||
return this._dataBuffer;
|
return this._dataBuffer;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
export class OutgoingHeader
|
export class OutgoingHeader
|
||||||
{
|
{
|
||||||
public static CLICK_FURNI = 6002;
|
public static CLICK_FURNI = 6002;
|
||||||
public static CLICK_USER = 10020;
|
|
||||||
|
|
||||||
public static ACHIEVEMENT_LIST = 219;
|
public static ACHIEVEMENT_LIST = 219;
|
||||||
public static AUTHENTICATION = -1;
|
public static AUTHENTICATION = -1;
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import { IMessageComposer } from '@nitrots/api';
|
|
||||||
|
|
||||||
export class ClickUserMessageComposer implements IMessageComposer<ConstructorParameters<typeof ClickUserMessageComposer>>
|
|
||||||
{
|
|
||||||
private _data: ConstructorParameters<typeof ClickUserMessageComposer>;
|
|
||||||
|
|
||||||
constructor(roomUnitId: number)
|
|
||||||
{
|
|
||||||
this._data = [ roomUnitId ];
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMessageArray()
|
|
||||||
{
|
|
||||||
return this._data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose(): void
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ export * from './BotPlaceComposer';
|
|||||||
export * from './BotRemoveComposer';
|
export * from './BotRemoveComposer';
|
||||||
export * from './BotSkillSaveComposer';
|
export * from './BotSkillSaveComposer';
|
||||||
export * from './ClickFurniMessageComposer';
|
export * from './ClickFurniMessageComposer';
|
||||||
export * from './ClickUserMessageComposer';
|
|
||||||
export * from './CompostPlantMessageComposer';
|
export * from './CompostPlantMessageComposer';
|
||||||
export * from './GetItemDataComposer';
|
export * from './GetItemDataComposer';
|
||||||
export * from './HarvestPetMessageComposer';
|
export * from './HarvestPetMessageComposer';
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ export class NitroEventType
|
|||||||
public static readonly SOCKET_CLOSED = 'SOCKET_CLOSED';
|
public static readonly SOCKET_CLOSED = 'SOCKET_CLOSED';
|
||||||
public static readonly SOCKET_ERROR = 'SOCKET_ERROR';
|
public static readonly SOCKET_ERROR = 'SOCKET_ERROR';
|
||||||
public static readonly SOCKET_CONNECTED = 'SOCKET_CONNECTED';
|
public static readonly SOCKET_CONNECTED = 'SOCKET_CONNECTED';
|
||||||
|
public static readonly SOCKET_RECONNECTING = 'SOCKET_RECONNECTING';
|
||||||
|
public static readonly SOCKET_RECONNECTED = 'SOCKET_RECONNECTED';
|
||||||
|
public static readonly SOCKET_RECONNECT_FAILED = 'SOCKET_RECONNECT_FAILED';
|
||||||
|
public static readonly SOCKET_REAUTHENTICATED = 'SOCKET_REAUTHENTICATED';
|
||||||
public static readonly AVATAR_ASSET_DOWNLOADED = 'AVATAR_ASSET_DOWNLOADED';
|
public static readonly AVATAR_ASSET_DOWNLOADED = 'AVATAR_ASSET_DOWNLOADED';
|
||||||
public static readonly AVATAR_ASSET_LOADED = 'AVATAR_ASSET_LOADED';
|
public static readonly AVATAR_ASSET_LOADED = 'AVATAR_ASSET_LOADED';
|
||||||
public static readonly AVATAR_EFFECT_DOWNLOADED = 'AVATAR_EFFECT_DOWNLOADED';
|
public static readonly AVATAR_EFFECT_DOWNLOADED = 'AVATAR_EFFECT_DOWNLOADED';
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { NitroEvent } from './NitroEvent';
|
||||||
|
|
||||||
|
export class ReconnectEvent extends NitroEvent
|
||||||
|
{
|
||||||
|
private _attempt: number;
|
||||||
|
private _maxAttempts: number;
|
||||||
|
|
||||||
|
constructor(type: string, attempt: number = 0, maxAttempts: number = 0)
|
||||||
|
{
|
||||||
|
super(type);
|
||||||
|
|
||||||
|
this._attempt = attempt;
|
||||||
|
this._maxAttempts = maxAttempts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get attempt(): number
|
||||||
|
{
|
||||||
|
return this._attempt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get maxAttempts(): number
|
||||||
|
{
|
||||||
|
return this._maxAttempts;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './ConfigurationEvent';
|
export * from './ConfigurationEvent';
|
||||||
export * from './MessageEvent';
|
export * from './MessageEvent';
|
||||||
export * from './NitroEvent';
|
export * from './NitroEvent';
|
||||||
|
export * from './ReconnectEvent';
|
||||||
export * from './SocketConnectionEvent';
|
export * from './SocketConnectionEvent';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { IFurnitureStackingHeightMap, ILegacyWallGeometry, IObjectData, IRoomCanvasMouseListener, IRoomEngineServices, IRoomGeometry, IRoomObject, IRoomObjectController, IRoomObjectEventManager, ISelectedRoomObjectData, IVector3D, MouseEventType, RoomObjectCategory, RoomObjectOperationType, RoomObjectPlacementSource, RoomObjectType, RoomObjectUserType, RoomObjectVariable } from '@nitrots/api';
|
import { IFurnitureStackingHeightMap, ILegacyWallGeometry, IObjectData, IRoomCanvasMouseListener, IRoomEngineServices, IRoomGeometry, IRoomObject, IRoomObjectController, IRoomObjectEventManager, ISelectedRoomObjectData, IVector3D, MouseEventType, RoomObjectCategory, RoomObjectOperationType, RoomObjectPlacementSource, RoomObjectType, RoomObjectUserType, RoomObjectVariable } from '@nitrots/api';
|
||||||
import { BotPlaceComposer, ClickFurniMessageComposer, ClickUserMessageComposer, FurnitureColorWheelComposer, FurnitureDiceActivateComposer, FurnitureDiceDeactivateComposer, FurnitureFloorUpdateComposer, FurnitureGroupInfoComposer, FurnitureMultiStateComposer, FurnitureOneWayDoorComposer, FurniturePickupComposer, FurniturePlaceComposer, FurniturePostItPlaceComposer, FurnitureRandomStateComposer, FurnitureWallMultiStateComposer, FurnitureWallUpdateComposer, GetCommunication, GetItemDataComposer, GetResolutionAchievementsMessageComposer, PetMoveComposer, PetPlaceComposer, RemoveWallItemComposer, RoomUnitLookComposer, RoomUnitWalkComposer, SetItemDataMessageComposer, SetObjectDataMessageComposer } from '@nitrots/communication';
|
import { BotPlaceComposer, ClickFurniMessageComposer, FurnitureColorWheelComposer, FurnitureDiceActivateComposer, FurnitureDiceDeactivateComposer, FurnitureFloorUpdateComposer, FurnitureGroupInfoComposer, FurnitureMultiStateComposer, FurnitureOneWayDoorComposer, FurniturePickupComposer, FurniturePlaceComposer, FurniturePostItPlaceComposer, FurnitureRandomStateComposer, FurnitureWallMultiStateComposer, FurnitureWallUpdateComposer, GetCommunication, GetItemDataComposer, GetResolutionAchievementsMessageComposer, PetMoveComposer, PetPlaceComposer, RemoveWallItemComposer, RoomUnitLookComposer, RoomUnitWalkComposer, SetItemDataMessageComposer, SetObjectDataMessageComposer } from '@nitrots/communication';
|
||||||
import { GetConfiguration } from '@nitrots/configuration';
|
import { GetConfiguration } from '@nitrots/configuration';
|
||||||
import { GetEventDispatcher, RoomEngineDimmerStateEvent, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomEngineObjectPlacedOnUserEvent, RoomEngineObjectPlaySoundEvent, RoomEngineRoomAdEvent, RoomEngineSamplePlaybackEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomObjectBadgeAssetEvent, RoomObjectDataRequestEvent, RoomObjectDimmerStateUpdateEvent, RoomObjectEvent, RoomObjectFloorHoleEvent, RoomObjectFurnitureActionEvent, RoomObjectHSLColorEnableEvent, RoomObjectHSLColorEnabledEvent, RoomObjectMouseEvent, RoomObjectMoveEvent, RoomObjectPlaySoundIdEvent, RoomObjectRoomAdEvent, RoomObjectSamplePlaybackEvent, RoomObjectSoundMachineEvent, RoomObjectStateChangedEvent, RoomObjectTileMouseEvent, RoomObjectWallMouseEvent, RoomObjectWidgetRequestEvent, RoomSpriteMouseEvent } from '@nitrots/events';
|
import { GetEventDispatcher, RoomEngineDimmerStateEvent, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomEngineObjectPlacedOnUserEvent, RoomEngineObjectPlaySoundEvent, RoomEngineRoomAdEvent, RoomEngineSamplePlaybackEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomObjectBadgeAssetEvent, RoomObjectDataRequestEvent, RoomObjectDimmerStateUpdateEvent, RoomObjectEvent, RoomObjectFloorHoleEvent, RoomObjectFurnitureActionEvent, RoomObjectHSLColorEnableEvent, RoomObjectHSLColorEnabledEvent, RoomObjectMouseEvent, RoomObjectMoveEvent, RoomObjectPlaySoundIdEvent, RoomObjectRoomAdEvent, RoomObjectSamplePlaybackEvent, RoomObjectSoundMachineEvent, RoomObjectStateChangedEvent, RoomObjectTileMouseEvent, RoomObjectWallMouseEvent, RoomObjectWidgetRequestEvent, RoomSpriteMouseEvent } from '@nitrots/events';
|
||||||
import { GetRoomSessionManager, GetSessionDataManager } from '@nitrots/session';
|
import { GetRoomSessionManager, GetSessionDataManager } from '@nitrots/session';
|
||||||
@@ -297,7 +297,7 @@ export class RoomObjectEventHandler implements IRoomCanvasMouseListener, IRoomOb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private clickRoomObject(event: RoomObjectMouseEvent, operation: string): void
|
private clickRoomObject(event: RoomObjectMouseEvent): void
|
||||||
{
|
{
|
||||||
if(!event || event.altKey || event.ctrlKey || event.shiftKey) return;
|
if(!event || event.altKey || event.ctrlKey || event.shiftKey) return;
|
||||||
|
|
||||||
@@ -319,25 +319,20 @@ export class RoomObjectEventHandler implements IRoomCanvasMouseListener, IRoomOb
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((category === RoomObjectCategory.UNIT) && (operation === RoomObjectOperationType.OBJECT_UNDEFINED) && (objectType === RoomObjectUserType.USER))
|
|
||||||
{
|
|
||||||
GetCommunication().connection.send(new ClickUserMessageComposer(objectId));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleRoomObjectMouseClickEvent(event: RoomObjectMouseEvent, roomId: number): void
|
private handleRoomObjectMouseClickEvent(event: RoomObjectMouseEvent, roomId: number): void
|
||||||
{
|
{
|
||||||
if(!event) return;
|
if(!event) return;
|
||||||
|
|
||||||
|
this.clickRoomObject(event);
|
||||||
|
|
||||||
let operation = RoomObjectOperationType.OBJECT_UNDEFINED;
|
let operation = RoomObjectOperationType.OBJECT_UNDEFINED;
|
||||||
|
|
||||||
const selectedData = this.getSelectedRoomObjectData(roomId);
|
const selectedData = this.getSelectedRoomObjectData(roomId);
|
||||||
|
|
||||||
if(selectedData) operation = selectedData.operation;
|
if(selectedData) operation = selectedData.operation;
|
||||||
|
|
||||||
this.clickRoomObject(event, operation);
|
|
||||||
|
|
||||||
let didWalk = false;
|
let didWalk = false;
|
||||||
let didMove = false;
|
let didMove = false;
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ export class FloorplanEditor
|
|||||||
|
|
||||||
private _image: HTMLImageElement;
|
private _image: HTMLImageElement;
|
||||||
|
|
||||||
public onTilemapChange: (() => void) | null = null;
|
|
||||||
|
|
||||||
constructor()
|
constructor()
|
||||||
{
|
{
|
||||||
const width = TILE_SIZE * MAX_NUM_TILE_PER_AXIS + 20;
|
const width = TILE_SIZE * MAX_NUM_TILE_PER_AXIS + 20;
|
||||||
@@ -299,8 +297,6 @@ export class FloorplanEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.renderSquareSelectionPreview();
|
this.renderSquareSelectionPreview();
|
||||||
|
|
||||||
if(this.onTilemapChange) this.onTilemapChange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderSquareSelectionPreview(): void
|
private renderSquareSelectionPreview(): void
|
||||||
@@ -477,7 +473,6 @@ export class FloorplanEditor
|
|||||||
this._squareSelectStart = null;
|
this._squareSelectStart = null;
|
||||||
this._squareSelectEnd = null;
|
this._squareSelectEnd = null;
|
||||||
this.clearCanvas();
|
this.clearCanvas();
|
||||||
this.onTilemapChange = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,49 @@
|
|||||||
import { IRoomHandlerListener, IRoomSession, IRoomSessionManager } from '@nitrots/api';
|
import { IRoomHandlerListener, IRoomSession, IRoomSessionManager } from '@nitrots/api';
|
||||||
import { GetCommunication } from '@nitrots/communication';
|
import { GetCommunication } from '@nitrots/communication';
|
||||||
import { GetEventDispatcher, RoomSessionEvent } from '@nitrots/events';
|
import { GetEventDispatcher, NitroEventType, RoomSessionEvent } from '@nitrots/events';
|
||||||
|
import { NitroLogger } from '@nitrots/utils';
|
||||||
import { RoomSession } from './RoomSession';
|
import { RoomSession } from './RoomSession';
|
||||||
import { BaseHandler, GenericErrorHandler, PetPackageHandler, PollHandler, RoomChatHandler, RoomDataHandler, RoomDimmerPresetsHandler, RoomPermissionsHandler, RoomPresentHandler, RoomSessionHandler, RoomUsersHandler, WordQuizHandler } from './handler';
|
import { BaseHandler, GenericErrorHandler, PetPackageHandler, PollHandler, RoomChatHandler, RoomDataHandler, RoomDimmerPresetsHandler, RoomPermissionsHandler, RoomPresentHandler, RoomSessionHandler, RoomUsersHandler, WordQuizHandler } from './handler';
|
||||||
|
|
||||||
|
const STORAGE_KEY_ROOM_ID = 'nitro.session.lastRoomId';
|
||||||
|
const STORAGE_KEY_ROOM_PASSWORD = 'nitro.session.lastRoomPassword';
|
||||||
|
|
||||||
export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerListener
|
export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerListener
|
||||||
{
|
{
|
||||||
private _handlers: BaseHandler[] = [];
|
private _handlers: BaseHandler[] = [];
|
||||||
private _sessions: Map<string, IRoomSession> = new Map();
|
private _sessions: Map<string, IRoomSession> = new Map();
|
||||||
private _pendingSession: IRoomSession = null;
|
private _pendingSession: IRoomSession = null;
|
||||||
|
|
||||||
private _sessionStarting: boolean = false;
|
private _sessionStarting: boolean = false;
|
||||||
private _viewerSession: IRoomSession = null;
|
private _viewerSession: IRoomSession = null;
|
||||||
|
private _lastRoomId: number = -1;
|
||||||
|
private _lastRoomPassword: string = null;
|
||||||
|
private _isReconnecting: boolean = false;
|
||||||
|
private _reconnectGuardTimer: ReturnType<typeof setTimeout> = null;
|
||||||
|
|
||||||
public async init(): Promise<void>
|
public async init(): Promise<void>
|
||||||
{
|
{
|
||||||
this.createHandlers();
|
this.createHandlers();
|
||||||
this.processPendingSession();
|
this.processPendingSession();
|
||||||
|
this.setupReconnectListener();
|
||||||
|
this.checkPersistedRoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkPersistedRoom(): void
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const storedRoomId = sessionStorage.getItem(STORAGE_KEY_ROOM_ID);
|
||||||
|
|
||||||
|
if(!storedRoomId) return;
|
||||||
|
|
||||||
|
const roomId = parseInt(storedRoomId, 10);
|
||||||
|
|
||||||
|
if(isNaN(roomId) || roomId <= 0) return;
|
||||||
|
this._lastRoomId = roomId;
|
||||||
|
this._lastRoomPassword = sessionStorage.getItem(STORAGE_KEY_ROOM_PASSWORD) || null;
|
||||||
|
this._isReconnecting = true;
|
||||||
|
}
|
||||||
|
catch(e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
private createHandlers(): void
|
private createHandlers(): void
|
||||||
@@ -40,6 +67,158 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private setupReconnectListener(): void
|
||||||
|
{
|
||||||
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_RECONNECTING, () =>
|
||||||
|
{
|
||||||
|
this._isReconnecting = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_RECONNECTED, () =>
|
||||||
|
{
|
||||||
|
this.clearGuardTimer();
|
||||||
|
this._reconnectGuardTimer = setTimeout(() =>
|
||||||
|
{
|
||||||
|
this._reconnectGuardTimer = null;
|
||||||
|
|
||||||
|
if(!this._isReconnecting) return;
|
||||||
|
this.attemptRoomReEntry();
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
|
||||||
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_REAUTHENTICATED, () =>
|
||||||
|
{
|
||||||
|
this.clearGuardTimer();
|
||||||
|
this.attemptRoomReEntry();
|
||||||
|
});
|
||||||
|
|
||||||
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_RECONNECT_FAILED, () =>
|
||||||
|
{
|
||||||
|
this.clearGuardTimer();
|
||||||
|
this._isReconnecting = false;
|
||||||
|
this._lastRoomId = -1;
|
||||||
|
this._lastRoomPassword = null;
|
||||||
|
this.clearPersistedRoom();
|
||||||
|
});
|
||||||
|
|
||||||
|
GetEventDispatcher().addEventListener(NitroEventType.SOCKET_CLOSED, () =>
|
||||||
|
{
|
||||||
|
this.clearGuardTimer();
|
||||||
|
this._isReconnecting = false;
|
||||||
|
this._lastRoomId = -1;
|
||||||
|
this._lastRoomPassword = null;
|
||||||
|
this.clearPersistedRoom();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearGuardTimer(): void
|
||||||
|
{
|
||||||
|
if(this._reconnectGuardTimer)
|
||||||
|
{
|
||||||
|
clearTimeout(this._reconnectGuardTimer);
|
||||||
|
this._reconnectGuardTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private attemptRoomReEntry(): void
|
||||||
|
{
|
||||||
|
const roomId = this._lastRoomId;
|
||||||
|
const password = this._lastRoomPassword;
|
||||||
|
|
||||||
|
if(roomId <= 0)
|
||||||
|
{
|
||||||
|
this._isReconnecting = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sessions.clear();
|
||||||
|
this._viewerSession = null;
|
||||||
|
this.createSession(roomId, password);
|
||||||
|
this.clearGuardTimer();
|
||||||
|
this._reconnectGuardTimer = setTimeout(() =>
|
||||||
|
{
|
||||||
|
this._reconnectGuardTimer = null;
|
||||||
|
|
||||||
|
if(this._isReconnecting)
|
||||||
|
{
|
||||||
|
this._isReconnecting = false;
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public tryRestoreSession(): boolean
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const storedRoomId = sessionStorage.getItem(STORAGE_KEY_ROOM_ID);
|
||||||
|
|
||||||
|
if(!storedRoomId) return false;
|
||||||
|
|
||||||
|
const roomId = parseInt(storedRoomId, 10);
|
||||||
|
|
||||||
|
if(isNaN(roomId) || roomId <= 0) return false;
|
||||||
|
|
||||||
|
const password = sessionStorage.getItem(STORAGE_KEY_ROOM_PASSWORD) || null;
|
||||||
|
|
||||||
|
this._isReconnecting = true;
|
||||||
|
|
||||||
|
this.createSession(roomId, password);
|
||||||
|
|
||||||
|
this.clearGuardTimer();
|
||||||
|
this._reconnectGuardTimer = setTimeout(() =>
|
||||||
|
{
|
||||||
|
this._reconnectGuardTimer = null;
|
||||||
|
|
||||||
|
if(this._isReconnecting)
|
||||||
|
{
|
||||||
|
this._isReconnecting = false;
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private persistRoom(roomId: number, password: string): void
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(roomId > 0)
|
||||||
|
{
|
||||||
|
sessionStorage.setItem(STORAGE_KEY_ROOM_ID, roomId.toString());
|
||||||
|
|
||||||
|
if(password)
|
||||||
|
{
|
||||||
|
sessionStorage.setItem(STORAGE_KEY_ROOM_PASSWORD, password);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sessionStorage.removeItem(STORAGE_KEY_ROOM_PASSWORD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.clearPersistedRoom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearPersistedRoom(): void
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sessionStorage.removeItem(STORAGE_KEY_ROOM_ID);
|
||||||
|
sessionStorage.removeItem(STORAGE_KEY_ROOM_PASSWORD);
|
||||||
|
}
|
||||||
|
catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
private setHandlers(session: IRoomSession): void
|
private setHandlers(session: IRoomSession): void
|
||||||
{
|
{
|
||||||
if(!this._handlers || !this._handlers.length) return;
|
if(!this._handlers || !this._handlers.length) return;
|
||||||
@@ -92,6 +271,10 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
this._viewerSession = roomSession;
|
this._viewerSession = roomSession;
|
||||||
|
|
||||||
|
this._lastRoomId = roomSession.roomId;
|
||||||
|
this._lastRoomPassword = roomSession.password;
|
||||||
|
this.persistRoom(roomSession.roomId, roomSession.password);
|
||||||
|
|
||||||
this.startSession(this._viewerSession);
|
this.startSession(this._viewerSession);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -125,6 +308,18 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
this._sessions.delete(this.getRoomId(id));
|
this._sessions.delete(this.getRoomId(id));
|
||||||
|
|
||||||
|
if(openLandingView && !this._isReconnecting)
|
||||||
|
{
|
||||||
|
this._lastRoomId = -1;
|
||||||
|
this._lastRoomPassword = null;
|
||||||
|
this.clearPersistedRoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._isReconnecting)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GetEventDispatcher().dispatchEvent(new RoomSessionEvent(RoomSessionEvent.ENDED, session, openLandingView));
|
GetEventDispatcher().dispatchEvent(new RoomSessionEvent(RoomSessionEvent.ENDED, session, openLandingView));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,15 +327,34 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
{
|
{
|
||||||
const session = this.getSession(id);
|
const session = this.getSession(id);
|
||||||
|
|
||||||
if(!session) return;
|
if(!session)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case RoomSessionHandler.RS_CONNECTED:
|
case RoomSessionHandler.RS_CONNECTED:
|
||||||
|
if(this._isReconnecting)
|
||||||
|
{
|
||||||
|
this.clearGuardTimer();
|
||||||
|
this._isReconnecting = false;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case RoomSessionHandler.RS_READY:
|
case RoomSessionHandler.RS_READY:
|
||||||
|
|
||||||
|
if(this._isReconnecting)
|
||||||
|
{
|
||||||
|
this.clearGuardTimer();
|
||||||
|
this._isReconnecting = false;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case RoomSessionHandler.RS_DISCONNECTED:
|
case RoomSessionHandler.RS_DISCONNECTED:
|
||||||
|
|
||||||
|
if(this._isReconnecting) return;
|
||||||
|
|
||||||
this.removeSession(id);
|
this.removeSession(id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -158,6 +372,9 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList
|
|||||||
|
|
||||||
this._sessions.set(this.getRoomId(toRoomId), existing);
|
this._sessions.set(this.getRoomId(toRoomId), existing);
|
||||||
|
|
||||||
|
this._lastRoomId = toRoomId;
|
||||||
|
this.persistRoom(toRoomId, existing.password);
|
||||||
|
|
||||||
this.setHandlers(existing);
|
this.setHandlers(existing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export class RoomChatHandler extends BaseHandler
|
|||||||
|
|
||||||
if(!parser) return;
|
if(!parser) return;
|
||||||
|
|
||||||
GetEventDispatcher().dispatchEvent(new RoomSessionChatEvent(RoomSessionChatEvent.CHAT_EVENT, session, parser.giverUserId, '', RoomSessionChatEvent.CHAT_TYPE_HAND_ITEM_RECEIVED, SystemChatStyleEnum.GENERIC, [], null, parser.handItemType));
|
GetEventDispatcher().dispatchEvent(new RoomSessionChatEvent(RoomSessionChatEvent.CHAT_EVENT, session, parser.giverUserId, '', RoomSessionChatEvent.CHAT_TYPE_HAND_ITEM_RECEIVED, SystemChatStyleEnum.GENERIC, [], parser.handItemType));
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRespectReceivedEvent(event: RespectReceivedEvent): void
|
private onRespectReceivedEvent(event: RespectReceivedEvent): void
|
||||||
@@ -136,7 +136,7 @@ export class RoomChatHandler extends BaseHandler
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetEventDispatcher().dispatchEvent(new RoomSessionChatEvent(RoomSessionChatEvent.CHAT_EVENT, session, petData.roomIndex, '', chatType, SystemChatStyleEnum.GENERIC, [], null, userRoomIndex));
|
GetEventDispatcher().dispatchEvent(new RoomSessionChatEvent(RoomSessionChatEvent.CHAT_EVENT, session, petData.roomIndex, '', chatType, SystemChatStyleEnum.GENERIC, null, userRoomIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
private onFloodControlEvent(event: FloodControlEvent): void
|
private onFloodControlEvent(event: FloodControlEvent): void
|
||||||
@@ -168,6 +168,6 @@ export class RoomChatHandler extends BaseHandler
|
|||||||
|
|
||||||
if(!parser) return;
|
if(!parser) return;
|
||||||
|
|
||||||
GetEventDispatcher().dispatchEvent(new RoomSessionChatEvent(RoomSessionChatEvent.CHAT_EVENT, session, session.ownRoomIndex, '', RoomSessionChatEvent.CHAT_TYPE_MUTE_REMAINING, SystemChatStyleEnum.GENERIC, [], null, parser.seconds));
|
GetEventDispatcher().dispatchEvent(new RoomSessionChatEvent(RoomSessionChatEvent.CHAT_EVENT, session, session.ownRoomIndex, '', RoomSessionChatEvent.CHAT_TYPE_MUTE_REMAINING, SystemChatStyleEnum.GENERIC, [], parser.seconds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,14 +63,13 @@ export class WiredFilter extends Filter
|
|||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec4 currentColor = texture(uTexture, vTextureCoord);
|
vec4 currentColor = texture(uTexture, vTextureCoord);
|
||||||
vec3 colorLine = uLineColor;
|
vec3 colorLine = uLineColor * currentColor.a;
|
||||||
vec3 colorOverlay = uColor;
|
vec3 colorOverlay = uColor * currentColor.a;
|
||||||
|
|
||||||
if(currentColor.r == 0.0 && currentColor.g == 0.0 && currentColor.b == 0.0 && currentColor.a > 0.0) {
|
if(currentColor.r == 0.0 && currentColor.g == 0.0 && currentColor.b == 0.0 && currentColor.a > 0.0) {
|
||||||
finalColor = vec4(colorLine.r, colorLine.g, colorLine.b, currentColor.a);
|
finalColor = vec4(colorLine.r, colorLine.g, colorLine.b, currentColor.a);
|
||||||
} else if(currentColor.a > 0.0) {
|
} else if(currentColor.a > 0.0) {
|
||||||
vec3 blendedOverlay = mix(currentColor.rgb, colorOverlay, 0.28);
|
finalColor = vec4(colorOverlay.r, colorOverlay.g, colorOverlay.b, currentColor.a);
|
||||||
finalColor = vec4(blendedOverlay.r, blendedOverlay.g, blendedOverlay.b, currentColor.a);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
|||||||
Reference in New Issue
Block a user