203 lines
6.4 KiB
JavaScript
203 lines
6.4 KiB
JavaScript
/**
|
|
* Game Server - Real-time Multiplayer
|
|
* Handles actual game instances, player connections, and real-time gameplay
|
|
*/
|
|
|
|
const express = require('express');
|
|
const http = require('http');
|
|
const socketIo = require('socket.io');
|
|
const cors = require('cors');
|
|
const helmet = require('helmet');
|
|
const compression = require('compression');
|
|
const dotenv = require('dotenv');
|
|
require('dotenv').config();
|
|
|
|
const logger = require('./utils/logger');
|
|
const connectDB = require('./config/database');
|
|
const { initializeGameSystems } = require('./systems/GameSystem');
|
|
const SocketHandlers = require('./socket/socketHandlers');
|
|
const ServerRegistrationService = require('./services/ServerRegistrationService');
|
|
const ModService = require('./services/ModService');
|
|
const modRoutes = require('./routes/mods');
|
|
const { errorHandler, notFound } = require('./middleware/errorHandler');
|
|
|
|
const app = express();
|
|
const server = http.createServer(app);
|
|
const io = socketIo(server, {
|
|
cors: {
|
|
origin: ["https://galaxystrike.online", "https://api.korvarix.com", "http://localhost:3000"],
|
|
methods: ["GET", "POST"],
|
|
credentials: true
|
|
}
|
|
});
|
|
|
|
// Middleware
|
|
app.use(helmet());
|
|
app.use(compression());
|
|
app.use(cors({
|
|
origin: ["https://galaxystrike.online", "https://api.korvarix.com", "http://localhost:3000"],
|
|
credentials: true
|
|
}));
|
|
app.use(express.json({ limit: '10mb' }));
|
|
app.use(express.urlencoded({ extended: true }));
|
|
|
|
// Game Server Routes (minimal - mostly for health checks and server management)
|
|
app.get('/health', (req, res) => {
|
|
res.status(200).json({
|
|
status: 'Game Server OK',
|
|
service: 'galaxystrikeonline-game',
|
|
timestamp: new Date().toISOString(),
|
|
uptime: process.uptime(),
|
|
activeServers: Object.keys(gameServers).length,
|
|
connectedPlayers: connectedPlayers.size
|
|
});
|
|
});
|
|
|
|
// Get server status
|
|
app.get('/api/game/status', (req, res) => {
|
|
res.json({
|
|
activeServers: Object.keys(gameServers).length,
|
|
connectedPlayers: connectedPlayers.size,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
});
|
|
|
|
// Mod management routes
|
|
app.use('/api/mods', modRoutes);
|
|
|
|
// Error handling
|
|
app.use(notFound);
|
|
app.use(errorHandler);
|
|
|
|
// Global game server instances
|
|
const gameServers = {};
|
|
let serverRegistration; // Global reference to registration service
|
|
|
|
// Player tracking
|
|
const connectedPlayers = new Set(); // Track actual player connections
|
|
let socketHandlers;
|
|
|
|
io.on('connection', (socket) => {
|
|
logger.info(`Game Server: Player connected - ${socket.id}`);
|
|
socketHandlers.handleConnection(socket);
|
|
});
|
|
|
|
// Handle uncaught errors
|
|
process.on('uncaughtException', (error) => {
|
|
logger.error('Uncaught Exception:', error);
|
|
});
|
|
|
|
process.on('unhandledRejection', (reason, promise) => {
|
|
logger.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
});
|
|
|
|
// Graceful shutdown handlers
|
|
async function gracefulShutdown(signal) {
|
|
logger.info(`[GRACEFUL SHUTDOWN] Received ${signal}, shutting down gracefully...`);
|
|
|
|
try {
|
|
// Stop accepting new connections
|
|
server.close(async () => {
|
|
logger.info('[GRACEFUL SHUTDOWN] HTTP server closed');
|
|
|
|
// Unregister from API
|
|
if (serverRegistration) {
|
|
await serverRegistration.stopHeartbeat();
|
|
const unregistered = await serverRegistration.unregisterWithAPI();
|
|
if (unregistered) {
|
|
logger.info('[GRACEFUL SHUTDOWN] Server unregistered from API successfully');
|
|
} else {
|
|
logger.warn('[GRACEFUL SHUTDOWN] Failed to unregister from API');
|
|
}
|
|
}
|
|
|
|
// Shutdown mod service
|
|
await ModService.shutdown();
|
|
|
|
// Close database connections
|
|
const mongoose = require('mongoose');
|
|
await mongoose.connection.close();
|
|
logger.info('[GRACEFUL SHUTDOWN] Database connections closed');
|
|
|
|
process.exit(0);
|
|
});
|
|
|
|
// Force shutdown after 30 seconds
|
|
setTimeout(() => {
|
|
logger.error('[GRACEFUL SHUTDOWN] Forced shutdown after timeout');
|
|
process.exit(1);
|
|
}, 30000);
|
|
|
|
} catch (error) {
|
|
logger.error('[GRACEFUL SHUTDOWN] Error during shutdown:', error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
|
|
// Handle Socket.IO adapter errors
|
|
io.engine.on('connection_error', (err) => {
|
|
logger.error('Socket.IO connection error:', err);
|
|
});
|
|
|
|
io.of('/').adapter.on('error', (err) => {
|
|
logger.error('Socket.IO adapter error:', err);
|
|
});
|
|
|
|
// Initialize database and game systems
|
|
async function startGameServer() {
|
|
try {
|
|
// Connect to database
|
|
await connectDB();
|
|
logger.info('Game Server: Database connected successfully');
|
|
|
|
// Initialize mod service
|
|
await ModService.initialize();
|
|
logger.info('Game Server: Mod service initialized');
|
|
|
|
// Initialize game systems
|
|
await initializeGameSystems();
|
|
logger.info('Game Server: Game systems initialized');
|
|
|
|
// Initialize server registration service
|
|
const gameServerUrl = `https://api.korvarix.com:${process.env.GAME_PORT || 3002}`;
|
|
const apiUrl = process.env.API_SERVER_URL || 'https://api.korvarix.com';
|
|
const serverName = process.env.SERVER_NAME || 'Game Server';
|
|
const serverRegion = process.env.SERVER_REGION || 'us-east';
|
|
const maxPlayers = parseInt(process.env.MAX_PLAYERS) || 10;
|
|
|
|
serverRegistration = new ServerRegistrationService(gameServerUrl, apiUrl, serverName, serverRegion, maxPlayers);
|
|
|
|
// Set up player count callback
|
|
serverRegistration.setPlayerCountCallback(() => connectedPlayers.size);
|
|
|
|
serverRegistration.startHeartbeat();
|
|
|
|
// Initialize socket handlers
|
|
socketHandlers = new SocketHandlers(io, gameServers, connectedPlayers);
|
|
|
|
// Make registration service available to socket handlers
|
|
socketHandlers.serverRegistration = serverRegistration;
|
|
|
|
// Start server
|
|
const PORT = process.env.GAME_PORT || 3002; // Game Server on port 3002
|
|
server.listen(PORT, () => {
|
|
logger.info(`Game Server running on port ${PORT}`);
|
|
logger.info('Game Server handles: Real-time Multiplayer, Game Instances, Socket.IO');
|
|
logger.info(`Game Server Name: ${serverName}`);
|
|
logger.info(`Game Server Region: ${serverRegion}`);
|
|
logger.info(`Game Server URL: ${gameServerUrl}`);
|
|
logger.info(`API Server URL: ${apiUrl}`);
|
|
});
|
|
} catch (error) {
|
|
logger.error('Failed to start Game Server:', error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
startGameServer();
|
|
|
|
module.exports = { app, server, io, gameServers };
|