# CLAUDE.md - Godot Client

## Service Overview
**Godot Client** for Code of Conquest - Native cross-platform game client using Godot 4.5 + GDScript.

**Tech Stack:** Godot 4.5 + GDScript + HTTPRequest
**Platforms:** Desktop (Windows, macOS, Linux), Mobile (Android, iOS), Web (HTML5)
**Location:** `/godot_client`

---

## Architecture Role

This Godot client is a **thin UI layer** that makes HTTP requests to the API backend:
- ✅ Render game UI (scenes, components)
- ✅ Handle user input
- ✅ Make HTTP requests to API backend
- ✅ Display API responses
- ✅ Client-side animations and effects
- ✅ Local state management (UI state only)

**What this service does NOT do:**
- ❌ No business logic (all in `/api`)
- ❌ No game mechanics calculations (use API)
- ❌ No direct database access (use API)
- ❌ No AI calls (use API)
- ❌ No authoritative game state (API is source of truth)

**Communication:**
```
Godot Client → HTTP Request → API Backend
      ↑                            ↓
      ←───── HTTP Response ────────┘
```

---

## Documentation Index

**Godot Client Documentation:**
- **[README.md](README.md)** - Setup and usage guide
- **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** - Client architecture overview
- **[docs/GETTING_STARTED.md](docs/GETTING_STARTED.md)** - Quickstart guide
- **[docs/EXPORT.md](docs/EXPORT.md)** - Platform export instructions
- **[docs/THEME_SETUP.md](docs/THEME_SETUP.md)** - UI theming guide
- **[docs/MULTIPLAYER.md](docs/MULTIPLAYER.md)** - Multiplayer client implementation
- **[docs/README.md](docs/README.md)** - Scene documentation workflow

**Project-Wide Documentation:**
- **[../docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md)** - System architecture overview
- **[../api/docs/API_REFERENCE.md](../api/docs/API_REFERENCE.md)** - API endpoints to call
- **[../docs/WEB_VS_CLIENT_SYSTEMS.md](../docs/WEB_VS_CLIENT_SYSTEMS.md)** - Feature distribution between frontends

---

## Development Guidelines

### Project Structure

```
godot_client/
├── project.godot          # Godot project configuration
├── scenes/                # Godot scene files (.tscn)
│   ├── main.tscn         # Entry point
│   ├── auth/             # Authentication scenes
│   ├── character/        # Character scenes
│   ├── combat/           # Combat scenes
│   └── components/       # Reusable UI components
├── scripts/               # GDScript code
│   ├── services/         # Singleton autoloads
│   ├── models/           # Data models
│   ├── components/       # Component scripts
│   └── utils/            # Helper utilities
└── assets/                # Game assets
    ├── fonts/            # Fonts
    ├── themes/           # UI themes
    └── ui/               # UI assets
```

### GDScript Coding Standards

**Style & Structure**
- Follow GDScript style guide (snake_case for functions/variables)
- Use PascalCase for class names
- Always include doc comments for classes and functions
- Prefer explicit types over dynamic typing
- Group related code with region comments
- **Do NOT apply styles/themes in code** - All visual styling (StyleBoxFlat, colors, fonts, margins) should be done in the Godot editor, not programmatically in GDScript

**Example:**
```gdscript
class_name CharacterCard
extends Control
## A UI component that displays character information.
##
## This card shows the character's name, level, class, and stats.
## It makes an HTTP request to fetch character data from the API.

#region Exports
@export var character_id: String = ""
@export var auto_load: bool = true
#endregion

#region Private Variables
var _character_data: Dictionary = {}
var _is_loading: bool = false
#endregion

#region Lifecycle
func _ready() -> void:
    """Initialize the character card."""
    if auto_load and character_id != "":
        load_character()

func _process(_delta: float) -> void:
    """Update card UI each frame."""
    pass
#endregion

#region Public Methods
func load_character() -> void:
    """Load character data from API."""
    if _is_loading:
        return

    _is_loading = true

    var url = Settings.api_base_url + "/api/v1/characters/" + character_id
    HTTPClient.get_request(url, _on_character_loaded, _on_character_error)

func refresh() -> void:
    """Refresh character data."""
    load_character()
#endregion

#region Private Methods
func _update_ui() -> void:
    """Update UI elements with character data."""
    $Name.text = _character_data.get("name", "Unknown")
    $Level.text = "Level " + str(_character_data.get("level", 1))

func _show_error(message: String) -> void:
    """Display error message to user."""
    $ErrorLabel.text = message
    $ErrorLabel.visible = true
#endregion

#region Signal Handlers
func _on_character_loaded(response: Dictionary) -> void:
    """Handle successful character data load."""
    _is_loading = false

    if response.has("result"):
        _character_data = response.result
        _update_ui()

func _on_character_error(error: String) -> void:
    """Handle character data load error."""
    _is_loading = false
    _show_error("Failed to load character: " + error)

func _on_button_pressed() -> void:
    """Handle button click."""
    refresh()
#endregion
```

**Code Organization:**
1. Class documentation
2. Exports (inspector variables)
3. Signals
4. Public constants
5. Private variables
6. Lifecycle methods (_ready, _process, etc.)
7. Public methods
8. Private methods
9. Signal handlers

### Service Singletons (Autoloads)

**Settings Service (`scripts/services/settings.gd`):**
```gdscript
extends Node
## Global settings and configuration management.

var api_base_url: String = "http://localhost:5000"
var environment: String = "development"
var version: String = "0.1.0"

func _ready() -> void:
    load_settings()

func load_settings() -> void:
    """Load settings from file or environment."""
    # Load from settings file or use defaults
    if FileAccess.file_exists("user://settings.json"):
        var file = FileAccess.open("user://settings.json", FileAccess.READ)
        var json = JSON.parse_string(file.get_as_text())
        file.close()

        if json:
            api_base_url = json.get("api_base_url", api_base_url)
            environment = json.get("environment", environment)

func save_settings() -> void:
    """Save settings to file."""
    var data = {
        "api_base_url": api_base_url,
        "environment": environment
    }

    var file = FileAccess.open("user://settings.json", FileAccess.WRITE)
    file.store_string(JSON.stringify(data, "\t"))
    file.close()
```

**HTTP Client Service (`scripts/services/http_client.gd`):**
```gdscript
extends Node
## Centralized HTTP client for API communication.

signal request_completed(response: Dictionary)
signal request_failed(error: String)

var _http_requests: Dictionary = {}

func get_request(url: String, on_success: Callable, on_error: Callable = Callable()) -> void:
    """Make a GET request to the API."""
    _make_request(url, HTTPClient.METHOD_GET, {}, on_success, on_error)

func post_request(url: String, data: Dictionary, on_success: Callable, on_error: Callable = Callable()) -> void:
    """Make a POST request to the API."""
    _make_request(url, HTTPClient.METHOD_POST, data, on_success, on_error)

func _make_request(url: String, method: int, data: Dictionary, on_success: Callable, on_error: Callable) -> void:
    """Internal method to make HTTP requests."""
    var http_request = HTTPRequest.new()
    add_child(http_request)

    # Store callbacks
    var request_id = str(http_request.get_instance_id())
    _http_requests[request_id] = {
        "on_success": on_success,
        "on_error": on_error,
        "node": http_request
    }

    # Connect signals
    http_request.request_completed.connect(_on_request_completed.bind(request_id))

    # Make request
    var headers = ["Content-Type: application/json"]
    var body = JSON.stringify(data) if method != HTTPClient.METHOD_GET else ""

    var error = http_request.request(url, headers, method, body)

    if error != OK:
        _handle_error(request_id, "Request failed: " + str(error))

func _on_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray, request_id: String) -> void:
    """Handle HTTP request completion."""
    var request_data = _http_requests.get(request_id)
    if not request_data:
        return

    # Parse response
    var json = JSON.parse_string(body.get_string_from_utf8())

    # Check for errors
    if result != HTTPRequest.RESULT_SUCCESS or response_code >= 400:
        var error_message = json.get("error", {}).get("message", "Request failed") if json else "Request failed"
        _handle_error(request_id, error_message)
        return

    # Success
    if request_data.on_success.is_valid():
        request_data.on_success.call(json)

    # Cleanup
    _cleanup_request(request_id)

func _handle_error(request_id: String, error: String) -> void:
    """Handle request error."""
    var request_data = _http_requests.get(request_id)
    if request_data and request_data.on_error.is_valid():
        request_data.on_error.call(error)

    _cleanup_request(request_id)

func _cleanup_request(request_id: String) -> void:
    """Clean up completed request."""
    var request_data = _http_requests.get(request_id)
    if request_data:
        request_data.node.queue_free()
        _http_requests.erase(request_id)
```

### Scene Organization

**Scene Structure:**
```
Main Scene (main.tscn)
├── UI Layer (CanvasLayer)
│   ├── MainMenu
│   ├── LoadingScreen
│   └── ErrorPopup
├── Game Layer (Node2D/Node3D)
│   ├── Character
│   ├── World
│   └── Combat
└── Services (Node)
    ├── AudioManager
    └── InputManager
```

**Scene Best Practices:**
- Keep scenes focused (single responsibility)
- Use scenes as components (reusable UI elements)
- Attach scripts to scene root nodes
- Use groups for easy node access (`node.add_to_group("enemies")`)
- Prefer signals over direct node references

### UI Theming

**Theme Structure:**
```gdscript
# Create programmatically or use theme resource
var theme = Theme.new()

# Colors
theme.set_color("font_color", "Label", Color.WHITE)
theme.set_color("font_color", "Button", Color("#e5e7eb"))

# Fonts
var title_font = load("res://assets/fonts/Cinzel-Bold.ttf")
theme.set_font("font", "TitleLabel", title_font)

# Stylebox
var button_style = StyleBoxFlat.new()
button_style.bg_color = Color("#8b5cf6")
button_style.corner_radius_top_left = 8
button_style.corner_radius_top_right = 8
button_style.corner_radius_bottom_left = 8
button_style.corner_radius_bottom_right = 8
theme.set_stylebox("normal", "Button", button_style)
```

### API Communication Patterns

**Simple GET Request:**
```gdscript
func load_characters() -> void:
    var url = Settings.api_base_url + "/api/v1/characters"
    HTTPClient.get_request(url, _on_characters_loaded, _on_characters_error)

func _on_characters_loaded(response: Dictionary) -> void:
    var characters = response.get("result", [])
    # Update UI with characters

func _on_characters_error(error: String) -> void:
    print("Error loading characters: ", error)
```

**POST Request with Data:**
```gdscript
func create_character(name: String, class_id: String, origin_id: String) -> void:
    var url = Settings.api_base_url + "/api/v1/characters"
    var data = {
        "name": name,
        "class_id": class_id,
        "origin_id": origin_id
    }

    HTTPClient.post_request(url, data, _on_character_created, _on_create_error)

func _on_character_created(response: Dictionary) -> void:
    var character = response.get("result")
    print("Character created: ", character.name)
    # Navigate to character screen

func _on_create_error(error: String) -> void:
    show_error_popup("Failed to create character: " + error)
```

### State Management

**StateManager Service (`scripts/services/state_manager.gd`):**
```gdscript
extends Node
## Global game state management.

signal state_changed(key: String, value: Variant)

var _state: Dictionary = {}

func set_value(key: String, value: Variant) -> void:
    """Set a state value."""
    _state[key] = value
    state_changed.emit(key, value)

func get_value(key: String, default: Variant = null) -> Variant:
    """Get a state value."""
    return _state.get(key, default)

func has_value(key: String) -> bool:
    """Check if state has a key."""
    return _state.has(key)

func clear() -> void:
    """Clear all state."""
    _state.clear()
```

**Usage:**
```gdscript
# Set current character
StateManager.set_value("current_character_id", "char_123")

# Get current character
var char_id = StateManager.get_value("current_character_id")

# Listen for changes
StateManager.state_changed.connect(_on_state_changed)

func _on_state_changed(key: String, value: Variant) -> void:
    if key == "current_character_id":
        load_character(value)
```

---

## Godot Workflow

### Project Setup (Autoloads)

In Project Settings → Autoload, add these singletons:

1. **Settings** - `scripts/services/settings.gd`
2. **HTTPClient** - `scripts/services/http_client.gd`
3. **StateManager** - `scripts/services/state_manager.gd`

### Creating a New Scene

1. **Plan the scene** - Sketch layout, define purpose
2. **Create scene file** - `scenes/feature/scene_name.tscn`
3. **Add nodes** - Build UI hierarchy
4. **Attach script** - `scripts/feature/scene_name.gd`
5. **Connect signals** - Wire up interactions
6. **Test in editor** - F6 to test scene
7. **Integrate** - Add to main scene or navigation

### Testing

**In Editor:**
- F5 - Run project
- F6 - Run current scene
- Use Debugger panel for breakpoints
- Monitor output for print statements

**Export Testing:**
- Test on target platforms (Desktop, Mobile, Web)
- Check API connectivity
- Verify UI scaling

---

## Export Configuration

### Desktop Export

**Windows:**
```
Platform: Windows Desktop
Architecture: x86_64
Export Template: Release
```

**macOS:**
```
Platform: macOS
Architecture: Universal (arm64 + x86_64)
Export Template: Release
Code Sign: Required for distribution
```

**Linux:**
```
Platform: Linux/X11
Architecture: x86_64
Export Template: Release
```

### Mobile Export

**Android:**
```
Platform: Android
Architecture: arm64-v8a
Min SDK: 21
Target SDK: 33
```

**iOS:**
```
Platform: iOS
Architecture: arm64
Deployment Target: iOS 12.0
Bundle ID: com.codeofconquest.game
```

### Web Export

```
Platform: Web
Export Type: HTML5
Progressive Web App: Yes
```

See [EXPORT.md](EXPORT.md) for detailed instructions.

---

## Git Standards

**Commit Messages:**
- Use conventional commit format: `feat:`, `fix:`, `style:`, `asset:`, etc.
- Examples:
  - `feat(godot): add character list scene`
  - `fix(http): handle API timeout errors`
  - `style(ui): update character card layout`
  - `asset(fonts): add Cinzel font family`

**Branch Strategy:**
- Branch off `dev` for features
- Merge back to `dev` for testing
- Promote to `master` for production

---

## Notes for Claude Code

When working on the Godot client:

1. **Thin client only** - No business logic, just UI and user interaction
2. **Always call API** - Use HTTPClient service for all data operations
3. **Handle errors gracefully** - Show user-friendly error popups
4. **Keep scenes modular** - Create reusable component scenes
5. **Use signals** - Prefer signals over direct node references
6. **Test on target platforms** - Verify exports work correctly
7. **Performance matters** - Optimize for mobile (low draw calls, minimize allocations)
8. **Follow Godot conventions** - Use GDScript idioms, not Python/JavaScript patterns

**Remember:**
- This is a thin client - all logic lives in the API backend
- The API serves multiple frontends (this Godot client and web UI)
- Godot handles rendering and input - API handles game state
- Keep it responsive - show loading indicators during API calls
- Mobile-first design - optimize for touch and smaller screens
