Files
SlipItIn/openwiki/domain/game-mechanics.md
2026-08-08 12:50:15 +02:00

9.1 KiB

type, title, description, tags, openwiki
type title description tags openwiki
Domain Model Game Domain & State Models Detailed domain model and state lifecycles for SlipItIn games, rounds, phrase decks, players, challenges, and client offline action queue.
domain
models
state-machine
entity-framework
privacy
offline-queue
roles change_kinds source_paths symbols validation_commands
domain
public-api
lifecycle
SlipItIn.Shared/Models/Game.cs
SlipItIn.Shared/Models/Player.cs
SlipItIn/Models/QueuedGameAction.cs
SlipItIn.Shared/DTOs/GameStateDto.cs
Game
Player
PlayerCard
SlipChallenge
QueuedGameAction
GameStateDto
PlayerHandDto
dotnet build SlipItIn.Shared/SlipItIn.Shared.csproj

Game Domain & State Models

This page describes the core domain entities, relational schema, state machines, offline action queue models, and data transfer objects (DTOs) that form the foundation of the SlipItIn game engine.

The domain model is secured by data privacy models defined in the system architecture, defines state lifecycles executed by real-time game workflows, and maps domain classes in C# project files indexed in the source map (SlipItIn.Shared/Models/, SlipItIn.Shared/DTOs/, and SlipItIn/Models/).


1. Entity Relationship Diagram (ERD)

The backend database schema is managed via Entity Framework Core (SlipItInDbContext) targeting PostgreSQL.

erDiagram
    User {
        int Id PK
        string Username
        string Email
        string PasswordHash
        bool IsActive
    }
    Game {
        int Id PK
        string LobbyCode
        int HostId FK
        GameStatus Status
        int MaxPlayers
        int RoundDurationSeconds
    }
    Player {
        int Id PK
        int UserId FK
        int GameId FK
        int Score
        bool IsReady
        string ConnectionId
    }
    Phrase {
        int Id PK
        string Text
        int CreatorId FK
        bool IsActive
    }
    GameRound {
        int Id PK
        int GameId FK
        int RoundNumber
        RoundStatus Status
    }
    PlayerCard {
        int Id PK
        int PlayerId FK
        int PhraseId FK
        int GameRoundId FK
        bool IsUsed
    }
    SlipChallenge {
        int Id PK
        int GameRoundId FK
        int ChallengingPlayerId FK
        int TargetPlayerId FK
        int TargetCardId FK
        ChallengeStatus Status
    }

    User ||--o{ Game : hosts
    User ||--o{ Player : participates_as
    User ||--o{ Phrase : creates
    Game ||--o{ Player : contains
    Game ||--o{ GameRound : has
    Player ||--o{ PlayerCard : holds
    Phrase ||--o{ PlayerCard : used_in
    GameRound ||--o{ PlayerCard : active_in
    GameRound ||--o{ SlipChallenge : contains
    Player ||--o{ SlipChallenge : challenges
    Player ||--o{ SlipChallenge : target_of
    PlayerCard ||--o{ SlipChallenge : targeted_by

Entity Relationship Diagram showing relational database schema for users, games, players, phrases, cards, rounds, and challenges.


2. Core Domain Entities (SlipItIn.Shared/Models)

User

Represents an authenticated account.

  • Properties: Id, Username, Email, PasswordHash (BCrypt), CreatedAt, IsActive.
  • Relations: Navigation properties to created Game instances, player entries (Players), and created phrases (Phrases).

Game

Represents a multiplayer game session / lobby.

  • Properties: Id, LobbyCode (6-char alphanumeric), HostId, Status (GameStatus), CreatedAt, StartedAt, EndedAt, MaxPlayers (default 8), RoundDurationSeconds (30-60s).
  • Relations: Host (User), Players (ICollection<Player>), Rounds (ICollection<GameRound>).

Player

Represents a user's participation inside a specific Game.

  • Properties: Id, UserId, GameId, Score, SuccessfulSlips, FailedSlips, JoinedAt, IsReady, ConnectionId (active SignalR connection ID).
  • Relations: User, Game, Cards (ICollection<PlayerCard>).

Phrase

Represents a secret phrase or sentence created for the game deck.

  • Properties: Id, Text, CreatorId, CreatedAt, IsActive.
  • Relations: Creator (User), PlayerCards (ICollection<PlayerCard>).

GameRound

Tracks a distinct round within a game.

  • Properties: Id, GameId, RoundNumber, Status (RoundStatus), StartedAt, EndedAt.
  • Relations: Game, ActiveCards (ICollection<PlayerCard>), Challenges (ICollection<SlipChallenge>).

PlayerCard

Represents a specific phrase card dealt to a player for a round.

  • Properties: Id, PlayerId, PhraseId, GameRoundId, IsUsed (boolean flag set when player submits slip), AssignedAt.
  • Relations: Player, Phrase, GameRound.

SlipChallenge

Represents an accusation made by one player against another player's submitted slip.

  • Properties: Id, GameRoundId, ChallengingPlayerId, TargetPlayerId, TargetCardId, Status (ChallengeStatus), CreatedAt, ResolvedAt.
  • Relations: GameRound, ChallengingPlayer, TargetPlayer, TargetCard.

3. Client State & Offline Action Queue Models (SlipItIn/Models)

QueuedGameAction

Represents a game action (such as SubmitSlip or ChallengeSlip) initiated on the client while offline (!SignalRService.IsConnected).

  • Properties:
    • Method: Target SignalR hub method name (e.g. "SubmitSlip", "ChallengeSlip").
    • ArgumentsJson: JSON serialized array of method arguments.
    • CreatedAtUtc: Timestamp recording when the action was taken.
  • Lifecycle: Enqueued into Preferences via GameStateService.EnqueueActionAsync(), replayed sequentially upon reconnection via GameStateService.FlushQueuedActionsAsync(), and removed from storage.

4. Enumerations & State Lifecycles

Game Status (GameStatus)

stateDiagram-v2
    [*] --> Lobby: CreateGameAsync()
    Lobby --> InProgress: StartGameAsync() (Host only)
    InProgress --> Completed: All rounds finished
    Lobby --> Cancelled: Host cancels
    InProgress --> Cancelled: Session abort

State diagram illustrating lifecycle transitions of a game session from lobby creation to completion or cancellation.

  • Lobby: Waiting for players to join and set ready status.
  • InProgress: Active gameplay with dealt cards and active rounds.
  • Completed: Game finished, final scores tallied.
  • Cancelled: Lobby or game terminated early.

Round Status (RoundStatus)

stateDiagram-v2
    [*] --> Waiting: StartGame / New Round
    Waiting --> Active: DealCardsAsync()
    Active --> Resolving: Challenge submitted
    Resolving --> Active: Challenge resolved
    Active --> Completed: Timer expires / All phrases used

State diagram illustrating round lifecycles from card dealing to challenge resolution.

Challenge Status (ChallengeStatus)

  • Pending: Accusation registered, awaiting response from the accused player.
  • Approved: Accusation confirmed (the phrase was indeed an invalid slip). The card remains with the accused player.
  • Rejected: Accusation rejected (the slip was legitimate). As a penalty, the card is transferred to the accuser's hand (PlayerCard.PlayerId = ChallengingPlayerId).

5. Data Transfer Objects (DTOs) & Data Privacy

To enforce security and data privacy (Architecture Overview), the backend exposes decoupled DTOs in SlipItIn.Shared/DTOs:

DTO Visibility Purpose & Content
LoginRequestDto Direct REST Credentials for authentication: Email, Password.
RegisterRequestDto Direct REST Account creation details: Username, Email, Password.
AuthResponseDto Direct REST JWT Access Token, Expiration, Username, Email.
GameStateDto Broadcast (Group) Public lobby/game status: GameId, LobbyCode, Status, CurrentRound, RoundTimeRemaining, Players (PlayerInfoDto array containing PlayerId, Username, Score, IsReady, and CardCount). No card text.
PlayerHandDto Unicast (Client) Private hand data sent strictly to the card owner: PlayerId, Cards (PlayerCardDto array containing CardId, PhraseId, Text, IsUsed).
SlipChallengeDto Unicast / Group Challenge notification: ChallengeId, ChallengingPlayerId, TargetPlayerId, TargetCardId, Status, CreatedAt.

6. Guidance for Future Agents & Developers

  • When to Consult: Consult this page when adding domain attributes, extending DTOs, adding new game state statuses, or modifying offline action serialization.
  • Invariants:
    • PlayerCard.IsUsed transitions from false to true upon SubmitSlip and cannot be reverted without server intervention.
    • QueuedGameAction.ArgumentsJson must store arguments in the exact order and type expected by GameHub methods.
  • Primary Source Files:
    • SlipItIn.Shared/Models/Game.cs
    • SlipItIn.Shared/Models/PlayerCard.cs
    • SlipItIn.Shared/DTOs/GameStateDto.cs
    • SlipItIn/Models/QueuedGameAction.cs
  • Minimal Validation Command:
    dotnet build SlipItIn.Shared/SlipItIn.Shared.csproj