export class WebSocketClient { constructor(app) { this.app = app; this.ws = null; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; } async connect(nickname) { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsUrl = `${protocol}//${window.location.host}/ws/${encodeURIComponent(nickname)}`; try { this.ws = new WebSocket(wsUrl); this.ws.onopen = () => { console.log('WebSocket connected'); this.reconnectAttempts = 0; }; this.ws.onmessage = (event) => { this.handleMessage(JSON.parse(event.data)); }; this.ws.onclose = () => { console.log('WebSocket disconnected'); this.attemptReconnect(nickname); }; this.ws.onerror = (error) => { console.error('WebSocket error:', error); }; } catch (error) { console.error('Failed to connect:', error); } } attemptReconnect(nickname) { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; console.log(`Reconnect attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}`); setTimeout(() => this.connect(nickname), 2000); } } handleMessage(data) { switch (data.type) { case 'init': this.app.onPlayerInit(data.player, data.game_state); break; case 'game_state_update': this.app.onGameStateUpdate(data.state); break; case 'cursor_move': this.app.onCursorMove(data.player_id, data.x, data.y); break; case 'building_placed': this.app.onBuildingPlaced(data.building); break; case 'building_removed': this.app.onBuildingRemoved(data.x, data.y); break; case 'building_updated': this.app.onBuildingUpdated(data.x, data.y, data.name); break; case 'player_joined': this.app.onPlayerJoined(data.player_id, data.nickname); break; case 'player_left': this.app.onPlayerLeft(data.player_id, data.nickname); break; case 'chat': this.app.onChatMessage(data.nickname, data.message, data.timestamp); break; case 'error': this.app.onError(data.message); break; } } send(data) { if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify(data)); } } sendCursorMove(x, y) { this.send({ type: 'cursor_move', x: x, y: y }); } placeBuilding(buildingType, x, y) { this.send({ type: 'place_building', building_type: buildingType, x: x, y: y }); } removeBuilding(x, y) { this.send({ type: 'remove_building', x: x, y: y }); } editBuilding(x, y, name) { this.send({ type: 'edit_building', x: x, y: y, name: name }); } sendChat(message, timestamp) { this.send({ type: 'chat', message: message, timestamp: timestamp }); } }