Merge branch 'Rendu' of github.com:OlaketalAmigo/Transcendence into Rendu
This commit is contained in:
@@ -140,6 +140,47 @@ async function saveRoundPoints(currentScores, roundStartScores) {
|
||||
}
|
||||
}
|
||||
|
||||
function handlePlayerDeparture(io, roomId, username) {
|
||||
const gameState = gameRooms.get(roomId);
|
||||
if (!gameState || !gameState.isPlaying) return;
|
||||
if (!Array.isArray(gameState.players)) return;
|
||||
|
||||
const leavingIndex = gameState.players.indexOf(username);
|
||||
if (leavingIndex === -1) return;
|
||||
|
||||
const wasDrawer = gameState.drawer === username;
|
||||
|
||||
gameState.players = gameState.players.filter(p => p !== username);
|
||||
if (gameState.scores) {
|
||||
delete gameState.scores[username];
|
||||
}
|
||||
|
||||
if (gameState.currentPlayerIndex >= leavingIndex) {
|
||||
gameState.currentPlayerIndex = Math.max(0, gameState.currentPlayerIndex - 1);
|
||||
}
|
||||
if (gameState.currentPlayerIndex >= gameState.players.length) {
|
||||
gameState.currentPlayerIndex = 0;
|
||||
}
|
||||
|
||||
if (wasDrawer && gameState.players.length > 0) {
|
||||
stopRoomTimer(roomId);
|
||||
const newDrawer = gameState.players[gameState.currentPlayerIndex];
|
||||
gameState.drawer = newDrawer;
|
||||
gameState.currentWord = '';
|
||||
gameState.revealedLetters = [];
|
||||
gameState.revealedWord = [];
|
||||
gameState.guessedLetters = [];
|
||||
gameState.wrongGuesses = 0;
|
||||
|
||||
io.to(roomId).emit('game-drawer-changed', {
|
||||
newDrawer: newDrawer,
|
||||
reason: 'drawer_left',
|
||||
message: `${username} (dessinateur) a quitte, ${newDrawer} devient le nouveau dessinateur`
|
||||
});
|
||||
startRoomTimer(io, roomId, 60);
|
||||
}
|
||||
}
|
||||
|
||||
function setupSocketIO(io)
|
||||
{
|
||||
ioInstance = io;
|
||||
@@ -276,6 +317,7 @@ function setupSocketIO(io)
|
||||
username: socket.user.username,
|
||||
userId: socket.user.userId
|
||||
});
|
||||
handlePlayerDeparture(io, roomId, socket.user.username);
|
||||
socket.leave(roomId);
|
||||
console.log(`${socket.user.username} left ${roomId}`);
|
||||
|
||||
@@ -574,7 +616,7 @@ function setupSocketIO(io)
|
||||
|
||||
// Points: 10 per letter found, -5 for wrong guess
|
||||
if (success) {
|
||||
points = lettersFound * 10;
|
||||
points = lettersFound * 5;
|
||||
gameState.scores[username] += points;
|
||||
} else {
|
||||
points = -5;
|
||||
@@ -673,42 +715,7 @@ function setupSocketIO(io)
|
||||
message: `${username} a quitté la partie`
|
||||
});
|
||||
|
||||
const gameState = gameRooms.get(roomId);
|
||||
if (gameState)
|
||||
{
|
||||
const wasDrawer = gameState.drawer === username;
|
||||
|
||||
gameState.players = gameState.players.filter(p => p !== username);
|
||||
delete gameState.scores[username];
|
||||
|
||||
io.to(roomId).emit('scores-updated', gameState.scores);
|
||||
|
||||
// If the drawer left and there are still enough players, choose a new drawer
|
||||
if (wasDrawer && gameState.players.length >= 1)
|
||||
{
|
||||
stopRoomTimer(roomId);
|
||||
// Pick the next player as the new drawer
|
||||
gameState.currentPlayerIndex = gameState.currentPlayerIndex % gameState.players.length;
|
||||
const newDrawer = gameState.players[gameState.currentPlayerIndex];
|
||||
gameState.drawer = newDrawer;
|
||||
|
||||
// Reset the word state for the new round
|
||||
gameState.currentWord = '';
|
||||
gameState.revealedLetters = [];
|
||||
gameState.revealedWord = [];
|
||||
gameState.guessedLetters = [];
|
||||
gameState.wrongGuesses = 0;
|
||||
|
||||
console.log(`Drawer ${username} left, new drawer is ${newDrawer}`);
|
||||
|
||||
io.to(roomId).emit('game-drawer-changed', {
|
||||
newDrawer: newDrawer,
|
||||
reason: 'drawer_left',
|
||||
message: `${username} (dessinateur) a quitté, ${newDrawer} devient le nouveau dessinateur`
|
||||
});
|
||||
startRoomTimer(io, roomId, 60);
|
||||
}
|
||||
}
|
||||
handlePlayerDeparture(io, roomId, username);
|
||||
|
||||
await checkAndStopSinglePlayerGame(io, roomId, dbRoomId);
|
||||
|
||||
@@ -956,6 +963,7 @@ function setupSocketIO(io)
|
||||
username: socket.user.username,
|
||||
userId: socket.user.userId
|
||||
});
|
||||
handlePlayerDeparture(io, roomId, socket.user.username);
|
||||
|
||||
// Get updated player list and broadcast
|
||||
if (dbRoomId) {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* Initializes windows and handles menu interactions
|
||||
*/
|
||||
import { windowRegistry } from './core/windows.js';
|
||||
import { API, STORAGE_KEYS } from './core/config.js';
|
||||
import { eventBus, Events } from './core/events.js';
|
||||
import { LoginWindow } from './windows/login.js';
|
||||
import { LogoutWindow } from './windows/logout.js';
|
||||
import { GlobalChat } from './windows/global_chat.js';
|
||||
@@ -17,6 +19,7 @@ import { StatsWindow } from './windows/stats.js';
|
||||
*/
|
||||
class App {
|
||||
constructor() {
|
||||
this.invalidateStaleToken();
|
||||
this.initWindows();
|
||||
this.initMenu();
|
||||
this.initPage();
|
||||
@@ -24,6 +27,51 @@ class App {
|
||||
this.colorizeUI();
|
||||
}
|
||||
|
||||
async invalidateStaleToken() {
|
||||
const token = localStorage.getItem(STORAGE_KEYS.AUTH_TOKEN);
|
||||
if (!token) return;
|
||||
|
||||
if (this.isJwtExpired(token)) {
|
||||
localStorage.removeItem(STORAGE_KEYS.AUTH_TOKEN);
|
||||
eventBus.emit(Events.USER_LOGGED_OUT);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(API.STATS.ME, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
if (response.status === 401) {
|
||||
localStorage.removeItem(STORAGE_KEYS.AUTH_TOKEN);
|
||||
eventBus.emit(Events.USER_LOGGED_OUT);
|
||||
setTimeout(() => window.location.reload(), 500);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Token validation skipped:', error);
|
||||
}
|
||||
}
|
||||
|
||||
isJwtExpired(token) {
|
||||
try {
|
||||
const payload = this.decodeJwtPayload(token);
|
||||
if (!payload || !payload.exp) return false;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
return payload.exp <= now;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
decodeJwtPayload(token) {
|
||||
const parts = token.split('.');
|
||||
if (parts.length < 2) return null;
|
||||
|
||||
const base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
|
||||
const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');
|
||||
return JSON.parse(atob(padded));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all windows
|
||||
*/
|
||||
|
||||
@@ -82,6 +82,7 @@ html {
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
color: var(--color-text);
|
||||
line-height: 1.5;
|
||||
|
||||
Reference in New Issue
Block a user