API/GameServer/server.js
2026-01-24 21:39:56 -04:00

331 lines
9.2 KiB
JavaScript

/**
* Game Server - Based on Client LocalServer Infrastructure
* Handles real-time multiplayer game instances and gameplay
*/
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const cors = require('cors');
const dotenv = require('dotenv');
require('dotenv').config();
const logger = require('./utils/logger');
const connectDB = require('./config/database');
const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
cors: {
origin: ["http://localhost:3000", "http://127.0.0.1:3000", "file://"],
methods: ["GET", "POST"],
credentials: true
}
});
// Game state
const gameInstances = new Map();
const connectedClients = new Map();
// Middleware
app.use(cors({
origin: ["http://localhost:3000", "http://127.0.0.1:3000", "file://"],
credentials: true
}));
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Health check endpoint
app.get('/health', (req, res) => {
res.status(200).json({
status: 'OK',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
mode: 'game-server',
activeInstances: gameInstances.size,
connectedClients: connectedClients.size
});
});
// API version endpoint
app.get('/api/ssc/version', (req, res) => {
res.status(200).json({
version: '1.0.0',
service: 'galaxystrikeonline-game-server',
timestamp: new Date().toISOString(),
mode: 'multiplayer'
});
});
// Game data endpoints (similar to LocalServer)
app.post('/api/game/player/:id/save', (req, res) => {
const playerId = req.params.id;
const playerData = req.body;
// Store player data in game instance
if (connectedClients.has(playerId)) {
connectedClients.get(playerId).playerData = playerData;
// Broadcast to other players in same instance
const instanceId = connectedClients.get(playerId).instanceId;
if (gameInstances.has(instanceId)) {
io.to(instanceId).emit('playerDataUpdated', {
playerId,
timestamp: Date.now()
});
}
}
res.status(200).json({
success: true,
message: 'Player data saved to game server'
});
});
app.get('/api/game/player/:id', (req, res) => {
const playerId = req.params.id;
if (connectedClients.has(playerId)) {
const playerData = connectedClients.get(playerId).playerData;
res.status(200).json({
success: true,
player: playerData
});
} else {
res.status(404).json({
success: false,
error: 'Player not connected to game server'
});
}
});
// Game system routes
app.use('/api/crafting', require('./routes/crafting'));
app.use('/api/quests', require('./routes/quests'));
app.use('/api/skills', require('./routes/skills'));
app.use('/api/ships', require('./routes/ships'));
app.use('/api/idle', require('./routes/idle'));
app.use('/api/dungeons', require('./routes/dungeons'));
app.use('/api/base', require('./routes/base'));
// Socket.IO handlers (based on LocalServer)
io.on('connection', (socket) => {
console.log('[GAME SERVER] Client connected:', socket.id);
connectedClients.set(socket.id, {
connectedAt: Date.now(),
playerData: null,
instanceId: null
});
// Authentication (similar to LocalServer)
socket.on('authenticate', (data) => {
console.log('[GAME SERVER] Authenticating client:', socket.id, data);
// In production, validate with API server
socket.emit('authenticated', {
success: true,
user: {
id: data.userId || socket.id,
username: data.username || 'Game Player',
token: 'game-token-' + Date.now()
}
});
});
// Game data events (similar to LocalServer)
socket.on('saveGameData', (data) => {
console.log('[GAME SERVER] Saving game data for:', socket.id);
if (connectedClients.has(socket.id)) {
connectedClients.get(socket.id).playerData = data;
}
socket.emit('gameDataSaved', {
success: true,
timestamp: Date.now()
});
});
socket.on('loadGameData', (data) => {
console.log('[GAME SERVER] Loading game data for:', socket.id);
const playerData = connectedClients.get(socket.id)?.playerData || {};
socket.emit('gameDataLoaded', {
success: true,
data: playerData
});
});
// Game-specific events
socket.on('joinGameInstance', (data) => {
const { instanceId } = data;
if (!gameInstances.has(instanceId)) {
gameInstances.set(instanceId, {
id: instanceId,
players: new Set(),
createdAt: Date.now()
});
}
const instance = gameInstances.get(instanceId);
instance.players.add(socket.id);
connectedClients.get(socket.id).instanceId = instanceId;
socket.join(instanceId);
socket.emit('joinedGameInstance', {
instanceId,
playerCount: instance.players.size
});
// Notify other players
socket.to(instanceId).emit('playerJoinedInstance', {
playerId: socket.id,
playerCount: instance.players.size
});
});
socket.on('leaveGameInstance', (data) => {
const clientData = connectedClients.get(socket.id);
if (clientData && clientData.instanceId) {
const instance = gameInstances.get(clientData.instanceId);
if (instance) {
instance.players.delete(socket.id);
socket.leave(clientData.instanceId);
// Clean up empty instances
if (instance.players.size === 0) {
gameInstances.delete(clientData.instanceId);
}
// Notify other players
socket.to(clientData.instanceId).emit('playerLeftInstance', {
playerId: socket.id,
playerCount: instance.players.size
});
}
clientData.instanceId = null;
}
});
socket.on('gameAction', (data) => {
const clientData = connectedClients.get(socket.id);
if (clientData && clientData.instanceId) {
// Broadcast game action to other players in same instance
socket.to(clientData.instanceId).emit('gameAction', {
playerId: socket.id,
action: data,
timestamp: Date.now()
});
}
});
socket.on('disconnect', () => {
console.log('[GAME SERVER] Client disconnected:', socket.id);
const clientData = connectedClients.get(socket.id);
if (clientData && clientData.instanceId) {
const instance = gameInstances.get(clientData.instanceId);
if (instance) {
instance.players.delete(socket.id);
// Clean up empty instances
if (instance.players.size === 0) {
gameInstances.delete(clientData.instanceId);
}
// Notify other players
socket.to(clientData.instanceId).emit('playerLeftInstance', {
playerId: socket.id,
playerCount: instance.players.size
});
}
}
connectedClients.delete(socket.id);
});
// Welcome message (similar to LocalServer)
socket.emit('welcome', {
message: 'Connected to game server',
serverInfo: {
mode: 'multiplayer',
activeInstances: gameInstances.size,
timestamp: new Date().toISOString()
}
});
});
// Start server
const PORT = process.env.PORT || 3002;
async function startServer() {
try {
// Connect to database
await connectDB();
server.listen(PORT, async () => {
console.log(`[GAME SERVER] Game server running on port ${PORT}`);
console.log(`[GAME SERVER] Socket.IO ready for multiplayer connections`);
// Register with API server
await registerWithAPIServer();
});
} catch (error) {
console.error('[GAME SERVER] Failed to start server:', error);
process.exit(1);
}
}
// Register this GameServer with the API server
async function registerWithAPIServer() {
try {
// Force use of local API server for development
const apiServerUrl = 'http://localhost:3001';
const gameServerUrl = 'https://dev.gameserver.galaxystrike.online';
const serverData = {
serverId: `devgame-server-${PORT}`,
name: 'Dev Game Server',
type: 'public', // Must be 'public' or 'private' according to model
region: 'Europe',
maxPlayers: 100, // Hardcoded to allow 100 players
currentPlayers: 0,
gameServerUrl: gameServerUrl,
owner: {
userId: 'developer',
username: 'Developer'
}
};
console.log(`[GAME SERVER] Registering with API server at ${apiServerUrl}`);
console.log(`[GAME SERVER] Server data:`, serverData);
const response = await fetch(`${apiServerUrl}/api/servers/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(serverData)
});
if (response.ok) {
const result = await response.json();
console.log(`[GAME SERVER] Successfully registered with API server:`, result);
} else {
const errorText = await response.text();
console.error(`[GAME SERVER] Failed to register with API server: ${response.status}`);
console.error(`[GAME SERVER] Error response:`, errorText);
}
} catch (error) {
console.error('[GAME SERVER] Error registering with API server:', error);
}
}
startServer();
module.exports = { app, server, io, gameInstances, connectedClients };