98 lines
3.1 KiB
Python
98 lines
3.1 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import asdict, dataclass, field
|
|
from datetime import datetime, timezone
|
|
from typing import Any
|
|
|
|
|
|
def utc_now_iso() -> str:
|
|
return datetime.now(timezone.utc).isoformat()
|
|
|
|
|
|
@dataclass
|
|
class Player:
|
|
player_id: str
|
|
room_id: str
|
|
name: str
|
|
is_host: bool = False
|
|
is_ready: bool = False
|
|
is_online: bool = True
|
|
joined_at: str = field(default_factory=utc_now_iso)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return asdict(self)
|
|
|
|
|
|
@dataclass
|
|
class PlayerAction:
|
|
player_id: str
|
|
player_name: str
|
|
content: str
|
|
submitted_at: str = field(default_factory=utc_now_iso)
|
|
action_type: str = "action"
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return asdict(self)
|
|
|
|
|
|
@dataclass
|
|
class GameState:
|
|
room_id: str
|
|
game_phase: str = "lobby"
|
|
chapter: int = 0
|
|
scene_id: str = "lobby"
|
|
scene_description: str = "玩家们聚集在雾港旅店的大堂,暴雨拍打着窗户。"
|
|
global_flags: dict[str, Any] = field(default_factory=dict)
|
|
discovered_clues: list[str] = field(default_factory=list)
|
|
inventory_by_player: dict[str, list[str]] = field(default_factory=dict)
|
|
npc_states: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
danger_level: int = 1
|
|
action_history: list[dict[str, Any]] = field(default_factory=list)
|
|
pending_choices: list[str] = field(default_factory=list)
|
|
ending_state: str | None = None
|
|
round_no: int = 0
|
|
last_updated_at: str = field(default_factory=utc_now_iso)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return asdict(self)
|
|
|
|
@classmethod
|
|
def from_dict(cls, payload: dict[str, Any]) -> "GameState":
|
|
return cls(
|
|
room_id=payload.get("room_id", ""),
|
|
game_phase=payload.get("game_phase", "lobby"),
|
|
chapter=int(payload.get("chapter", 0)),
|
|
scene_id=payload.get("scene_id", "lobby"),
|
|
scene_description=payload.get(
|
|
"scene_description", "玩家们聚集在雾港旅店的大堂,暴雨拍打着窗户。"
|
|
),
|
|
global_flags=dict(payload.get("global_flags", {})),
|
|
discovered_clues=list(payload.get("discovered_clues", [])),
|
|
inventory_by_player={
|
|
key: list(value) for key, value in dict(payload.get("inventory_by_player", {})).items()
|
|
},
|
|
npc_states={
|
|
key: dict(value) for key, value in dict(payload.get("npc_states", {})).items()
|
|
},
|
|
danger_level=int(payload.get("danger_level", 1)),
|
|
action_history=list(payload.get("action_history", [])),
|
|
pending_choices=list(payload.get("pending_choices", [])),
|
|
ending_state=payload.get("ending_state"),
|
|
round_no=int(payload.get("round_no", 0)),
|
|
last_updated_at=payload.get("last_updated_at", utc_now_iso()),
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class RoomSnapshot:
|
|
room_id: str
|
|
status: str
|
|
host_player_id: str
|
|
players: list[dict[str, Any]]
|
|
game_state: dict[str, Any]
|
|
pending_actions: list[dict[str, Any]]
|
|
messages: list[dict[str, Any]]
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return asdict(self)
|