Monster System Architecture¶
Overview¶
The Monster System provides a modular, scalable architecture for managing monster data in Stingbatbot. The system follows separation of concerns principles with specialized modules handling different aspects of monster management, including both core monsters and custom user-created monsters.
Architecture Components¶
Context Module (Stingbatbot.Monsters
)¶
Responsibility: Public API and delegation to specialized modules
The main context module serves as the public interface for all monster operations. It uses defdelegate
to route calls to appropriate submodules, providing a clean and maintainable API.
Key Functions:
- create/1
, update/2
: Database operations
- search_by_name/3
: Enhanced search with server_id and user_id context
- csv_row_to_attrs/1
: CSV data conversion
- parse_attack_string/1
: Attack description parsing
Operations Module (Stingbatbot.Monsters.Operations
)¶
Responsibility: Database operations and data transformation
This module handles all database interactions and complex data transformations, keeping the schema focused on validation.
Key Functions:
- create/1
: Creates monsters with data transformation
- update/2
: Updates monsters with data transformation
- create_changeset/1
: Creates changesets with data preparation
- prepare_monster_attrs/1
: Handles attack parsing and talent processing
- talents_to_array/1
: Converts talent fields to arrays
Data Transformation Pipeline:
1. Attack Parsing: Converts atk_description
to structured attack data
2. Talent Processing: Consolidates talent_1 through talent_10 into arrays
3. Type Conversion: Handles data type conversions for database storage
Maps Module (Stingbatbot.Monsters.Maps
)¶
Responsibility: Struct/map conversions for JSONB storage
This module handles the conversion between Elixir structs and plain maps for JSONB storage, including key type conversions.
Key Functions:
- monster_to_map/1
: Converts Monster struct to map for storage
- monster_from_map/1
: Converts map back to Monster struct
- attack_to_map/1
: Converts MonsterAttack struct to map
- attack_from_map/1
: Converts map to MonsterAttack struct
- attacks_from_maps/1
: Batch conversion of attack maps to structs
Query Module (Stingbatbot.Monsters.Query
)¶
Responsibility: Complex database queries and search functionality
This module handles advanced query operations with optimized search algorithms, including support for custom monsters and source filtering.
Key Functions:
- search_by_name/3
: Enhanced search with server_id and user_id context
- Source filtering support (e.g., source:CR
, source:Homebrew
)
- Handles name conflicts between core and custom monsters
- Excludes unapproved monsters from search results
Search Features: - Core Monsters: Available everywhere (server_id and user_id are nil) - Custom Monsters: Server-scoped (filtered by server_id) - Source Filtering: Filter by specific sources - Approval Status: Only approved monsters are searchable
ListBy Module (Stingbatbot.Monsters.ListBy
)¶
Responsibility: Filtered monster listings
This module provides specialized listing functionality with various filtering options.
Key Functions:
- list_by/1
: Lists monsters with filtering options
TextParser Module (Stingbatbot.Monsters.TextParser
)¶
Responsibility: Parse raw monster text into structured data
This module handles the parsing of free-form monster descriptions in Shadowdark format.
Key Functions:
- parse/1
: Main parsing function for monster text
- Handles multi-line descriptions, complex stat blocks, and talents
- Supports various monster formats and edge cases
Utility Modules¶
CsvParser: Converts CSV rows to monster attributes MonsterImporter: Handles CSV file processing and import workflow ParseAttack: Parses attack descriptions into structured data MonsterNaming: Generates unique monster names
Data Flow¶
Monster Creation Flow¶
- Input: Raw data (CSV row, user input, API call)
- Conversion: Data converted to attribute map
- Transformation:
prepare_monster_attrs/1
processes: - Attack descriptions → structured attack data
- Talent fields → consolidated arrays
- Type conversions and normalization
- Validation: Monster schema validates transformed data
- Storage: Data stored with JSONB for complex fields
Custom Monster Creation Flow¶
- Input: Raw text from Discord command
- Parsing:
TextParser.parse/1
converts text to attributes - Validation: Monster schema validates parsed data
- Storage: Monster stored as unapproved (approved_at is nil)
- Approval: User approves via Discord interaction
- Activation: Monster becomes searchable after approval
Monster Retrieval Flow¶
- Query: Database query for monster data with context
- Filtering: Results filtered by server_id and approval status
- Conversion: Maps converted back to structs via Maps module
- Usage: Structured data available for game mechanics
Schema Design¶
Monster Schema¶
The Monster schema focuses purely on validation, with data transformation handled externally:
schema "monsters" do
field :name, :string
field :ac, :integer
field :hp, :integer
field :atk_description, :string
field :attacks, {:array, :map}, default: [] # JSONB storage
field :talents, {:array, :string}, default: [] # JSONB storage
field :server_id, :integer # For custom monsters
field :user_id, :integer # For custom monsters
field :source, :string # Source identifier
field :raw_text, :string # Original text for custom monsters
field :approved_at, :utc_datetime_usec # Approval timestamp
# ... other fields
end
Unique Constraints:
- name
and source
: Allows same monster name in different sources
- Core monsters have server_id
and user_id
as nil and source as CR
Attack Storage¶
Attacks are stored as JSONB maps for flexibility: - Storage: Plain maps with string keys - Usage: Converted to MonsterAttack structs when needed - Benefits: Flexible schema, easy to extend
Integration with Game Mechanics¶
Attack System Integration¶
- Parsing: Attack descriptions parsed into MonsterAttack structs
- Storage: Attacks stored as maps in JSONB
- Combat: Converted back to structs for attack rolls
- Critical Hits: Full support for critical hit mechanics
Command Integration¶
- Monster Commands: Use the public API for all operations
- Search: Integrated search functionality with source filtering
- Import: CSV import workflow support
- Custom Monsters: Add monster command with approval workflow
Benefits of This Architecture¶
Separation of Concerns¶
- Schema: Pure validation logic
- Operations: Data transformation and database operations
- Maps: Struct/map conversions
- Query/ListBy: Specialized query logic
- TextParser: Custom monster text parsing
Maintainability¶
- Clear APIs: Each module has a well-defined responsibility
- Easy Testing: Modules can be tested in isolation
- Extensibility: New functionality can be added without modifying existing code
Performance¶
- Optimized Queries: Specialized query modules for complex operations
- Efficient Storage: JSONB for complex data structures
- Lazy Loading: Data converted only when needed
- Context-Aware Search: Efficient filtering by server and user context
Future Considerations¶
Planned Enhancements¶
- Advanced Search: More sophisticated search and filtering options
- Bulk Operations: Efficient bulk import and update operations
- Caching: Performance optimization through caching
- Monster Sharing: Export/import custom monsters between servers
Extension Points¶
- New Data Types: Easy to add new monster attributes
- Custom Parsers: Extensible parsing for different data formats
- Integration APIs: Clean interfaces for external integrations
- Image Support: Potential for custom monster images