Files
skelly/docs/CODE_OF_CONDUCT.md
Vladimir nett00n Budylnikov 538459f323
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
codemap generation
2025-10-01 14:36:21 +04:00

20 KiB

Code of Conduct - Skelly Project

Overview

Coding standards and development practices for the Skelly project. These guidelines help developers contribute effectively while maintaining code quality and project consistency.

Core Principles

1. Code Clarity Over Cleverness

  • Write code that is easy to read
  • Use descriptive variable and function names
  • Prefer explicit code over "clever" solutions
  • Comment complex logic and business rules

2. Consistency First

  • Follow existing code patterns
  • Use same naming conventions throughout
  • Maintain consistent indentation and formatting
  • Follow Godot's GDScript style guide

3. Incremental Development

  • Make small, focused commits
  • Test changes before committing
  • Don't break existing functionality
  • Use debug system to verify changes

GDScript Coding Standards

Naming Conventions

📋 Quick Reference: For complete naming convention details, see the Naming Convention Quick Reference section below.

# 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

# 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

# Private functions: prefix with underscore
func _ready():
func _initialize_grid():

File Organization

# 1. extends statement
extends Node2D

# 2. class_name (if applicable)
class_name Match3Controller

# 3. Constants
const GRID_SIZE := Vector2i(8, 8)

# 4. Signals
signal match_found(tiles: Array)

# 5. Variables
var grid := []
@onready var debug_ui = $DebugUI

# 6. Functions (lifecycle first, then custom)
func _ready():
func _process(delta):
func custom_function():

Documentation Requirements

# Required for all public functions
func set_gem_pool(gem_indices: Array) -> void:
    """Set specific gem types as the active pool"""
    _update_all_tiles_gem_pool(gem_indices)
    print("Set gem pool to: ", gem_indices)

# Document complex algorithms
func _get_match_line(start: Vector2i, dir: Vector2i) -> Array:
    """Find all matching tiles in a line from start position in given direction"""
    var line = [grid[start.y][start.x]]
    var type = grid[start.y][start.x].tile_type
    # Implementation...

Project-Specific Guidelines

Scene Management

  • All scene transitions go through GameManager
  • Never use get_tree().change_scene_to_file() directly
  • Define scene paths as constants in GameManager
# ✅ Correct
GameManager.start_match3_game()

# ❌ Wrong
get_tree().change_scene_to_file("res://scenes/game/Game.tscn")

Autoload Usage

  • Use autoloads for global state only
  • Don't access autoloads from deeply nested components
  • Pass data through signals or direct references when possible
# ✅ Correct - using signals
signal settings_changed
SettingsManager.volume_changed.connect(_on_volume_changed)

# ✅ Also correct - direct access for global state
var current_language = SettingsManager.get_setting("language")

# ❌ Wrong - tight coupling
func some_deep_function():
    SettingsManager.set_setting("volume", 0.5)  # Too deep in call stack

Debug System Integration

  • Always connect to DebugManager signals for debug UI
  • Use structured logging instead of plain print statements
  • Remove temporary debug logs before committing (unless permanently useful)
# ✅ Correct debug integration
func _connect_to_global_debug() -> void:
    DebugManager.debug_ui_toggled.connect(_on_debug_ui_toggled)
    debug_ui.visible = DebugManager.is_debug_ui_visible()

# ✅ Good structured logging
DebugManager.log_debug("Debug UI toggled to: " + str(visible), "Match3")
DebugManager.log_info("Initialized " + str(tiles.size()) + " tiles", "TileSystem")

# ❌ Bad logging practices
print("test")  # Not descriptive, use structured logging
print(some_variable)  # No context, use proper log level

Logging Standards

  • Use DebugManager.log_*() functions instead of print() or push_error()
  • Choose log levels based on message importance and audience
  • Include categories to organize log output by system/component
  • Format messages with clear, descriptive text and relevant context
# ✅ Correct logging usage
DebugManager.log_info("Game scene loaded successfully", "SceneManager")
DebugManager.log_warn("Audio file not found, using default", "AudioManager")
DebugManager.log_error("Failed to save settings: " + error_message, "Settings")

# ❌ Wrong approaches
print("loaded")  # Use DebugManager.log_info() with category
push_error("error")  # Use DebugManager.log_error() with context
if debug_mode: print("debug info")  # Use DebugManager.log_debug()

Asset Management

  • Document every asset in assets/sources.yaml
  • Include source information, license details, and attribution
  • Document modifications made to original assets
  • Verify license compatibility before adding assets
  • Update sources.yaml in same commit as adding asset
# ✅ Correct asset addition workflow
# 1. Add asset file to appropriate assets/ subdirectory
# 2. Update assets/sources.yaml with complete metadata
# 3. Commit both files together with descriptive message

# Example sources.yaml entry:
# audio:
#   sfx:
#     "button_click.wav":
#       source: "https://freesound.org/people/user/sounds/12345/"
#       license: "CC BY 3.0"
#       attribution: "Button Click by SoundArtist"
#       modifications: "Normalized volume, trimmed silence"
#       usage: "UI button interactions"

Error Handling

  • Check if resources loaded successfully
  • Use DebugManager.log_error() for critical failures
  • Provide fallback behavior when possible
  • Include meaningful context in error messages
# Good error handling with structured logging
func load_scene(path: String) -> void:
    var packed_scene := load(path)
    if not packed_scene or not packed_scene is PackedScene:
        DebugManager.log_error("Failed to load scene at: %s" % path, "SceneLoader")
        return
    DebugManager.log_info("Successfully loaded scene: %s" % path, "SceneLoader")
    get_tree().change_scene_to_packed(packed_scene)

Memory Management Standards

Critical Rules:

  1. Always use queue_free() instead of free() for node cleanup
  2. Wait for frame completion after queueing nodes for removal
  3. Clear references before cleanup to prevent access to freed memory
  4. Connect signals properly for dynamically created nodes
# ✅ Correct memory management
for child in children_to_remove:
    child.queue_free()
await get_tree().process_frame  # Wait for cleanup

# ❌ Dangerous pattern (causes crashes)
for child in children_to_remove:
    child.free()  # Immediate deletion can crash

Why This Matters: Using free() causes immediate deletion which can crash if the node is still referenced elsewhere. queue_free() waits until it's safe to delete.

See Also: ARCHITECTURE.md for architectural rationale.

Input Validation Standards

All user inputs must be validated before processing.

Validation Requirements:

  1. Type checking: Verify input types before processing
  2. Bounds checking: Validate numeric ranges and array indices
  3. Null checking: Handle null and empty inputs gracefully
  4. Whitelist validation: Validate against known good values
# ✅ Proper input validation
func set_volume(value: float, setting_key: String) -> bool:
    # Whitelist validation
    if not setting_key in ["master_volume", "music_volume", "sfx_volume"]:
        DebugManager.log_error("Invalid volume setting key: " + str(setting_key), "Settings")
        return false

    # Bounds checking
    var clamped_value = clamp(value, 0.0, 1.0)
    if clamped_value != value:
        DebugManager.log_warn("Volume value clamped from %f to %f" % [value, clamped_value], "Settings")

    SettingsManager.set_setting(setting_key, clamped_value)
    return true

# ✅ Grid movement validation
func _move_cursor(direction: Vector2i) -> void:
    # Bounds checking
    if abs(direction.x) > 1 or abs(direction.y) > 1:
        DebugManager.log_error("Invalid cursor direction: " + str(direction), "Match3")
        return

    # Null/empty checking
    if not grid or grid.is_empty():
        DebugManager.log_error("Grid not initialized", "Match3")
        return

    # Process validated input
    var new_pos = cursor_pos + direction
    # ... continue with validated data

See Also: ARCHITECTURE.md for architectural decision rationale.

Code Quality Checklist

Before committing code, verify:

  • All user inputs validated (type, bounds, null checks)
  • Error handling with fallback mechanisms implemented
  • Memory cleanup uses queue_free() not free()
  • No global static state introduced
  • Proper logging with categories and appropriate levels
  • Race condition protection for async operations
  • Input actions defined in project input map
  • Resources loaded with null/type checking
  • Documentation updated for new public APIs
  • Test coverage for new functionality

Git Workflow

Commit Guidelines

  • Use clear, descriptive commit messages
  • Start with a verb in imperative mood
  • Keep first line under 50 characters
  • Add body if needed for complex changes
# Good commit messages
Add gem pool management to match-3 system
Fix debug UI visibility toggle issue
Update documentation for new debug system

# Bad commit messages
fix bug
update
wip

Branch Management

  • Create feature branches for new functionality
  • Use descriptive branch names: feature/debug-ui, fix/tile-positioning
  • Keep branches focused on single features
  • Delete branches after merging

Before Committing

  1. Test your changes in the Godot editor
  2. Check that existing functionality still works
  3. Use the debug system to verify your implementation
  4. Run the project and navigate through affected areas
  5. Remove temporary debug code

Code Review Guidelines

For Reviewers

  • Focus on code clarity and maintainability
  • Check for adherence to project patterns
  • Verify that autoloads are used appropriately
  • Ensure debug integration is properly implemented
  • Test the changes yourself

For Contributors

  • Explain complex logic in commit messages or comments
  • Provide context for why changes were made
  • Test edge cases and error conditions
  • Ask questions if project patterns are unclear

Testing Approach

Manual Testing Requirements

  • Test in Godot editor with F5 run
  • Verify debug UI works with F12 toggle
  • Check scene transitions work
  • Test on different screen sizes (mobile target)
  • Verify audio and settings integration

Debug System Testing

  • Ensure debug panels appear/disappear correctly
  • Test all debug buttons and controls
  • 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

# 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

# ✅ 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

# 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

# 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

# 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

# Format: <type>: <description>
# 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

# Don't bypass GameManager
get_tree().change_scene_to_file("some_scene.tscn")

# Don't hardcode paths
var tile = load("res://scenes/game/gameplays/Tile.tscn")

# Don't ignore null checks
var node = get_node("SomeNode")
node.do_something()  # Could crash if node doesn't exist

# Don't create global state in random scripts
# Use autoloads instead

Asset Management Violations

# Don't add assets without documentation
# Adding audio/new_music.mp3 without updating sources.yaml

# Don't use assets without verifying licenses
# Using copyrighted music without permission

# Don't modify assets without documenting changes
# Editing sprites without noting modifications in sources.yaml

# Don't commit assets and documentation separately
git add assets/sprites/new_sprite.png
git commit -m "add sprite"  # Missing sources.yaml update

# Correct approach
git add assets/sprites/new_sprite.png assets/sources.yaml
git commit -m "add new sprite with attribution"

Performance Issues

# Don't search nodes repeatedly
func _process(delta):
    var ui = get_node("UI")  # Expensive every frame

# Cache node references
@onready var ui = $UI
func _process(delta):
    ui.update_display()  # Much better

Debug System Misuse

# Don't create separate debug systems
var my_debug_enabled = false
print("debug: " + some_info)  # Don't use plain print()

# Use the global debug and logging systems
if DebugManager.is_debug_enabled():
    show_debug_info()
DebugManager.log_debug("Debug information: " + some_info, "MyComponent")

Learning Resources

Godot-Specific

General Programming

  • Clean Code principles
  • SOLID principles (adapted for game development)
  • Git best practices

Getting Help

When Stuck

  1. Check existing code for similar patterns
  2. Review project documentation (docs/)
  3. Use the debug system to understand current state
  4. Ask specific questions about project architecture
  5. Test your understanding with small experiments

Code Review Process

  • Submit pull requests early and often
  • Ask for feedback on approach before implementing large features
  • Be open to suggestions and alternative approaches
  • Learn from review feedback for future contributions

Summary

This code of conduct emphasizes:

  • Clarity: Write code that others can understand
  • Consistency: Follow established patterns
  • Integration: Use the project's systems properly
  • Learning: Continuously improve your skills

Remember: It's better to ask questions and write clear, simple code than to guess and create complex, hard-to-maintain solutions. The goal is to contribute effectively to a codebase that will grow and evolve over time.