# Project Inspection & Asset Discovery via Python

> **API names below are illustrative.** Use `query_ue_api` to discover exact names before calling.

## CRITICAL — Content Paths vs Filesystem Paths

Two different path systems in UE — **NEVER confuse them**:

| Path Type | Example | Used In |
|-----------|---------|---------|
| **UE Content Path** | `/Game/Blueprints/BP_Hero` | `load_asset()`, `does_asset_exist()`, `save_asset()`, `compile_and_check` |
| **Filesystem Path** | `Content/Blueprints/BP_Hero.uasset` | `list_files`, `search_files`, `read_file`, `write_file` |

**Translation rules:**
- `/Game/Foo/Bar` on disk = `Content/Foo/Bar.uasset`
- `/Game/` prefix = `Content/` directory on disk
- `.uasset` extension is **OMITTED** in UE content paths, **PRESENT** on disk
- **NEVER use `/Game/` paths with `list_files` or `search_files`** — use `Content/` instead
- `/Game/` paths are ONLY for Python `unreal` API: `load_asset`, `does_asset_exist`, `save_asset`

## Find existing assets (AssetRegistry — correct UE5 API)

**NEVER use `get_assets_by_class('Blueprint')` — this is deprecated in UE5.** Use `ARFilter` with `class_paths`:

```python
import unreal
ar = unreal.AssetRegistryHelpers.get_asset_registry()

# Find ALL Blueprints in project
fltr = unreal.ARFilter()
fltr.class_paths = [unreal.TopLevelAssetPath('/Script/Engine', 'Blueprint')]
fltr.package_paths = ['/Game']
fltr.recursive_paths = True
assets = ar.get_assets(fltr)
print(f'Total Blueprints: {len(assets)}')
for a in assets[:30]:
    print(f'  {a.package_name}')

# Find assets in a specific folder
fltr2 = unreal.ARFilter()
fltr2.package_paths = ['/Game/Blueprints']
fltr2.recursive_paths = True
folder_assets = ar.get_assets(fltr2)
for a in folder_assets:
    print(f'  {a.asset_name} ({a.asset_class_path.asset_name})')
```

## Check if asset exists before creating
```python
import unreal
path = '/Game/Blueprints/BP_HealthComponent'
if unreal.EditorAssetLibrary.does_asset_exist(path):
    bp = unreal.load_asset(path)
    gen = bp.generated_class()
    parent = gen.get_super_class().get_name() if gen else 'unknown'
    print(f'Already exists: {bp.get_name()}, parent: {parent}')
else:
    print('Does not exist — safe to create')
```

## Level / actor inspection (CORRECT UE5 API)

**NEVER use `EditorLevelLibrary` — it is deprecated.** Use subsystem pattern:

```python
import unreal
# CORRECT — use EditorActorSubsystem
subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
actors = subsystem.get_all_level_actors()
print(f'Total actors: {len(actors)}')

from collections import Counter
counts = Counter(a.get_class().get_name() for a in actors)
for cls, n in counts.most_common(10):
    print(f'  {cls}: {n}')

# Spawn an actor (CORRECT way)
subsystem.spawn_actor_from_class(
    unreal.load_class(None, '/Script/Engine.PointLight'),
    unreal.Vector(0, 0, 200)
)
```

## List actors by World Outliner folder

Actors are organized into folders in the World Outliner. ALWAYS inspect by folder to understand scene structure:

```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})')
```

Use `set_folder_path('FolderName')` on every spawned actor to organize it into the correct category (Environment, Lighting, Gameplay, etc.).

## Deprecated API replacements

| Deprecated (DO NOT USE) | Correct Replacement |
|------------------------|---------------------|
| `EditorLevelLibrary.get_all_level_actors()` | `get_editor_subsystem(EditorActorSubsystem).get_all_level_actors()` |
| `EditorLevelLibrary.get_editor_world()` | `get_editor_subsystem(UnrealEditorSubsystem).get_editor_world()` |
| `EditorLevelLibrary.spawn_actor_from_class()` | `get_editor_subsystem(EditorActorSubsystem).spawn_actor_from_class()` |
| `ar.get_assets_by_class('Blueprint')` | `ARFilter` with `class_paths` (see above) |

## Get project information
```python
import unreal
print(f'Project: {unreal.SystemLibrary.get_project_name()}')
print(f'Project Dir: {unreal.Paths.project_dir()}')
print(f'Content Dir: {unreal.Paths.project_content_dir()}')
print(f'Config Dir: {unreal.Paths.project_config_dir()}')
print(f'Engine Version: {unreal.SystemLibrary.get_engine_version()}')
```

## Read project config
```python
import unreal, os, configparser
config_dir = unreal.Paths.project_config_dir()
engine_ini = os.path.join(config_dir, 'DefaultEngine.ini')
if os.path.exists(engine_ini):
    config = configparser.ConfigParser(strict=False)
    config.read(engine_ini, encoding='utf-8')
    for section in config.sections()[:10]:
        print(f'[{section}]')
```

## Critical rules
- **ALWAYS use `Content/` for filesystem tools (`list_files`, `search_files`), `/Game/` ONLY for Python `unreal` API**
- **ALWAYS check `does_asset_exist(path)` BEFORE creating any asset** — avoid duplicates
- **Use `ARFilter` with `class_paths`** for asset enumeration — NOT `get_assets_by_class`
- **Use `get_editor_subsystem()`** for level/actor operations — NOT `EditorLevelLibrary`
- Use `unreal.Paths` for all project path queries (cross-platform safe)
- For log parsing, read from end of file (last 100-200 lines)
