Game-Server/API/socket/socketHandlers.js
2026-01-24 16:47:19 -04:00

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;