Files
liars-bar-game/server/index.js
T

164 lines
3.8 KiB
JavaScript

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const RoomManager = require('./game/room');
const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
});
const roomManager = new RoomManager();
// 中間件
app.use(express.json());
// 驗證房間權限
function validateRoom(socket, roomId) {
if (!socket.rooms.has(roomId)) {
socket.emit('error', { message: '無權限操作此房間' });
return false;
}
return true;
}
// Socket.IO 連線
io.on('connection', (socket) => {
console.log(`玩家連線: ${socket.id}`);
// 建立房間
socket.on('createRoom', (data) => {
const room = roomManager.createRoom(socket.id);
socket.join(room.id);
socket.data = { roomId: room.id };
io.to(room.id).emit('roomCreated', room);
console.log(`房間建立: ${room.id}`);
});
// 加入房間
socket.on('joinRoom', (data) => {
const { roomId } = data;
const result = roomManager.joinRoom(roomId, socket.id);
if (result.error) {
socket.emit('error', { message: result.error });
return;
}
socket.join(roomId);
socket.data = { roomId };
io.to(roomId).emit('playerJoined', result.room);
console.log(`玩家加入房間: ${roomId}`);
});
// 開始遊戲
socket.on('startGame', (data) => {
const { roomId } = data;
if (!validateRoom(socket, roomId)) return;
const result = roomManager.startGame(roomId);
if (result.error) {
socket.emit('error', { message: result.error });
return;
}
io.to(roomId).emit('gameStarted', result.gameState);
console.log(`遊戲開始: ${roomId}`);
});
// 出牌
socket.on('playCard', (data) => {
const { roomId, cardIndex } = data;
if (!validateRoom(socket, roomId)) return;
const room = roomManager.getRoom(roomId);
if (!room || !room.engine) {
socket.emit('error', { message: '遊戲未開始' });
return;
}
const result = room.engine.playCard(socket.id, cardIndex);
if (result.error) {
socket.emit('error', { message: result.error });
return;
}
// 廣播出牌結果
io.to(roomId).emit('cardPlayed', {
playerId: socket.id,
cardIndex,
nextPlayerId: result.nextPlayerId,
gameState: room.engine.getGameState()
});
});
// 質疑
socket.on('challenge', (data) => {
const { roomId } = data;
if (!validateRoom(socket, roomId)) return;
const room = roomManager.getRoom(roomId);
if (!room || !room.engine) {
socket.emit('error', { message: '遊戲未開始' });
return;
}
const result = room.engine.challenge(socket.id);
if (result.error) {
socket.emit('error', { message: result.error });
return;
}
// 廣播質疑結果
io.to(roomId).emit('challenged', {
challengerId: socket.id,
result,
gameState: room.engine.getGameState()
});
});
// 斷線處理
socket.on('disconnect', () => {
console.log(`玩家斷線: ${socket.id}`);
// 清理房間
const removed = roomManager.removePlayer(socket.id);
if (removed) {
io.to(removed.roomId).emit('playerDisconnected', {
playerId: socket.id,
room: removed.room
});
}
});
});
// REST API
app.get('/api/rooms', (req, res) => {
res.json(roomManager.listRooms());
});
app.post('/api/rooms', (req, res) => {
const { hostId } = req.body;
const room = roomManager.createRoom(hostId);
res.json(room);
});
// 啟動伺服器
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`伺服器啟動在 http://localhost:${PORT}`);
});
module.exports = { app, io };