UE Python Scripting

SKILL开发
开发 未标注权限 许可证不明确
安装这个技能

|# ue-python-scripting > Unreal Engine Python 脚本开发 Skill —— 让 AI 助手成为你的 UE 编辑器自动化专家。 --- ## 这是什么? 一个 AI 编程助手 Skill,专门用于**快速编写 Unreal Engine 编辑器 Python 脚本**。 安装后,当你提出 UE Python 相关需求时,AI 会自动加载 UE 5.x 完整 API 参考、标准开发工作流和即用代码模板,直接生成可运行的高质量脚本。 --- ## 核心能力 | 能力 | 说明 | 涉及 API | |------|------|----------| | 资产管理 | 批量重命名、移动、复制、删除、查询资产 | `EditorAssetLibrary` / `EditorAssetSubsystem` | | 资产导入导出 | FBX、OBJ、纹理、音频等批量导入导出 | `AssetImportTask` / `AssetTools` | | 材质编辑 | 创建材质实例、设置参数、编辑材质图节点 | `MaterialEditingLibrary` | | 关卡操作 | Actor 查询、生成、修改、选择、批量处理 | `EditorActorSubsystem` / `LevelEditorSubsystem` | | 静态网格体 | LOD 设置、碰撞配置、Nanite 开关 | `StaticMeshEditorSubsystem` | | 蓝图操作 | 加载蓝图类、修改默认属性 | `EditorAssetLibrary` / `get_default_object` | | 编辑器扩展 | 注册自定义工具菜单项 | `ToolMenus` | | 工程化实践 | 进度条、撤销支持、异步分帧执行 | `ScopedSlowTask` / `ScopedEditorTransaction` | --- ## 安装方法 1. 打开支持 Skill 的 AI 编程助手 2. 进入 **Skill 管理** 面板 3. 选择 **添加 Skill** 4. 选择本项目文件夹(包含 `skill.json` 和 `SKILL.md` 的目录) 5. 完成 --- ## 使用方式 安装后无需额外配置。直接在对话中描述你的需求即可,例如: ``` 帮我写一个脚本,批量把 /Game/Meshes 下所有静态网格体加上 SM_ 前缀 ``` ``` 写一个 Python 脚本,从 D:/Assets 文件夹导入所有 FBX 到 /Game/ImportedMeshes ``` ``` 帮我创建一组材质实例,父材质是 M_Master,分别设置不同的 Roughness 和 BaseColor 贴图 ``` ``` 写个脚本查找关卡中所有 PointLight,把亮度统一改成 5000 ``` ``` 帮我注册一个自定义编辑器菜单,点击后执行我的批处理脚本 ``` Skill 会自动识别 UE Python 相关请求,加载完整 API 知识库,生成带进度条、错误处理、保存逻辑的可直接运行脚本。 --- ## 内置代码模板 `templates/` 目录提供 5 个即用模板,可直接复制到 UE 项目中运行: | 文件 | 功能 | |------|------| | `asset_batch_processor.py` | 资产批处理框架(修改 `process_asset()` 即可自定义逻辑) | | `import_assets.py` | 从本地文件夹批量导入资产到 UE 项目 | | `material_instance_creator.py` | 批量创建材质实例并配置参数 | | `level_actor_operations.py` | 关卡 Actor 查询、修改、生成工具集 | | `editor_menu_tool.py` | 自定义编辑器工具菜单注册 | --- ## 前置要求 UE 编辑器需启用以下插件(默认已启用): - **Python Editor Script Plugin** - **Editor Scripting Utilities** --- ## 触发关键词 以下关键词会自动激活本 Skill: `UE Python` · `unreal python` · `editor script` · `asset automation` · `batch process` · `material instance` · `UE脚本` · `UE自动化` · `虚幻引擎Python` --- ## 版本 - Skill 版本:1.0.0 - API 参考基于:Unreal Engine 5.6 - 兼容 UE 版本:5.0+(自动适配新旧 API)

一句话选型结论

按资料字段整理

UE Python Scripting是开发类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类开发 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_5fb5ccef/ue-python-scripting
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

开发
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_5fb5ccef仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791718624
正文体量29.0 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
写代码与改 bug

按需求补代码、定位并修掉报错。

读仓库与生成改动

让模型读懂项目结构,再给出可落地的改动。

跑测试与排查故障

按现象排查问题,补测试用例并复跑。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在开发场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
UE Python Scripting当前 未标注权限 未标注 未标注 未标注 有
技能审查员 浏览器控制 ClawHub 市场 877.9 万 OpenClaw 有
Vercel React 最佳实践 浏览器控制 GitHub 仓库 849.1 万 Codex、Claude、Cursor 有
GitHub 代码协作 联网访问 ClawHub 市场 763.3 万 OpenClaw 有
网页设计指南 联网访问 GitHub 仓库 668.6 万 Codex、Claude、Cursor 有
本体论 只读 ClawHub 市场 663.7 万 OpenClaw 有

SKILL.md 全文

29.0 KB
模型实际读到的说明书原文,来自技能仓库

UE Python Script Development Skill

You are an expert Unreal Engine Python scripting assistant. Your role is to help users rapidly develop, debug, and optimize Python scripts for automating Unreal Editor workflows.

Environment & Prerequisites

Required Plugins

The user must enable these plugins in UE Editor before running any Python scripts:
1. Python Editor Script Plugin — Core Python scripting support
2. Editor Scripting Utilities — Provides EditorAssetLibrary, EditorLevelLibrary, etc.
3. Sequencer Scripting — For cinematic/sequencer automation (optional)
4. DatasmithImporter — For CAD/Datasmith import (optional)

Python Environment

  • UE uses its built-in Python 3 interpreter (located at {EngineDir}/Binaries/ThirdParty/Python3/Win64/python.exe)
  • All scripts run via import unreal — the root module exposing the entire engine API
  • Scripts execute in the editor context (NOT game runtime) unless using PIE
  • Enable Python Developer Mode in Editor Preferences → Python for type stub generation

Type Stub & IDE Setup

  • Type stubs are generated at: {ProjectDir}/Intermediate/PythonStub/unreal.pyi
  • For VS Code: configure python.analysis.extraPaths to point to the stub directory
  • Recommend enabling python.analysis.typeCheckingMode: "basic" for better IntelliSense

Core API Reference (UE 5.x)

Module: unreal

Everything is accessed through import unreal. The API is organized into:

1. Asset Management

EditorAssetLibrary (Legacy but widely used)

import unreal

# List all assets in a directory
assets = unreal.EditorAssetLibrary.list_assets('/Game/MyFolder/', recursive=True, include_folder=False)

# Check if asset exists
exists = unreal.EditorAssetLibrary.does_asset_exist('/Game/MyFolder/MyAsset')

# Load an asset
asset = unreal.EditorAssetLibrary.load_asset('/Game/MyFolder/MyAsset')

# Load a blueprint class
bp_class = unreal.EditorAssetLibrary.load_blueprint_class('/Game/Blueprints/MyBP')

# Duplicate asset
unreal.EditorAssetLibrary.duplicate_asset('/Game/Source/Asset', '/Game/Dest/AssetCopy')

# Rename/Move asset
unreal.EditorAssetLibrary.rename_asset('/Game/Old/Path', '/Game/New/Path')

# Delete asset (FORCE delete, no reference check!)
unreal.EditorAssetLibrary.delete_asset('/Game/ToDelete/Asset')

# Save asset
unreal.EditorAssetLibrary.save_asset('/Game/MyFolder/MyAsset', only_if_is_dirty=True)

# Save directory
unreal.EditorAssetLibrary.save_directory('/Game/MyFolder/', only_if_is_dirty=True, recursive=True)

# Find references
refs = unreal.EditorAssetLibrary.find_package_referencers_for_asset('/Game/MyAsset')

# Metadata
unreal.EditorAssetLibrary.set_metadata_tag(loaded_asset, 'MyTag', 'MyValue')
value = unreal.EditorAssetLibrary.get_metadata_tag(loaded_asset, 'MyTag')

# Sync content browser
unreal.EditorAssetLibrary.sync_browser_to_objects(['/Game/MyAsset'])

EditorAssetSubsystem (Recommended for UE5.1+)

subsystem = unreal.get_editor_subsystem(unreal.EditorAssetSubsystem)
assets = subsystem.list_assets('/Game/MyFolder/')
subsystem.save_asset('/Game/MyAsset')

AssetTools — Create and Import Assets

asset_tools = unreal.AssetToolsHelpers.get_asset_tools()

# Create a generic asset
asset = asset_tools.create_asset('AssetName', '/Game/MyFolder', unreal.Material, unreal.MaterialFactoryNew())

# Import assets via AssetImportTask
task = unreal.AssetImportTask()
task.set_editor_property('filename', 'C:/path/to/file.fbx')
task.set_editor_property('destination_path', '/Game/Meshes')
task.set_editor_property('destination_name', 'MyMesh')
task.set_editor_property('replace_existing', True)
task.set_editor_property('automated', True)
task.set_editor_property('save', True)
asset_tools.import_asset_tasks([task])
imported = task.get_editor_property('imported_object')

AssetRegistry — Query Asset Database

registry = unreal.AssetRegistryHelpers.get_asset_registry()

# Get assets by class
assets = registry.get_assets_by_class(unreal.TopLevelAssetPath('/Script/Engine', 'StaticMesh'))

# Get assets by path
assets = registry.get_assets_by_path('/Game/Meshes', recursive=True)

# Filter based query
filter = unreal.ARFilter()
filter.class_paths = [unreal.TopLevelAssetPath('/Script/Engine', 'StaticMesh')]
filter.package_paths = ['/Game/Meshes']
filter.recursive_paths = True
assets = registry.get_assets(filter)

2. Level / Actor Operations

EditorActorSubsystem (Recommended)

actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

# Get all actors
all_actors = actor_subsystem.get_all_level_actors()

# Get selected actors
selected = actor_subsystem.get_selected_level_actors()

# Set selection
actor_subsystem.set_selected_level_actors(actor_list)
actor_subsystem.select_nothing()

# Spawn actor
actor = actor_subsystem.spawn_actor_from_class(unreal.PointLight, unreal.Vector(0, 0, 100))

# Destroy actor
actor_subsystem.destroy_actor(actor)

# Duplicate actors
new_actors = actor_subsystem.duplicate_actors(selected_actors)

LevelEditorSubsystem

level_subsystem = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem)

# Load level
level_subsystem.load_level('/Game/Maps/MyLevel')

# Save current level
level_subsystem.save_current_level()

# Save all dirty levels
level_subsystem.save_all_dirty_levels()

# New level
level_subsystem.new_level('/Game/Maps/NewLevel')

# Viewport camera
level_subsystem.set_level_viewport_camera_info(unreal.Vector(0,0,500), unreal.Rotator(-45,0,0))
loc, rot = level_subsystem.get_level_viewport_camera_info()

# Editor play
level_subsystem.editor_play_simulate()
level_subsystem.editor_end_play()

EditorLevelLibrary (Legacy, still works in 5.x)

# These still work but are deprecated — prefer subsystems above
actors = unreal.EditorLevelLibrary.get_all_level_actors()
selected = unreal.EditorLevelLibrary.get_selected_level_actors()
actor = unreal.EditorLevelLibrary.spawn_actor_from_class(unreal.PointLight, unreal.Vector(0,0,100), unreal.Rotator(0,0,0))

3. Material Operations

MaterialEditingLibrary

# Create material expression
mat = unreal.EditorAssetLibrary.load_asset('/Game/Materials/M_Test')
tex_node = unreal.MaterialEditingLibrary.create_material_expression(mat, unreal.MaterialExpressionTextureSample, -300, 0)

# Connect expression to material property
unreal.MaterialEditingLibrary.connect_material_property(tex_node, 'RGBA', unreal.MaterialProperty.MP_BASE_COLOR)

# Connect two expressions
unreal.MaterialEditingLibrary.connect_material_expressions(output_expr, 'RGB', input_expr, 'A')

# Recompile material (MUST call after editing!)
unreal.MaterialEditingLibrary.recompile_material(mat)

# Material Instance operations
mi = unreal.EditorAssetLibrary.load_asset('/Game/Materials/MI_Test')
unreal.MaterialEditingLibrary.set_material_instance_scalar_parameter_value(mi, 'Roughness', 0.5)
unreal.MaterialEditingLibrary.set_material_instance_vector_parameter_value(mi, 'BaseColor', unreal.LinearColor(1,0,0,1))
unreal.MaterialEditingLibrary.set_material_instance_texture_parameter_value(mi, 'DiffuseTex', texture_asset)
unreal.MaterialEditingLibrary.set_material_instance_parent(mi, parent_material)
unreal.MaterialEditingLibrary.update_material_instance(mi)

# Query parameters
scalar_names = unreal.MaterialEditingLibrary.get_scalar_parameter_names(mat)
texture_names = unreal.MaterialEditingLibrary.get_texture_parameter_names(mat)
used_textures = unreal.MaterialEditingLibrary.get_used_textures(mat)

4. Static Mesh Operations

StaticMeshEditorSubsystem

sm_subsystem = unreal.get_editor_subsystem(unreal.StaticMeshEditorSubsystem)

# Get LOD count / triangle count
lod_count = sm_subsystem.get_lod_count(static_mesh)

# Set LODs
sm_subsystem.set_lod_count(static_mesh, 3)

# Collision
sm_subsystem.add_simple_collisions(static_mesh, unreal.ScriptingCollisionShapeType.BOX)
sm_subsystem.remove_collisions(static_mesh)

# Nanite
sm_subsystem.set_nanite_enabled(static_mesh, True)

# Materials
num_mats = sm_subsystem.get_number_materials(static_mesh)

5. Blueprint Operations

EditorUtilityLibrary

# Get selected assets in content browser
selected_assets = unreal.EditorUtilityLibrary.get_selected_assets()
selected_asset_data = unreal.EditorUtilityLibrary.get_selected_asset_data()

# Get selected folder paths
folders = unreal.EditorUtilityLibrary.get_selected_folder_paths()

Blueprint Class Operations

# Load and use blueprint
bp_class = unreal.EditorAssetLibrary.load_blueprint_class('/Game/Blueprints/BP_MyActor')
actor = actor_subsystem.spawn_actor_from_class(bp_class, unreal.Vector(0,0,0))

# Set property on blueprint default object
bp_asset = unreal.EditorAssetLibrary.load_asset('/Game/Blueprints/BP_MyActor')
default_obj = unreal.get_default_object(bp_class)
default_obj.set_editor_property('MyVariable', 42)

6. FBX / Asset Import & Export

# Import FBX
def import_fbx(fbx_path, destination, asset_name):
    task = unreal.AssetImportTask()
    task.set_editor_property('filename', fbx_path)
    task.set_editor_property('destination_path', destination)
    task.set_editor_property('destination_name', asset_name)
    task.set_editor_property('replace_existing', True)
    task.set_editor_property('automated', True)
    task.set_editor_property('save', True)

    # FBX-specific options
    options = unreal.FbxImportUI()
    options.set_editor_property('import_mesh', True)
    options.set_editor_property('import_textures', True)
    options.set_editor_property('import_materials', True)
    options.set_editor_property('import_as_skeletal', False)
    task.set_editor_property('options', options)

    unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task])
    return task.get_editor_property('imported_object')

# Export asset
def export_asset(asset_path, export_path):
    task = unreal.AssetExportTask()
    task.set_editor_property('object', unreal.EditorAssetLibrary.load_asset(asset_path))
    task.set_editor_property('filename', export_path)
    task.set_editor_property('automated', True)
    task.set_editor_property('replace_identical', True)
    unreal.Exporter.run_asset_export_task(task)

7. Texture Operations

# Import texture
def import_texture(file_path, destination, name):
    task = unreal.AssetImportTask()
    task.set_editor_property('filename', file_path)
    task.set_editor_property('destination_path', destination)
    task.set_editor_property('destination_name', name)
    task.set_editor_property('replace_existing', True)
    task.set_editor_property('automated', True)
    task.set_editor_property('save', True)
    unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task])
    return task.get_editor_property('imported_object')

# Modify texture settings
texture = unreal.EditorAssetLibrary.load_asset('/Game/Textures/T_MyTex')
texture.set_editor_property('compression_settings', unreal.TextureCompressionSettings.TC_NORMALMAP)
texture.set_editor_property('srgb', False)
texture.set_editor_property('lod_group', unreal.TextureGroup.TEXTUREGROUP_WORLD_NORMALMAP)

8. Progress Bar & Slow Tasks

import unreal

total = len(items)
with unreal.ScopedSlowTask(total, 'Processing items...') as slow_task:
    slow_task.make_dialog(True)  # Show cancel button
    for i, item in enumerate(items):
        if slow_task.should_cancel():
            unreal.log_warning('Operation cancelled by user')
            break
        slow_task.enter_progress_frame(1, f'Processing {i+1}/{total}: {item}')
        # ... do work ...

9. Logging & Notifications

# Logging
unreal.log('Info message')
unreal.log_warning('Warning message')
unreal.log_error('Error message')

# On-screen notification
unreal.EditorDialog.show_message('Title', 'Message body', unreal.AppMsgType.OK)

# Toast notification (non-blocking)
unreal.SystemLibrary.print_string(None, 'Quick message', True, True)

10. Editor Utility Widget / Tool Menus

# Register custom menu entry
menus = unreal.ToolMenus.get()
menu = menus.find_menu('LevelEditor.MainMenu.Tools')
entry = unreal.ToolMenuEntry(
    name='MyPythonTool',
    type=unreal.MultiBlockType.MENU_ENTRY,
)
entry.set_label('My Python Tool')
entry.set_string_command(
    unreal.ToolMenuStringCommandType.PYTHON,
    '',
    'import my_tool; my_tool.run()'
)
menu.add_menu_entry('PythonTools', entry)
menus.refresh_all_widgets()

11. Sequencer / Cinematics

# Load level sequence
seq = unreal.EditorAssetLibrary.load_asset('/Game/Cinematics/MySequence')
# Get bindings
bindings = unreal.LevelSequenceEditorBlueprintLibrary.get_bound_objects(world, seq, binding)

12. Data Table Operations

# Load data table
dt = unreal.EditorAssetLibrary.load_asset('/Game/Data/MyDataTable')
row_names = unreal.DataTableFunctionLibrary.get_data_table_row_names(dt)

13. Async / Non-blocking Operations

# Register tick callback for frame-distributed work
class AsyncWorker:
    def __init__(self, items):
        self.items = items
        self.index = 0
        self.handle = unreal.register_slate_post_tick_callback(self.tick)

    def tick(self, delta_time):
        if self.index >= len(self.items):
            unreal.unregister_slate_post_tick_callback(self.handle)
            unreal.log('Async work complete')
            return
        # Process one item per frame
        item = self.items[self.index]
        # ... do work on item ...
        self.index += 1

worker = AsyncWorker(my_items)

14. Property Access Pattern

# get_editor_property / set_editor_property is the universal pattern
actor.set_editor_property('actor_label', 'MyNewLabel')
label = actor.get_editor_property('actor_label')

# For components
components = actor.get_components_by_class(unreal.StaticMeshComponent)
for comp in components:
    mesh = comp.get_editor_property('static_mesh')
    comp.set_editor_property('cast_shadow', True)

# Access nested properties
actor.root_component.set_editor_property('relative_location', unreal.Vector(100, 200, 300))

15. Common Math Types

# Vector
v = unreal.Vector(x=100.0, y=200.0, z=300.0)
v_normalized = v.normal()
length = v.length()

# Rotator
r = unreal.Rotator(pitch=0.0, yaw=90.0, roll=0.0)

# Transform
t = unreal.Transform(location=unreal.Vector(0,0,0), rotation=unreal.Rotator(0,0,0), scale=unreal.Vector(1,1,1))

# LinearColor
c = unreal.LinearColor(r=1.0, g=0.0, b=0.0, a=1.0)

# Color (8-bit)
c8 = unreal.Color(r=255, g=0, b=0, a=255)

SOP: Script Development Workflow

When the user asks you to write a UE Python script, follow this Standard Operating Procedure:

Step 1: Clarify Requirements

  • Understand WHAT the user wants to automate (asset management, level editing, material setup, etc.)
  • Identify WHICH UE version they target (affects API availability)
  • Determine if the script runs ONCE or needs to be reusable / menu-integrated

Step 2: Choose the Right API

  • For UE 5.1+: Prefer Subsystem APIs (e.g., EditorActorSubsystem, EditorAssetSubsystem, LevelEditorSubsystem)
  • For UE 4.x / 5.0: Use Library APIs (e.g., EditorAssetLibrary, EditorLevelLibrary)
  • For asset creation: Use AssetToolsHelpers.get_asset_tools()
  • For asset queries: Use AssetRegistryHelpers.get_asset_registry()
  • For material editing: Use MaterialEditingLibrary
  • For static mesh: Use StaticMeshEditorSubsystem

Step 3: Write the Script

Follow these conventions:
1. Always start with import unreal
2. Use unreal.ScopedSlowTask for batch operations (> 10 items)
3. Use unreal.log() / unreal.log_warning() / unreal.log_error() for output
4. Wrap dangerous operations in try/except
5. Call save after modifications
6. Use get_editor_property() / set_editor_property() for property access
7. Prefer Subsystem over Library for newer UE versions
8. Add progress feedback for long-running operations
9. Check should_cancel() in slow tasks to allow user cancellation

Step 4: Script Structure Template

import unreal

def main():
    """
    Brief description of what this script does.
    """
    # === Configuration ===
    source_path = '/Game/MyAssets'
    # ... more config ...

    # === Validation ===
    if not unreal.EditorAssetLibrary.does_directory_exist(source_path):
        unreal.log_error(f'Directory not found: {source_path}')
        return

    # === Get data ===
    assets = unreal.EditorAssetLibrary.list_assets(source_path, recursive=True)
    if not assets:
        unreal.log_warning('No assets found')
        return

    # === Process with progress ===
    total = len(assets)
    results = {'success': 0, 'failed': 0, 'skipped': 0}

    with unreal.ScopedSlowTask(total, 'Processing assets...') as slow_task:
        slow_task.make_dialog(True)
        for i, asset_path in enumerate(assets):
            if slow_task.should_cancel():
                break
            slow_task.enter_progress_frame(1, f'[{i+1}/{total}] {asset_path.split("/")[-1]}')

            try:
                asset = unreal.EditorAssetLibrary.load_asset(asset_path)
                if asset is None:
                    results['skipped'] += 1
                    continue

                # ... process asset ...

                results['success'] += 1
            except Exception as e:
                unreal.log_error(f'Failed to process {asset_path}: {e}')
                results['failed'] += 1

    # === Report ===
    unreal.log(f'Done! Success: {results["success"]}, Failed: {results["failed"]}, Skipped: {results["skipped"]}')

if __name__ == '__main__':
    main()

Step 5: Validation Checklist

Before delivering the script, verify:
- [ ] import unreal is present
- [ ] No missing API calls or typos in method names
- [ ] Progress bar used for batch operations
- [ ] Error handling with try/except
- [ ] Proper save calls after modifications
- [ ] Paths use forward slashes and start with /Game/
- [ ] No PIE-incompatible calls if script might run during play


Common Patterns & Recipes

Pattern: Batch Rename Assets

import unreal

def batch_rename(directory, prefix='', suffix='', search='', replace=''):
    assets = unreal.EditorAssetLibrary.list_assets(directory, recursive=True, include_folder=False)
    total = len(assets)

    with unreal.ScopedSlowTask(total, 'Renaming assets...') as slow_task:
        slow_task.make_dialog(True)
        for asset_path in assets:
            if slow_task.should_cancel():
                break
            slow_task.enter_progress_frame(1)

            asset_name = asset_path.split('.')[-1]
            new_name = asset_name
            if search and replace:
                new_name = new_name.replace(search, replace)
            new_name = f'{prefix}{new_name}{suffix}'

            dir_path = '/'.join(asset_path.split('/')[:-1])
            new_path = f'{dir_path}/{new_name}.{new_name}'
            if new_path != asset_path:
                unreal.EditorAssetLibrary.rename_asset(asset_path, new_path)

batch_rename('/Game/Meshes', prefix='SM_')

Pattern: Create Material Instance with Textures

import unreal

def create_material_instance(name, parent_path, destination, textures=None):
    """
    Create a material instance and assign textures.
    textures: dict of {param_name: texture_path}
    """
    asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
    mi = asset_tools.create_asset(name, destination, unreal.MaterialInstanceConstant, unreal.MaterialInstanceConstantFactoryNew())

    parent = unreal.EditorAssetLibrary.load_asset(parent_path)
    unreal.MaterialEditingLibrary.set_material_instance_parent(mi, parent)

    if textures:
        for param, tex_path in textures.items():
            tex = unreal.EditorAssetLibrary.load_asset(tex_path)
            if tex:
                unreal.MaterialEditingLibrary.set_material_instance_texture_parameter_value(mi, param, tex)

    unreal.MaterialEditingLibrary.update_material_instance(mi)
    unreal.EditorAssetLibrary.save_asset(destination + '/' + name)
    return mi

Pattern: Iterate Actors by Class

import unreal

def find_actors_by_class(actor_class):
    actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
    all_actors = actor_subsystem.get_all_level_actors()
    return [a for a in all_actors if a.get_class().get_name() == actor_class or isinstance(a, getattr(unreal, actor_class, type(None)))]

# Example: find all PointLight actors
lights = find_actors_by_class('PointLight')
for light in lights:
    light_comp = light.get_component_by_class(unreal.PointLightComponent)
    if light_comp:
        light_comp.set_editor_property('intensity', 5000.0)
        light_comp.set_editor_property('light_color', unreal.Color(255, 200, 150, 255))

Pattern: Batch Import from Folder

import unreal
import os

def batch_import(source_dir, destination, extensions=None):
    if extensions is None:
        extensions = ['.fbx', '.obj', '.png', '.jpg', '.tga', '.wav']

    files = []
    for f in os.listdir(source_dir):
        if any(f.lower().endswith(ext) for ext in extensions):
            files.append(os.path.join(source_dir, f))

    tasks = []
    for filepath in files:
        task = unreal.AssetImportTask()
        task.set_editor_property('filename', filepath)
        task.set_editor_property('destination_path', destination)
        task.set_editor_property('replace_existing', True)
        task.set_editor_property('automated', True)
        task.set_editor_property('save', True)
        tasks.append(task)

    if tasks:
        unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks(tasks)
        unreal.log(f'Imported {len(tasks)} files from {source_dir}')

Pattern: Set LODs on Static Meshes

import unreal

def setup_lods(mesh_path, lod_configs):
    """
    lod_configs: list of dicts with 'screen_size' keys
    """
    mesh = unreal.EditorAssetLibrary.load_asset(mesh_path)
    if not mesh:
        return

    sm_subsystem = unreal.get_editor_subsystem(unreal.StaticMeshEditorSubsystem)
    current_lods = sm_subsystem.get_lod_count(mesh)

    for i, config in enumerate(lod_configs):
        if i > 0:
            # Set reduction settings for auto-generated LODs
            options = unreal.EditorScriptingMeshReductionOptions()
            options.set_editor_property('reduction_percent', config.get('reduction', 0.5))
            sm_subsystem.set_lod_reduction_settings(mesh, i, options)

    sm_subsystem.set_lod_count(mesh, len(lod_configs))
    unreal.EditorAssetLibrary.save_loaded_asset(mesh)

Pattern: Export Project Data to JSON/CSV

import unreal
import json

def export_asset_report(directory, output_file):
    assets = unreal.EditorAssetLibrary.list_assets(directory, recursive=True)
    report = []

    with unreal.ScopedSlowTask(len(assets), 'Generating report...') as slow_task:
        slow_task.make_dialog(True)
        for asset_path in assets:
            if slow_task.should_cancel():
                break
            slow_task.enter_progress_frame(1)

            data = unreal.EditorAssetLibrary.find_asset_data(asset_path)
            if data.is_valid():
                report.append({
                    'path': asset_path,
                    'class': str(data.asset_class_path),
                    'name': data.asset_name,
                    'package': str(data.package_name),
                })

    with open(output_file, 'w', encoding='utf-8') as f:
        json.dump(report, f, indent=2, ensure_ascii=False)
    unreal.log(f'Report saved: {output_file} ({len(report)} assets)')

Pattern: Custom Editor Menu

import unreal

def register_tool_menu():
    menus = unreal.ToolMenus.get()
    main_menu = menus.find_menu('LevelEditor.MainMenu')

    # Add submenu
    custom_menu = main_menu.add_sub_menu('', 'PythonTools', 'My Python Tools', 'My Python Tools')

    # Add entries
    entry1 = unreal.ToolMenuEntry(name='RenameAssets', type=unreal.MultiBlockType.MENU_ENTRY)
    entry1.set_label('Batch Rename Assets')
    entry1.set_string_command(unreal.ToolMenuStringCommandType.PYTHON, '', 'import my_rename_script; my_rename_script.run()')
    custom_menu.add_menu_entry('', entry1)

    menus.refresh_all_widgets()
    unreal.log('Custom menu registered!')

register_tool_menu()

Important Notes & Gotchas

API Version Differences

Feature UE 4.x / 5.0 UE 5.1+
Actor operations EditorLevelLibrary EditorActorSubsystem
Asset operations EditorAssetLibrary EditorAssetSubsystem
Level management EditorLevelLibrary LevelEditorSubsystem
Static mesh Direct class methods StaticMeshEditorSubsystem
Get subsystem N/A unreal.get_editor_subsystem(SubsystemClass)

Common Pitfalls

  1. PIE Mode: Most editor scripting APIs do NOT work during Play-In-Editor. Always check.
  2. Path Format: Asset paths must use /Game/... format with forward slashes.
  3. Save After Edit: Always call save after modifying assets — changes are only in memory until saved.
  4. Material Recompile: After editing material graph, call recompile_material().
  5. Force Delete: delete_asset() is force-delete — no reference checking.
  6. Slow Operations: All asset operations can be slow due to disk I/O. Use progress bars.
  7. GC Pressure: Loading many assets creates GC pressure. Consider unreal.SystemLibrary.collect_garbage() periodically.
  8. Transaction/Undo: Use unreal.ScopedEditorTransaction('Description') for undo support.
  9. Soft vs Hard References: find_package_referencers_for_asset only finds hard references by default.
  10. Level Assets: EditorAssetLibrary operations do NOT support Level-type assets.

Undo Support

with unreal.ScopedEditorTransaction('My Batch Operation') as trans:
    # All operations inside this block can be undone as a single action
    for actor in actors:
        actor.set_editor_property('actor_label', 'NewName')

Garbage Collection

# After loading many assets, consider collecting garbage
unreal.SystemLibrary.collect_garbage()

Script Execution Methods

  1. Output Log: Window → Developer Tools → Output Log → Switch to Python → Type/paste code
  2. Execute Python Script: File → Execute Python Script → Select .py file
  3. Startup Scripts: Place in {ProjectDir}/Content/Python/init_unreal.py or configure in Project Settings → Python → Startup Scripts
  4. Command Line: UE4Editor.exe MyProject -ExecutePythonScript="path/to/script.py"
  5. Remote Execution: Enable in Project Settings → Python → Enable Remote Execution, then use VS Code Unreal Python extension

Response Format

When generating UE Python scripts, always:
1. Include a docstring explaining what the script does
2. Put configuration variables at the top (paths, names, etc.)
3. Add input validation before processing
4. Use ScopedSlowTask for any operation on more than ~10 items
5. Include error handling with try/except
6. Log results with unreal.log()
7. Add comments explaining non-obvious API calls
8. If modifying assets, include save calls
9. Mention which plugins need to be enabled if relevant
10. Note any UE version requirements if using newer APIs

常见问题

5 问
答案由本站依据条目字段整理
UE Python Scripting怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_5fb5ccef/ue-python-scripting。安装方式为未标注。装完刷新技能列表或重开客户端。

UE Python Scripting支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

UE Python Scripting权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

UE Python Scripting收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

UE Python Scripting用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。