285 lines
7.6 KiB
JavaScript
285 lines
7.6 KiB
JavaScript
/**
|
|
* Game System - Manages game instances and real-time multiplayer logic
|
|
*/
|
|
|
|
const logger = require('../utils/logger');
|
|
|
|
class GameSystem {
|
|
constructor() {
|
|
this.gameInstances = new Map(); // serverId -> game instance
|
|
this.playerConnections = new Map(); // socketId -> player data
|
|
}
|
|
|
|
async initializeGameSystems() {
|
|
logger.info('Initializing Game Server systems...');
|
|
|
|
// Initialize any game systems needed
|
|
this.initializeEconomySystem();
|
|
this.initializeDungeonSystem();
|
|
|
|
logger.info('Game Server systems initialized successfully');
|
|
}
|
|
|
|
initializeEconomySystem() {
|
|
// Economy system initialization for game server
|
|
logger.info('Economy System initialized for Game Server');
|
|
}
|
|
|
|
initializeDungeonSystem() {
|
|
// Dungeon system initialization for game server
|
|
logger.info('Dungeon System initialized for Game Server');
|
|
}
|
|
|
|
createGameInstance(serverData) {
|
|
const gameId = serverData.id;
|
|
|
|
const gameInstance = {
|
|
id: gameId,
|
|
name: serverData.name,
|
|
type: serverData.type,
|
|
region: serverData.region,
|
|
maxPlayers: serverData.maxPlayers,
|
|
currentPlayers: 0,
|
|
players: new Map(), // socketId -> player data
|
|
gameState: {
|
|
active: false,
|
|
startTime: null,
|
|
currentDungeon: null,
|
|
enemies: new Map(),
|
|
items: new Map(),
|
|
environment: null
|
|
},
|
|
createdAt: new Date(),
|
|
lastActivity: new Date()
|
|
};
|
|
|
|
this.gameInstances.set(gameId, gameInstance);
|
|
logger.info(`Game instance created: ${gameId} - ${serverData.name}`);
|
|
|
|
return gameInstance;
|
|
}
|
|
|
|
joinGameInstance(socket, serverId, playerData) {
|
|
const gameInstance = this.gameInstances.get(serverId);
|
|
|
|
if (!gameInstance) {
|
|
logger.error(`Game instance not found: ${serverId}`);
|
|
return false;
|
|
}
|
|
|
|
if (gameInstance.currentPlayers >= gameInstance.maxPlayers) {
|
|
logger.warn(`Game instance full: ${serverId}`);
|
|
return false;
|
|
}
|
|
|
|
// Add player to game instance
|
|
gameInstance.players.set(socket.id, {
|
|
socketId: socket.id,
|
|
userId: playerData.userId,
|
|
username: playerData.username,
|
|
joinedAt: new Date(),
|
|
isReady: false,
|
|
ship: playerData.currentShip || null,
|
|
stats: playerData.stats || { level: 1, health: 100 }
|
|
});
|
|
|
|
// Track player connection
|
|
this.playerConnections.set(socket.id, {
|
|
gameId: serverId,
|
|
socket: socket,
|
|
data: playerData
|
|
});
|
|
|
|
gameInstance.currentPlayers++;
|
|
gameInstance.lastActivity = new Date();
|
|
|
|
// Join socket to game room
|
|
socket.join(`game_${serverId}`);
|
|
|
|
logger.info(`Player ${playerData.username} joined game instance ${serverId}`);
|
|
|
|
return gameInstance;
|
|
}
|
|
|
|
leaveGameInstance(socket, serverId) {
|
|
const gameInstance = this.gameInstances.get(serverId);
|
|
|
|
if (!gameInstance) {
|
|
logger.error(`Game instance not found: ${serverId}`);
|
|
return false;
|
|
}
|
|
|
|
const player = gameInstance.players.get(socket.id);
|
|
if (player) {
|
|
gameInstance.players.delete(socket.id);
|
|
gameInstance.currentPlayers--;
|
|
gameInstance.lastActivity = new Date();
|
|
|
|
// Leave socket room
|
|
socket.leave(`game_${serverId}`);
|
|
|
|
// Remove player connection tracking
|
|
this.playerConnections.delete(socket.id);
|
|
|
|
logger.info(`Player ${player.username} left game instance ${serverId}`);
|
|
|
|
// Clean up empty game instances
|
|
if (gameInstance.currentPlayers === 0) {
|
|
this.cleanupGameInstance(serverId);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
cleanupGameInstance(serverId) {
|
|
const gameInstance = this.gameInstances.get(serverId);
|
|
|
|
if (gameInstance && gameInstance.currentPlayers === 0) {
|
|
this.gameInstances.delete(serverId);
|
|
logger.info(`Cleaned up empty game instance: ${serverId}`);
|
|
}
|
|
}
|
|
|
|
getGameInstance(serverId) {
|
|
return this.gameInstances.get(serverId);
|
|
}
|
|
|
|
getAllGameInstances() {
|
|
return Array.from(this.gameInstances.values()).map(instance => ({
|
|
id: instance.id,
|
|
name: instance.name,
|
|
type: instance.type,
|
|
region: instance.region,
|
|
currentPlayers: instance.currentPlayers,
|
|
maxPlayers: instance.maxPlayers,
|
|
gameState: instance.gameState.active ? 'active' : 'waiting',
|
|
createdAt: instance.createdAt
|
|
}));
|
|
}
|
|
|
|
getPlayerConnection(socketId) {
|
|
return this.playerConnections.get(socketId);
|
|
}
|
|
|
|
// Game action handlers
|
|
handlePlayerAction(socket, actionType, actionData) {
|
|
const connection = this.playerConnections.get(socket.id);
|
|
if (!connection) {
|
|
logger.warn(`No connection found for socket: ${socket.id}`);
|
|
return false;
|
|
}
|
|
|
|
const gameInstance = this.gameInstances.get(connection.gameId);
|
|
if (!gameInstance) {
|
|
logger.warn(`No game instance found for player: ${socket.id}`);
|
|
return false;
|
|
}
|
|
|
|
const player = gameInstance.players.get(socket.id);
|
|
if (!player) {
|
|
logger.warn(`Player not found in game instance: ${socket.id}`);
|
|
return false;
|
|
}
|
|
|
|
// Handle different action types
|
|
switch (actionType) {
|
|
case 'move':
|
|
return this.handlePlayerMove(gameInstance, player, actionData);
|
|
case 'attack':
|
|
return this.handlePlayerAttack(gameInstance, player, actionData);
|
|
case 'interact':
|
|
return this.handlePlayerInteract(gameInstance, player, actionData);
|
|
case 'chat':
|
|
return this.handlePlayerChat(gameInstance, player, actionData);
|
|
default:
|
|
logger.warn(`Unknown action type: ${actionType}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
handlePlayerMove(gameInstance, player, moveData) {
|
|
// Update player position
|
|
player.position = moveData.position;
|
|
gameInstance.lastActivity = new Date();
|
|
|
|
// Broadcast movement to other players in the game
|
|
const socket = this.playerConnections.get(player.socketId)?.socket;
|
|
if (socket) {
|
|
socket.to(`game_${gameInstance.id}`).emit('playerMoved', {
|
|
playerId: player.socketId,
|
|
username: player.username,
|
|
position: moveData.position
|
|
});
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
handlePlayerAttack(gameInstance, player, attackData) {
|
|
// Handle combat logic
|
|
logger.info(`Player ${player.username} attacked in game ${gameInstance.id}`);
|
|
|
|
// Broadcast attack to other players
|
|
const socket = this.playerConnections.get(player.socketId)?.socket;
|
|
if (socket) {
|
|
socket.to(`game_${gameInstance.id}`).emit('playerAttacked', {
|
|
playerId: player.socketId,
|
|
username: player.username,
|
|
target: attackData.target,
|
|
damage: attackData.damage
|
|
});
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
handlePlayerInteract(gameInstance, player, interactData) {
|
|
// Handle interaction logic (picking up items, activating objects, etc.)
|
|
logger.info(`Player ${player.username} interacted in game ${gameInstance.id}`);
|
|
|
|
return true;
|
|
}
|
|
|
|
handlePlayerChat(gameInstance, player, chatData) {
|
|
// Handle chat messages
|
|
const message = {
|
|
playerId: player.socketId,
|
|
username: player.username,
|
|
message: chatData.message,
|
|
timestamp: new Date()
|
|
};
|
|
|
|
// Broadcast chat to all players in the game
|
|
const socket = this.playerConnections.get(player.socketId)?.socket;
|
|
if (socket) {
|
|
socket.to(`game_${gameInstance.id}`).emit('chatMessage', message);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Singleton instance
|
|
let gameSystem = null;
|
|
|
|
async function initializeGameSystems() {
|
|
if (!gameSystem) {
|
|
gameSystem = new GameSystem();
|
|
await gameSystem.initializeGameSystems();
|
|
}
|
|
return gameSystem;
|
|
}
|
|
|
|
function getGameSystem() {
|
|
return gameSystem;
|
|
}
|
|
|
|
module.exports = {
|
|
GameSystem,
|
|
initializeGameSystems,
|
|
getGameSystem
|
|
};
|