<!-- SUMMARY -->
# Blueprint ActorComponent — Quick Reference
- **ActorComponent** = reusable behaviour module. NO Transform — use SceneComponent if needed.
- **3-Step Workflow** (ALWAYS this order, each step = ONE `execute_python` call with INLINE code):
  1. Step 1: Create BP (parent=ActorComponent) + variables + dispatchers + compile + set defaults via CDO
  2. Step 2: Build ALL functions with `build_graph_from_spec` (ONE call per function) + compile
  3. Step 3: EventGraph via `build_graph_from_spec` (graph_type=event_graph) + validate + describe + save
- **build_graph_from_spec for ALL graphs** — functions AND EventGraph. Creates graph + params + nodes + connections atomically.
- **ALWAYS** check `has_member_variable(bp, name)` before creating variables/dispatchers
- **ALWAYS** compile between structure changes and graph building
- **NEVER create external .py script files** — ALL code goes INLINE inside `execute_python` tool calls
<!-- END SUMMARY -->

# Blueprint ActorComponent — Creating Component Blueprints

**CRITICAL: Do NOT create external .py script files.** ALL Python code must be written INLINE inside `execute_python` tool calls. Never reference or create files like `Blueprint_ActorComponent_Create.py` — these do not exist.

**An ActorComponent Blueprint is NOT an Actor.** It is a reusable behaviour module attached to any Actor via SCS. ActorComponent has no Transform — use SceneComponent if you need world position.

## 3-Step Workflow (ALWAYS this order)

Build any component in exactly 3 `execute_python` calls with INLINE Python code. Do NOT split into more. Do NOT create external .py files.

---

### Step 1 — Create BP + variables + dispatchers + compile + defaults

#### Adding Variables with add_member_variable (PREFERRED)

`helpers.add_member_variable(bp, 'VarName', 'type_string')` — adds a Blueprint member variable by type name string. Much simpler than `BlueprintEditorLibrary.add_member_variable` which requires constructing `EdGraphPinType`.

```python
import unreal
helpers = unreal.UNDBlueprintHelpers

bp = unreal.load_asset('/Game/Blueprints/BP_MyComponent')

# Add variables with simple type strings
helpers.add_member_variable(bp, 'Health', 'float')
helpers.add_member_variable(bp, 'MaxHealth', 'float')
helpers.add_member_variable(bp, 'IsAlive', 'bool')
helpers.add_member_variable(bp, 'PlayerName', 'string')
helpers.add_member_variable(bp, 'Score', 'int')
helpers.add_member_variable(bp, 'SpawnLocation', 'Vector')
helpers.add_member_variable(bp, 'CharacterColor', 'LinearColor')

# Object/class references — use object:ClassName or class:ClassName
helpers.add_member_variable(bp, 'WeaponClass', 'class:Actor')
helpers.add_member_variable(bp, 'TargetActor', 'object:Actor')

# Struct/enum references — use struct:FullPath or enum:FullPath
helpers.add_member_variable(bp, 'HitResult', 'struct:/Script/Engine.HitResult')
helpers.add_member_variable(bp, 'TeamID', 'enum:/Script/Engine.ECollisionChannel')

# Compile after adding variables
unreal.BlueprintEditorLibrary.compile_blueprint(bp)
```

Supported type strings: `bool`, `byte`, `int`, `int64`, `float`, `double`, `string`, `text`, `name`, `Vector`, `Rotator`, `Transform`, `LinearColor`, `Vector2D`, `object:ClassName`, `class:ClassName`, `struct:FullPath`, `enum:FullPath`.

#### Setting Variable Defaults with set_variable_default

`helpers.set_variable_default(bp, 'VarName', 'value_string')` — sets the CDO default value for a variable. Call AFTER `compile_blueprint`.

```python
# Compile first so generated_class exists
unreal.BlueprintEditorLibrary.compile_blueprint(bp)

# Set defaults
helpers.set_variable_default(bp, 'Health', '100.0')
helpers.set_variable_default(bp, 'MaxHealth', '100.0')
helpers.set_variable_default(bp, 'IsAlive', 'true')
helpers.set_variable_default(bp, 'PlayerName', 'Player')
helpers.set_variable_default(bp, 'Score', '0')

# Compile and save
unreal.BlueprintEditorLibrary.compile_blueprint(bp)
unreal.EditorAssetLibrary.save_loaded_asset(bp)
```

**FIRST call `query_ue_api` to discover exact API names for each operation:**

| Operation | query_ue_api keyword |
|-----------|---------------------|
| Create Blueprint | `"create Blueprint asset parent"` |
| Add variable | `"add member variable Blueprint"` |
| Type descriptor | `"get basic type by name"` |
| Has variable (dedup) | `"has member variable"` |
| Add dispatcher | `"add event dispatcher"` |
| Dispatcher param | `"add dispatcher parameter"` |
| Compile | `"compile blueprint"` |
| Save | `"save asset editor"` |

Use returned function signatures directly. ALWAYS `has_member_variable` before adding variables/dispatchers.

**Order:** check exists → create/load → add variables → add dispatchers → **compile** → set CDO defaults via `get_default_object(bp.generated_class())` → compile+save

---

### Step 2 — Build ALL function graphs with build_graph_from_spec

Use `build_graph_from_spec` for EVERY function. It creates the function graph, adds params/return values, creates nodes, and wires connections in ONE atomic call. Do NOT create empty function shells first.

**Function spec structure:**
```json
{
    "graph_type": "function", "function_name": "MyFunction",
    "params": [{"name": "ParamName", "type": "real"}],
    "return_values": [{"name": "ReturnValue", "type": "real"}],
    "nodes": [
        {"id": "node_id", "type": "node_type", ...}
    ],
    "connections": [
        {"from": "entry", "from_pin": "then", "to": "node_id", "to_pin": "execute"}
    ],
    "pin_defaults": [{"node": "node_id", "pin": "PinName", "value": "0.0"}]
}
```

**Node types available:** `variable_get`, `variable_set`, `function_call` (needs `library`+`function`), `self_call`, `branch`, `sequence`, `function_result`, `call_delegate`, `bind_delegate`, `unbind_delegate`, `clear_delegate`, `event`, `custom_event`.

**Special IDs:** `"entry"` = FunctionEntry, `"result"` = FunctionResult (auto-mapped, always available).

**Key patterns (apply to ANY component, not just specific systems):**
- **Pure getter** (returns a variable): `entry.then → result.execute`, `variable_get.VarName → result.ReturnValue`
- **Setter with notification**: `entry.then → variable_set.execute → call_delegate.execute`, connect input param to both set and delegate
- **Modifier with clamp**: `variable_get → math_op → FClamp → variable_set`, use `pin_defaults` for clamp bounds

Call `build_graph_from_spec(bp, json.dumps(spec))` for each function. Parse the JSON result and check `success` and `errors`. After all functions, compile and save.

Discover math function names via `query_ue_api('math Double')` or `query_ue_api('FClamp')` — search by operation keyword, not by exact name.

---

### Step 3 — EventGraph via build_graph_from_spec + validate + final save

**EventGraph spec — initialize runtime state from defaults on BeginPlay:**
```json
{
    "graph_type": "event_graph",
    "nodes": [
        {"id": "bp",      "type": "event",        "event_name": "ReceiveBeginPlay", "x": 0,   "y": 0},
        {"id": "get_def", "type": "variable_get",  "variable": "DefaultVar",         "x": 250, "y": 50},
        {"id": "set_rt",  "type": "variable_set",  "variable": "RuntimeVar",         "x": 450, "y": 0}
    ],
    "connections": [
        {"from": "bp",      "from_pin": "then",       "to": "set_rt",  "to_pin": "execute"},
        {"from": "get_def", "from_pin": "DefaultVar", "to": "set_rt",  "to_pin": "RuntimeVar"}
    ]
}
```

**After EventGraph is built, perform the mandatory validation gate:**

1. **Compile** the blueprint.
2. **Validate** — call `validate_blueprint_graphs(bp)`. If errors are returned, fix them before `attempt_completion`.
3. **Remove orphans** — call `remove_orphaned_nodes(bp)`. If any removed, compile again.
4. **Describe** — call `describe_graph_logic(bp)`. READ the output and verify it matches intended behavior before `attempt_completion`.
5. **Save** the asset.

---

## Attaching component to an Actor Blueprint

**CRITICAL:** Python CANNOT access `bp.simple_construction_script` in UE 5.7 — it raises AttributeError.
Use `unreal.UNDBlueprintHelpers` C++ wrappers instead:

```python
import unreal
helpers = unreal.UNDBlueprintHelpers

# Load Actor BP
actor_bp = unreal.load_asset('/Game/Blueprints/BP_MyActor')

# Add a custom ActorComponent (use generated_class path)
comp_bp = unreal.load_asset('/Game/Components/BP_HealthComponent')
# For custom component BPs, the class path after compile is:
# '/Game/Components/BP_HealthComponent.BP_HealthComponent_C'

# Add built-in components
helpers.add_component_to_blueprint(actor_bp, 'SpringArmComponent', 'SpringArm')
helpers.add_component_to_blueprint(actor_bp, 'CameraComponent', 'Camera', 'SpringArm')

# Set component properties
helpers.set_component_property(actor_bp, 'SpringArm', 'TargetArmLength', '300.0')
helpers.set_component_property(actor_bp, 'SpringArm', 'bUsePawnControlRotation', 'true')

# List components to verify
for comp in helpers.get_blueprint_components(actor_bp):
    print(comp)

# Compile and save
unreal.KismetEditorLibrary.compile_blueprint(actor_bp)
unreal.EditorAssetLibrary.save_loaded_asset(actor_bp)
```

**Note:** Only Actor Blueprints have SCS. ActorComponents do NOT — you cannot nest components via SCS on a component.

## Critical rules

1. **3 execute_python calls max** for a full component. Never more.
2. **Compile order is mandatory:** variables + dispatchers → `compile_blueprint()` → graphs/nodes → CDO defaults → `compile_blueprint()`
3. **Defaults** — `compile_blueprint()` first → get CDO via `get_default_object(bp.generated_class())` → `set_editor_property('VarName', value)`.
4. **Always check `if node is None`** — print error and STOP.
5. **`has_member_variable` before creating** — prevents VarName_0, VarName_1 duplicates.
6. **validate + describe before `attempt_completion`** — mandatory.
7. **Use `UNDBlueprintHelpers` for components** — `helpers.add_component_to_blueprint(bp, 'ClassName', 'Name')`. NEVER use `bp.simple_construction_script`.
8. **No SCS on components** — `ActorComponent` has no SCS, only Actor Blueprints do.
9. **Start with `query_ue_api`** — use the query keywords from the table above to discover exact API names before writing Python code.

## Common failure patterns

| Symptom | Cause | Fix |
|---------|-------|-----|
| Variable Set node has no data pin | Skipped compile after `add_member_variable` | compile after variables, before graph nodes |
| Call Delegate node does nothing | Skipped compile after `add_event_dispatcher` | compile after dispatchers |
| CDO `set_editor_property` has no effect | Called before `compile_blueprint` | compile first — `generated_class()` needs it |
| Empty function (entry node only) | Created function shell without logic | Use `build_graph_from_spec` — it creates graph + nodes + connections atomically |
| `Found more than one function: BeginPlay` | Tried to create BeginPlay as function graph | use `build_graph_from_spec` with `"graph_type": "event_graph"` and `"type": "event"` node |
| Factory/library method not found | Hardcoded API name that changed | use `query_ue_api('keyword')` with a descriptive keyword to discover current names |

## Component design principles

- **Single responsibility** — one component = one concern
- **Dispatchers for communication** — component broadcasts state changes, owning Actor listens and reacts
- **Initialize mutable state in BeginPlay** — SET runtime value = default value
- **Pure getters** for state queries — no side effects
- **Impure modifiers** that validate and clamp values — always clamp to valid range before setting
- **Separate detection from reaction** — component detects change and broadcasts, Actor decides response
