with one click
asset-management
// Search, find, open, move, duplicate, save, delete, import, and export assets
// Search, find, open, move, duplicate, save, delete, import, and export assets
| name | asset-management |
| display_name | Asset Discovery & Management |
| description | Search, find, open, move, duplicate, save, delete, import, and export assets |
| vibeue_classes | ["AssetDiscoveryService"] |
| unreal_classes | ["EditorAssetLibrary"] |
search_assets Does NOT Search Engine Contentsearch_assets(term, type) only searches /Game/ content. There is NO third parameter.
# WRONG - will error (only 2 params exist)
assets = unreal.AssetDiscoveryService.search_assets("Cube", "", True)
# CORRECT - use list_assets_in_path for engine content
engine_assets = unreal.AssetDiscoveryService.list_assets_in_path("/Engine")
cubes = [a for a in engine_assets if "Cube" in str(a.asset_name)]
| WRONG (old) | CORRECT (UE 5.7) |
|---|---|
asset.name | asset.asset_name |
asset.path | asset.package_path |
asset.asset_class | asset.asset_class_path |
To bring an image file from disk into the Content Browser, use the manage_asset import action
(or AssetDiscoveryService.import_asset). Do NOT call unreal.AssetToolsHelpers...import_asset_tasks
or ImportAssets from execute_python_code — those pump the game-thread task graph and trip a
RecursionGuard assertion that crashes the editor when run from inside a tool call.
# PREFERRED — MCP tool (robust, no crash)
# manage_asset(action="import",
# source_file_path="C:/Images/rocks.jpg",
# destination_path="/Game/UI/Textures",
# asset_name="T_Rocks")
# Python equivalent (same safe C++ path)
import unreal
path, err = unreal.AssetDiscoveryService.import_asset(
"C:/Images/rocks.jpg", "/Game/UI/Textures", "T_Rocks")
print(path or err)
# WRONG — crashes the editor (TaskGraph RecursionGuard assertion)
# tasks = [unreal.AssetImportTask()]; unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks(tasks)
Supported image formats: png, jpg, jpeg, bmp, tga, dds, exr, hdr, tiff, tif, psd, pcx.
Use /Game/... paths, not file system paths.
# WRONG - file system path
asset = unreal.AssetDiscoveryService.find_asset_by_path("C:/Projects/Content/BP_Player.uasset")
# CORRECT - content browser path
asset = unreal.AssetDiscoveryService.find_asset_by_path("/Game/Blueprints/BP_Player")
Duplicating creates a new asset identity. References stay pointed at the original asset, so deleting the original after a duplicate can break those references.
Use a real move instead:
import unreal
unreal.AssetDiscoveryService.move_asset(
"/Game/StateTree/STT_Rotate",
"/Game/StateTree/Tasks/STT_Rotate"
)
# MCP equivalent
# manage_asset(action="move", source_path="/Game/StateTree/STT_Rotate", destination_path="/Game/StateTree/Tasks/STT_Rotate")
| Does NOT Exist | Alternative |
|---|---|
asset_exists() | find_asset_by_path() → check for None |
is_asset_in_use() | get_asset_referencers() → check if empty |
rename_asset() | move_asset(old_path, new_path) |
export_asset() | export_texture() for textures only |
import unreal
# By name (partial match) - ONLY searches /Game/ content
results = unreal.AssetDiscoveryService.search_assets("Player", "Blueprint")
for asset in results:
print(f"{asset.asset_name}: {asset.package_path}")
# By folder
assets = unreal.AssetDiscoveryService.list_assets_in_path("/Game/Blueprints")
# By type only
all_bps = unreal.AssetDiscoveryService.get_assets_by_type("Blueprint")
import unreal
# Search engine content (e.g., for built-in meshes like Cube)
engine_assets = unreal.AssetDiscoveryService.list_assets_in_path("/Engine")
cubes = [a for a in engine_assets if "Cube" in str(a.asset_name)]
# Filter by type
meshes = unreal.AssetDiscoveryService.list_assets_in_path("/Engine", "StaticMesh")
import unreal
asset = unreal.AssetDiscoveryService.find_asset_by_path("/Game/BP_Player")
if asset:
print(f"Found: {asset.asset_name}")
else:
print("Not found - create it")
import unreal
success = unreal.AssetDiscoveryService.duplicate_asset("/Game/BP_Enemy", "/Game/BP_EnemyBoss")
if success:
print("Duplicated")
import unreal
success = unreal.AssetDiscoveryService.move_asset(
"/Game/StateTree/STT_Rotate",
"/Game/StateTree/Tasks/STT_Rotate"
)
if success:
print("Moved without breaking references")
import unreal
# Save specific asset
unreal.AssetDiscoveryService.save_asset("/Game/BP_Player")
# Save all dirty assets
count = unreal.AssetDiscoveryService.save_all_assets()
print(f"Saved {count} assets")
import unreal
refs = unreal.AssetDiscoveryService.get_asset_referencers("/Game/SM_Weapon")
if len(refs) == 0:
unreal.AssetDiscoveryService.delete_asset("/Game/SM_Weapon")
else:
print(f"In use by {len(refs)} assets")
import unreal
# Import (disk → Content Browser). Returns (asset_path, error); asset_path is "" on failure.
# Pass a destination FOLDER + optional asset name.
path, err = unreal.AssetDiscoveryService.import_asset(
"C:/Textures/logo.png", "/Game/Textures", "T_Logo")
print(path or err)
# import_texture(src, dest_asset_path) still works (takes a full asset path) and now uses the
# same crash-safe importer under the hood:
unreal.AssetDiscoveryService.import_texture("C:/Textures/logo.png", "/Game/Textures/T_Logo")
# Export (project → file system)
unreal.AssetDiscoveryService.export_texture("/Game/Textures/T_Logo", "C:/Exports/logo.png")
Prefer the
manage_assetimport action in tool flows:manage_asset(action="import", source_file_path="C:/Textures/logo.png", destination_path="/Game/Textures", asset_name="T_Logo")
import unreal
# Get all open assets
open_assets = unreal.AssetDiscoveryService.get_open_assets()
print(f"Editing {len(open_assets)} assets")
# Check if specific asset is open
if unreal.AssetDiscoveryService.is_asset_open("/Game/BP_Player"):
print("BP_Player is open")
# Get selected assets in Content Browser
selected = unreal.AssetDiscoveryService.get_content_browser_selections()
for asset in selected:
print(asset.asset_name)
# Get primary selection
asset = unreal.AssetData()
if unreal.AssetDiscoveryService.get_primary_content_browser_selection(asset):
print(f"Selected: {asset.asset_name}")
Assets not covered by VibeUE services (e.g., LandscapeGrassType) require AssetToolsHelpers + a factory:
import unreal
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
# LandscapeGrassType
factory = unreal.LandscapeGrassTypeFactory()
lgt = asset_tools.create_asset("LGT_MyGrass", "/Game/Landscape", unreal.LandscapeGrassType, factory)
# After creation, set properties via set_editor_property, then save
unreal.EditorAssetLibrary.save_asset("/Game/Landscape/LGT_MyGrass")
Tip: Use
discover_python_module("unreal", name_filter="Factory")to find available factories for other asset types.
search_assets(term, type) searches by name/type but may return empty for niche types like LandscapeGrassType. If search returns nothing:
get_assets_by_type("LandscapeGrassType") for type-specific querieslist_assets_in_path("/Game/SomeFolder") and filter in PythonLandscapeGrassType, not GrassType)Blueprint - Blueprint classesWidgetBlueprint - UMG Widget BlueprintsTexture2D - Texture assetsStaticMesh - Static mesh assetsSkeletalMesh - Skeletal mesh assetsMaterial - MaterialsMaterialInstanceConstant - Material instancesDataTable - Data TablesPrimaryDataAsset - Primary Data AssetsLandscapeGrassType - Landscape grass/vegetation scatter typesLandscapeLayerInfoObject - Landscape paint layer infoConfigure Niagara emitter internals - modules, renderers, rapid iteration parameters, graph positioning, and scratch-pad authoring (Custom HLSL + node graph)
Create and manage Niagara particle systems - system lifecycle, adding/copying emitters, user parameters, system script settings, scratch-pad authoring
Create and modify Blueprint assets, variables, functions, and components
Navigate, inspect AND author Animation Blueprints, state machines, states, transitions and transition rules
Preview, validate, bake, and manipulate animation sequences with constraint-aware bone editing
Add, connect, and configure nodes in Blueprint event graphs and function graphs