diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 1276055..d04307b 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -4,9 +4,10 @@ "WebSearch", "Bash(find:*)", "Bash(godot:*)", - "Bash(python:*)" + "Bash(python:*)", + "Bash(git mv:*)" ], "deny": [], "ask": [] } -} +} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 7d6f188..b4ded8f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,4 +6,4 @@ - Use TDD methodology for development; - Use static data types; - Keep documentation up to date; -- Always run gdlint, gdformat and run tests; +- Always run tests `tools\run_development.py --yaml --silent`; diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md index 690f831..930c81b 100644 --- a/docs/CLAUDE.md +++ b/docs/CLAUDE.md @@ -28,7 +28,7 @@ Guidance for Claude Code (claude.ai/code) when working with this repository. - Invalid swaps automatically revert after animation - State machine: WAITING → SELECTING → SWAPPING → PROCESSING - Test scripts located in `tests/` directory for system validation -- Use `test_logging.gd` to validate the logging system functionality +- Use `TestLogging.gd` to validate the logging system functionality ### Audio Configuration - Music: Located in `assets/audio/music/` directory with loop configuration in AudioManager @@ -111,7 +111,7 @@ Guidance for Claude Code (claude.ai/code) when working with this repository. - `src/autoloads/SettingsManager.gd` - Settings management with input validation and security - `src/autoloads/DebugManager.gd` - Debug system integration - `scenes/game/game.gd` - Main game scene with modular gameplay system -- `scenes/game/gameplays/match3_gameplay.gd` - Match-3 implementation with input validation +- `scenes/game/gameplays/Match3Gameplay.gd` - Match-3 implementation with input validation - `scenes/game/gameplays/tile.gd` - Instance-based tile behavior without global state - `scenes/ui/DebugMenuBase.gd` - Unified debug menu base class - `scenes/ui/SettingsMenu.gd` - Settings UI with input validation @@ -123,8 +123,9 @@ Guidance for Claude Code (claude.ai/code) when working with this repository. ### Before Making Changes 1. Check `docs/MAP.md` for architecture 2. Review `docs/CODE_OF_CONDUCT.md` for coding standards -3. Understand existing patterns before implementing features -4. If adding assets, prepare `assets/sources.yaml` documentation +3. **Review naming conventions**: See [Naming Convention Quick Reference](CODE_OF_CONDUCT.md#naming-convention-quick-reference) for all file and code naming standards +4. Understand existing patterns before implementing features +5. If adding assets, prepare `assets/sources.yaml` documentation following [asset naming conventions](CODE_OF_CONDUCT.md#5-asset-file-naming) ### Testing Changes - Run project with F5 in Godot Editor @@ -132,10 +133,10 @@ Guidance for Claude Code (claude.ai/code) when working with this repository. - Verify scene transitions work - Check mobile compatibility if UI changes made - Use test scripts from `tests/` directory to validate functionality -- Run `test_logging.gd` after logging system changes +- Run `TestLogging.gd` after logging system changes - **Save system testing**: Run save/load test suites after SaveManager changes - **Checksum validation**: Test `test_checksum_issue.gd` to verify deterministic checksums -- **Migration compatibility**: Run `test_migration_compatibility.gd` for version upgrades +- **Migration compatibility**: Run `TestMigrationCompatibility.gd` for version upgrades ### Common Implementation Patterns - **Scene transitions**: Use `GameManager.start_game_with_mode()` with built-in validation diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md index e2cf2fa..ff1330c 100644 --- a/docs/CODE_OF_CONDUCT.md +++ b/docs/CODE_OF_CONDUCT.md @@ -27,6 +27,9 @@ Coding standards and development practices for the Skelly project. These guideli ## GDScript Coding Standards ### Naming Conventions + +> 📋 **Quick Reference**: For complete naming convention details, see the **[Naming Convention Quick Reference](#naming-convention-quick-reference)** section below. + ```gdscript # Variables and functions: snake_case var player_health: int = 100 @@ -39,6 +42,11 @@ const TILE_SPACING := 54 # Classes: PascalCase class_name PlayerController +# Scene files (.tscn) and Script files (.gd): PascalCase +# MainMenu.tscn, MainMenu.gd +# Match3Gameplay.tscn, Match3Gameplay.gd +# TestAudioManager.gd (test files) + # Signals: past_tense signal health_changed signal game_started @@ -100,7 +108,7 @@ func _get_match_line(start: Vector2i, dir: Vector2i) -> Array: GameManager.start_match3_game() # ❌ Wrong -get_tree().change_scene_to_file("res://scenes/game.tscn") +get_tree().change_scene_to_file("res://scenes/game/Game.tscn") ``` ### Autoload Usage @@ -263,6 +271,207 @@ wip - Verify debug state persists across scene changes - Check debug code doesn't affect release builds +## Naming Convention Quick Reference + +> 🎯 **Single Source of Truth**: This section contains all naming conventions for the Skelly project. All other documentation files reference this section to avoid duplication and ensure consistency. + +### 1. GDScript Code Elements + +```gdscript +# Variables and functions: snake_case +var player_health: int = 100 +func calculate_damage() -> int: + +# Constants: SCREAMING_SNAKE_CASE +const MAX_HEALTH := 100 +const TILE_SPACING := 54 + +# Classes: PascalCase +class_name PlayerController + +# Signals: past_tense_with_underscores +signal health_changed +signal game_started +signal match_found + +# Private functions: prefix with underscore +func _ready(): +func _initialize_grid(): +``` + +### 2. File Naming Standards + +#### Script and Scene Files +```gdscript +# ✅ Correct: All .gd and .tscn files use PascalCase +MainMenu.tscn / MainMenu.gd +Match3Gameplay.tscn / Match3Gameplay.gd +ClickomaniaGameplay.tscn / ClickomaniaGameplay.gd +ValueStepper.tscn / ValueStepper.gd + +# Test files: PascalCase with "Test" prefix +TestAudioManager.gd +TestGameManager.gd +TestMatch3Gameplay.gd + +# ❌ Wrong: Old snake_case style (being migrated) +main_menu.tscn / main_menu.gd +TestAudioManager.gd +``` + +**Rules:** +- Scene files (.tscn) must match their script file name exactly +- All new files must use PascalCase +- Test files use "Test" prefix + PascalCase +- Autoload scripts follow PascalCase (GameManager.gd, AudioManager.gd) + +### 3. Directory Naming Conventions + +#### Source Code Directories +``` +# Source directories: snake_case +src/autoloads/ +scenes/game/gameplays/ +scenes/ui/components/ +tests/helpers/ + +# Root directories: lowercase +docs/ +tests/ +tools/ +data/ +``` + +#### Asset Directories +``` +# Asset directories: kebab-case +assets/audio-files/ +assets/ui-sprites/ +assets/game-textures/ +assets/fonts/ +localization/ +``` + +### 4. Resource and Configuration Files + +```bash +# Configuration files: lowercase with dots +project.godot +gdlintrc +.gdformatrc +.editorconfig +export_presets.cfg + +# Godot resource files (.tres): PascalCase +data/DefaultBusLayout.tres +data/PlayerSaveData.tres +scenes/ui/DefaultTheme.tres + +# Asset metadata: kebab-case +assets/asset-sources.yaml +assets/audio-files/audio-sources.yaml +assets/ui-sprites/sprite-sources.yaml + +# Development files: kebab-case +requirements.txt +development-tools.md +``` + +### 5. Asset File Naming + +```bash +# Audio files: kebab-case in kebab-case directories +assets/audio-files/background-music.ogg +assets/audio-files/ui-sounds/button-click.wav +assets/audio-files/game-sounds/match-sound.wav + +# Visual assets: kebab-case +assets/ui-sprites/main-menu-background.png +assets/game-textures/gem-blue.png +assets/fonts/main-ui-font.ttf + +# Import settings: match the original file +background-music.ogg.import +button-click.wav.import +``` + +**Asset Rules:** +- All asset files use kebab-case +- Organized in kebab-case directories +- Import files automatically match asset names +- Document all assets in `asset-sources.yaml` + +### 6. Git Workflow Conventions + +#### Branch Naming +```bash +# Feature branches: feature/description-with-hyphens +feature/new-gameplay-mode +feature/settings-ui-improvement +feature/audio-system-upgrade + +# Bug fixes: fix/description-with-hyphens +fix/tile-positioning-bug +fix/save-data-corruption +fix/debug-menu-visibility + +# Refactoring: refactor/component-name +refactor/match3-input-system +refactor/autoload-structure + +# Documentation: docs/section-name +docs/code-of-conduct-update +docs/api-documentation +``` + +#### Commit Message Format +```bash +# Format: : +# Examples: +feat: add dark mode toggle to settings menu +fix: resolve tile swap animation timing issue +docs: update naming conventions in code of conduct +refactor: migrate print statements to DebugManager +test: add comprehensive match3 validation tests +``` + +### 7. Quick Reference Summary + +| File Type | Convention | Example | +|-----------|------------|---------| +| **GDScript Files** | PascalCase | `MainMenu.gd`, `AudioManager.gd` | +| **Scene Files** | PascalCase | `MainMenu.tscn`, `Match3Gameplay.tscn` | +| **Test Files** | Test + PascalCase | `TestAudioManager.gd` | +| **Variables/Functions** | snake_case | `player_health`, `calculate_damage()` | +| **Constants** | SCREAMING_SNAKE_CASE | `MAX_HEALTH`, `TILE_SPACING` | +| **Classes** | PascalCase | `class_name PlayerController` | +| **Signals** | past_tense | `health_changed`, `game_started` | +| **Directories** | snake_case (src) / kebab-case (assets) | `src/autoloads/`, `assets/audio-files/` | +| **Assets** | kebab-case | `background-music.ogg`, `gem-blue.png` | +| **Config Files** | lowercase.extension | `project.godot`, `.gdformatrc` | +| **Branches** | type/kebab-case | `feature/new-gameplay`, `fix/tile-bug` | + +> ✅ **Status**: All major file naming inconsistencies have been resolved. The project now follows consistent PascalCase naming for all .gd and .tscn files. + +### 8. File Renaming Migration Guide + +When renaming files to follow conventions: + +**Step-by-step procedure:** +1. **Use Git rename**: `git mv old_file.gd NewFile.gd` (preserves history) +2. **Update .tscn references**: Modify script path in scene files +3. **Update code references**: Search and replace all `preload()` and `load()` statements +4. **Update project.godot**: If file is referenced in autoloads or project settings +5. **Update documentation**: Search all .md files for old references +6. **Update test files**: Modify any test files that reference the renamed file +7. **Run validation**: Execute `gdlint`, `gdformat`, and project tests +8. **Verify in editor**: Load scenes in Godot editor to confirm everything works + +**Tools for validation:** +- `python tools/run_development.py --test` - Run all tests +- `python tools/run_development.py --lint` - Check code quality +- `python tools/run_development.py --format` - Ensure consistent formatting + ## Common Mistakes to Avoid ### Architecture Violations @@ -271,7 +480,7 @@ wip get_tree().change_scene_to_file("some_scene.tscn") # Don't hardcode paths -var tile = load("res://scenes/game/gameplays/tile.tscn") +var tile = load("res://scenes/game/gameplays/Tile.tscn") # Don't ignore null checks var node = get_node("SomeNode") diff --git a/docs/CODE_QUALITY.md b/docs/CODE_QUALITY.md index 4b56b59..c8c0d20 100644 --- a/docs/CODE_QUALITY.md +++ b/docs/CODE_QUALITY.md @@ -2,6 +2,8 @@ This document outlines the code quality standards implemented in the Skelly project and provides guidelines for maintaining high-quality, reliable code. +> 📋 **Naming Standards**: All code follows the [Naming Convention Quick Reference](CODE_OF_CONDUCT.md#naming-convention-quick-reference) for consistent file, class, and variable naming. + ## Overview of Improvements A comprehensive code quality improvement was conducted to eliminate critical flaws, improve maintainability, and ensure production-ready reliability. The improvements focus on memory safety, error handling, architecture quality, and input validation. @@ -28,7 +30,7 @@ for child in children_to_remove: ``` **Files Improved:** -- `scenes/game/gameplays/match3_gameplay.gd` +- `scenes/game/gameplays/Match3Gameplay.gd` - `scenes/game/gameplays/tile.gd` ### 2. Error Handling & Recovery @@ -111,7 +113,7 @@ static func set_active_gem_pool(gem_indices: Array) -> void: **Files Improved:** - `scenes/game/gameplays/tile.gd` -- `scenes/game/gameplays/match3_gameplay.gd` +- `scenes/game/gameplays/Match3Gameplay.gd` ## 🟡 Code Quality Improvements @@ -173,7 +175,7 @@ func _move_cursor(direction: Vector2i) -> void: **Files Improved:** - `scenes/ui/SettingsMenu.gd` -- `scenes/game/gameplays/match3_gameplay.gd` +- `scenes/game/gameplays/Match3Gameplay.gd` - `src/autoloads/GameManager.gd` ## Development Standards diff --git a/docs/MAP.md b/docs/MAP.md index a5f0e28..88cbc01 100644 --- a/docs/MAP.md +++ b/docs/MAP.md @@ -3,6 +3,8 @@ ## Overview Skelly is a Godot 4.4 game project featuring multiple gameplay modes. The project supports match-3 puzzle gameplay with planned clickomania gameplay through a modular gameplay architecture. It follows a modular structure with clear separation between scenes, autoloads, assets, and data. +> 📋 **Naming Conventions**: All file and directory naming follows the standards defined in [Naming Convention Quick Reference](CODE_OF_CONDUCT.md#naming-convention-quick-reference). + ## Project Root Structure ``` @@ -150,8 +152,8 @@ The game now uses a modular gameplay architecture where different game modes can ### Current Gameplay Modes -#### Match-3 Mode (`scenes/game/gameplays/match3_gameplay.tscn`) -1. **Match3 Controller** (`scenes/game/gameplays/match3_gameplay.gd`) +#### Match-3 Mode (`scenes/game/gameplays/Match3Gameplay.tscn`) +1. **Match3 Controller** (`scenes/game/gameplays/Match3Gameplay.gd`) - Grid management (8x8 default) with memory-safe node cleanup - Match detection algorithms with bounds checking and validation - Tile dropping and refilling with signal connections @@ -178,7 +180,7 @@ The game now uses a modular gameplay architecture where different game modes can - Smooth animations with Tween system - **Memory Safety**: Resource management and cleanup -#### Clickomania Mode (`scenes/game/gameplays/clickomania_gameplay.tscn`) +#### Clickomania Mode (`scenes/game/gameplays/ClickomaniaGameplay.tscn`) - Planned implementation for clickomania-style gameplay - Will integrate with same scoring and UI systems as match-3 @@ -262,9 +264,9 @@ sprites: - `MainStrings.ru.translation` - Russian translations ### Testing & Validation (`tests/`) -- `test_logging.gd` - DebugManager logging system validation +- `TestLogging.gd` - DebugManager logging system validation - **`test_checksum_issue.gd`** - SaveManager checksum validation and deterministic hashing -- **`test_migration_compatibility.gd`** - SaveManager version migration and backward compatibility +- **`TestMigrationCompatibility.gd`** - SaveManager version migration and backward compatibility - **`test_save_system_integration.gd`** - Complete save/load workflow integration testing - **`test_checksum_fix_verification.gd`** - JSON serialization checksum fix verification - `README.md` - Brief directory overview (see docs/TESTING.md for full guidelines) @@ -296,7 +298,7 @@ GameManager --> main.tscn, game.tscn GameManager --> scenes/game/gameplays/*.tscn (via GAMEPLAY_SCENES constant) Main --> MainMenu.tscn, SettingsMenu.tscn Game --> GameplayContainer (dynamic loading of gameplay scenes) -Game --> scenes/game/gameplays/match3_gameplay.tscn, clickomania_gameplay.tscn +Game --> scenes/game/gameplays/Match3Gameplay.tscn, ClickomaniaGameplay.tscn ``` ### Asset Dependencies diff --git a/docs/TESTING.md b/docs/TESTING.md index 1057264..0a3aa62 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -11,9 +11,11 @@ The `tests/` directory contains: - Performance benchmarks - Debugging tools +> 📋 **File Naming**: All test files follow the [naming conventions](CODE_OF_CONDUCT.md#2-file-naming-standards) with PascalCase and "Test" prefix (e.g., `TestAudioManager.gd`). + ## Current Test Files -### `test_logging.gd` +### `TestLogging.gd` Test script for DebugManager logging system. **Features:** @@ -26,10 +28,10 @@ Test script for DebugManager logging system. **Usage:** ```gdscript # Option 1: Add as temporary autoload -# In project.godot, add: tests/test_logging.gd +# In project.godot, add: tests/TestLogging.gd # Option 2: Instantiate in a scene -var test_script = preload("res://tests/test_logging.gd").new() +var test_script = preload("res://tests/TestLogging.gd").new() add_child(test_script) # Option 3: Run directly from editor @@ -49,7 +51,7 @@ Follow these conventions for new test files: ### File Naming - Use descriptive names starting with `test_` -- Example: `test_audio_manager.gd`, `test_scene_transitions.gd` +- Example: `TestAudioManager.gd`, `test_scene_transitions.gd` ### File Structure ```gdscript @@ -104,20 +106,20 @@ func test_error_conditions(): ### System Tests Test core autoload managers and global systems: -- `test_logging.gd` - DebugManager logging system +- `TestLogging.gd` - DebugManager logging system - `test_checksum_issue.gd` - SaveManager checksum validation and deterministic hashing -- `test_migration_compatibility.gd` - SaveManager version migration and backward compatibility +- `TestMigrationCompatibility.gd` - SaveManager version migration and backward compatibility - `test_save_system_integration.gd` - Complete save/load workflow integration testing - `test_checksum_fix_verification.gd` - Verification of JSON serialization checksum fixes -- `test_settings_manager.gd` - SettingsManager security validation, input validation, and error handling -- `test_game_manager.gd` - GameManager scene transitions, race condition protection, and input validation -- `test_audio_manager.gd` - AudioManager functionality, resource loading, and volume management +- `TestSettingsManager.gd` - SettingsManager security validation, input validation, and error handling +- `TestGameManager.gd` - GameManager scene transitions, race condition protection, and input validation +- `TestAudioManager.gd` - AudioManager functionality, resource loading, and volume management ### Component Tests Test individual game components: -- `test_match3_gameplay.gd` - Match-3 gameplay mechanics, grid management, and match detection -- `test_tile.gd` - Tile component behavior, visual feedback, and memory safety -- `test_value_stepper.gd` - ValueStepper UI component functionality and settings integration +- `TestMatch3Gameplay.gd` - Match-3 gameplay mechanics, grid management, and match detection +- `TestTile.gd` - Tile component behavior, visual feedback, and memory safety +- `TestValueStepper.gd` - ValueStepper UI component functionality and settings integration ### Integration Tests Test system interactions and workflows: @@ -135,7 +137,7 @@ SaveManager implements security features requiring testing for modifications. **Tests**: Checksum generation, JSON serialization consistency, save/load cycles **Usage**: Run after checksum algorithm changes -#### **`test_migration_compatibility.gd`** - Version Migration +#### **`TestMigrationCompatibility.gd`** - Version Migration **Tests**: Backward compatibility, missing field addition, data structure normalization **Usage**: Test save format upgrades @@ -164,7 +166,7 @@ SaveManager implements security features requiring testing for modifications. #### **Test Sequence After Modifications** 1. `test_checksum_issue.gd` - Verify checksum consistency -2. `test_migration_compatibility.gd` - Check version upgrades +2. `TestMigrationCompatibility.gd` - Check version upgrades 3. `test_save_system_integration.gd` - Validate workflow 4. Manual testing with corrupted files 5. Performance validation @@ -182,7 +184,7 @@ godot --headless --script tests/test_checksum_issue.gd # Run all save system tests godot --headless --script tests/test_checksum_issue.gd -godot --headless --script tests/test_migration_compatibility.gd +godot --headless --script tests/TestMigrationCompatibility.gd godot --headless --script tests/test_save_system_integration.gd ``` @@ -200,7 +202,7 @@ For CI/CD integration: - name: Run Test Suite run: | godot --headless --script tests/test_checksum_issue.gd - godot --headless --script tests/test_migration_compatibility.gd + godot --headless --script tests/TestMigrationCompatibility.gd # Add other tests as needed ``` diff --git a/scenes/game/game.gd b/scenes/game/game.gd index 49472b8..d1e443b 100644 --- a/scenes/game/game.gd +++ b/scenes/game/game.gd @@ -1,8 +1,8 @@ extends Control const GAMEPLAY_SCENES = { - "match3": "res://scenes/game/gameplays/match3_gameplay.tscn", - "clickomania": "res://scenes/game/gameplays/clickomania_gameplay.tscn" + "match3": "res://scenes/game/gameplays/Match3Gameplay.tscn", + "clickomania": "res://scenes/game/gameplays/ClickomaniaGameplay.tscn" } var current_gameplay_mode: String diff --git a/scenes/game/game.tscn b/scenes/game/game.tscn index 2a7bdcd..3de0209 100644 --- a/scenes/game/game.tscn +++ b/scenes/game/game.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=4 format=3 uid="uid://dmwkyeq2l7u04"] +[gd_scene load_steps=4 format=3 uid="uid://8c2w55brpwmm"] [ext_resource type="Script" uid="uid://bs4veuda3h358" path="res://scenes/game/game.gd" id="1_uwrxv"] [ext_resource type="PackedScene" path="res://scenes/ui/DebugToggle.tscn" id="3_debug"] diff --git a/scenes/game/gameplays/clickomania_gameplay.gd b/scenes/game/gameplays/ClickomaniaGameplay.gd similarity index 100% rename from scenes/game/gameplays/clickomania_gameplay.gd rename to scenes/game/gameplays/ClickomaniaGameplay.gd diff --git a/scenes/game/gameplays/ClickomaniaGameplay.gd.uid b/scenes/game/gameplays/ClickomaniaGameplay.gd.uid new file mode 100644 index 0000000..8abd6fa --- /dev/null +++ b/scenes/game/gameplays/ClickomaniaGameplay.gd.uid @@ -0,0 +1 @@ +uid://bkheckv0upd82 diff --git a/scenes/game/gameplays/clickomania_gameplay.tscn b/scenes/game/gameplays/ClickomaniaGameplay.tscn similarity index 81% rename from scenes/game/gameplays/clickomania_gameplay.tscn rename to scenes/game/gameplays/ClickomaniaGameplay.tscn index d24cc4f..5d81e71 100644 --- a/scenes/game/gameplays/clickomania_gameplay.tscn +++ b/scenes/game/gameplays/ClickomaniaGameplay.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=2 format=3 uid="uid://cl7g8v0eh3mam"] -[ext_resource type="Script" path="res://scenes/game/gameplays/clickomania_gameplay.gd" id="1_script"] +[ext_resource type="Script" path="res://scenes/game/gameplays/ClickomaniaGameplay.gd" id="1_script"] [node name="Clickomania" type="Node2D"] script = ExtResource("1_script") diff --git a/scenes/game/gameplays/Match3DebugMenu.gd b/scenes/game/gameplays/Match3DebugMenu.gd index a37243c..7fc7416 100644 --- a/scenes/game/gameplays/Match3DebugMenu.gd +++ b/scenes/game/gameplays/Match3DebugMenu.gd @@ -4,7 +4,7 @@ extends DebugMenuBase func _ready(): # Set specific configuration for Match3DebugMenu log_category = "Match3" - target_script_path = "res://scenes/game/gameplays/match3_gameplay.gd" + target_script_path = "res://scenes/game/gameplays/Match3Gameplay.gd" # Call parent's _ready super() diff --git a/scenes/game/gameplays/match3_gameplay.gd b/scenes/game/gameplays/Match3Gameplay.gd similarity index 100% rename from scenes/game/gameplays/match3_gameplay.gd rename to scenes/game/gameplays/Match3Gameplay.gd diff --git a/scenes/game/gameplays/Match3Gameplay.gd.uid b/scenes/game/gameplays/Match3Gameplay.gd.uid new file mode 100644 index 0000000..83bf43f --- /dev/null +++ b/scenes/game/gameplays/Match3Gameplay.gd.uid @@ -0,0 +1 @@ +uid://dbbi8ooysxp7f diff --git a/scenes/game/gameplays/match3_gameplay.tscn b/scenes/game/gameplays/Match3Gameplay.tscn similarity index 90% rename from scenes/game/gameplays/match3_gameplay.tscn rename to scenes/game/gameplays/Match3Gameplay.tscn index 75da6e9..f61848a 100644 --- a/scenes/game/gameplays/match3_gameplay.tscn +++ b/scenes/game/gameplays/Match3Gameplay.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=3 format=3 uid="uid://b4kv7g7kllwgb"] -[ext_resource type="Script" uid="uid://o8crf6688lan" path="res://scenes/game/gameplays/match3_gameplay.gd" id="1_mvfdp"] +[ext_resource type="Script" uid="uid://o8crf6688lan" path="res://scenes/game/gameplays/Match3Gameplay.gd" id="1_mvfdp"] [ext_resource type="PackedScene" uid="uid://b76oiwlifikl3" path="res://scenes/game/gameplays/Match3DebugMenu.tscn" id="2_debug_menu"] [node name="Match3" type="Node2D"] diff --git a/scenes/game/gameplays/match3_input_handler.gd b/scenes/game/gameplays/Match3InputHandler.gd similarity index 100% rename from scenes/game/gameplays/match3_input_handler.gd rename to scenes/game/gameplays/Match3InputHandler.gd diff --git a/scenes/game/gameplays/Match3InputHandler.gd.uid b/scenes/game/gameplays/Match3InputHandler.gd.uid new file mode 100644 index 0000000..4869819 --- /dev/null +++ b/scenes/game/gameplays/Match3InputHandler.gd.uid @@ -0,0 +1 @@ +uid://ogm8w7l6bhif diff --git a/scenes/game/gameplays/match3_save_manager.gd b/scenes/game/gameplays/Match3SaveManager.gd similarity index 100% rename from scenes/game/gameplays/match3_save_manager.gd rename to scenes/game/gameplays/Match3SaveManager.gd diff --git a/scenes/game/gameplays/Match3SaveManager.gd.uid b/scenes/game/gameplays/Match3SaveManager.gd.uid new file mode 100644 index 0000000..ae7aa17 --- /dev/null +++ b/scenes/game/gameplays/Match3SaveManager.gd.uid @@ -0,0 +1 @@ +uid://duheejfr6de6x diff --git a/scenes/game/gameplays/match3_validator.gd b/scenes/game/gameplays/Match3Validator.gd similarity index 100% rename from scenes/game/gameplays/match3_validator.gd rename to scenes/game/gameplays/Match3Validator.gd diff --git a/scenes/game/gameplays/Match3Validator.gd.uid b/scenes/game/gameplays/Match3Validator.gd.uid new file mode 100644 index 0000000..aa27079 --- /dev/null +++ b/scenes/game/gameplays/Match3Validator.gd.uid @@ -0,0 +1 @@ +uid://dy3aym6riijct diff --git a/scenes/game/gameplays/clickomania_gameplay.gd.uid b/scenes/game/gameplays/clickomania_gameplay.gd.uid deleted file mode 100644 index 7d8d986..0000000 --- a/scenes/game/gameplays/clickomania_gameplay.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bapywtqdghjqp diff --git a/scenes/main/main.tscn b/scenes/main/main.tscn index 45ad126..4bf1105 100644 --- a/scenes/main/main.tscn +++ b/scenes/main/main.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=5 format=3 uid="uid://ci2gk11211n0d"] +[gd_scene load_steps=5 format=3 uid="uid://bwvq7u0mv5dku"] [ext_resource type="Script" uid="uid://rvuchiy0guv3" path="res://scenes/main/Main.gd" id="1_0wfyh"] [ext_resource type="PackedScene" uid="uid://gbe1jarrwqsi" path="res://scenes/main/SplashScreen.tscn" id="1_o5qli"] diff --git a/scenes/ui/DebugMenuBase.gd b/scenes/ui/DebugMenuBase.gd index 14ffeeb..8641db0 100644 --- a/scenes/ui/DebugMenuBase.gd +++ b/scenes/ui/DebugMenuBase.gd @@ -8,7 +8,7 @@ const MIN_GRID_SIZE := 3 const MIN_TILE_TYPES := 3 const SCENE_SEARCH_COOLDOWN := 0.5 -@export var target_script_path: String = "res://scenes/game/gameplays/match3_gameplay.gd" +@export var target_script_path: String = "res://scenes/game/gameplays/Match3Gameplay.gd" @export var log_category: String = "DebugMenu" var match3_scene: Node2D diff --git a/tests/README.md b/tests/README.md index 0f1a547..2ad65d5 100644 --- a/tests/README.md +++ b/tests/README.md @@ -9,13 +9,13 @@ For complete testing guidelines, conventions, and usage instructions, see: ## Current Files -- `test_logging.gd` - Comprehensive logging system validation script +- `TestLogging.gd` - Comprehensive logging system validation script ## Quick Usage ```gdscript # Add as temporary autoload or run in scene -var test_script = preload("res://tests/test_logging.gd").new() +var test_script = preload("res://tests/TestLogging.gd").new() add_child(test_script) ``` diff --git a/tests/test_audio_manager.gd b/tests/TestAudioManager.gd similarity index 100% rename from tests/test_audio_manager.gd rename to tests/TestAudioManager.gd diff --git a/tests/TestAudioManager.gd.uid b/tests/TestAudioManager.gd.uid new file mode 100644 index 0000000..5575bcd --- /dev/null +++ b/tests/TestAudioManager.gd.uid @@ -0,0 +1 @@ +uid://bloix8dfixjem diff --git a/tests/test_game_manager.gd b/tests/TestGameManager.gd similarity index 100% rename from tests/test_game_manager.gd rename to tests/TestGameManager.gd diff --git a/tests/TestGameManager.gd.uid b/tests/TestGameManager.gd.uid new file mode 100644 index 0000000..af3ebef --- /dev/null +++ b/tests/TestGameManager.gd.uid @@ -0,0 +1 @@ +uid://b0ua34ofjdirr diff --git a/tests/test_logging.gd b/tests/TestLogging.gd similarity index 100% rename from tests/test_logging.gd rename to tests/TestLogging.gd diff --git a/tests/TestLogging.gd.uid b/tests/TestLogging.gd.uid new file mode 100644 index 0000000..cb1fc53 --- /dev/null +++ b/tests/TestLogging.gd.uid @@ -0,0 +1 @@ +uid://brqb7heh3g0ja diff --git a/tests/test_match3_gameplay.gd b/tests/TestMatch3Gameplay.gd similarity index 99% rename from tests/test_match3_gameplay.gd rename to tests/TestMatch3Gameplay.gd index 49321f8..6337cda 100644 --- a/tests/test_match3_gameplay.gd +++ b/tests/TestMatch3Gameplay.gd @@ -50,7 +50,7 @@ func setup_test_environment(): TestHelperClass.print_step("Test Environment Setup") # Load Match3 scene - match3_scene = load("res://scenes/game/gameplays/match3_gameplay.tscn") + match3_scene = load("res://scenes/game/gameplays/Match3Gameplay.tscn") TestHelperClass.assert_not_null(match3_scene, "Match3 scene loads successfully") # Create test viewport for isolated testing diff --git a/tests/TestMatch3Gameplay.gd.uid b/tests/TestMatch3Gameplay.gd.uid new file mode 100644 index 0000000..1a08c12 --- /dev/null +++ b/tests/TestMatch3Gameplay.gd.uid @@ -0,0 +1 @@ +uid://cmv4qyq0x0bvv diff --git a/tests/test_migration_compatibility.gd b/tests/TestMigrationCompatibility.gd similarity index 100% rename from tests/test_migration_compatibility.gd rename to tests/TestMigrationCompatibility.gd diff --git a/tests/TestMigrationCompatibility.gd.uid b/tests/TestMigrationCompatibility.gd.uid new file mode 100644 index 0000000..5235311 --- /dev/null +++ b/tests/TestMigrationCompatibility.gd.uid @@ -0,0 +1 @@ +uid://graevpkmrau4 diff --git a/tests/test_mouse_support.gd b/tests/TestMouseSupport.gd similarity index 91% rename from tests/test_mouse_support.gd rename to tests/TestMouseSupport.gd index 9872820..55cecd0 100644 --- a/tests/test_mouse_support.gd +++ b/tests/TestMouseSupport.gd @@ -4,8 +4,8 @@ extends SceneTree ## This test verifies that mouse input, hover events, and tile selection work correctly # Preloaded scenes to avoid duplication -const MATCH3_SCENE = preload("res://scenes/game/gameplays/match3_gameplay.tscn") -const TILE_SCENE = preload("res://scenes/game/gameplays/tile.tscn") +const MATCH3_SCENE = preload("res://scenes/game/gameplays/Match3Gameplay.tscn") +const TILE_SCENE = preload("res://scenes/game/gameplays/Tile.tscn") func _initialize(): @@ -34,12 +34,12 @@ func test_match3_scene_loading(): print("Testing Match3 scene loading...") if not MATCH3_SCENE: - print("❌ FAILED: Could not load match3_gameplay.tscn") + print("❌ FAILED: Could not load Match3Gameplay.tscn") return var match3_instance = MATCH3_SCENE.instantiate() if not match3_instance: - print("❌ FAILED: Could not instantiate match3_gameplay scene") + print("❌ FAILED: Could not instantiate Match3Gameplay scene") return root.add_child(match3_instance) diff --git a/tests/TestMouseSupport.gd.uid b/tests/TestMouseSupport.gd.uid new file mode 100644 index 0000000..492adb7 --- /dev/null +++ b/tests/TestMouseSupport.gd.uid @@ -0,0 +1 @@ +uid://kdrhd734kdel diff --git a/tests/test_scene_validation.gd b/tests/TestSceneValidation.gd similarity index 99% rename from tests/test_scene_validation.gd rename to tests/TestSceneValidation.gd index 87ec5d9..2b194ad 100644 --- a/tests/test_scene_validation.gd +++ b/tests/TestSceneValidation.gd @@ -151,7 +151,7 @@ func test_critical_scenes(): "res://scenes/main/main.tscn", "res://scenes/game/game.tscn", "res://scenes/ui/MainMenu.tscn", - "res://scenes/game/gameplays/match3_gameplay.tscn" + "res://scenes/game/gameplays/Match3Gameplay.tscn" ] for scene_path in critical_scenes: diff --git a/tests/TestSceneValidation.gd.uid b/tests/TestSceneValidation.gd.uid new file mode 100644 index 0000000..7f33b9e --- /dev/null +++ b/tests/TestSceneValidation.gd.uid @@ -0,0 +1 @@ +uid://dco5ddmpe5o74 diff --git a/tests/test_settings_manager.gd b/tests/TestSettingsManager.gd similarity index 100% rename from tests/test_settings_manager.gd rename to tests/TestSettingsManager.gd diff --git a/tests/TestSettingsManager.gd.uid b/tests/TestSettingsManager.gd.uid new file mode 100644 index 0000000..8403a28 --- /dev/null +++ b/tests/TestSettingsManager.gd.uid @@ -0,0 +1 @@ +uid://btqloxgb5460v diff --git a/tests/test_tile.gd b/tests/TestTile.gd similarity index 100% rename from tests/test_tile.gd rename to tests/TestTile.gd diff --git a/tests/TestTile.gd.uid b/tests/TestTile.gd.uid new file mode 100644 index 0000000..4d387fe --- /dev/null +++ b/tests/TestTile.gd.uid @@ -0,0 +1 @@ +uid://cf6uxd4ewd7n8 diff --git a/tests/test_value_stepper.gd b/tests/TestValueStepper.gd similarity index 100% rename from tests/test_value_stepper.gd rename to tests/TestValueStepper.gd diff --git a/tests/TestValueStepper.gd.uid b/tests/TestValueStepper.gd.uid new file mode 100644 index 0000000..0653698 --- /dev/null +++ b/tests/TestValueStepper.gd.uid @@ -0,0 +1 @@ +uid://copuu5lcw562s diff --git a/tests/test_audio_manager.gd.uid b/tests/test_audio_manager.gd.uid deleted file mode 100644 index 75681b3..0000000 --- a/tests/test_audio_manager.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bo0vdi2uhl8bm diff --git a/tests/test_game_manager.gd.uid b/tests/test_game_manager.gd.uid deleted file mode 100644 index c2c9b00..0000000 --- a/tests/test_game_manager.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cxoh80im7pak diff --git a/tests/test_logging.gd.uid b/tests/test_logging.gd.uid deleted file mode 100644 index 8eb4521..0000000 --- a/tests/test_logging.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bwygfhgn60iw3 diff --git a/tests/test_match3_gameplay.gd.uid b/tests/test_match3_gameplay.gd.uid deleted file mode 100644 index b86f64e..0000000 --- a/tests/test_match3_gameplay.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b0jpu50jmbt7t diff --git a/tests/test_migration_compatibility.gd.uid b/tests/test_migration_compatibility.gd.uid deleted file mode 100644 index 12f8751..0000000 --- a/tests/test_migration_compatibility.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cnhiygvadc13 diff --git a/tests/test_mouse_support.gd.uid b/tests/test_mouse_support.gd.uid deleted file mode 100644 index 980abbf..0000000 --- a/tests/test_mouse_support.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://gnepq3ww2d0a diff --git a/tests/test_scene_validation.gd.uid b/tests/test_scene_validation.gd.uid deleted file mode 100644 index bb856d6..0000000 --- a/tests/test_scene_validation.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b6kwoodf4xtfg diff --git a/tests/test_settings_manager.gd.uid b/tests/test_settings_manager.gd.uid deleted file mode 100644 index 8c10245..0000000 --- a/tests/test_settings_manager.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dopm8ivgucbgd diff --git a/tests/test_tile.gd.uid b/tests/test_tile.gd.uid deleted file mode 100644 index 3c4ff56..0000000 --- a/tests/test_tile.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bdn1rf14bqwv4 diff --git a/tests/test_value_stepper.gd.uid b/tests/test_value_stepper.gd.uid deleted file mode 100644 index 2664881..0000000 --- a/tests/test_value_stepper.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cfofaihfhmh8q diff --git a/tools/run_development.py b/tools/run_development.py index 906c370..10ee50d 100644 --- a/tools/run_development.py +++ b/tools/run_development.py @@ -11,6 +11,7 @@ Usage examples: python tools/run_development.py --ruff # Only Python format & lint python tools/run_development.py --validate # Only file validation python tools/run_development.py --validate --silent # Silent validation (only errors) + python tools/run_development.py --naming # Only naming convention check python tools/run_development.py --test --yaml # Test results in YAML format python tools/run_development.py --steps lint ruff test # Custom workflow python tools/run_development.py --async-mode # Force async mode @@ -20,6 +21,7 @@ Features: - Python formatting & linting with Ruff (fast formatter + linter with auto-fix) - Test execution - YAML, TOML, and JSON file validation (respects .gitignore) +- PascalCase naming convention checks for .tscn and .gd files - Colored output and comprehensive error reporting - Machine-readable YAML output for CI/CD integration - **Async processing for significantly faster execution with multiple files** @@ -622,6 +624,57 @@ def validate_json_file(file_path: Path) -> Tuple[bool, str]: return False, f"Error reading file: {e}" +def check_naming_convention(file_path: Path) -> Tuple[bool, str]: + """Check if file follows PascalCase naming convention for .tscn and .gd files.""" + file_name = file_path.name + + # Skip files that shouldn't follow PascalCase + if file_path.suffix not in [".tscn", ".gd"]: + return True, "" + + # Skip certain directories and files + skip_dirs = {"autoloads", "helpers"} + if any(part in skip_dirs for part in file_path.parts): + return True, "" + + # Skip project-specific files that are exempt + exempt_files = { + "project.godot", + "icon.svg", + "export_presets.cfg", + "default_bus_layout.tres", + } + if file_name in exempt_files: + return True, "" + + # Check PascalCase pattern + name_without_ext = file_path.stem + + # PascalCase: starts with capital letter, can have more capitals, no underscores or hyphens + if not re.match(r"^[A-Z][a-zA-Z0-9]*$", name_without_ext): + return ( + False, + f"File name '{file_name}' should use PascalCase (e.g., 'MainMenu.gd', 'Match3Gameplay.tscn')", + ) + + return True, "" + + +def get_naming_files(project_root: Path) -> List[Path]: + """Get all .tscn and .gd files that should follow naming conventions.""" + files = [] + for pattern in ["**/*.tscn", "**/*.gd"]: + files.extend(project_root.glob(pattern)) + + # Filter out files that should be ignored + filtered_files = [] + for file_path in files: + if not should_skip_file(file_path): + filtered_files.append(file_path) + + return filtered_files + + async def validate_json_file_async(file_path: Path) -> Tuple[bool, str]: """Validate a JSON file asynchronously.""" if aiofiles is None: @@ -1249,6 +1302,100 @@ async def run_validate_async( ) +def run_naming( + project_root: Path, silent: bool = False, yaml_output: bool = False +) -> Tuple[bool, Dict]: + """Check naming conventions for .tscn and .gd files.""" + if not silent and not yaml_output: + print_header("📝 Naming Convention Check") + + # Get all files that should follow naming conventions + naming_files = get_naming_files(project_root) + total_files = len(naming_files) + + if total_files == 0: + if not silent: + msg = "No .tscn or .gd files found to check naming conventions." + colored_msg = Colors.colorize(msg, Colors.YELLOW) + print(colored_msg) + return True, {"Total files": 0, "Valid files": 0, "Invalid files": 0} + + if not silent and not yaml_output: + count_msg = f"Checking naming conventions for {total_files} files..." + colored_count = Colors.colorize(count_msg, Colors.BLUE) + print(colored_count) + print() + + # Process files + valid_files = 0 + invalid_files = 0 + all_output = [] + + for file_path in naming_files: + is_valid, error_msg = check_naming_convention(file_path) + relative_path = file_path.relative_to(project_root) + + if is_valid: + valid_files += 1 + if not silent and not yaml_output: + file_msg = f"📄 Checking: {relative_path}" + colored_file = Colors.colorize(file_msg, Colors.CYAN) + success_msg = " ✅ Follows PascalCase convention" + colored_success = Colors.colorize(success_msg, Colors.GREEN) + all_output.extend([file_msg, success_msg]) + print(colored_file) + print(colored_success) + else: + invalid_files += 1 + # Always show naming errors, even in silent mode + if not yaml_output: + file_msg = f"📄 Checking: {relative_path}" + colored_file = Colors.colorize(file_msg, Colors.CYAN) + error_msg_display = f" ❌ {error_msg}" + colored_error = Colors.colorize(error_msg_display, Colors.RED) + all_output.extend([file_msg, error_msg_display]) + print(colored_file) + print(colored_error) + + # Results summary + overall_success = invalid_files == 0 + stats = { + "Total files": total_files, + "Valid files": valid_files, + "Invalid files": invalid_files, + } + + if not silent and not yaml_output: + print() + if overall_success: + success_msg = "✅ All files follow PascalCase naming convention!" + colored_success = Colors.colorize(success_msg, Colors.GREEN) + print(colored_success) + else: + error_msg = f"❌ {invalid_files} file(s) don't follow PascalCase convention" + colored_error = Colors.colorize(error_msg, Colors.RED) + print(colored_error) + + if yaml_output: + # Collect only failed files for YAML output (don't include all files) + failed_paths = [] + + for file_path in naming_files: + relative_path_str = str(file_path.relative_to(project_root)) + is_valid, error_msg = check_naming_convention(file_path) + + if not is_valid: + failed_paths.append(relative_path_str) + + results = { + **stats, # Include stats at top level for consistency + "failed_paths": failed_paths, # For failed_items extraction + } + output_yaml_results("naming", results, overall_success) + + return overall_success, stats + + def run_format( project_root: Path, silent: bool = False, yaml_output: bool = False ) -> Tuple[bool, Dict]: @@ -1476,7 +1623,7 @@ def discover_test_files(project_root: Path) -> List[Tuple[Path, str]]: for test_dir, prefix in test_dirs: test_path = project_root / test_dir if test_path.exists(): - for test_file in test_path.glob("test_*.gd"): + for test_file in test_path.glob("Test*.gd"): test_files.append((test_file, prefix)) return test_files @@ -1754,6 +1901,10 @@ def run_workflow( "📋 File format validation (yaml/toml/json)", lambda root: run_validate(root, silent, yaml_output), ), + "naming": ( + "📝 Naming convention check (PascalCase)", + lambda root: run_naming(root, silent, yaml_output), + ), } if not silent: @@ -1903,6 +2054,12 @@ async def run_workflow_async( "📋 File format validation (yaml/toml/json)", lambda root: run_validate_async(root, silent, yaml_output), ), + "naming": ( + "📝 Naming convention check (PascalCase)", + lambda root: run_naming( + root, silent, yaml_output + ), # Using sync version - lightweight + ), } if not silent: @@ -2017,8 +2174,8 @@ async def main_async(): parser.add_argument( "--steps", nargs="+", - choices=["lint", "format", "test", "validate", "ruff"], - default=["format", "lint", "ruff", "test", "validate"], + choices=["lint", "format", "test", "validate", "ruff", "naming"], + default=["format", "lint", "ruff", "test", "validate", "naming"], help="Workflow steps to run", ) parser.add_argument("--lint", action="store_true", help="Run GDScript linting") @@ -2030,6 +2187,9 @@ async def main_async(): parser.add_argument( "--ruff", action="store_true", help="Run Python formatting & linting with ruff" ) + parser.add_argument( + "--naming", action="store_true", help="Check PascalCase naming conventions" + ) parser.add_argument( "--silent", "-s", @@ -2078,6 +2238,7 @@ async def main_async(): root, args.silent, args.yaml ), "ruff": lambda root: run_ruff_async(root, args.silent, args.yaml), + "naming": lambda root: run_naming(root, args.silent, args.yaml), } success, _ = await step_funcs[steps[0]](project_root) else: @@ -2087,6 +2248,7 @@ async def main_async(): "test": lambda root: run_tests(root, args.silent, args.yaml), "validate": lambda root: run_validate(root, args.silent, args.yaml), "ruff": lambda root: run_ruff(root, args.silent, args.yaml), + "naming": lambda root: run_naming(root, args.silent, args.yaml), } success, _ = step_funcs[steps[0]](project_root) else: @@ -2114,8 +2276,8 @@ def main(): parser.add_argument( "--steps", nargs="+", - choices=["lint", "format", "test", "validate", "ruff"], - default=["format", "lint", "ruff", "test", "validate"], + choices=["lint", "format", "test", "validate", "ruff", "naming"], + default=["format", "lint", "ruff", "test", "validate", "naming"], help="Workflow steps to run", ) parser.add_argument("--lint", action="store_true", help="Run GDScript linting") @@ -2131,6 +2293,9 @@ def main(): action="store_true", help="Run Python formatting & linting with ruff", ) + parser.add_argument( + "--naming", action="store_true", help="Check PascalCase naming conventions" + ) parser.add_argument( "--silent", "-s", @@ -2173,6 +2338,7 @@ def main(): "test": lambda root: run_tests(root, args.silent, args.yaml), "validate": lambda root: run_validate(root, args.silent, args.yaml), "ruff": lambda root: run_ruff(root, args.silent, args.yaml), + "naming": lambda root: run_naming(root, args.silent, args.yaml), } success, _ = step_funcs[steps[0]](project_root) else: