codemap generation
Some checks failed
Some checks failed
This commit is contained in:
424
docs/ARCHITECTURE.md
Normal file
424
docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# System Architecture
|
||||
|
||||
High-level architecture guide for the Skelly project, explaining system design, architectural patterns, and design decisions.
|
||||
|
||||
**Quick Links**:
|
||||
- **Coding Standards**: See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
|
||||
- **Testing Protocols**: See [TESTING.md](TESTING.md)
|
||||
- **Component APIs**: See [UI_COMPONENTS.md](UI_COMPONENTS.md)
|
||||
|
||||
## Overview
|
||||
|
||||
Skelly uses a service-oriented architecture with **autoload managers** providing global services, **scene-based components** implementing gameplay, and **signal-based communication** for loose coupling.
|
||||
|
||||
**Key Architectural Principles**:
|
||||
- **Instance-based design**: No global static state for testability
|
||||
- **Signal-driven communication**: Loose coupling between systems
|
||||
- **Service layer pattern**: Autoloads as singleton services
|
||||
- **State machines**: Explicit state management for complex flows
|
||||
- **Defensive programming**: Input validation, error recovery, fallback mechanisms
|
||||
|
||||
## Autoload System
|
||||
|
||||
Autoloads provide singleton services accessible globally. Each has a specific responsibility.
|
||||
|
||||
### GameManager
|
||||
**Responsibility**: Scene transitions and game state coordination
|
||||
|
||||
**Key Features**:
|
||||
- Centralized scene loading with error handling
|
||||
- Race condition protection via `is_changing_scene` flag
|
||||
- Scene path constants for maintainability
|
||||
- Gameplay mode validation with whitelist
|
||||
- Never use `get_tree().change_scene_to_file()` directly
|
||||
|
||||
**Usage**:
|
||||
```gdscript
|
||||
# ✅ Correct
|
||||
GameManager.start_game_with_mode("match3")
|
||||
|
||||
# ❌ Wrong
|
||||
get_tree().change_scene_to_file("res://scenes/game/Game.tscn")
|
||||
```
|
||||
|
||||
**Files**: `src/autoloads/GameManager.gd`
|
||||
|
||||
### SaveManager
|
||||
**Responsibility**: Save/load game state with security and data integrity
|
||||
|
||||
**Key Features**:
|
||||
- **Tamper Detection**: Deterministic checksums detect save file modification
|
||||
- **Race Condition Protection**: Save operation locking prevents concurrent conflicts
|
||||
- **Permissive Validation**: Auto-repair system fixes corrupted data
|
||||
- **Type Safety**: NaN/Infinity/bounds checking for numeric values
|
||||
- **Memory Protection**: File size limits prevent memory exhaustion
|
||||
- **Version Migration**: Backward-compatible save format upgrades
|
||||
- **Error Recovery**: Multi-layered backup and fallback systems
|
||||
|
||||
**Security Model**:
|
||||
```gdscript
|
||||
# Checksum validates data integrity
|
||||
save_data["_checksum"] = _calculate_checksum(save_data)
|
||||
|
||||
# Auto-repair fixes corrupted fields
|
||||
if not _validate_save_data(data):
|
||||
data = _repair_save_data(data)
|
||||
|
||||
# Race condition protection
|
||||
if _is_saving:
|
||||
return # Prevent concurrent saves
|
||||
```
|
||||
|
||||
**Testing**: See [TESTING.md](TESTING.md#save-system-testing-protocols) for comprehensive test suites validating checksums, migration, and integration.
|
||||
|
||||
**Files**: `src/autoloads/SaveManager.gd`
|
||||
|
||||
### SettingsManager
|
||||
**Responsibility**: User settings persistence and validation
|
||||
|
||||
**Key Features**:
|
||||
- Input validation with NaN/Infinity checks
|
||||
- Bounds checking for numeric values
|
||||
- Security hardening against invalid inputs
|
||||
- Default fallback values
|
||||
- Type coercion with validation
|
||||
|
||||
**Files**: `src/autoloads/SettingsManager.gd`
|
||||
|
||||
### DebugManager
|
||||
**Responsibility**: Unified logging and debug UI coordination
|
||||
|
||||
**Key Features**:
|
||||
- Structured logging with log levels (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)
|
||||
- Category-based log organization
|
||||
- Global debug UI toggle (F12 key)
|
||||
- Log level filtering for development/production
|
||||
- Replaces all `print()` and `push_error()` calls
|
||||
|
||||
**Usage**: See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md#logging-standards) for logging best practices.
|
||||
|
||||
**Files**: `src/autoloads/DebugManager.gd`
|
||||
|
||||
### AudioManager
|
||||
**Responsibility**: Music and sound effect playback
|
||||
|
||||
**Key Features**:
|
||||
- Audio bus system (Music, SFX)
|
||||
- Volume control per bus
|
||||
- Loop configuration for music
|
||||
- UI click sounds
|
||||
|
||||
**Files**: `src/autoloads/AudioManager.gd`
|
||||
|
||||
### LocalizationManager
|
||||
**Responsibility**: Language switching and translation management
|
||||
|
||||
**Key Features**:
|
||||
- Multi-language support (English, Russian)
|
||||
- Runtime language switching
|
||||
- Translation file management
|
||||
|
||||
**Files**: `src/autoloads/LocalizationManager.gd`
|
||||
|
||||
## Scene Management Pattern
|
||||
|
||||
All scene transitions flow through **GameManager** to ensure consistent error handling and state management.
|
||||
|
||||
### Scene Loading Flow
|
||||
|
||||
```
|
||||
User Action
|
||||
↓
|
||||
GameManager.start_game_with_mode(mode)
|
||||
↓
|
||||
Validate mode (whitelist check)
|
||||
↓
|
||||
Check is_changing_scene flag
|
||||
↓
|
||||
Load PackedScene with validation
|
||||
↓
|
||||
change_scene_to_packed()
|
||||
↓
|
||||
Reset is_changing_scene flag
|
||||
```
|
||||
|
||||
### Race Condition Prevention
|
||||
|
||||
```gdscript
|
||||
var is_changing_scene: bool = false
|
||||
|
||||
func start_game_with_mode(gameplay_mode: String) -> void:
|
||||
# Prevent concurrent scene changes
|
||||
if is_changing_scene:
|
||||
DebugManager.log_warn("Scene change already in progress", "GameManager")
|
||||
return
|
||||
|
||||
is_changing_scene = true
|
||||
# ... scene loading logic ...
|
||||
is_changing_scene = false
|
||||
```
|
||||
|
||||
**Why This Matters**: Multiple rapid button clicks or input events could trigger concurrent scene loads, causing crashes or undefined state.
|
||||
|
||||
## Modular Gameplay System
|
||||
|
||||
Game modes are implemented as separate gameplay modules in `scenes/game/gameplays/`.
|
||||
|
||||
### Gameplay Architecture
|
||||
|
||||
```
|
||||
Game.tscn (Main scene)
|
||||
↓
|
||||
├─> Match3Gameplay.tscn (Match-3 mode)
|
||||
├─> ClickomaniaGameplay.tscn (Clickomania mode)
|
||||
└─> [Future gameplay modes]
|
||||
```
|
||||
|
||||
**Pattern**: Each gameplay mode:
|
||||
- Extends Control or Node2D
|
||||
- Emits `score_changed` signal
|
||||
- Implements `_ready()` for initialization
|
||||
- Handles input independently
|
||||
- Includes optional debug menu
|
||||
|
||||
**Files**: `scenes/game/gameplays/`
|
||||
|
||||
## Design Patterns Used
|
||||
|
||||
### Instance-Based Architecture
|
||||
|
||||
**Problem**: Static variables prevent testing and create hidden dependencies.
|
||||
|
||||
**Solution**: Instance-based architecture with explicit dependencies.
|
||||
|
||||
```gdscript
|
||||
# ❌ Bad: Static global state
|
||||
static var current_gem_pool = [0, 1, 2, 3, 4]
|
||||
|
||||
# ✅ Good: Instance-based
|
||||
var active_gem_types: Array = []
|
||||
|
||||
func set_active_gem_types(gem_indices: Array) -> void:
|
||||
active_gem_types = gem_indices.duplicate()
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Each instance isolated for testing
|
||||
- No hidden global state
|
||||
- Explicit dependencies
|
||||
- Thread-safe by default
|
||||
|
||||
### Signal-Based Communication
|
||||
|
||||
**Pattern**: Use signals for loose coupling between systems.
|
||||
|
||||
```gdscript
|
||||
# Component emits signal
|
||||
signal score_changed(new_score: int)
|
||||
|
||||
# Parent connects to signal
|
||||
gameplay.score_changed.connect(_on_score_changed)
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Loose coupling
|
||||
- Easy to test components in isolation
|
||||
- Clear event flow
|
||||
- Flexible subscription model
|
||||
|
||||
### Service Layer Pattern
|
||||
|
||||
Autoloads act as singleton services providing global functionality.
|
||||
|
||||
**Pattern**:
|
||||
- Autoloads expose public API methods
|
||||
- Components call autoload methods
|
||||
- Autoloads emit signals for state changes
|
||||
- Never nest autoload calls deeply
|
||||
|
||||
### State Machine Pattern
|
||||
|
||||
Complex workflows use explicit state machines.
|
||||
|
||||
**Example**: Match-3 tile swapping
|
||||
```
|
||||
WAITING → SELECTING → SWAPPING → PROCESSING → WAITING
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Clear state transitions
|
||||
- Easy to debug
|
||||
- Prevents invalid state combinations
|
||||
- Self-documenting code
|
||||
|
||||
## Critical Architecture Decisions
|
||||
|
||||
### Memory Management: queue_free() Over free()
|
||||
|
||||
**Decision**: Always use `queue_free()` instead of `free()` for node cleanup.
|
||||
|
||||
**Rationale**:
|
||||
- `free()` causes immediate deletion (crashes if referenced)
|
||||
- `queue_free()` waits until safe deletion point
|
||||
- Prevents use-after-free bugs
|
||||
|
||||
**Implementation**:
|
||||
```gdscript
|
||||
# ✅ Correct
|
||||
for child in children_to_remove:
|
||||
child.queue_free()
|
||||
await get_tree().process_frame # Wait for cleanup
|
||||
|
||||
# ❌ Dangerous
|
||||
for child in children_to_remove:
|
||||
child.free() # Can crash
|
||||
```
|
||||
|
||||
**Impact**: Eliminated multiple potential crash points. See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md#memory-management-standards) for standards.
|
||||
|
||||
### Race Condition Prevention: State Flags
|
||||
|
||||
**Decision**: Use state flags to prevent concurrent operations.
|
||||
|
||||
**Rationale**:
|
||||
- Async operations can overlap without protection
|
||||
- Multiple rapid inputs can trigger race conditions
|
||||
- State flags provide simple, effective protection
|
||||
|
||||
**Implementation**: Used in GameManager (scene loading), SaveManager (save operations), and gameplay systems (tile swapping).
|
||||
|
||||
### Error Recovery: Fallback Mechanisms
|
||||
|
||||
**Decision**: Provide fallback behavior for all critical failures.
|
||||
|
||||
**Rationale**:
|
||||
- Games should degrade gracefully, not crash
|
||||
- User experience > strict validation
|
||||
- Log errors but continue operation
|
||||
|
||||
**Examples**:
|
||||
- Settings file corrupted? Load defaults
|
||||
- Scene load failed? Return to main menu
|
||||
- Audio file missing? Continue without sound
|
||||
|
||||
### Input Validation: Whitelist Approach
|
||||
|
||||
**Decision**: Validate all user inputs against known-good values.
|
||||
|
||||
**Rationale**:
|
||||
- Security hardening
|
||||
- Prevent invalid state
|
||||
- Clear error messages
|
||||
- Self-documenting code
|
||||
|
||||
**Implementation**: Used in SettingsManager (volume, language), GameManager (gameplay modes), Match3Gameplay (grid movements).
|
||||
|
||||
## System Interactions
|
||||
|
||||
### Typical Game Flow
|
||||
|
||||
```
|
||||
Main Menu
|
||||
↓
|
||||
[GameManager.start_game_with_mode("match3")]
|
||||
↓
|
||||
Game Scene Loads
|
||||
↓
|
||||
Match3Gameplay initializes
|
||||
↓
|
||||
├─> SettingsManager (load difficulty)
|
||||
├─> AudioManager (play background music)
|
||||
└─> DebugManager (setup debug UI)
|
||||
↓
|
||||
Gameplay Loop
|
||||
↓
|
||||
├─> Input handling
|
||||
├─> Score updates (emit score_changed signal)
|
||||
├─> SaveManager (autosave high score)
|
||||
└─> DebugManager (log important events)
|
||||
```
|
||||
|
||||
### Signal Flow Example: Score Change
|
||||
|
||||
```
|
||||
Match3Gameplay detects match
|
||||
↓
|
||||
[emit score_changed(new_score)]
|
||||
↓
|
||||
Game.gd receives signal
|
||||
↓
|
||||
Updates score display UI
|
||||
↓
|
||||
SaveManager.save_high_score(score)
|
||||
```
|
||||
|
||||
### Debug System Integration
|
||||
|
||||
```
|
||||
User presses F12
|
||||
↓
|
||||
DebugManager.toggle_debug_ui()
|
||||
↓
|
||||
[emit debug_ui_toggled(visible)]
|
||||
↓
|
||||
All debug menus receive signal
|
||||
↓
|
||||
Show/hide debug panels
|
||||
```
|
||||
|
||||
## Quality Improvements
|
||||
|
||||
The project implements high-quality code standards from the start:
|
||||
|
||||
**Key Quality Features**:
|
||||
- **Memory Safety**: Uses `queue_free()` pattern for safe node cleanup
|
||||
- **Error Handling**: Comprehensive error handling with fallbacks
|
||||
- **Race Condition Protection**: State flag protection for async operations
|
||||
- **Instance-Based Architecture**: No global static state for testability
|
||||
- **Code Reuse**: Base class architecture (DebugMenuBase) for common functionality
|
||||
- **Input Validation**: Complete validation coverage for all user inputs
|
||||
|
||||
These standards are enforced through the [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md#code-quality-checklist) quality checklist.
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Extending the Architecture
|
||||
|
||||
When adding new features:
|
||||
|
||||
1. **New autoload?**
|
||||
- Only if truly global and used by many systems
|
||||
- Consider dependency injection instead
|
||||
- Keep autoloads focused on single responsibility
|
||||
|
||||
2. **New gameplay mode?**
|
||||
- Create in `scenes/game/gameplays/`
|
||||
- Extend appropriate base class
|
||||
- Emit `score_changed` signal
|
||||
- Add to GameManager mode whitelist
|
||||
|
||||
3. **New UI component?**
|
||||
- Create in `scenes/ui/components/`
|
||||
- Follow [UI_COMPONENTS.md](UI_COMPONENTS.md) patterns
|
||||
- Support keyboard/gamepad navigation
|
||||
- Emit signals for state changes
|
||||
|
||||
### Architecture Review Checklist
|
||||
|
||||
Before committing architectural changes:
|
||||
|
||||
- [ ] No new global static state introduced
|
||||
- [ ] All autoload access justified and documented
|
||||
- [ ] Signal-based communication used appropriately
|
||||
- [ ] Error handling with fallbacks implemented
|
||||
- [ ] Input validation in place
|
||||
- [ ] Memory management uses `queue_free()`
|
||||
- [ ] Race condition protection if async operations
|
||||
- [ ] Testing strategy defined
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- **[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)**: Coding standards and best practices
|
||||
- **[TESTING.md](TESTING.md)**: Testing protocols and procedures
|
||||
- **[UI_COMPONENTS.md](UI_COMPONENTS.md)**: Component API reference
|
||||
- **[CLAUDE.md](CLAUDE.md)**: LLM assistant quick start guide
|
||||
Reference in New Issue
Block a user