feat: reconexión de sesión + 6 nuevas categorías + corrección de bugs

- Añade sistema de reconexión tras refresh/cierre del navegador
  - Persistencia de sesión en localStorage (3h TTL)
  - Banner de reconexión en Home
  - Evento rejoin_room en backend

- Nuevas categorías: Series TV, Marvel/DC, Disney, Memes, Pokémon, Mitología

- Correcciones de bugs:
  - Fix: juego bloqueado al fallar robo (steal decision)
  - Fix: jugador duplicado al cambiar de equipo
  - Fix: rotación incorrecta de turno tras fallo

- Config: soporte para Cloudflare tunnel (allowedHosts)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-27 01:53:32 +00:00
parent 6248037b47
commit 112f489e40
9 changed files with 327 additions and 12 deletions

View File

@@ -141,9 +141,17 @@ class GameManager:
else:
# Original team failed - enable steal
failed_team = room["current_team"]
room["can_steal"] = True
# Advance failed team's player index (they had their turn)
team_players = room["teams"][failed_team]
room["current_player_index"][failed_team] = (
room["current_player_index"][failed_team] + 1
) % len(team_players)
# Switch to other team for potential steal
room["current_team"] = "B" if room["current_team"] == "A" else "A"
room["current_team"] = "B" if failed_team == "A" else "A"
# Check if game is over (all questions answered)
all_answered = all(

View File

@@ -168,6 +168,23 @@ class RoomManager:
return json.loads(data)
return None
async def update_player(self, socket_id: str, updates: dict) -> Optional[dict]:
"""Update player info."""
await self.connect()
data = await self.redis.get(f"player:{socket_id}")
if not data:
return None
player = json.loads(data)
player.update(updates)
await self.redis.setex(
f"player:{socket_id}",
3600 * 3,
json.dumps(player)
)
return player
async def get_player_stats(self, room_code: str, player_name: str) -> Optional[dict]:
"""Obtiene stats de un jugador."""
await self.connect()