forked from karylab/liars-bar-game
164 lines
3.8 KiB
JavaScript
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 };
|