Removed obsolete scripts that were not imported or used: - card_interaction_rule_engine.py - card_profile_extractor.py - create_card_interaction_graph.py - interaction_determinator.py - interaction_pipeline.py - interaction_recommender.py - interaction_schema.py - recommendation_engine.py - migrate_complete.py - migrate_schema.py - test_interaction_determinator.py - check_mtgjson_full.py - check_mtgjson_status.py - verify_integration.py - verify_mtgjson_data.py - sanity_check_mtgjson.py - investigate_sets.py - inspect_db.py - code_review.md - monitor/mtg_monitor.py Removed test artifacts: - test.db - test_download.py - test_system.py - setup_db.py - BACKEND_TESTING_SUMMARY.md - CHAT_PROMPT_TEST.md - CONTINUATION_PROMPT.md - PORTED_STATE.md - SPEC_synergy-mapping-engine.md - STATE.md - SUPPORTED_FILE_TYPES.md Removed sensitive/environment files: - .env.local - state.json (backend) Cleaned up: - __pycache__ directories - venv directory Backend scripts/ directory now contains only essential data loading and maintenance scripts.
23 KiB
23 KiB
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
.protofiles — 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
GameEventcontainers 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.cppis 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)
- Event-driven game state: Server authoritative, client event-driven UI.
- Zone abstraction: Hand/Stack/Table/Graveyard/Exile/Library as separate zone types.
- Command pattern: Player actions as discrete commands, validated server-side.
- Phase system: 11-phase MTG turn structure with sub-phases.
- Replay system: Serialize game events for replay capability.
- Card database: Structure for card info, sets, printing history.
- Deck management: Tree structure, sideboard plans, format support.
What to Modernize
- Protocol: Replace protobuf over TCP with WebSocket (or gRPC-Web) for browser.
- API: Add REST/GraphQL layer for external integrations.
- Frontend: Replace Qt Widgets with React/Next.js or Vue 3.
- State management: Replace Qt signals/slots with state machines (XState) or Zustand.
- Backend: Replace C++/MySQL with TypeScript/Node.js or Python/FastAPI + PostgreSQL.
- Card images: Bundle card images with the application or use CDN.
- Real-time: Use WebSocket for live game state sync.
- Mobile: Responsive design from the start.
- 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) |