import enum import uuid from datetime import datetime from sqlalchemy import DateTime, ForeignKey, Integer, String from sqlalchemy import Enum as SAEnum from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database import Base class Mode(str, enum.Enum): casual = "casual" class ServerStatus(str, enum.Enum): available = "available" full = "full" offline = "offline" # No account/auth system yet (GodotSteam auth is still on the networking # checklist), so callsign is the identity key for now — same as the game # client itself, which only has a free-text name field today. class Player(Base): __tablename__ = "players" id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4) callsign: Mapped[str] = mapped_column(String(32), unique=True, index=True) mmr: Mapped[int] = mapped_column(Integer, default=1000) wins: Mapped[int] = mapped_column(Integer, default=0) losses: Mapped[int] = mapped_column(Integer, default=0) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) class GameServer(Base): __tablename__ = "game_servers" id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4) ip: Mapped[str] = mapped_column(String(255)) port: Mapped[int] = mapped_column(Integer) mode: Mapped[Mode] = mapped_column(SAEnum(Mode)) status: Mapped[ServerStatus] = mapped_column(SAEnum(ServerStatus), default=ServerStatus.available) last_heartbeat: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) # DB-stored fallback shown immediately in the server list; a live server # is queried directly for its real-time count (see # spacewar/autoload/network_manager.gd's UDP query responder and # menu/server_select.gd's ping probe), which overrides this in the UI # once that probe answers. player_count: Mapped[int] = mapped_column(Integer, default=0) max_players: Mapped[int] = mapped_column(Integer, default=50) class Match(Base): __tablename__ = "matches" id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4) mode: Mapped[Mode] = mapped_column(SAEnum(Mode)) server_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("game_servers.id")) started_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) players: Mapped[list["MatchPlayer"]] = relationship(back_populates="match") class MatchPlayer(Base): __tablename__ = "match_players" id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4) match_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("matches.id")) player_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("players.id")) team: Mapped[int] = mapped_column(Integer) # 0 or 1 match: Mapped["Match"] = relationship(back_populates="players")