CLAUDE: Auto-start game when both lineups submitted
- Broadcast game_state_update in game_engine.start_game() so frontend receives the active state immediately - Add auto-start safeguard to /lineup-status endpoint for stuck pending games (both in-memory and database code paths) - Fix None handling in state_manager._rebuild_state_from_data() for pending games with null inning/half values Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
1f5e290d8b
commit
4cb8e3f6c4
@ -858,6 +858,16 @@ async def get_lineup_status(game_id: str):
|
|||||||
for p in (away_lineup.players if away_lineup else [])
|
for p in (away_lineup.players if away_lineup else [])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Safeguard: Auto-start game if both lineups ready but game still pending
|
||||||
|
game_status = state.status
|
||||||
|
if home_count >= 9 and away_count >= 9 and game_status == "pending":
|
||||||
|
try:
|
||||||
|
logger.info(f"Auto-starting game {game_id} (in-memory) - both lineups ready but game was pending")
|
||||||
|
await game_engine.start_game(game_uuid)
|
||||||
|
game_status = "active"
|
||||||
|
except Exception as start_error:
|
||||||
|
logger.warning(f"Failed to auto-start game {game_id}: {start_error}")
|
||||||
|
|
||||||
return LineupStatusResponse(
|
return LineupStatusResponse(
|
||||||
game_id=game_id,
|
game_id=game_id,
|
||||||
home_team_id=state.home_team_id,
|
home_team_id=state.home_team_id,
|
||||||
@ -866,7 +876,7 @@ async def get_lineup_status(game_id: str):
|
|||||||
away_lineup_submitted=away_count >= 9,
|
away_lineup_submitted=away_count >= 9,
|
||||||
home_lineup_count=home_count,
|
home_lineup_count=home_count,
|
||||||
away_lineup_count=away_count,
|
away_lineup_count=away_count,
|
||||||
game_status=state.status,
|
game_status=game_status,
|
||||||
home_lineup=home_lineup_data,
|
home_lineup=home_lineup_data,
|
||||||
away_lineup=away_lineup_data,
|
away_lineup=away_lineup_data,
|
||||||
)
|
)
|
||||||
@ -905,6 +915,20 @@ async def get_lineup_status(game_id: str):
|
|||||||
if lineup.player_id is not None
|
if lineup.player_id is not None
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Safeguard: Auto-start game if both lineups are ready but game is still pending
|
||||||
|
# This handles edge cases where lineups were submitted before the auto-start fix
|
||||||
|
game_status = game.status
|
||||||
|
if home_count >= 9 and away_count >= 9 and game_status == "pending":
|
||||||
|
try:
|
||||||
|
logger.info(f"Auto-starting game {game_id} - both lineups ready but game was pending")
|
||||||
|
# First recover game into state manager (required before start_game)
|
||||||
|
await state_manager.recover_game(game_uuid)
|
||||||
|
await game_engine.start_game(game_uuid)
|
||||||
|
game_status = "active"
|
||||||
|
except Exception as start_error:
|
||||||
|
logger.warning(f"Failed to auto-start game {game_id}: {start_error}")
|
||||||
|
# Continue with pending status - user can retry
|
||||||
|
|
||||||
return LineupStatusResponse(
|
return LineupStatusResponse(
|
||||||
game_id=game_id,
|
game_id=game_id,
|
||||||
home_team_id=game.home_team_id,
|
home_team_id=game.home_team_id,
|
||||||
@ -913,7 +937,7 @@ async def get_lineup_status(game_id: str):
|
|||||||
away_lineup_submitted=away_count >= 9,
|
away_lineup_submitted=away_count >= 9,
|
||||||
home_lineup_count=home_count,
|
home_lineup_count=home_count,
|
||||||
away_lineup_count=away_count,
|
away_lineup_count=away_count,
|
||||||
game_status=game.status,
|
game_status=game_status,
|
||||||
home_lineup=home_lineup_data,
|
home_lineup=home_lineup_data,
|
||||||
away_lineup=away_lineup_data,
|
away_lineup=away_lineup_data,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -253,6 +253,14 @@ class GameEngine:
|
|||||||
# Update state
|
# Update state
|
||||||
state_manager.update_state(game_id, state)
|
state_manager.update_state(game_id, state)
|
||||||
|
|
||||||
|
# Broadcast game_state_update so all connected clients get the new active state
|
||||||
|
if self._connection_manager:
|
||||||
|
await self._connection_manager.broadcast_to_game(
|
||||||
|
str(game_id),
|
||||||
|
"game_state_update",
|
||||||
|
state.model_dump(mode='json')
|
||||||
|
)
|
||||||
|
|
||||||
# Emit decision_required event for real-time frontend notification
|
# Emit decision_required event for real-time frontend notification
|
||||||
await self._emit_decision_required(game_id, state, "awaiting_defensive", timeout_seconds=self.DECISION_TIMEOUT)
|
await self._emit_decision_required(game_id, state, "awaiting_defensive", timeout_seconds=self.DECISION_TIMEOUT)
|
||||||
|
|
||||||
|
|||||||
@ -322,7 +322,8 @@ class StateManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Determine fielding team based on current half
|
# Determine fielding team based on current half
|
||||||
current_half = game.get("current_half", "top")
|
# Use `or` to handle explicit None values from database (not just missing keys)
|
||||||
|
current_half = game.get("current_half") or "top"
|
||||||
home_team_id = game["home_team_id"]
|
home_team_id = game["home_team_id"]
|
||||||
away_team_id = game["away_team_id"]
|
away_team_id = game["away_team_id"]
|
||||||
|
|
||||||
@ -381,7 +382,7 @@ class StateManager:
|
|||||||
home_team_is_ai=game.get("home_team_is_ai", False),
|
home_team_is_ai=game.get("home_team_is_ai", False),
|
||||||
away_team_is_ai=game.get("away_team_is_ai", False),
|
away_team_is_ai=game.get("away_team_is_ai", False),
|
||||||
status=game["status"],
|
status=game["status"],
|
||||||
inning=game.get("current_inning", 1),
|
inning=game.get("current_inning") or 1,
|
||||||
half=current_half,
|
half=current_half,
|
||||||
home_score=game.get("home_score", 0),
|
home_score=game.get("home_score", 0),
|
||||||
away_score=game.get("away_score", 0),
|
away_score=game.get("away_score", 0),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user