# Cockatrice Architecture Analysis ## Target: /home/wall-o/projects/mtgonline/C++ ## Date: 2026-07-20 --- ## 1. Project Overview **Cockatrice** (v3.1.0 "Graduation Day") is a mature open-source MTG online client/server application written in C++20 using Qt 5/6. It has been maintained for many years and represents a battle-tested implementation of an online card game. ### Key Architectural Decisions: - **Server-Client separation**: The server (`servatrice`) is authoritative; the client (`cockatrice`) is a thin visualizer that sends commands through the server. - **Protocol Buffers**: All network communication uses `.proto` files — no custom serialization. This is the canonical contract between components. - **Event-driven game loop**: Qt signals/slots drive game state transitions. - **Plugin-like library structure**: Core logic lives in `libcockatrice_*` shared libraries. --- ## 2. Top-Level Directory Structure ``` Cockatrice/ ├── CMakeLists.txt # Root build system (C++20, Qt5/6, Protobuf) ├── servatrice/ # SERVER application │ ├── src/ │ │ ├── servatrice.cpp/h # Main server class │ │ ├── serversocketinterface.cpp/h # Per-client socket handler (~106KB — single massive file) │ │ ├── servatrice_database_interface.cpp/h # Database operations │ │ ├── isl_interface.cpp/h # Inter-server-link (cluster) support │ │ ├── smtp/ # Email support │ │ └── main.cpp/h │ ├── migrations/ # DB schema migrations │ └── resources/ # Config, SQL init ├── cockatrice/ # CLIENT application │ ├── src/ │ │ ├── client/ # Client network layer │ │ │ ├── network/ │ │ │ │ ├── connection_controller/ # Connection lifecycle │ │ │ │ ├── interfaces/ # Client-server interface abstractions │ │ │ │ ├── parsers/ # Protocol message parsers │ │ │ │ └── update/ # Auto-update checks │ │ │ ├── sound_engine.cpp/h # Audio feedback │ │ │ └── settings/ │ │ ├── game/ # GAME ENGINE │ │ │ ├── abstract_game.h/cpp # Game abstraction │ │ │ ├── game.cpp/h # Concrete game instance │ │ │ ├── game_event_handler.cpp/h # Central event dispatch │ │ │ ├── game_meta_info.h/cpp # Game metadata (wraps protobuf) │ │ │ ├── game_state.h/cpp # Board state tracking │ │ │ ├── phase.h/cpp # Turn phase definitions │ │ │ ├── player/ # Player logic │ │ │ │ ├── player_actions.cpp/h # Player commands │ │ │ │ ├── player_event_handler.cpp/h │ │ │ │ ├── player_logic.cpp/h # Player AI/logic │ │ │ │ ├── player_manager.cpp/h # Multiplayer coordination │ │ │ │ └── event_processing_options.h │ │ │ ├── board/ # Board visualization state │ │ │ │ ├── card_list.cpp/h │ │ │ │ ├── card_state.cpp/h │ │ │ │ └── counter_state.cpp/h │ │ │ ├── zones/ # Zone logic │ │ │ │ ├── card_zone_algorithms.h │ │ │ │ ├── card_zone_logic.cpp/h │ │ │ │ ├── hand_zone_logic.cpp/h │ │ │ │ ├── pile_zone_logic.cpp/h │ │ │ │ ├── stack_zone_logic.cpp/h │ │ │ │ ├── table_zone_logic.cpp/h │ │ │ │ └── view_zone_logic.cpp/h │ │ │ ├── replay.cpp/h # Game replay system │ │ │ └── arrow_registry.cpp/h # Card targeting arrows │ │ ├── game_graphics/ # Visual rendering layer │ │ │ ├── game_scene.cpp/h # QGraphicsScene for the board │ │ │ ├── game_view.cpp/h # View controller │ │ │ ├── board/ │ │ │ ├── deckview/ │ │ │ ├── dialogs/ │ │ │ ├── phases_toolbar.cpp/h # Phase navigation UI │ │ │ ├── player/ │ │ │ ├── tally/ # Life total displays │ │ │ ├── z_value_layer_manager.h │ │ │ └── z_values.h │ │ ├── database/ │ │ │ └── interface/ │ │ ├── filters/ # Deck/card filter system │ │ │ ├── deck_filter_string.cpp/h │ │ │ ├── filter_builder.cpp/h │ │ │ └── filter_tree_model.cpp/h │ │ ├── interface/ # UI/UX layer │ │ │ ├── window_main.cpp/h # Main application window │ │ │ ├── layouts/ │ │ │ ├── widgets/ │ │ │ ├── theme_manager.cpp/h # Theming system │ │ │ ├── card_picture_loader/ │ │ │ ├── deck_loader/ │ │ │ ├── pixel_map_generator.cpp/h │ │ │ ├── logger.cpp/h │ │ │ └── palette_editor/ │ │ └── main.cpp/h # Client entry point ├── oracle/ # CARD DATABASE TOOL │ └── (downloads card data from MTGJSON) ├── libcockatrice_card/ # Card data model library │ └── libcockatrice/card/ │ ├── card_info.cpp/h # Card information model │ ├── database/ # Card database access │ ├── format/ # Deck format support │ ├── import/ # Deck importers │ ├── printing/ # Printing history │ ├── relation/ # Card relationships │ └── set/ # Set data ├── libcockatrice_deck_list/ # Deck list management library │ └── libcockatrice/deck_list/ │ ├── deck_list.cpp/h # Core deck list class │ ├── deck_list_node_tree.cpp/h # Tree structure for decks │ ├── sideboard_plan.cpp/h # Sideboarding │ └── tree/ ├── libcockatrice_network/ # Network protocol library │ └── libcockatrice/network/ │ └── network/ # TCP client/server ├── libcockatrice_protocol/ # Protocol definition library │ └── libcockatrice/protocol/ # .proto file translations to C++ ├── libcockatrice_rng/ # RNG library (SFMT) ├── libcockatrice_settings/ # Settings/preferences ├── libcockatrice_utility/ # Utility functions ├── docker-compose.yml # Dev environment (MySQL + Servatrice) └── doc/ # Documentation (Doxygen) ``` --- ## 3. Gameplay Engine Architecture ### 3.1 Core Game Loop — Event-Driven Architecture ``` ┌─────────────────────────────────────────────────────────────────────┐ │ GAME ENGINE │ │ │ │ ┌──────────────┐ ┌──────────────────┐ ┌───────────────────┐ │ │ │ Client │ │ Game │ │ Event Handler │ │ │ │ (User Input)│──▶│ (AbstractGame) │◀──│ (Central Dispatch)│ │ │ └──────────────┘ └──────────────────┘ └───────────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌─────────────┐ ┌──────────────────┐ │ │ │ GameState │ │ PlayerManager │ │ │ │ (Board State)│ │ (Multiplayer │ │ │ │ │ │ Coordination) │ │ │ └─────────────┘ └──────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────┐ ┌──────────────────┐ │ │ │ CardZone │ │ PlayerLogic │ │ │ │ (Hand/ │ │ (Actions, Rules │ │ │ │ Stack/ │ │ Processing) │ │ │ │ Table/ │ └──────────────────┘ │ │ │ Graveyard) │ │ │ └─────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 3.2 Game Class Hierarchy | Class | Role | Key Data | |-------|------|----------| | `AbstractGame` | Base game abstraction | `gameMetaInfo`, `gameState`, `gameEventHandler`, `playerManager` | | `Game` | Concrete online/offline game | Extends AbstractGame with client list | | `GameMetaInfo` | Wraps protobuf `ServerInfo_Game` | gameId, maxPlayers, description, started, spectators settings | | `GameState` | Board state tracking | currentPhase, activePlayer, hostId, gameTimer, clients | | `GameEventHandler` | **Central event dispatch** (~21KB handler) | Processes all game events, prepares commands | | `Phase` | Turn phase definitions | 11 phases with sub-phases, colors, sounds | ### 3.3 Phase System (MTG Turn Structure) ``` Phases::phases[] array contains 11 phases: 1. Untap 2. Upkeep 3. Draw 4. Main 1 5. Combat (with sub-phases) - Beginning of Combat - Declare Attackers - Declare Blockers - Combat Damage - End of Combat 6. Main 2 7. End of Turn 8. Cleanup (plus unknownPhase as sentinel) ``` Sub-phases are tracked via `Phases::subPhasesEnd` — the combat phase has 5 sub-phases. ### 3.4 Player System | Class | Role | File Size | |-------|------|-----------| | `PlayerManager` | Coordinates all players in a game | ~2.5KB header | | `PlayerLogic` | Per-player game logic (actions, rules) | ~10.7KB | | `PlayerActions` | Concrete player commands (play, tap, draw, etc.) | **~64KB** — single massive file | | `PlayerEventHandler` | Per-player event processing | ~24KB | | `EventProcessingOptions` | Flags controlling event processing | ~575B | ### 3.5 Zone System | Zone | File | Description | |------|------|-------------| | `CardZone` | `card_zone_logic.cpp/h` | Base class for all zones | | `HandZone` | `hand_zone_logic.cpp/h` | Player's hand (secret zone) | | `StackZone` | `stack_zone_logic.cpp/h` | The stack ( spells, abilities) | | `TableZone` | `table_zone_logic.cpp/h` | Battlefield (permanent zone) | | `PileZone` | `pile_zone_logic.cpp/h` | Graveyard, exile, library | | `ViewZone` | `view_zone_logic.cpp/h` | Shared view zones (for effects) | | `CardZoneAlgorithms` | `card_zone_algorithms.h` | Search, shuffle, sort algorithms | Each zone type implements its own `CardZoneLogic` subclass. ### 3.6 Command/Event Architecture ``` User Action (GUI) │ ▼ GameCommand (protobuf message) │ ▼ GameEventHandler.processGameEventContainer() │ ▼ PlayerLogic.handleCommand() │ ▼ CardZoneLogic (state change) │ ▼ GameEvent (sent to all clients) │ ▼ Client receives & displays ``` ### 3.7 Replay System `replay.cpp/h` — Games are recorded as a stream of protobuf events and can be replayed identically. This is a direct serialization of `GameReplay` protobuf messages. ### 3.8 Card State on Board | Class | Role | |-------|------| | `CardState` | Card face-up/face-down, tapped, counters | | `CardList` | Ordered/unordered collection of cards in a zone | | `CounterState` | Life total, poison counters, etc. | | `ArrowData` | Targeting arrow visual | | `ArrowRegistry` | Manages targeting arrows | --- ## 4. Network Protocol Architecture ### 4.1 Communication Stack ``` ┌─────────────────────────────────────────────────────────┐ │ Application Layer │ │ - GameCommands (play, draw, tap, attack, etc.) │ │ - GameEvents (state changes broadcast to all clients) │ │ - Chat messages, user management │ │ - Deck management │ │ - Room management │ │ - Admin commands │ ├─────────────────────────────────────────────────────────┤ │ Protocol Layer │ │ - Protocol Buffers (.proto files) │ │ - Message types: ServerInfo_Game, ServerInfo_Player, │ │ Event_Join, Command_PlayCard, etc. │ ├─────────────────────────────────────────────────────────┤ │ Network Layer │ │ - TCP connections │ │ - Connection pooling │ │ - ISL (Inter-Server Link) for clustering │ └─────────────────────────────────────────────────────────┘ ``` ### 4.2 Key Protocol Messages (from .pb files) | Category | Example Messages | |----------|-----------------| | **Game State** | `ServerInfo_Game`, `ServerInfo_Player`, `Event_GameStateChanged` | | **Player Actions** | `Command_PlayCard`, `Command_Attack`, `Command_Damage`, `Command_DrawCard` | | **Events** | `Event_Join`, `Event_Leave`, `Event_SetActivePlayer`, `Event_SetActivePhase` | | **User Management** | `ServerInfo_User`, `Command_Acknowledge`, `Command_SpectateGame` | | **Chat** | `Event_GameSay`, `ServerInfo_Chat` | | **Decks** | Deck list serialization, sideboard plans | ### 4.3 Authority Model - **Server is authoritative**: All game state changes go through the server. - **Client sends commands, server validates**: The client cannot manipulate the game state directly. - **Events are broadcast**: Server sends `GameEvent` containers to all connected clients. - **Replays are deterministic**: Same command sequence produces identical game states. --- ## 5. Server Architecture (Servatrice) ### 5.1 Server Class Hierarchy | Class | Role | |-------|------| | `Servatrice` | Main server class (~42KB) — manages connections, rooms, games | | `ServatriceDatabaseInterface` | Database operations (~58KB) — user accounts, decks, logs | | `ServerSocketInterface` | Per-client handler (~106KB) — handles all client messages | | `IslInterface` | Inter-server-link for clustering | | `ServerLogger` | Centralized logging | ### 5.2 Server Features - **Room management**: Games are organized in rooms; rooms have game types. - **User accounts**: MySQL-backed with authentication, password reset, email. - **Deck storage**: Decks saved to database with versioning. - **Game logging**: Full game event logs for disputes. - **Spectator system**: Spectators can watch (with optional omniscient mode). - **Admin commands**: Kicking, banning, game management. - **Clustering**: ISL protocol for running multiple servers in a cluster. - **Email**: SMTP support for registration/password reset. ### 5.3 Database Schema (MySQL) The `servatrice.sql` file defines the schema including: - User accounts, groups, bans - Deck lists with versioning - Game logs - Room/game state tables - Admin logs --- ## 6. Card Database (Oracle) The `oracle` module downloads and maintains the card database: - Sources: MTGJSON data - Local storage: SQLite or file-based - Features: Card searching, printing history, set filtering - Updates: Periodic refresh capability --- ## 7. Deck Management | Component | Role | |-----------|------| | `DeckList` | Core deck data structure (cards, sideboard, categories) | | `DeckListNodeTree` | Tree structure for organizing decks | | `SideboardPlan` | Pre/post-sideboard plan management | | `DeckListHistoryManager` | Deck version history | | `DeckFilterString` | Card name filtering | Deck formats supported: Commander, Standard, Modern, Legacy, Vintage, etc. --- ## 8. UI/Rendering Architecture ### 8.1 Qt Graphics Framework ``` ┌─────────────────────────────────────────────────────────┐ │ Window Main (window_main.cpp) — ~44KB │ │ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │ │ │ Game │ │ Chat/Log │ │ Deck/Filter │ │ │ │ Scene │ │ Panel │ │ Panel │ │ │ │ (QScene) │ │ │ │ │ │ │ └──────────┘ └──────────────┘ └──────────────────┘ │ │ │ │ │ ▼ │ │ GameScene (game_scene.cpp) — ~23KB │ │ GameView (game_view.cpp) — ~10KB │ │ PhasesToolbar — Phase navigation │ │ ZValueLayerManager — 2D depth ordering │ └─────────────────────────────────────────────────────────┘ ``` ### 8.2 Theming System - SVG-based card back designs - Configurable themes (backgrounds, colors, layouts) - Card picture loading from external URLs - Custom counters and tally displays --- ## 9. Technology Stack Summary | Layer | Technology | |-------|-----------| | Language | C++20 | | GUI Framework | Qt 5 or Qt 6 (QtWidgets) | | Network Protocol | Protocol Buffers (3.21+) | | Build System | CMake 3.10+ | | Server Database | MySQL | | Card Database | SQLite / file-based (Oracle) | | Packaging | CPack (DEB, RPM, NSIS, DMG) | | Networking | Qt TCP | | Serialization | protobuf | | RNG | SFMT (Sobol/Smirnov) | | Translations | Qt .ts files | | Documentation | Doxygen | --- ## 10. Key Architectural Patterns | Pattern | Where Used | |---------|-----------| | **MVC (via Qt)** | `game_state` (model), `game_scene` (view), `GameEventHandler` (controller) | | **Event Bus** | Qt signals/slots for all state transitions | | **Command Pattern** | `Command_PlayCard`, `Command_Attack`, etc. — all game actions are commands | | **Observer** | `GameEventHandler` emits signals to update UI on every state change | | **Strategy** | `CardZoneLogic` subclasses (Hand, Stack, Table, Pile, View) | | **Facade** | `AbstractGame` wraps all game subsystems behind a single interface | | **Adapter** | `GameMetaInfo` wraps protobuf messages with Qt-friendly getters | | **Singleton** | Settings cache, database interface | | **Memento** | `DeckListMemento` for undo/redo in deck editing | | **Repository** | `ServatriceDatabaseInterface` abstracts MySQL access | | **Plugin (debatable)** | ISL interface for adding server nodes | --- ## 11. Strengths & Weaknesses (for modern web adaptation) ### Strengths - **Clear authority model**: Server is always right — ideal for web multiplayer. - **Deterministic replay**: Game events are serialized, enabling perfect replays. - **Zone abstraction**: Each zone type is independently implementable. - **Phase system**: Well-defined MTG turn structure. - **Command/Event separation**: Clean separation between what a player *wants* to do and what *happens*. ### Weaknesses (for web adaptation) - **Desktop-first**: Qt Widgets, not designed for browser deployment. - **Massive files**: `serversocketinterface.cpp` is 106KB — monolithic. - **No web protocol**: Only TCP, no WebSocket, no REST. - **No mobile**: No responsive design, no mobile clients. - **Complex build**: Qt + CMake + protobuf + MySQL — heavy dev environment. - **No real-time scaling**: Single-server architecture (ISL is clustering, not load balancing). - **No card images built-in**: External URL loading only. - **No API**: No REST/GraphQL for external integrations. --- ## 12. Relevance to Modern Web MTG App ### What to Reuse (Architecture Patterns) 1. **Event-driven game state**: Server authoritative, client event-driven UI. 2. **Zone abstraction**: Hand/Stack/Table/Graveyard/Exile/Library as separate zone types. 3. **Command pattern**: Player actions as discrete commands, validated server-side. 4. **Phase system**: 11-phase MTG turn structure with sub-phases. 5. **Replay system**: Serialize game events for replay capability. 6. **Card database**: Structure for card info, sets, printing history. 7. **Deck management**: Tree structure, sideboard plans, format support. ### What to Modernize 1. **Protocol**: Replace protobuf over TCP with **WebSocket** (or gRPC-Web) for browser. 2. **API**: Add **REST/GraphQL** layer for external integrations. 3. **Frontend**: Replace Qt Widgets with **React/Next.js** or **Vue 3**. 4. **State management**: Replace Qt signals/slots with **state machines** (XState) or **Zustand**. 5. **Backend**: Replace C++/MySQL with **TypeScript/Node.js** or **Python/FastAPI** + **PostgreSQL**. 6. **Card images**: Bundle card images with the application or use CDN. 7. **Real-time**: Use **WebSocket** for live game state sync. 8. **Mobile**: Responsive design from the start. 9. **Testing**: Unit test the game engine in isolation (no GUI dependency). ### Suggested Tech Stack for Modern Web MTG | Component | Recommendation | |-----------|---------------| | Frontend | Next.js 14+ (React, TypeScript) | | Game State | XState (state machines) or Zustand | | UI Rendering | React Three Fiber (3D) or PixiJS (2D) | | Backend | FastAPI (Python) or Hono (TypeScript) | | Database | PostgreSQL (user data) + Redis (game state cache) | | Real-time | WebSocket (via FastAPI or Socket.IO) | | Card Data | MTGJSON v5 (already available in project) | | Auth | JWT + refresh tokens | | Deployment | Docker Compose (already used in project) |