254 lines
5.2 KiB
JavaScript
254 lines
5.2 KiB
JavaScript
import {query} from '../db.js';
|
|
|
|
// Create the room with name as the only parameter
|
|
// max_players, status and the other variables have their default values defined in db.js
|
|
async function createRoom(name, userId)
|
|
{
|
|
const result = await query
|
|
(
|
|
`INSERT INTO game_rooms (name) VALUES ($1) RETURNING *`,
|
|
[name]
|
|
);
|
|
const room = result.rows[0];
|
|
|
|
await query
|
|
(
|
|
'INSERT INTO game_players (room_id, user_id) VALUES ($1, $2)',
|
|
[room.id, userId]
|
|
);
|
|
return (room);
|
|
}
|
|
|
|
async function getRoomById(roomId)
|
|
{
|
|
const result = await query
|
|
(
|
|
'SELECT * FROM game_rooms WHERE id = $1',
|
|
[roomId]
|
|
);
|
|
return (result.rows[0]);
|
|
}
|
|
|
|
// List all the waiting rooms and the player amount in each of them
|
|
async function listActiveRooms()
|
|
{
|
|
const result = await query
|
|
(
|
|
`SELECT r.*, COUNT(p.id) as player_count
|
|
FROM game_rooms r
|
|
LEFT JOIN game_players p ON r.id = p.room_id
|
|
WHERE r.status = 'waiting'
|
|
GROUP BY r.id
|
|
ORDER BY player_count DESC, r.created_at DESC`
|
|
);
|
|
return (result.rows);
|
|
}
|
|
|
|
async function listPlayingRooms()
|
|
{
|
|
const result = await query
|
|
(
|
|
`SELECT r.*, COUNT(p.id) as player_count
|
|
FROM game_rooms r
|
|
LEFT JOIN game_players p ON r.id = p.room_id
|
|
WHERE r.status = 'playing'
|
|
GROUP BY r.id
|
|
ORDER BY player_count DESC, r.created_at DESC`
|
|
);
|
|
return (result.rows);
|
|
}
|
|
|
|
async function spectateRoom(roomId, userId)
|
|
{
|
|
const room = await getRoomById(roomId);
|
|
if (!room)
|
|
throw new Error('Room not found');
|
|
|
|
if (room.status !== 'playing')
|
|
throw new Error('Room is not in playing status');
|
|
|
|
// Check if user is already a player in any active game
|
|
const playerInGame = await query
|
|
(
|
|
`SELECT r.id, r.name, r.status
|
|
FROM game_rooms r
|
|
JOIN game_players gp ON r.id = gp.room_id
|
|
WHERE gp.user_id = $1 AND r.status IN ('waiting', 'playing')
|
|
LIMIT 1`,
|
|
[userId]
|
|
);
|
|
|
|
if (playerInGame.rows.length > 0)
|
|
{
|
|
const gameRoom = playerInGame.rows[0];
|
|
if (gameRoom.id === parseInt(roomId))
|
|
throw new Error('You cannot spectate a game you are playing in');
|
|
else
|
|
throw new Error('You are already in an active game');
|
|
}
|
|
|
|
return (room);
|
|
}
|
|
|
|
async function leaveSpectateRoom(roomId, userId)
|
|
{
|
|
const playerCount = await query
|
|
(
|
|
'SELECT COUNT(*) FROM game_players WHERE room_id = $1',
|
|
[roomId]
|
|
);
|
|
|
|
if (parseInt(playerCount.rows[0].count) === 0)
|
|
{
|
|
await query
|
|
(
|
|
'DELETE FROM game_rooms WHERE id = $1',
|
|
[roomId]
|
|
);
|
|
}
|
|
}
|
|
|
|
async function joinRoom(roomId, userId)
|
|
{
|
|
const room = await getRoomById(roomId);
|
|
if (!room)
|
|
throw new Error('Room not found');
|
|
|
|
const playerCount = await query
|
|
(
|
|
'SELECT COUNT(*) FROM game_players WHERE room_id = $1',
|
|
[roomId]
|
|
);
|
|
|
|
if (parseInt(playerCount.rows[0].count) >= 8)
|
|
throw new Error('Room is full');
|
|
if (room.status !== 'waiting')
|
|
throw new Error('Game already started or ended');
|
|
const result = await query
|
|
(
|
|
'INSERT INTO game_players (room_id, user_id) VALUES ($1, $2) RETURNING *',
|
|
[roomId, userId]
|
|
);
|
|
return (result.rows[0]);
|
|
}
|
|
|
|
async function leaveRoom(roomId, userId)
|
|
{
|
|
await query
|
|
(
|
|
'DELETE FROM game_players WHERE room_id = $1 AND user_id = $2',
|
|
[roomId, userId]
|
|
);
|
|
|
|
const playerCount = await query
|
|
(
|
|
'SELECT COUNT(*) FROM game_players WHERE room_id = $1',
|
|
[roomId]
|
|
);
|
|
|
|
if (parseInt(playerCount.rows[0].count) === 0)
|
|
{
|
|
await query
|
|
(
|
|
'DELETE FROM game_rooms WHERE id = $1',
|
|
[roomId]
|
|
);
|
|
}
|
|
}
|
|
|
|
// List the players in the room and their scores
|
|
// Useful for the scoreboard and also tell which player is currently drawing
|
|
async function getRoomPlayers(roomId)
|
|
{
|
|
const result = await query
|
|
(
|
|
`SELECT gp.*, u.username, u.avatar_url, u.total_points, u.games_played, u.games_won
|
|
FROM game_players gp
|
|
JOIN users u ON gp.user_id = u.id
|
|
WHERE gp.room_id = $1
|
|
ORDER BY gp.score DESC`,
|
|
[roomId]
|
|
);
|
|
return (result.rows);
|
|
}
|
|
|
|
// Get the current room of a user (if any)
|
|
async function getCurrentRoom(userId)
|
|
{
|
|
const result = await query
|
|
(
|
|
`SELECT r.*
|
|
FROM game_rooms r
|
|
JOIN game_players gp ON r.id = gp.room_id
|
|
WHERE gp.user_id = $1 AND r.status IN ('waiting', 'playing')
|
|
LIMIT 1`,
|
|
[userId]
|
|
);
|
|
return (result.rows[0] || null);
|
|
}
|
|
|
|
// Update room status (waiting, playing, ended)
|
|
async function updateRoomStatus(roomId, status)
|
|
{
|
|
const validStatuses = ['waiting', 'playing', 'ended'];
|
|
if (!validStatuses.includes(status))
|
|
throw new Error('Invalid status');
|
|
|
|
let updateQuery = 'UPDATE game_rooms SET status = $1';
|
|
const params = [status, roomId];
|
|
|
|
if (status === 'playing')
|
|
{
|
|
updateQuery += ', started_at = NOW()';
|
|
}
|
|
else if (status === 'ended')
|
|
{
|
|
updateQuery += ', ended_at = NOW()';
|
|
}
|
|
|
|
updateQuery += ' WHERE id = $2 RETURNING *';
|
|
|
|
const result = await query(updateQuery, params);
|
|
return (result.rows[0]);
|
|
}
|
|
|
|
async function resetRoomScores(roomId)
|
|
{
|
|
await query
|
|
(
|
|
'UPDATE game_players SET score = 0 WHERE room_id = $1',
|
|
[roomId]
|
|
);
|
|
}
|
|
|
|
async function cleanupEndedRooms()
|
|
{
|
|
await query
|
|
(
|
|
'DELETE FROM game_players WHERE room_id IN (SELECT id FROM game_rooms WHERE status = $1)',
|
|
['ended']
|
|
);
|
|
|
|
await query
|
|
(
|
|
'DELETE FROM game_rooms WHERE status = $1',
|
|
['ended']
|
|
);
|
|
}
|
|
|
|
export default
|
|
{
|
|
createRoom,
|
|
getRoomById,
|
|
listActiveRooms,
|
|
listPlayingRooms,
|
|
spectateRoom,
|
|
leaveSpectateRoom,
|
|
joinRoom,
|
|
leaveRoom,
|
|
getRoomPlayers,
|
|
getCurrentRoom,
|
|
updateRoomStatus,
|
|
resetRoomScores,
|
|
cleanupEndedRooms
|
|
}; |