diff --git a/packages/communication/src/SocketConnection.ts b/packages/communication/src/SocketConnection.ts index d252924..fc4dac5 100644 --- a/packages/communication/src/SocketConnection.ts +++ b/packages/communication/src/SocketConnection.ts @@ -11,19 +11,13 @@ export class SocketConnection implements IConnection private _codec: ICodec = new EvaWireFormat(); private _dataBuffer: ArrayBuffer = null; private _isReady: boolean = false; - private _pendingClientMessages: IMessageComposer[] = []; private _pendingServerMessages: IMessageDataWrapper[] = []; - private _isAuthenticated: boolean = false; - - // Store callbacks for cleanup private _onOpenCallback: (event: Event) => void = null; private _onCloseCallback: (event: Event) => void = null; private _onErrorCallback: (event: Event) => void = null; private _onMessageCallback: (event: MessageEvent) => void = null; - - // Reconnection state private _socketUrl: string = null; private _reconnectAttempt: number = 0; private _reconnectTimer: ReturnType = null; @@ -51,8 +45,6 @@ export class SocketConnection implements IConnection this._socket = new WebSocket(socketUrl); this._socket.binaryType = 'arraybuffer'; - - // Store callbacks for cleanup this._onOpenCallback = () => this.onSocketOpened(); this._onCloseCallback = (event: Event) => this.onSocketClosed(event as CloseEvent); this._onErrorCallback = () => this.onSocketError(); @@ -72,8 +64,6 @@ export class SocketConnection implements IConnection { if(this._isReconnecting) { - NitroLogger.log('[SocketConnection] Reconnected successfully after ' + this._reconnectAttempt + ' attempt(s)'); - this._reconnectAttempt = 0; this._isReconnecting = false; @@ -99,8 +89,6 @@ export class SocketConnection implements IConnection if(code === 1000 || code === 1001) { - NitroLogger.log('[SocketConnection] Server closed cleanly (code ' + code + ') - not reconnecting'); - this._isAuthenticated = false; this._isReady = false; @@ -122,7 +110,6 @@ export class SocketConnection implements IConnection { if(this._isReconnecting) { - NitroLogger.log('[SocketConnection] Reconnect attempt ' + this._reconnectAttempt + ' failed'); return; } @@ -136,8 +123,6 @@ export class SocketConnection implements IConnection { if(this._reconnectAttempt >= SocketConnection.MAX_RECONNECT_ATTEMPTS) { - NitroLogger.log('[SocketConnection] Max reconnect attempts reached (' + SocketConnection.MAX_RECONNECT_ATTEMPTS + ')'); - this._isReconnecting = false; this._wasAuthenticated = false; @@ -160,8 +145,6 @@ export class SocketConnection implements IConnection 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, @@ -189,7 +172,7 @@ export class SocketConnection implements IConnection 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; diff --git a/packages/events/src/EventDispatcher.ts b/packages/events/src/EventDispatcher.ts index fd1ae2d..f95aa3c 100644 --- a/packages/events/src/EventDispatcher.ts +++ b/packages/events/src/EventDispatcher.ts @@ -52,11 +52,9 @@ export class EventDispatcher implements IEventDispatcher { if(!event) return false; - // Debug: log SOCKET_ events to trace reconnection flow if(event.type && event.type.startsWith('SOCKET_')) { const listenerCount = this._listeners.get(event.type)?.length ?? 0; - console.log('[EventDispatcher] Dispatching ' + event.type + ' (listeners: ' + listenerCount + ')'); } NitroLogger.events('Dispatched Event', event.type); diff --git a/packages/session/src/RoomSessionManager.ts b/packages/session/src/RoomSessionManager.ts index 4e7bf7e..45903e4 100644 --- a/packages/session/src/RoomSessionManager.ts +++ b/packages/session/src/RoomSessionManager.ts @@ -19,7 +19,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList private _sessionStarting: boolean = false; private _viewerSession: IRoomSession = null; - // Reconnection state tracking private _lastRoomId: number = -1; private _lastRoomPassword: string = null; private _isReconnecting: boolean = false; @@ -34,9 +33,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList this.createHandlers(); this.processPendingSession(); 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(); } @@ -52,19 +48,12 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList 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._lastRoomPassword = sessionStorage.getItem(STORAGE_KEY_ROOM_PASSWORD) || null; - // Enable guard to block DesktopViewEvent until we enter the stored room this._isReconnecting = true; } - catch(e) - { - // sessionStorage not available - } + catch(e){} } private createHandlers(): void @@ -90,56 +79,31 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList 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, () => { - // 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(); - - // Re-persist room to sessionStorage (it was cleared in removeSession) if(this._lastRoomId > 0) { this.persistRoom(this._lastRoomId, this._lastRoomPassword); } - - console.log('[RoomSessionManager] SOCKET_RECONNECTING fired! lastRoomId=' + this._lastRoomId); 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, () => { - 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._reconnectGuardTimer = setTimeout(() => { this._reconnectGuardTimer = null; if(!this._isReconnecting) return; - - NitroLogger.log('[RoomSessionManager] REAUTHENTICATED timeout - attempting fallback room re-entry for room ' + this._lastRoomId); this.attemptRoomReEntry(); }, 5000); }); - // REAUTHENTICATED: SSO handshake completed, connection is ready to send messages 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.clearGuardTimer(); this.attemptRoomReEntry(); }); @@ -155,11 +119,8 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList 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, () => { - NitroLogger.log('[RoomSessionManager] SOCKET_CLOSED - clearing persisted room'); this.clearGuardTimer(); this._isReconnecting = false; this._lastRoomId = -1; @@ -209,30 +170,17 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList if(roomId <= 0) { - NitroLogger.log('[RoomSessionManager] No room to re-enter (lastRoomId=' + roomId + '), dropping guard'); this._isReconnecting = false; 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); 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)); - // 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._reconnectGuardTimer = setTimeout(() => { @@ -240,7 +188,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList if(this._isReconnecting) { - NitroLogger.log('[RoomSessionManager] Session resume guard timeout - dropping guard'); this._isReconnecting = false; } }, 5000); @@ -248,21 +195,9 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList return; } - NitroLogger.log('[RoomSessionManager] Re-entering room ' + roomId); - - // No existing session — full room entry (e.g. page reload restore) this._sessions.clear(); 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); - - // 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._reconnectGuardTimer = setTimeout(() => { @@ -270,19 +205,11 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList if(this._isReconnecting) { - NitroLogger.log('[RoomSessionManager] Guard timeout (10s) - dropping guard'); this._isReconnecting = false; } }, 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 { try @@ -297,7 +224,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList const password = sessionStorage.getItem(STORAGE_KEY_ROOM_PASSWORD) || null; - // Read saved position for page-reload restore let spawnX = -1; let spawnY = -1; @@ -314,17 +240,10 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList 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.createSession(roomId, password, spawnX, spawnY); - - // Drop the guard when room entry succeeds or after timeout this.clearGuardTimer(); this._reconnectGuardTimer = setTimeout(() => { @@ -332,7 +251,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList if(this._isReconnecting) { - NitroLogger.log('[RoomSessionManager] Restore guard timeout (10s) - dropping guard'); this._isReconnecting = false; } }, 10000); @@ -367,10 +285,7 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList this.clearPersistedRoom(); } } - catch(e) - { - // sessionStorage not available (private browsing, etc.) - fail silently - } + catch(e) {} } private clearPersistedRoom(): void @@ -379,14 +294,8 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList { sessionStorage.removeItem(STORAGE_KEY_ROOM_ID); 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 @@ -396,10 +305,7 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList sessionStorage.removeItem(STORAGE_KEY_POS_X); sessionStorage.removeItem(STORAGE_KEY_POS_Y); } - catch(e) - { - // ignore - } + catch(e) {} } private snapshotSavedPosition(): void @@ -414,7 +320,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList this._savedPosX = parseInt(posX, 10); this._savedPosY = parseInt(posY, 10); - NitroLogger.log('[RoomSessionManager] Snapshot saved position (' + this._savedPosX + ', ' + this._savedPosY + ')'); } catch(e) { @@ -476,8 +381,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList GetEventDispatcher().dispatchEvent(new RoomSessionEvent(RoomSessionEvent.CREATED, roomSession)); this._viewerSession = roomSession; - - // Track room for reconnection (memory + sessionStorage) this._lastRoomId = roomSession.roomId; this._lastRoomPassword = roomSession.password; this.persistRoom(roomSession.roomId, roomSession.password); @@ -513,13 +416,8 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList 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) { - NitroLogger.log('[RoomSessionManager] removeSession fully blocked by reconnect guard (room=' + id + ', openLandingView=' + openLandingView + ')'); - return; } @@ -527,11 +425,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList 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.scheduleRoomIdClear(); } @@ -545,43 +438,19 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList if(!session) { - NitroLogger.log('[RoomSessionManager] sessionUpdate(' + type + ') - no session found for id ' + id); - return; } switch(type) { 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; 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) { - NitroLogger.log('[RoomSessionManager] Room ready confirmed - dropping guard in 3s'); - - // 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) + 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)); this._savedPosX = -1; this._savedPosY = -1; @@ -594,18 +463,14 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList if(this._isReconnecting) { - NitroLogger.log('[RoomSessionManager] Post-ready grace period elapsed - dropping guard'); - this._isReconnecting = false; + this._isReconnecting = false; } }, 3000); } return; 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; this.removeSession(id); @@ -625,7 +490,6 @@ export class RoomSessionManager implements IRoomSessionManager, IRoomHandlerList this._sessions.set(this.getRoomId(toRoomId), existing); - // Update tracked room this._lastRoomId = toRoomId; this.persistRoom(toRoomId, existing.password);