diff --git a/AGENTS.md b/AGENTS.md index 06e4857..ce006ba 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -223,6 +223,46 @@ opponent_deck_count=len(opponent.deck) # ONLY count 5. **Tests**: Include docstrings explaining "what" and "why" for each test. 6. **Phaser in Vue**: Keep Phaser scenes focused on rendering. Game logic lives in backend. 7. **Services**: Never bypass the service layer for business logic. +8. **Core Engine Independence**: Keep `app/core/` decoupled from DB/network (see below). + +--- + +## Core Engine Independence (Offline Fork Support) + +> **Long-term goal**: The `backend/app/core/` module should remain forkable as a standalone offline game. + +The game engine must stay **completely decoupled** from network and database concerns to enable a future offline/standalone version of the RPG campaign mode. + +### Rules for `app/core/` Module + +| DO | DON'T | +|----|-------| +| Accept `CardDefinition` objects as parameters | Import from `app.services` or `app.api` | +| Use `RandomProvider` protocol for RNG | Import database session types | +| Keep state self-contained in `GameState` | Make network calls or database queries | +| Use sync logic (async wrappers at service layer) | Require authentication or user sessions | +| Load configuration from `RulesConfig` objects | Hard-code database connection strings | + +### Import Boundaries + +```python +# ALLOWED in app/core/ +from app.core.models import CardDefinition, GameState +from app.core.config import RulesConfig +from app.core.rng import RandomProvider + +# FORBIDDEN in app/core/ +from app.services.card_service import CardService # NO - DB dependency +from app.api.deps import get_current_user # NO - Auth dependency +from sqlalchemy.ext.asyncio import AsyncSession # NO - DB dependency +``` + +### Why This Matters + +See `docs/ARCHITECTURE.md#offline-standalone-fork` for full details. The core engine should be directly copyable to a standalone Python application with: +- Card definitions loaded from JSON files +- Save data stored locally +- No network or authentication requirements --- diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index e55b39d..c4f35d0 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -12,6 +12,7 @@ This document provides a detailed technical overview of the Mantimon TCG archite 6. [Game Engine](#game-engine) 7. [AI System](#ai-system) 8. [Security Considerations](#security-considerations) +9. [Offline Standalone Fork](#offline-standalone-fork) --- @@ -820,3 +821,115 @@ async def validate_action(game: GameState, player_id: str, action: dict) -> Vali return ValidationResult(False, "Unknown action type") ``` + +--- + +## Offline Standalone Fork + +> **Design Consideration**: The architecture intentionally supports forking as a completely offline, standalone experience for the RPG/campaign mode. + +### Why This Matters + +The primary gameplay experience is a single-player RPG campaign. While the live service provides multiplayer and cloud saves, many players may prefer: +- Offline play without internet dependency +- Local save files they fully control +- A self-contained executable with no account requirements +- Modding and customization freedom + +### Architecture Principles for Fork Compatibility + +The `backend/app/core/` game engine is designed to be **completely decoupled** from network and database concerns: + +| Component | Live Service | Offline Fork | +|-----------|--------------|--------------| +| Game Engine (`core/`) | Same | Same (copy directly) | +| Card Definitions | PostgreSQL | Embedded JSON files | +| Save Data | PostgreSQL + Redis | Local JSON/SQLite files | +| Authentication | OAuth/JWT | None needed | +| Multiplayer | WebSocket/Socket.io | Removed entirely | +| RNG | SecureRandom | SeededRandom (for replays) | + +### Core Engine Independence + +The game engine has **zero dependencies** on: +- Database connections +- Network I/O +- Authentication/sessions +- Redis caching +- WebSocket communication + +All it needs: +- `RulesConfig` (can be hardcoded or loaded from JSON) +- `CardDefinition` objects (can be embedded or loaded from files) +- `RandomProvider` (SeededRandom works offline) + +### Potential Offline Package Structure + +``` +mantimon-offline/ +├── game/ +│ ├── core/ # Direct copy of backend/app/core/ +│ ├── campaign/ # NPC definitions, dialog, progression +│ │ ├── clubs/ # Club data (NPCs, leaders, rewards) +│ │ ├── dialog/ # NPC dialog trees +│ │ └── progression.py # Campaign state machine +│ ├── cards/ # Card definitions as JSON +│ │ ├── base_set.json +│ │ └── expansion_1.json +│ └── saves/ # Local save directory +│ └── slot_1.json +├── ui/ # Could reuse Phaser or use PyGame/Godot +├── assets/ # Card images, sounds +└── main.py # Entry point +``` + +### Packaging Options for Distribution + +| Approach | Bundle Size | Complexity | UI Reuse | +|----------|-------------|------------|----------| +| **Electron + Python** | ~150MB | Medium | Full web UI | +| **Tauri + Python** | ~30MB | High | Full web UI | +| **PyInstaller + PyGame** | ~50MB | Low | New UI needed | +| **Godot + GDScript port** | ~40MB | Medium | New UI needed | +| **Nuitka + embedded browser** | ~80MB | Medium | Phaser reuse | + +### What Stays, What Goes + +**Keep (copy to fork):** +- `backend/app/core/` - Entire game engine +- `frontend/src/game/` - Phaser scenes (if using web UI) +- Card definitions (export from DB to JSON) +- Campaign/NPC data + +**Remove (not needed offline):** +- `backend/app/api/` - REST endpoints +- `backend/app/websocket/` - Multiplayer sync +- `backend/app/services/` - DB-backed services +- Authentication system +- Matchmaking/lobby + +### Development Guidelines + +To maintain fork compatibility, follow these rules when developing the core engine: + +1. **No imports from `app.api`, `app.websocket`, or `app.services`** in `app.core` +2. **No database session dependencies** in core engine functions +3. **Card definitions passed in**, not fetched - `GameEngine.create_game()` receives a card registry +4. **RNG injected via protocol** - `RandomProvider` allows swapping implementations +5. **State is self-contained** - `GameState` includes everything needed to resume a game +6. **No async required** - Core logic is sync; async wrappers added at service layer + +### Testing Offline Viability + +The existing test suite validates offline compatibility: +- All `tests/core/` tests run without database +- `SeededRandom` enables deterministic testing +- Card fixtures are created in-memory, not loaded from DB + +### Future: Official Offline Release + +If demand exists, an official offline version could be released: +1. Export campaign data and card definitions to JSON +2. Bundle core engine with a lightweight UI wrapper +3. Distribute as standalone executable (itch.io, Steam, etc.) +4. Optional: Steam Workshop for community card sets