reconexion basada en el UUID
This commit is contained in:
@@ -226,6 +226,16 @@ export class GameRoom extends Room<GameState> {
|
||||
|
||||
// Removed nextRound handler - rounds now auto-advance
|
||||
|
||||
// Persist reconnection token per UUID (sent by client after join)
|
||||
this.onMessage("registerReconnection", (client, token: string) => {
|
||||
const uuid = this.sessionToUuid.get(client.sessionId);
|
||||
if (!uuid) return;
|
||||
try {
|
||||
const { NameManager } = require("../utils/nameManager");
|
||||
NameManager.getInstance().setReconnectToken(uuid, (token || '').toString());
|
||||
} catch {}
|
||||
});
|
||||
|
||||
this.onMessage("admin:kick", (client, playerId: string) => {
|
||||
this.handleKick(playerId);
|
||||
});
|
||||
@@ -233,6 +243,44 @@ export class GameRoom extends Room<GameState> {
|
||||
|
||||
onJoin(client: Client, options: any) {
|
||||
console.log(`[GameRoom] ${client.sessionId} joined room ${this.roomId} with name: ${options.playerName}`);
|
||||
const uuid = options?.uuid as string | undefined;
|
||||
|
||||
// UUID-based reconnection: if game already started or room is full, allow join if UUID matches a participant
|
||||
if ((this.state.gameStatus !== GameStatus.WAITING || this.state.players.size >= 2) && uuid) {
|
||||
// Try to find a matching player by UUID
|
||||
let foundKey: string | null = null;
|
||||
this.state.players.forEach((p, key) => {
|
||||
if ((p as any).uuid && (p as any).uuid === uuid) {
|
||||
foundKey = key;
|
||||
}
|
||||
});
|
||||
if (foundKey) {
|
||||
// Rebind player to new sessionId
|
||||
const player = this.state.players.get(foundKey!);
|
||||
if (player) {
|
||||
this.state.players.delete(foundKey!);
|
||||
player.sessionId = client.sessionId;
|
||||
player.connected = true;
|
||||
this.state.players.set(client.sessionId, player);
|
||||
if (this.state.p1Id === foundKey) this.state.p1Id = client.sessionId;
|
||||
if (this.state.p2Id === foundKey) this.state.p2Id = client.sessionId;
|
||||
this.sessionToUuid.set(client.sessionId, uuid);
|
||||
// Let client know identity
|
||||
client.send("playerInfo", { sessionId: client.sessionId, name: player.name, roomId: this.roomId });
|
||||
// If paused and both connected, resume
|
||||
if (this.state.gameStatus === GameStatus.PAUSED && this.getConnectedPlayersCount() === 2) {
|
||||
this.state.resumeGame();
|
||||
this.setMetadata({
|
||||
gameStatus: 'playing',
|
||||
currentRound: this.state.currentRound,
|
||||
currentVariant: this.state.currentVariant
|
||||
});
|
||||
broadcastDashboardUpdate();
|
||||
}
|
||||
return; // Do not proceed with normal join flow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling for shuffled players
|
||||
if (this.isWaitingForShuffledPlayers && options.uuid) {
|
||||
@@ -246,8 +294,8 @@ export class GameRoom extends Room<GameState> {
|
||||
}
|
||||
|
||||
// Store UUID mapping if provided
|
||||
if (options.uuid) {
|
||||
this.sessionToUuid.set(client.sessionId, options.uuid);
|
||||
if (uuid) {
|
||||
this.sessionToUuid.set(client.sessionId, uuid);
|
||||
}
|
||||
|
||||
// Use the playerName passed from the lobby - don't generate a new one!
|
||||
@@ -259,6 +307,7 @@ export class GameRoom extends Room<GameState> {
|
||||
const p = this.state.players.get(client.sessionId);
|
||||
if (p) {
|
||||
p.color = playerColor;
|
||||
if (uuid) (p as any).uuid = uuid;
|
||||
}
|
||||
|
||||
client.send("playerInfo", {
|
||||
@@ -280,6 +329,14 @@ export class GameRoom extends Room<GameState> {
|
||||
if (this.state.players.size === 2 && this.state.gameStatus === GameStatus.WAITING) {
|
||||
this.startGame();
|
||||
}
|
||||
|
||||
// Persist current room mapping by UUID
|
||||
if (uuid) {
|
||||
try {
|
||||
const { NameManager } = require("../utils/nameManager");
|
||||
NameManager.getInstance().setCurrentRoom(uuid, this.roomId);
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
onLeave(client: Client, consented: boolean) {
|
||||
@@ -400,6 +457,20 @@ export class GameRoom extends Room<GameState> {
|
||||
});
|
||||
// Notify dashboard of game end
|
||||
broadcastDashboardUpdate();
|
||||
|
||||
// Clear UUID -> current room mapping and reconnection tokens for participants
|
||||
try {
|
||||
const { NameManager } = require("../utils/nameManager");
|
||||
const toClear: string[] = [];
|
||||
this.state.players.forEach((p) => {
|
||||
const u = (p as any)?.uuid;
|
||||
if (u) toClear.push(u);
|
||||
});
|
||||
toClear.forEach(u => {
|
||||
NameManager.getInstance().clearCurrentRoom(u);
|
||||
NameManager.getInstance().clearReconnectToken(u);
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
private resolveP2Action() {
|
||||
|
||||
@@ -44,6 +44,32 @@ export class LobbyRoom extends Room<LobbyState> {
|
||||
// Store UUID mapping if provided
|
||||
if (options.uuid) {
|
||||
this.sessionToUuid.set(client.sessionId, options.uuid);
|
||||
|
||||
// If this UUID has a current active game room assignment, redirect there
|
||||
try {
|
||||
const currentRoomId = NameManager.getInstance().getCurrentRoom(options.uuid);
|
||||
if (currentRoomId) {
|
||||
// Verify room exists and is not finished
|
||||
matchMaker.query({ roomId: currentRoomId }).then((rooms) => {
|
||||
const room = rooms[0];
|
||||
const status = room?.metadata?.gameStatus || "waiting";
|
||||
if (room && status !== "finished") {
|
||||
const token = NameManager.getInstance().getReconnectToken(options.uuid);
|
||||
if (token) {
|
||||
// Prefer reconnection token to bypass room lock
|
||||
client.send("resumeReconnection", { token });
|
||||
} else {
|
||||
// Fallback to joinById path
|
||||
client.send("resumeGame", { roomId: currentRoomId });
|
||||
}
|
||||
// Mark as in game on lobby state to avoid duplicate quickPlay
|
||||
const p = this.state.players.get(client.sessionId);
|
||||
if (p) p.inGame = true;
|
||||
return;
|
||||
}
|
||||
}).catch(() => {});
|
||||
}
|
||||
} catch {}
|
||||
|
||||
// Check for shuffle redirect FIRST
|
||||
if (NameManager.getInstance().isShuffleInProgress()) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Schema, type } from "@colyseus/schema";
|
||||
|
||||
export class Player extends Schema {
|
||||
@type("string") sessionId: string = "";
|
||||
@type("string") uuid: string = "";
|
||||
@type("string") name: string = "";
|
||||
@type("number") clicks: number = 0;
|
||||
@type("boolean") connected: boolean = true;
|
||||
@@ -22,6 +23,7 @@ export class Player extends Schema {
|
||||
this.eloteTokens = 0;
|
||||
this.shameTokens = 0;
|
||||
this.color = "#667eea";
|
||||
this.uuid = "";
|
||||
}
|
||||
|
||||
incrementClicks(): void {
|
||||
|
||||
@@ -6,6 +6,8 @@ export class NameManager {
|
||||
// For shuffle functionality
|
||||
private roomAssignments: Map<string, { roomId: string; role: 'P1' | 'P2' }> = new Map();
|
||||
private shuffleInProgress: boolean = false;
|
||||
private uuidToCurrentRoom: Map<string, string> = new Map();
|
||||
private uuidToReconnectToken: Map<string, string> = new Map();
|
||||
|
||||
private constructor() {}
|
||||
|
||||
@@ -68,6 +70,34 @@ export class NameManager {
|
||||
return Array.from(this.uuidToName.values());
|
||||
}
|
||||
|
||||
// Current game room assignment (for reconnection by UUID)
|
||||
setCurrentRoom(uuid: string, roomId: string): void {
|
||||
if (!uuid || !roomId) return;
|
||||
this.uuidToCurrentRoom.set(uuid, roomId);
|
||||
}
|
||||
|
||||
getCurrentRoom(uuid: string): string | undefined {
|
||||
return this.uuidToCurrentRoom.get(uuid);
|
||||
}
|
||||
|
||||
clearCurrentRoom(uuid: string): void {
|
||||
this.uuidToCurrentRoom.delete(uuid);
|
||||
}
|
||||
|
||||
// Reconnection token per UUID (to join locked rooms)
|
||||
setReconnectToken(uuid: string, token: string): void {
|
||||
if (!uuid || !token) return;
|
||||
this.uuidToReconnectToken.set(uuid, token);
|
||||
}
|
||||
|
||||
getReconnectToken(uuid: string): string | undefined {
|
||||
return this.uuidToReconnectToken.get(uuid);
|
||||
}
|
||||
|
||||
clearReconnectToken(uuid: string): void {
|
||||
this.uuidToReconnectToken.delete(uuid);
|
||||
}
|
||||
|
||||
// Shuffle functionality methods
|
||||
startShuffle(): void {
|
||||
this.shuffleInProgress = true;
|
||||
|
||||
Reference in New Issue
Block a user