refactor(gameplay): move transition event composition into service
All checks were successful
CI / test-and-quality (pull_request) Successful in 3m36s
CI / test-and-quality (push) Successful in 3m37s

This commit is contained in:
2026-03-17 11:58:39 +00:00
parent 9baade0105
commit 8a07433f11
3 changed files with 37 additions and 36 deletions

View File

@@ -1,9 +1,11 @@
import random
from dataclasses import dataclass
from typing import Any
from django.db import transaction
from .models import GameSession, Guess, LieAnswer, Player, Question, RoundConfig, RoundQuestion, ScoreEvent
from .payloads import build_finish_game_phase_event, build_start_next_round_phase_event
@dataclass(frozen=True)
@@ -12,12 +14,16 @@ class RoundTransitionResult:
round_config: RoundConfig
round_question: RoundQuestion
should_broadcast: bool
phase_event_name: str | None = None
phase_event_payload: dict[str, Any] | None = None
@dataclass(frozen=True)
class FinishGameResult:
session: GameSession
should_broadcast: bool
phase_event_name: str | None = None
phase_event_payload: dict[str, Any] | None = None
@dataclass(frozen=True)
@@ -102,6 +108,9 @@ def start_next_round(session: GameSession) -> RoundTransitionResult:
round_question = None
should_broadcast = False
phase_event_name = None
phase_event_payload = None
if locked_session.status == GameSession.Status.SCOREBOARD:
previous_round_config = RoundConfig.objects.filter(
session=locked_session,
@@ -129,6 +138,9 @@ def start_next_round(session: GameSession) -> RoundTransitionResult:
locked_session.status = GameSession.Status.LIE
locked_session.save(update_fields=["current_round", "status"])
should_broadcast = True
phase_event = build_start_next_round_phase_event(locked_session, next_round_config, round_question)
phase_event_name = phase_event["name"]
phase_event_payload = phase_event["payload"]
elif locked_session.status == GameSession.Status.LIE:
if locked_session.current_round <= 1:
raise ValueError("next_round_invalid_phase")
@@ -152,6 +164,8 @@ def start_next_round(session: GameSession) -> RoundTransitionResult:
round_config=next_round_config,
round_question=round_question,
should_broadcast=should_broadcast,
phase_event_name=phase_event_name,
phase_event_payload=phase_event_payload,
)
@@ -160,15 +174,25 @@ def finish_game(session: GameSession) -> FinishGameResult:
with transaction.atomic():
locked_session = GameSession.objects.select_for_update().get(pk=session.pk)
should_broadcast = False
phase_event_name = None
phase_event_payload = None
if locked_session.status == GameSession.Status.SCOREBOARD:
locked_session.status = GameSession.Status.FINISHED
locked_session.save(update_fields=["status"])
should_broadcast = True
phase_event = build_finish_game_phase_event(locked_session)
phase_event_name = phase_event["name"]
phase_event_payload = phase_event["payload"]
elif locked_session.status != GameSession.Status.FINISHED:
raise ValueError("finish_game_invalid_phase")
return FinishGameResult(session=locked_session, should_broadcast=should_broadcast)
return FinishGameResult(
session=locked_session,
should_broadcast=should_broadcast,
phase_event_name=phase_event_name,
phase_event_payload=phase_event_payload,
)