182 lines
5.0 KiB
JavaScript
182 lines
5.0 KiB
JavaScript
const express = require('express');
|
|
const http = require('http');
|
|
const { Server } = require('socket.io');
|
|
const cors = require('cors');
|
|
const { GameManager } = require('./game/GameManager');
|
|
|
|
const app = express();
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
|
|
const server = http.createServer(app);
|
|
const io = new Server(server, {
|
|
cors: { origin: '*', methods: ['GET', 'POST'] },
|
|
});
|
|
|
|
const gm = new GameManager();
|
|
|
|
app.get('/api/cards', (req, res) => {
|
|
res.json(gm.getCardList());
|
|
});
|
|
|
|
app.get('/api/starter-decks', (req, res) => {
|
|
res.json(gm.getStarterDecks());
|
|
});
|
|
|
|
app.get('/api/rooms', (req, res) => {
|
|
res.json(gm.getRooms());
|
|
});
|
|
|
|
io.on('connection', (socket) => {
|
|
let playerName = 'Player';
|
|
let playerId = socket.id;
|
|
|
|
console.log(`Player connected: ${playerId}`);
|
|
|
|
socket.on('setName', (name) => {
|
|
playerName = name || 'Player';
|
|
socket.emit('nameSet', { id: playerId, name: playerName });
|
|
});
|
|
|
|
socket.on('createRoom', (data) => {
|
|
const room = gm.createRoom(playerId, playerName, data?.roomName);
|
|
socket.join(room.id);
|
|
socket.emit('roomCreated', room);
|
|
io.emit('roomsUpdated', gm.getRooms());
|
|
});
|
|
|
|
socket.on('joinRoom', (data) => {
|
|
const result = gm.joinRoom(data.roomId, playerId, playerName);
|
|
if (result.error) {
|
|
socket.emit('error', { message: result.error });
|
|
return;
|
|
}
|
|
socket.join(data.roomId);
|
|
socket.emit('roomJoined', result.room);
|
|
io.to(data.roomId).emit('roomUpdated', result.room);
|
|
io.emit('roomsUpdated', gm.getRooms());
|
|
});
|
|
|
|
socket.on('leaveRoom', () => {
|
|
const currentRoomId = gm.playerRooms.get(playerId);
|
|
const result = gm.leaveRoom(playerId);
|
|
if (result.error) return;
|
|
|
|
if (currentRoomId) {
|
|
socket.leave(currentRoomId);
|
|
if (!result.roomDeleted) {
|
|
io.to(currentRoomId).emit('roomUpdated', result.room);
|
|
}
|
|
}
|
|
io.emit('roomsUpdated', gm.getRooms());
|
|
});
|
|
|
|
socket.on('selectDeck', (data) => {
|
|
const result = gm.selectDeck(playerId, data.deckColor);
|
|
if (result.error) {
|
|
socket.emit('error', { message: result.error });
|
|
return;
|
|
}
|
|
const roomId = gm.playerRooms.get(playerId);
|
|
io.to(roomId).emit('roomUpdated', result.room);
|
|
});
|
|
|
|
socket.on('selectCustomDeck', (data) => {
|
|
const result = gm.selectCustomDeck(playerId, data.cardIds);
|
|
if (result.error) {
|
|
socket.emit('error', { message: result.error });
|
|
return;
|
|
}
|
|
const roomId = gm.playerRooms.get(playerId);
|
|
io.to(roomId).emit('roomUpdated', result.room);
|
|
});
|
|
|
|
socket.on('startGame', () => {
|
|
const roomId = gm.playerRooms.get(playerId);
|
|
if (!roomId) {
|
|
socket.emit('error', { message: 'Not in a room' });
|
|
return;
|
|
}
|
|
|
|
const room = gm.getRoomDetails(roomId);
|
|
if (!room || room.hostId !== playerId) {
|
|
socket.emit('error', { message: 'Only the host can start the game' });
|
|
return;
|
|
}
|
|
|
|
const result = gm.startGame(roomId);
|
|
if (result.error) {
|
|
socket.emit('error', { message: result.error });
|
|
return;
|
|
}
|
|
|
|
room.players.forEach((p) => {
|
|
const playerState = gm.getGameState(result.gameId, p.id);
|
|
io.to(p.id).emit('gameStarted', { gameId: result.gameId, state: playerState });
|
|
});
|
|
});
|
|
|
|
socket.on('gameAction', (data) => {
|
|
const roomId = gm.playerRooms.get(playerId);
|
|
if (!roomId) return;
|
|
|
|
const room = gm.getRoomDetails(roomId);
|
|
if (!room || !room.gameId) return;
|
|
|
|
const result = gm.handleGameAction(room.gameId, playerId, data.action);
|
|
if (result.error) {
|
|
socket.emit('actionError', { message: result.error });
|
|
return;
|
|
}
|
|
|
|
room.players.forEach((p) => {
|
|
const playerState = gm.getGameState(room.gameId, p.id);
|
|
io.to(p.id).emit('gameStateUpdated', playerState);
|
|
});
|
|
|
|
if (result.needsResponse) {
|
|
socket.emit('needsResponse', {
|
|
type: result.needsResponse,
|
|
options: result.options,
|
|
});
|
|
}
|
|
});
|
|
|
|
socket.on('getRooms', () => {
|
|
socket.emit('roomsUpdated', gm.getRooms());
|
|
});
|
|
|
|
socket.on('disconnect', () => {
|
|
console.log(`Player disconnected: ${playerId}`);
|
|
const roomId = gm.playerRooms.get(playerId);
|
|
if (roomId) {
|
|
const result = gm.leaveRoom(playerId);
|
|
if (result && !result.error) {
|
|
if (!result.roomDeleted) {
|
|
io.to(roomId).emit('roomUpdated', result.room);
|
|
io.to(roomId).emit('playerDisconnected', { playerId, playerName });
|
|
}
|
|
io.emit('roomsUpdated', gm.getRooms());
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
const PORT = process.env.PORT || 3001;
|
|
server.listen(PORT, '0.0.0.0', () => {
|
|
const os = require('os');
|
|
const interfaces = os.networkInterfaces();
|
|
let lanIp = 'localhost';
|
|
for (const iface of Object.values(interfaces)) {
|
|
for (const alias of iface) {
|
|
if (alias.family === 'IPv4' && !alias.internal) {
|
|
lanIp = alias.address;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
console.log(`\n Arcane Duels Server running on:`);
|
|
console.log(` Local: http://localhost:${PORT}`);
|
|
console.log(` Network: http://${lanIp}:${PORT}\n`);
|
|
});
|