codemap generation
Some checks failed
Continuous Integration / Code Formatting (push) Successful in 31s
Continuous Integration / Code Quality Check (push) Successful in 28s
Continuous Integration / Test Execution (push) Failing after 17s
Continuous Integration / CI Summary (push) Failing after 4s

This commit is contained in:
2025-10-01 14:36:21 +04:00
parent 550b2ac220
commit 538459f323
17 changed files with 3732 additions and 499 deletions

424
docs/ARCHITECTURE.md Normal file
View 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