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 'player_stats_update':
this.app.onPlayerStatsUpdate(data.player);
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
});
}
}