# Blueprint Variable Management via Python

All variable operations use `execute_python` with `import unreal`. Always verify results with print().

## CRITICAL — Type name rules for get_basic_type_by_name()

`get_basic_type_by_name()` accepts ONLY these 8 names — any other string silently defaults to `int` and breaks everything:

| Valid name | Meaning | WRONG names (will break!) |
|------------|---------|---------------------------|
| `'real'` | float/double | ~~`'float'`~~ ~~`'double'`~~ ~~`'Real'`~~ |
| `'bool'` | boolean | ~~`'boolean'`~~ ~~`'Bool'`~~ |
| `'int'` | int32 | ~~`'int32'`~~ ~~`'integer'`~~ |
| `'int64'` | int64 | — |
| `'string'` | FString | ~~`'str'`~~ ~~`'FString'`~~ |
| `'name'` | FName | ~~`'FName'`~~ |
| `'text'` | FText | ~~`'FText'`~~ |
| `'byte'` | uint8 | ~~`'uint8'`~~ |

**For object/class/struct types, NEVER use get_basic_type_by_name() — use dedicated helpers:**
- Object: `lib.get_object_reference_type(unreal.Actor)` — NEVER `get_basic_type_by_name('object')`
- Class ref: `lib.get_class_reference_type(unreal.Actor)` — NEVER `get_basic_type_by_name('class')`
- Struct: `lib.get_struct_type(...)` — NEVER `get_basic_type_by_name('vector')`

## CRITICAL — Compile BEFORE building graphs that reference variables

After adding variables with `add_member_variable()`, you **MUST** call `compile_blueprint()` BEFORE calling `build_graph_from_spec()` for graphs that use those variables. Without compilation, the generated class doesn't know about the new variable and variable_get/variable_set node pins will be empty/broken.

## Variable naming
- PascalCase for all variables: `Score`, `MoveSpeed`, `ItemCount`
- Booleans: prefix with b — `bIsActive`, `bCanInteract`, `bHasFlag` (NEVER `IsActive`, `CanInteract`)
- Arrays/collections: use plural — `Items`, `Targets`, `ActiveEffects`

## Add a variable to a Blueprint

```python
import unreal
bp = unreal.load_asset('/Game/Blueprints/BP_MyActor')
lib = unreal.BlueprintEditorLibrary
helpers = unreal.UNDBlueprintHelpers

# ALWAYS check first — prevents _0 duplicates
if not helpers.has_member_variable(bp, 'MyVar'):
    float_type = lib.get_basic_type_by_name('real')  # 'real' = float. NEVER 'float'!
    lib.add_member_variable(bp, 'MyVar', float_type)

# All basic types:
# lib.get_basic_type_by_name('real')   — float/double
# lib.get_basic_type_by_name('bool')   — boolean
# lib.get_basic_type_by_name('int')    — int32
# lib.get_basic_type_by_name('string') — FString
# lib.get_basic_type_by_name('name')   — FName
# lib.get_basic_type_by_name('text')   — FText
# lib.get_basic_type_by_name('byte')   — uint8

# For object/struct types:
# lib.get_object_reference_type(unreal.Actor)
# lib.get_class_reference_type(unreal.Actor)

lib.compile_blueprint(bp)
print(f'Added variable to {bp.get_path_name()}')
```

## Set variable defaults via CDO

After `compile_blueprint()`, get the CDO and use `set_editor_property`:

```python
import unreal
bp = unreal.load_asset('/Game/Blueprints/BP_MyActor')
lib = unreal.BlueprintEditorLibrary

lib.compile_blueprint(bp)  # MUST compile first — CDO needs GeneratedClass

cdo = unreal.get_default_object(bp.generated_class())
cdo.set_editor_property('MyVar', 100.0)
cdo.set_editor_property('MaxVar', 100.0)
cdo.set_editor_property('bFlag', False)
cdo.set_editor_property('Speed', 600.0)
print('Defaults set OK')

# Compile again to bake defaults, then save — query_ue_api('compile_blueprint') and query_ue_api('save_asset')
```

**Python types for `set_editor_property`:**
| Variable type | Python value |
|---------------|-------------|
| float/real | `100.0` |
| bool | `True` / `False` |
| int | `5` |
| string | `'Hello'` |
| FName | `unreal.Name('MyName')` or `'MyName'` |

**Key requirement:** `compile_blueprint()` MUST be called BEFORE accessing the CDO — otherwise `generated_class()` returns None.
`BlueprintEditorLibrary` has NO `set_blueprint_variable_default_value` method — do not search for it.

## Set variable replication / flags / RepNotify

Discover replication and variable flag methods via `query_ue_api('BlueprintEditorLibrary replicate')` or `query_ue_api('set variable replication')` — do NOT guess method names.

**Critical anti-patterns (NOT discoverable via reflection — memorise these):**
- **NEVER** `prop.set_editor_property('replicated', True)` — `prop` here is a property descriptor object from `gen_class.properties()`, NOT a UObject; `set_editor_property` does nothing on it
- To find the correct replication method → `query_ue_api('BlueprintEditorLibrary set replicated')`

## List existing variables
```python
bp = unreal.load_asset('/Game/Blueprints/BP_MyActor')
gen_class = bp.generated_class()
if gen_class:
    for prop in gen_class.properties():
        print(f'  {prop.get_name()} ({prop.get_class().get_name()})')
```

## CRITICAL RULES
- ALWAYS check `does_asset_exist` before creating — never create duplicates
- ALWAYS `compile_blueprint()` after `add_member_variable()` and BEFORE creating Variable Get/Set nodes and BEFORE accessing CDO for defaults
- ALWAYS print results so the output confirms success
- Fix in place — NEVER create BP_v2, BP_Fixed, BP_Copy
- Warnings are informational — do NOT loop on unfixable warnings
- NEVER use `get_basic_type_by_name('float')` — use `'real'` instead
- NEVER use `get_basic_type_by_name('object')` — use `get_object_reference_type()` instead
- NEVER use `unreal.PinType` — this class does NOT exist in UE5 Python. Types are obtained ONLY via `lib.get_basic_type_by_name()` / `lib.get_object_reference_type()` / `lib.get_struct_type()`
- NEVER call `prop.set_editor_property(...)` on property descriptors from `gen_class.properties()` — they are NOT UObjects. For any per-variable flags: `query_ue_api('BlueprintEditorLibrary variable')` to find the correct method
- For replication: add variables FIRST → `compile_blueprint()` → THEN call the replication method from BlueprintEditorLibrary → `compile_blueprint()` again
- For setting defaults: `compile_blueprint()` first → `cdo = unreal.get_default_object(bp.generated_class())` → `cdo.set_editor_property('VarName', value)`
