init
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.orm import GameState
|
||||
from app.models.schemas import GamePhase, GameStateResponse
|
||||
|
||||
|
||||
class GameStateManager:
|
||||
PHASE_ORDER = GamePhase.ordered_phases()
|
||||
PHASE_COUNT = len(PHASE_ORDER)
|
||||
|
||||
async def get_state(self, session: AsyncSession) -> Optional[GameState]:
|
||||
result = await session.execute(
|
||||
select(GameState).order_by(GameState.created_at.desc()).limit(1)
|
||||
)
|
||||
return result.scalars().first()
|
||||
|
||||
async def get_or_create_state(self, session: AsyncSession) -> GameState:
|
||||
state = await self.get_state(session)
|
||||
if state is None:
|
||||
state = GameState(
|
||||
current_phase=GamePhase.INTRO.value,
|
||||
is_running=False,
|
||||
is_paused=False,
|
||||
)
|
||||
session.add(state)
|
||||
await session.commit()
|
||||
await session.refresh(state)
|
||||
return state
|
||||
|
||||
async def next_phase(self, session: AsyncSession) -> GameState:
|
||||
state = await self.get_or_create_state(session)
|
||||
current = state.current_phase
|
||||
try:
|
||||
idx = self.PHASE_ORDER.index(current)
|
||||
if idx < self.PHASE_COUNT - 1:
|
||||
state.current_phase = self.PHASE_ORDER[idx + 1]
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
state.phase_started_at = datetime.utcnow()
|
||||
state.updated_at = datetime.utcnow()
|
||||
await session.commit()
|
||||
await session.refresh(state)
|
||||
return state
|
||||
|
||||
async def prev_phase(self, session: AsyncSession) -> GameState:
|
||||
state = await self.get_or_create_state(session)
|
||||
current = state.current_phase
|
||||
try:
|
||||
idx = self.PHASE_ORDER.index(current)
|
||||
if idx > 0:
|
||||
state.current_phase = self.PHASE_ORDER[idx - 1]
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
state.phase_started_at = datetime.utcnow()
|
||||
state.updated_at = datetime.utcnow()
|
||||
await session.commit()
|
||||
await session.refresh(state)
|
||||
return state
|
||||
|
||||
def get_current_phase(self, state: GameState) -> str:
|
||||
return state.current_phase
|
||||
|
||||
def get_progress_percent(self, state: GameState) -> float:
|
||||
try:
|
||||
idx = self.PHASE_ORDER.index(state.current_phase)
|
||||
return (idx / max(self.PHASE_COUNT - 1, 1)) * 100
|
||||
except ValueError:
|
||||
return 0.0
|
||||
|
||||
async def start_game(self, session: AsyncSession, script_id: str) -> GameState:
|
||||
state = await self.get_or_create_state(session)
|
||||
state.active_script_id = script_id
|
||||
state.current_phase = GamePhase.INTRO.value
|
||||
state.is_running = True
|
||||
state.is_paused = False
|
||||
state.phase_started_at = datetime.utcnow()
|
||||
state.updated_at = datetime.utcnow()
|
||||
await session.commit()
|
||||
await session.refresh(state)
|
||||
return state
|
||||
|
||||
async def pause_game(self, session: AsyncSession) -> GameState:
|
||||
state = await self.get_or_create_state(session)
|
||||
state.is_paused = True
|
||||
state.updated_at = datetime.utcnow()
|
||||
await session.commit()
|
||||
await session.refresh(state)
|
||||
return state
|
||||
|
||||
async def resume_game(self, session: AsyncSession) -> GameState:
|
||||
state = await self.get_or_create_state(session)
|
||||
state.is_paused = False
|
||||
state.updated_at = datetime.utcnow()
|
||||
await session.commit()
|
||||
await session.refresh(state)
|
||||
return state
|
||||
|
||||
async def reset(self, session: AsyncSession) -> GameState:
|
||||
state = await self.get_or_create_state(session)
|
||||
state.current_phase = GamePhase.INTRO.value
|
||||
state.current_speaker_id = None
|
||||
state.speaker_order = []
|
||||
state.active_script_id = None
|
||||
state.is_running = False
|
||||
state.is_paused = False
|
||||
state.phase_started_at = None
|
||||
state.config = {}
|
||||
state.updated_at = datetime.utcnow()
|
||||
await session.commit()
|
||||
await session.refresh(state)
|
||||
return state
|
||||
|
||||
async def set_speaker(self, session: AsyncSession, character_id: str) -> GameState:
|
||||
state = await self.get_or_create_state(session)
|
||||
state.current_speaker_id = character_id
|
||||
state.updated_at = datetime.utcnow()
|
||||
await session.commit()
|
||||
await session.refresh(state)
|
||||
return state
|
||||
|
||||
def to_response(self, state: GameState) -> GameStateResponse:
|
||||
return GameStateResponse(
|
||||
id=state.id,
|
||||
current_phase=GamePhase(state.current_phase),
|
||||
current_speaker_id=state.current_speaker_id,
|
||||
speaker_order=state.speaker_order or [],
|
||||
active_script_id=state.active_script_id,
|
||||
is_running=state.is_running,
|
||||
is_paused=state.is_paused,
|
||||
phase_started_at=state.phase_started_at,
|
||||
config=state.config or {},
|
||||
progress_percent=self.get_progress_percent(state),
|
||||
)
|
||||
|
||||
|
||||
game_state_manager = GameStateManager()
|
||||
Reference in New Issue
Block a user