# Level Design and Environment

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

## Discovering Level APIs at Runtime

Before any level operation, discover the correct subsystem and methods:

1. **Find the actor subsystem**: Use `query_ue_api('EditorActorSubsystem')` to discover the editor subsystem for actor spawning, selection, listing, and deletion.
2. **Find available methods**: Once you know the subsystem class name, use `dir()` on the subsystem instance or `query_ue_api` to list its methods. Look for methods related to spawning, getting actors, destroying actors.
3. **Get the subsystem instance**: Editor subsystems are retrieved via `unreal.get_editor_subsystem(ClassName)`.

Always discover API names at runtime — never assume method signatures from memory.

## Level Creation Workflow

Before placing anything in a level, always:

1. **Inspect existing actors** — get all level actors via the editor actor subsystem, print their names, classes, and locations. This prevents duplicates and helps understand the current scene.
2. **Plan placement** — decide on positions, scales, and labels before spawning.
3. **Spawn actors** — use the subsystem's spawn methods. Always check the return value for None.
4. **Label everything** — call `set_actor_label()` on every spawned actor with a descriptive name.
5. **Verify** — print actor names and locations after spawning to confirm success.

## Placing Static Meshes

To place a static mesh (e.g., a BasicShapes cube for blockout):

1. Load the mesh asset using `unreal.load_asset()` with the content path (e.g., `/Engine/BasicShapes/Cube`).
2. Spawn an actor from the loaded mesh object using the editor actor subsystem's spawn method, providing a `unreal.Vector` for location.
3. Set scale via `set_actor_scale3d(unreal.Vector(x, y, z))`.
4. Set a descriptive label via `set_actor_label('MyFloor')`.
5. Print the result to confirm placement.

## Batch Placement Pattern

For repetitive elements (walls, cover, pillars), use Python loops:

1. **Define placement data** as a list of tuples: `(label, location_vector, scale_vector)`.
2. **Loop and spawn** each entry, applying label and scale.
3. This is far more reliable than placing objects one-by-one across multiple tool calls.

Example data structure (adapt dimensions to your game's scale, all values in cm):
- Floor: location (0,0,0), scale (40,40,0.1)
- North wall: location (0,2000,200), scale (40,0.2,4)
- South wall: location (0,-2000,200), scale (40,0.2,4)
- East wall: location (2000,0,200), scale (0.2,40,4)
- West wall: location (-2000,0,200), scale (0.2,40,4)

## Actor Transforms

Actors expose these transform methods directly (no subsystem needed):
- `set_actor_location(unreal.Vector(x,y,z), sweep=False, teleport=False)`
- `set_actor_rotation(unreal.Rotator(pitch,yaw,roll), teleport=False)`
- `set_actor_scale3d(unreal.Vector(x,y,z))`

## Lighting Setup — Outdoor Scene

An outdoor scene typically needs these actor types (discover their exact class names via `query_ue_api`):

1. **Directional Light (sun)** — the key light. Rotation around pitch -45° and slight yaw for natural shadows. Set intensity and a warm light color via `set_editor_property` on the light component.
2. **Sky Light** — ambient fill. Provides soft indirect illumination.
3. **Sky Atmosphere** — realistic atmospheric scattering.
4. **Exponential Height Fog** — depth cue, low density (around 0.015).

Workflow for each light actor:
1. Discover the actor class via `query_ue_api` (e.g., search for "DirectionalLight", "SkyLight", "SkyAtmosphere", "ExponentialHeightFog").
2. Spawn it via the editor actor subsystem.
3. Get the light component via `get_component_by_class()` — discover the component class name via `query_ue_api('DirectionalLightComponent')` or `query_ue_api('PointLightComponent')` depending on the light type.
4. Set properties on the component via `set_editor_property('property_name', value)`.
5. Label the actor descriptively.

## Lighting Setup — Indoor Scene

Indoor scenes use localized light sources instead of strong sky illumination:

1. **Point Lights** — omnidirectional, set intensity in lumens (e.g., 5000), set attenuation radius to control range, warm color for accent.
2. **Spot Lights** — directional cone of light, set inner/outer cone angles (e.g., 15°/35°), higher intensity for dramatic pools of light. Rotation controls where the cone points.

Discover via `query_ue_api('PointLight')`, `query_ue_api('SpotLight')`, and their component classes (`query_ue_api('PointLightComponent')`, `query_ue_api('SpotLightComponent')`) before spawning.

## Applying Materials

To apply a material to a spawned actor:

1. Load the material asset via `unreal.load_asset('/Game/Materials/MI_YourMaterial')`.
2. Get the mesh component from the actor via `get_component_by_class()` — discover the static mesh component class via `query_ue_api('StaticMeshComponent')`.
3. Call `set_material(slot_index, material)` on the component. Slot 0 is typically the first material slot.

## Spawning PlayerStart

PlayerStart defines where the player spawns. Discover the class via `query_ue_api('PlayerStart')`, then spawn it via the editor actor subsystem at the desired location. Always label it.

## Deleting Actors

To remove actors by label pattern:

1. Get all level actors via the editor actor subsystem.
2. Filter by `get_actor_label()` using string matching.
3. Call `destroy_actor()` on each match.
4. Print how many were removed.

## Saving the Level

Discover the level-saving method via `query_ue_api('save current level')`. The save method is on the editor actor subsystem or a level editor subsystem. Always save after placing or modifying actors.

## Key Mesh Paths (BasicShapes for Blockout)

- `/Engine/BasicShapes/Cube` — walls, floors, cover, platforms, ramps
- `/Engine/BasicShapes/Cylinder` — pillars, pipes, towers
- `/Engine/BasicShapes/Sphere` — decorative elements, markers
- `/Engine/BasicShapes/Cone` — directional markers, roofs
- `/Engine/BasicShapes/Plane` — thin surfaces, decal bases

## Common Blockout Recipes

All values in centimeters (UE default unit). Adapt to your game's scale.

- **Floor**: Cube at Z=0, scale (RoomWidth/100, RoomDepth/100, 0.1)
- **Wall**: Cube, scale (WallLength/100, 0.2, WallHeight/100)
- **Half-cover**: Cube at Z=45, scale (1.5, 0.2, 0.9) — 150x20x90 cm
- **Full cover**: Cube at Z=90, scale (1.5, 0.2, 1.8) — 150x20x180 cm
- **Pillar**: Cylinder, scale (0.5, 0.5, 3.0) — 50cm radius, 300cm tall
- **Platform**: Cube at Z=100, scale (3, 3, 1) — elevated area
- **Ramp**: Cube rotated Pitch=-20°, positioned to connect height levels
- **Staircase**: Loop of Cubes, each step +20cm Z, +30cm forward

## World Outliner Organization (MANDATORY)

Every spawned actor MUST be assigned to a folder in the World Outliner for scene organization.

### Standard Folder Categories

Use these folder names consistently across all levels:
- `Environment` — floor, walls, ceiling, terrain, rocks, trees, decorative meshes
- `Environment/Blockout` — blockout geometry (BasicShapes during prototyping)
- `Lighting` — all light actors (DirectionalLight, PointLight, SpotLight, SkyLight)
- `Lighting/Atmosphere` — SkyAtmosphere, ExponentialHeightFog, VolumetricCloud
- `Gameplay` — PlayerStart, spawn points, triggers, volumes, gameplay-specific actors
- `Gameplay/Cover` — cover objects, barricades, shields
- `Gameplay/Pickups` — health packs, ammo, weapons, collectibles
- `AI` — AI controllers, spawn points, patrol waypoints, EQS contexts
- `Audio` — ambient sound actors, audio volumes, reverb zones
- `VFX` — Niagara systems, particle emitters, decals

### Setting Folder Path

```python
import unreal

# Set folder on a spawned actor
actor.set_folder_path('Environment/Blockout')

# Nested folders use forward slash
light_actor.set_folder_path('Lighting')
fog_actor.set_folder_path('Lighting/Atmosphere')
player_start.set_folder_path('Gameplay')
cover_actor.set_folder_path('Gameplay/Cover')

# Read current folder
print(f'{actor.get_actor_label()}: folder={actor.get_folder_path()}')
```

### Batch Placement with Folders

When placing multiple actors in a loop, assign folder immediately after spawn:

```python
walls = [
    ('Wall_North', unreal.Vector(0, 2000, 200), unreal.Vector(40, 0.2, 4)),
    ('Wall_South', unreal.Vector(0, -2000, 200), unreal.Vector(40, 0.2, 4)),
]
for label, loc, scale in walls:
    a = subsystem.spawn_actor_from_class(cube_class, loc)
    a.set_actor_scale3d(scale)
    a.set_actor_label(label)
    a.set_folder_path('Environment/Blockout')
    print(f'Placed {label} in Environment/Blockout')
```

### Listing Actors by Folder

To inspect what exists in the scene, organized by folder:

```python
import unreal
from collections import defaultdict

subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
actors = subsystem.get_all_level_actors()

by_folder = defaultdict(list)
for a in actors:
    folder = str(a.get_folder_path()) or '(Root)'
    by_folder[folder].append(a)

for folder in sorted(by_folder.keys()):
    print(f'\n=== {folder} ({len(by_folder[folder])} actors) ===')
    for a in by_folder[folder]:
        loc = a.get_actor_location()
        print(f'  {a.get_actor_label()}: {a.get_class().get_name()} at ({loc.x:.0f},{loc.y:.0f},{loc.z:.0f})')
```

ALWAYS run this folder-organized listing during audits to verify actors are properly categorized.

## CRITICAL RULES

- **Blockout with BasicShapes first** — never skip to final meshes
- **ALWAYS `set_actor_label()`** on every spawned actor — unlabeled actors are impossible to manage
- **ALWAYS `set_folder_path()`** on every spawned actor — organize into categories (Environment, Lighting, Gameplay, etc.)
- **List level actors by folder before spawning** to check for duplicates and understand scene organization
- **Use batch placement** (for-loops) for repetitive objects — never place one-by-one across multiple tool calls
- **Save frequently** after placing or modifying actors
- **ALWAYS `print()`** results to verify operations succeeded
- **Discover APIs at runtime** — use `query_ue_api` and `dir()` to find correct class/method names before calling them
- For materials workflow, see the **materials** knowledge module
- For VFX/particles, see the **niagara** knowledge module
