273 lines
8.0 KiB
JavaScript
273 lines
8.0 KiB
JavaScript
const logger = require('../utils/logger');
|
|
const { getGameSystem } = require('../systems/GameSystem');
|
|
const Player = require('../models/Player');
|
|
|
|
class SocketHandlers {
|
|
constructor(io) {
|
|
this.io = io;
|
|
this.connectedUsers = new Map(); // userId -> socket.id
|
|
this.userSockets = new Map(); // socket.id -> userId
|
|
}
|
|
|
|
handleConnection(socket) {
|
|
logger.info(`Client connected: ${socket.id}`);
|
|
|
|
// Authentication
|
|
socket.on('authenticate', async (token) => {
|
|
try {
|
|
const jwt = require('jsonwebtoken');
|
|
const decoded = jwt.verify(token, process.env.JWT_SECRET || 'fallback_secret');
|
|
|
|
const player = await Player.findOne({ userId: decoded.userId });
|
|
if (!player) {
|
|
socket.emit('auth_error', { error: 'Player not found' });
|
|
return;
|
|
}
|
|
|
|
// Store user connection
|
|
this.connectedUsers.set(decoded.userId, socket.id);
|
|
this.userSockets.set(socket.id, decoded.userId);
|
|
|
|
socket.userId = decoded.userId;
|
|
socket.emit('authenticated', { userId: decoded.userId });
|
|
|
|
logger.info(`User authenticated: ${decoded.userId}`);
|
|
|
|
// Join user to their current server if any
|
|
if (player.currentServer) {
|
|
socket.join(player.currentServer);
|
|
this.broadcastToServer(player.currentServer, 'user_joined', {
|
|
userId: decoded.userId,
|
|
username: player.username
|
|
});
|
|
}
|
|
|
|
} catch (error) {
|
|
logger.error('Authentication error:', error);
|
|
socket.emit('auth_error', { error: 'Invalid token' });
|
|
}
|
|
});
|
|
|
|
// Server management
|
|
socket.on('join_server', async (data) => {
|
|
try {
|
|
if (!socket.userId) {
|
|
socket.emit('error', { error: 'Not authenticated' });
|
|
return;
|
|
}
|
|
|
|
const gameSystem = getGameSystem();
|
|
const server = await gameSystem.joinServer(data.serverId, socket.userId);
|
|
|
|
// Update player's current server
|
|
await Player.findOneAndUpdate(
|
|
{ userId: socket.userId },
|
|
{ currentServer: data.serverId }
|
|
);
|
|
|
|
// Join socket room
|
|
socket.join(data.serverId);
|
|
|
|
socket.emit('server_joined', { server });
|
|
this.broadcastToServer(data.serverId, 'user_joined', {
|
|
userId: socket.userId,
|
|
serverId: data.serverId
|
|
});
|
|
|
|
logger.info(`User ${socket.userId} joined server ${data.serverId}`);
|
|
|
|
} catch (error) {
|
|
logger.error('Error joining server:', error);
|
|
socket.emit('error', { error: error.message });
|
|
}
|
|
});
|
|
|
|
socket.on('leave_server', async (data) => {
|
|
try {
|
|
if (!socket.userId) {
|
|
socket.emit('error', { error: 'Not authenticated' });
|
|
return;
|
|
}
|
|
|
|
const gameSystem = getGameSystem();
|
|
const server = await gameSystem.leaveServer(data.serverId, socket.userId);
|
|
|
|
// Update player's current server
|
|
await Player.findOneAndUpdate(
|
|
{ userId: socket.userId },
|
|
{ currentServer: null }
|
|
);
|
|
|
|
// Leave socket room
|
|
socket.leave(data.serverId);
|
|
|
|
socket.emit('server_left', { server });
|
|
this.broadcastToServer(data.serverId, 'user_left', {
|
|
userId: socket.userId,
|
|
serverId: data.serverId
|
|
});
|
|
|
|
logger.info(`User ${socket.userId} left server ${data.serverId}`);
|
|
|
|
} catch (error) {
|
|
logger.error('Error leaving server:', error);
|
|
socket.emit('error', { error: error.message });
|
|
}
|
|
});
|
|
|
|
// Game actions
|
|
socket.on('game_action', async (data) => {
|
|
try {
|
|
if (!socket.userId) {
|
|
socket.emit('error', { error: 'Not authenticated' });
|
|
return;
|
|
}
|
|
|
|
const gameSystem = getGameSystem();
|
|
const result = await gameSystem.processGameAction(socket.userId, data);
|
|
|
|
socket.emit('action_result', { action: data.type, result });
|
|
|
|
// Broadcast relevant actions to server
|
|
if (data.broadcast && socket.userId) {
|
|
const player = await Player.findOne({ userId: socket.userId });
|
|
if (player && player.currentServer) {
|
|
this.broadcastToServer(player.currentServer, 'user_action', {
|
|
userId: socket.userId,
|
|
username: player.username,
|
|
action: data.type,
|
|
result
|
|
});
|
|
}
|
|
}
|
|
|
|
} catch (error) {
|
|
logger.error('Error processing game action:', error);
|
|
socket.emit('error', { error: error.message });
|
|
}
|
|
});
|
|
|
|
// Chat functionality
|
|
socket.on('send_message', async (data) => {
|
|
try {
|
|
if (!socket.userId) {
|
|
socket.emit('error', { error: 'Not authenticated' });
|
|
return;
|
|
}
|
|
|
|
const player = await Player.findOne({ userId: socket.userId });
|
|
if (!player || !player.currentServer) {
|
|
socket.emit('error', { error: 'Not in a server' });
|
|
return;
|
|
}
|
|
|
|
const message = {
|
|
userId: socket.userId,
|
|
username: player.username,
|
|
message: data.message,
|
|
timestamp: new Date(),
|
|
type: data.type || 'chat'
|
|
};
|
|
|
|
// Broadcast to server
|
|
this.broadcastToServer(player.currentServer, 'new_message', message);
|
|
|
|
logger.info(`Chat message from ${socket.userId} in server ${player.currentServer}`);
|
|
|
|
} catch (error) {
|
|
logger.error('Error sending message:', error);
|
|
socket.emit('error', { error: error.message });
|
|
}
|
|
});
|
|
|
|
// Real-time updates
|
|
socket.on('request_server_status', async () => {
|
|
try {
|
|
if (!socket.userId) {
|
|
socket.emit('error', { error: 'Not authenticated' });
|
|
return;
|
|
}
|
|
|
|
const player = await Player.findOne({ userId: socket.userId });
|
|
if (!player || !player.currentServer) {
|
|
socket.emit('server_status', { server: null });
|
|
return;
|
|
}
|
|
|
|
const gameSystem = getGameSystem();
|
|
const server = gameSystem.servers.get(player.currentServer);
|
|
|
|
if (server) {
|
|
const players = await Player.find({
|
|
userId: { $in: server.players }
|
|
}).select('userId username info.stats.level');
|
|
|
|
socket.emit('server_status', {
|
|
server: {
|
|
id: server.id,
|
|
name: server.name,
|
|
currentPlayers: server.players.length,
|
|
maxPlayers: server.maxPlayers,
|
|
players: players.map(p => ({
|
|
userId: p.userId,
|
|
username: p.username,
|
|
level: p.info.stats.level
|
|
}))
|
|
}
|
|
});
|
|
}
|
|
|
|
} catch (error) {
|
|
logger.error('Error getting server status:', error);
|
|
socket.emit('error', { error: error.message });
|
|
}
|
|
});
|
|
|
|
// Disconnection
|
|
socket.on('disconnect', async () => {
|
|
logger.info(`Client disconnected: ${socket.id}`);
|
|
|
|
const userId = this.userSockets.get(socket.id);
|
|
if (userId) {
|
|
// Remove from tracking
|
|
this.connectedUsers.delete(userId);
|
|
this.userSockets.delete(socket.id);
|
|
|
|
// Notify server if user was in one
|
|
const player = await Player.findOne({ userId });
|
|
if (player && player.currentServer) {
|
|
this.broadcastToServer(player.currentServer, 'user_disconnected', {
|
|
userId,
|
|
username: player.username
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
broadcastToServer(serverId, event, data) {
|
|
this.io.to(serverId).emit(event, data);
|
|
}
|
|
|
|
sendToUser(userId, event, data) {
|
|
const socketId = this.connectedUsers.get(userId);
|
|
if (socketId) {
|
|
this.io.to(socketId).emit(event, data);
|
|
}
|
|
}
|
|
|
|
broadcastToAll(event, data) {
|
|
this.io.emit(event, data);
|
|
}
|
|
|
|
getConnectedUsers() {
|
|
return Array.from(this.connectedUsers.keys());
|
|
}
|
|
|
|
getUserCount() {
|
|
return this.connectedUsers.size;
|
|
}
|
|
}
|
|
|
|
module.exports = SocketHandlers;
|