mcpField
U
unreal-blueprint-codegen

unreal-blueprint-codegen

github.com/maystudios开发26111 次安装11 周前更新
代码仓库

关于 unreal-blueprint-codegen

unreal-blueprint-codegen 是面向 Unreal Engine 5.4–5.7 编辑器模块开发者的技能,用 C++ 程序化生成 Blueprint、Widget Blueprint 等 .uasset。它提供节点连线、编译、保存流程及版本注意事项,适用于可重复生成资产的场景。

主要功能

  1. 01用 C++ 生成 Blueprint 资产
  2. 02构建函数图和事件图
  3. 03生成 Widget Blueprint 层级与动画
  4. 04编译并保存资产包
  5. 05提供双阶段编译指导
  6. 06整理引擎版本注意事项

适用场景

  1. 01批量生成可重复使用的示例资产
  2. 02程序化创建 Blueprint 变量和节点
  3. 03从 C++ 构建 Widget Blueprint 与动画
  4. 04排查节点引脚或编译问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/maystudios/claude-skills --skill unreal-blueprint-codegen

安装后在 Claude Code 中输入/unreal-blueprint-codegen确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/experiment-module-template/
uplugin-snippet.json
assets/experiment-module-template/Source/MyExperimentEditor/
MyExperimentEditor.Build.cs
assets/experiment-module-template/Source/MyExperimentEditor/Private/
MyExperimentEditorModule.cpp
MyExperimentLibrary.cpp
assets/experiment-module-template/Source/MyExperimentEditor/Public/
MyExperimentEditorModule.h
MyExperimentLibrary.h
references/
caveats.md
k2node-cookbook.md
two-pass-compile.md
widget-blueprint-cookbook.md

详细介绍

Unreal Engine Blueprint 代码生成(UE 5.4–5.7)

在编辑器模块中从 C++ 生成完整的 .uasset 文件(Blueprint、Widget Blueprint、领域资源)。已针对 UE 5.7 验证。大多数模式也适用于 UE 5.4 及更高版本。

适用场景

用户希望以编程方式创作资源内容——变量、函数图表、事件图表连线、Widget 层级结构、UMG 动画、自定义资源图表——而不是在编辑器中逐项点击。典型用例:生成 Marketplace 示例内容(快速入门、操作指南、演示对话),使其能够以可复现的方式重新生成,而不是手动精简二进制 .uasset 文件。

如果用户只想在运行时实例化 Widget(游戏运行时调用 CreateWidget / WidgetTree->ConstructWidget),那么这项技能有点大材小用——那只是常规 UMG 操作。

硬性前提

  • C++ 编辑器模块,Type=Editor(或 UncookedOnly)。Python 无法创作事件图表——UEdGraph/UK2Node_* 不对外开放。如果需要 Python 入口,请在 C++ 中设置 UBlueprintFunctionLibrary,并从 Python 调用其 UFUNCTION。
  • 模块至少需要依赖:UnrealEd、BlueprintGraph、Kismet、KismetCompiler、AssetTools、AssetRegistry。对于 Widget Blueprint,还需添加 UMG、UMGEditor、MovieScene、MovieSceneTracks。可参阅 assets/experiment-module-template/ 中可正常工作的 .Build.cs。
  • IWYU:显式包含每个引擎头文件。在自己的头文件中前置声明 UPackage/UObject 等;仅在 .cpp 中引入完整头文件。

30 秒快速理解

Asset = UPackage  +  UObject (e.g. UBlueprint / UWidgetBlueprint / UMyAsset)
                     |
                     +-- source UEdGraph (editor-only, what designers see)
                     |     +-- UK2Node_* / UEdGraphNode_* (the boxes)
                     |           +-- UEdGraphPin (the wires)
                     |
                     +-- generated UClass  <- produced by CompileBlueprint
                           +-- FProperty / UFunction (what code uses at runtime)

在图表上生成编辑器节点,连接它们的引脚,然后调用 CompileBlueprint 生成类。保存包。

决策树

目标阅读
向常规 Blueprint 添加变量、函数、自定义事件、数学节点references/k2node-cookbook.md
构建包含 Widget 层级结构的 Widget Blueprintreferences/widget-blueprint-cookbook.md
从 C++ 添加 UMG 动画(UWidgetAnimation + MovieScene 轨道/关键帧)references/widget-blueprint-cookbook.md
编译器提示“找不到函数”、FindPinChecked 断言失败,或节点没有引脚references/two-pass-compile.md — 调试前请先阅读
需要一个可供起步的模块骨架assets/experiment-module-template/
遇到奇怪的引擎 API 特性或特定版本问题references/caveats.md

标准工作流

对于每个生成器函数:

  1. 创建/加载包:调用 CreatePackage(*FullPath),然后调用 Package->FullyLoad()。
  2. 创建资源:使用 FKismetEditorUtilities::CreateBlueprint(...)(同时适用于 UBlueprint 和 UWidgetBlueprint——传入正确的 Blueprint 类 + GeneratedClass)。
  3. 构建内容——变量、函数图表、Widget 树、动画。
  4. 连接事件图表/调用用户函数——仅当连线引用了步骤 3 中创建的内容时,才在中间编译后执行(参阅 two-pass-compile.md)。
  5. MarkBlueprintAsStructurallyModified + CompileBlueprint——最后调用一次(或分两阶段调用两次)。
  6. 保存:调用 FAssetRegistryModule::AssetCreated(Asset) + Package->MarkPackageDirty() + UPackage::SavePackage(...)。

骨架:

#include "Engine/Blueprint.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "UObject/SavePackage.h"

UBlueprint* CreateBP(const FString& PackagePath, const FString& AssetName, UClass* ParentClass)
{
    const FString FullPath = PackagePath / AssetName;
    UPackage* Package = CreatePackage(*FullPath);
    Package->FullyLoad();

    UBlueprint* BP = FKismetEditorUtilities::CreateBlueprint(
        ParentClass,                  // e.g. AActor::StaticClass() or UUserWidget::StaticClass()
        Package,
        FName(*AssetName),
        BPTYPE_Normal,
        UBlueprint::StaticClass(),    // or UWidgetBlueprint::StaticClass()
        UBlueprintGeneratedClass::StaticClass(),  // or UWidgetBlueprintGeneratedClass::StaticClass()
        FName("MyGenerator"));        // calling-context tag; any FName

    // ... build content here ...

    FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
    FKismetEditorUtilities::CompileBlueprint(BP);

    FAssetRegistryModule::AssetCreated(BP);
    Package->MarkPackageDirty();
    const FString Filename = FPackageName::LongPackageNameToFilename(
        Package->GetName(), FPackageName::GetAssetPackageExtension());
    FSavePackageArgs Args;
    Args.TopLevelFlags = RF_Public | RF_Standalone;
    UPackage::SavePackage(Package, BP, *Filename, Args);

    return BP;
}

关键规则(即使跳过操作指南也请阅读)

1. 在 UK2Node_CallFunction 上调用 AllocateDefaultPins 之前,先设置 SetExternalMember
UK2Node_CallFunction* Node = NewObject<UK2Node_CallFunction>(Graph);
Node->FunctionReference.SetExternalMember(
    GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, PrintString),
    UKismetSystemLibrary::StaticClass());
Node->AllocateDefaultPins();   // AFTER. Reverse and the node spawns pinless.

UK2Node_VariableSet/Get 也遵循相同规则:先设置变量引用,再调用 AllocateDefaultPins。

2. MarkBlueprintAsStructurallyModified 与 Modified
  • StructurallyModified:添加或移除任何节点、添加或移除任何变量、引脚拓扑发生任何变化。强制重新生成类布局。
  • Modified:仅调整现有节点或变量的属性(例如更改默认值)。

对于代码生成,几乎总是使用 MarkBlueprintAsStructurallyModified。

3. 函数调用必须接入执行链,否则会被剔除

非纯函数(带有执行引脚)必须接入执行链。如果连接了它们的数据输出,却没有连接执行引脚,BP 编译器就会剔除该调用,数据引脚将读取默认值。表现为警告 "由于未连接其 Exec 引脚,X 已被剔除"。

// WRONG — Compute is non-pure, exec not wired, gets pruned:
EvtThen->MakeLinkTo(SetCounter->GetExecPin());
ComputeRet->MakeLinkTo(CounterValPin);  // reads default, not actual return

// RIGHT — Compute in the chain:
EvtThen->MakeLinkTo(CallCompute->GetExecPin());
CallCompute->GetThenPin()->MakeLinkTo(SetCounter->GetExecPin());
ComputeRet->MakeLinkTo(CounterValPin);
4. 避开 (0,0)——自动生成的默认事件位于此处

基于 AActor 的 BP 和 Widget Blueprint 都会在 (0, 0) 自动生成占位事件(BeginPlay、Tick、ActorBeginOverlap、PreConstruct、Construct)。请将节点放在远处,例如 Y=-300、X=-400。否则,用户打开资源时会看到一团乱麻。

5. 节点引用新建内容时,分两轮编译

如果创建函数 Compute,然后在同一轮中连线引用它的 CallCompute,那么 CallCompute 上的 AllocateDefaultPins 会在 Compute 反映到生成的类之前运行——InValue/ReturnValue 的引脚不会存在,导致 FindPinChecked 触发断言。解决方法:构建函数后先编译,再连接调用。通过 UK2Node_VariableGet 引用 UMG 动画时也一样。请参阅 references/two-pass-compile.md。

UE 5.7 常见问题(完整列表见 caveats.md)

  • PlayAnimationByName 在 5.7 的 UUserWidget 上不存在。 只有 PlayAnimation(UWidgetAnimation*, ...)。请通过 UK2Node_VariableGet 获取动画,而不是使用字符串。
  • 动画 FName 必须与显示标签相同。 UUserWidget::GetAnimationByName 会匹配 GetFName()。两者都要设置:NewObject<UWidgetAnimation>(WBP, FName("SlideIn"), ...),以及 Anim->SetDisplayLabel(TEXT("SlideIn"))。
  • Outer 层级至关重要。 UWidgetAnimation 的外层对象必须是 WBP。UMovieScene 的外层对象必须是动画。外层对象错误 → 动画不会出现在编辑器的 Animations 面板中。
  • 生成的资源引用的所有标签都必须使用 UE_DEFINE_GAMEPLAY_TAG_STATIC。 在生成器函数中运行时调用 UGameplayTagsManager::AddNativeGameplayTag 为时已晚——编辑器 UI 的标签树已经构建完成。请在模块加载时注册。
  • Python 无法访问 UEdGraph / UK2Node_*。 编写事件图的唯一方式是使用 C++。如果需要通过 Python 调用,请将生成器作为 BlueprintCallable UFUNCTION 暴露在 UBlueprintFunctionLibrary 上。
  • FBlueprintEditorUtils::AddFunctionGraph 默认不会生成 Result 节点。 只有 Entry。如果函数有返回值,请使用 FGraphNodeCreator<UK2Node_FunctionResult> 手动创建一个。

FEdGraphPinType 速查表

FEdGraphPinType T;
T.PinCategory = UEdGraphSchema_K2::PC_Boolean;            // bool
T.PinCategory = UEdGraphSchema_K2::PC_Int;                // int32
T.PinCategory = UEdGraphSchema_K2::PC_Real;
T.PinSubCategory = UEdGraphSchema_K2::PC_Float;           // float
T.PinSubCategory = UEdGraphSchema_K2::PC_Double;          // double
T.PinCategory = UEdGraphSchema_K2::PC_String;             // FString
T.PinCategory = UEdGraphSchema_K2::PC_Name;               // FName
T.PinCategory = UEdGraphSchema_K2::PC_Text;               // FText
T.PinCategory = UEdGraphSchema_K2::PC_Object;             // object ref
T.PinSubCategoryObject = AActor::StaticClass();           //   (with target class)
T.ContainerType = EPinContainerType::Array;               // wrap as TArray<>
T.ContainerType = EPinContainerType::Set;                 // TSet<>
T.ContainerType = EPinContainerType::Map;                 // TMap<>  (PinValueType for value)

与以下代码搭配使用:FBlueprintEditorUtils::AddMemberVariable(BP, FName("MyVar"), T, FString(TEXT("DefaultValueAsString")));

工作流检查清单

使用此技能实现生成器时:

  1. 确认编辑器模块及其所需依赖项均已存在(模板见 assets/experiment-module-template/)。
  2. 阅读 references/k2node-cookbook.md,了解适用于相应资源类型的模式。
  3. 对于 Widget 蓝图,还要阅读 references/widget-blueprint-cookbook.md。
  4. 如果连线涉及同一函数中创建的内容,请规划两遍编译结构(references/two-pass-compile.md)。
  5. 在认定新行为是错误之前,先查阅 references/caveats.md,了解已知陷阱。
  6. 测试时,先构建编辑器目标,再打开编辑器、调用 UFUNCTION(通常通过输出日志中的 Python),并目视检查资源。
  7. 反复迭代:如果节点看起来不对(红色错误边框、缺少引脚、“X 个已修剪”警告、数据应流经之处却显示默认值),通常是以下原因之一:缺少执行线、分配顺序错误、缺少两遍编译,或引脚名称错误。

此技能不涵盖的内容

  • 生成资源的烹饪 / 打包——它们是常规 .uasset 文件,和其他资源一样打包发布。
  • 编辑器实用工具控件 / Blutilities——你可以从中调用生成器 UFUNCTION,但设计 EUW 属于单独的 UMG 工作。
  • 运行时 UMG——游戏代码中的 CreateWidget、AddToViewport、动画 PlayAnimation 调用。这不属于代码生成。
  • 自定义 UEdGraph 模式——如果要生成到特定领域的图表(对话、任务、能力树)中,请使用插件自己的编译器入口点。静态编译器类通常不会导出,因此如果链接失败,请调用图表的更新方法(例如 UMyGraph::UpdateAsset()),而不是静态编译器。

评论

支持 Markdown