为什么Editor类型模块中导出的蓝图接口在蓝图编辑器中无法使用—及代码位于引擎不同文件夹的意义

摘要:
对于编辑器实现,它如何使蓝图可调用接口在不同的编辑器中可见。因为UBlueprint本身位于引擎的运行时文件夹中,如果函数是编辑器类型,则在运行时蓝图编辑器中无法看到它。
一、问题

在UE中添加一些简单的蓝图接口,然后在蓝图编辑器中始终无法找到对应节点,无论是否勾选"Context Sensitive"。因为实现代码非常简单,简单到没有出错的可能,所以就觉得很神奇。好在尽管有很多乱七八糟的干扰信息,但是网上还是有答案https://forums.unrealengine.com/t/c-blueprint-function-not-showing-up-in-blueprint-editor/46359/8。对于编辑器实现来说,它是怎么做到一个蓝图可调用接口(BlueprintCallable)在不同的编辑器中可见的。这里讨论的问题不在于找到解决这个问题的方法,而是在茫茫UE代码中找到它对应代码的具体实现位置。

二、一个模块是Editor/Runtime对生成代码的影响

在.uplugin文件中对模块的描述中会声明文件是Editor类型还是Runtime类型,这些标志位将会对UHT生成的文件产生影响:通过对比不同配置下UHT生成的Package文件可以发现:如果一个模块配置的类型是Editor,则为该模块生成的Package描述中设置了在PKG_EditorOnly标志位,也就是说一个模块是否是EditorOnly在运行时可以判断的(而不仅仅是构建时)。
我们以UnLua代码的UnLuaEditor模块为例,该模块配置的类型为Editor,在该模块对应的包(Package)描述文件UnLuaIntermediateBuildWin64UE4EditorIncUnLuaEditorUnLuaEditor.init.gen.cpp中可以看到:
void EmptyLinkFunctionForGeneratedCodeUnLuaEditor_init() {}
UPackage* Z_Construct_UPackage__Script_UnLuaEditor()
{
static UPackage* ReturnPackage = nullptr;
if (!ReturnPackage)
{
static const UE4CodeGen_Private::FPackageParams PackageParams = {
"/Script/UnLuaEditor",
nullptr,
0,
PKG_CompiledIn | 0x00000040,
0xB9DBA038,
0x096E84BD,
METADATA_PARAMS(nullptr, 0)
};
UE4CodeGen_Private::ConstructUPackage(ReturnPackage, PackageParams);
}
return ReturnPackage;
}
注意其中的
PKG_CompiledIn | 0x00000040,
标志位,其中的0x00000040对应的标志标识这是一个只在编辑器中使用的模块
PKG_EditorOnly = 0x00000040, ///< This is editor-only package (for example: editor module script package)

三、EngineSource文件夹下模块的类型是什么

细心的同学会发现:引擎内部源代码并没有一个地方描述根文件夹下模块的类型,那么它们的类型是如何确定的?
在UnrealBuildToolSystemRulesCompiler.cs:UnrealBuildTool.RulesCompiler.CreateEngineOrEnterpriseRulesAssembly函数中可以看到,其中对于引擎内部代码的分类是通过所在文件来区分:在Runtime文件夹下的模块都是Runtime类型,Editor文件夹下的是Editor类型
private static RulesAssembly CreateEngineOrEnterpriseRulesAssembly(RulesScope Scope, List<DirectoryReference> RootDirectories, string AssemblyPrefix, IReadOnlyList<PluginInfo> Plugins, bool bReadOnly, bool bSkipCompile, RulesAssembly Parent)
{
……
AddEngineModuleRulesWithContext(SourceDirectory, "Runtime", DefaultModuleContext, UHTModuleType.EngineRuntime, ModuleFileToContext);
AddEngineModuleRulesWithContext(SourceDirectory, "Developer", DefaultModuleContext, UHTModuleType.EngineDeveloper, ModuleFileToContext);
AddEngineModuleRulesWithContext(SourceDirectory, "Editor", DefaultModuleContext, UHTModuleType.EngineEditor, ModuleFileToContext);
AddEngineModuleRulesWithContext(SourceDirectory, "ThirdParty", DefaultModuleContext, UHTModuleType.EngineThirdParty, ModuleFileToContext);
……
}

四、蓝图编辑器如何判断哪些接口可以在编辑器中使用

经过各种猜测、调试、验证,确定判断一个接口是否可以在一个蓝图中使用的接口通过BlueprintActionFilterImpl::IsHiddenInNonEditorBlueprint函数来判断。这里判断调用接口是否是编辑器特有模块还是比较直观的。流程是先判断一个接口是不是一个编辑器特有接口(函数),如果是的话判断当前编辑的蓝图对象的父类(Blueprint->ParentClass,通常是Native C++类)是在哪个模块,如果不是Editor模块(IsEditorOnlyObject函数完成判断)则不显示。由于UBlueprint本身在引擎的Runtime文件夹,所以如果一个Function是Editor类型的,它是没办法在运行时蓝图编辑器中可见的。
static bool BlueprintActionFilterImpl::IsHiddenInNonEditorBlueprint(FBlueprintActionFilter const& Filter, FBlueprintActionInfo& BlueprintAction)
{
const UFunction* Function = BlueprintAction.GetAssociatedFunction();
bool bVisible = true;
if (Function)
{
const bool bIsEditorOnlyFunction = IsEditorOnlyObject(Function) || Function->HasAnyFunctionFlags(FUNC_EditorOnly);
const bool bIsUncookedOnlyFunction = Function->GetOutermost()->HasAnyPackageFlags(PKG_UncookedOnly);
if (bIsEditorOnlyFunction)
{
for (const UBlueprint* Blueprint : Filter.Context.Blueprints)
{
const UClass* BlueprintClass = Blueprint->ParentClass;
const bool bIsEditorBlueprintClass = (BlueprintClass != nullptr) && IsEditorOnlyObject(BlueprintClass);
bVisible &= bIsEditorBlueprintClass;
}
}
if (bIsUncookedOnlyFunction)
{
for (const UBlueprint* Blueprint : Filter.Context.Blueprints)
{
const UClass* BlueprintClass = Blueprint->ParentClass;
const bool bIsEditorBlueprintClass = (BlueprintClass != nullptr) && IsEditorOnlyObject(BlueprintClass);
const bool bIsUncookedBlueprintClass = (BlueprintClass != nullptr) && BlueprintClass->GetOutermost()->HasAnyPackageFlags(PKG_UncookedOnly);
bVisible &= (bIsEditorBlueprintClass || bIsUncookedBlueprintClass);
}
}
}
return !bVisible;
}

免责声明:文章转载自《为什么Editor类型模块中导出的蓝图接口在蓝图编辑器中无法使用—及代码位于引擎不同文件夹的意义》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇apt-get损坏修复Centos7 设置、查看、添加、删除服务的开机启动项下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【网络开发】组播各种参数的设置及其意义

D类IP地址(224.0.0.0到239.255.255.255)不识别互联网内的单个接口,但识别接口组,被称为多播组。 单个网络上的组成员利用IGMP协议在系统之间通信。多播路由器用多播选录协议,如DVMRP(distance vector multicast  routing protocol,距离向量多播路由选择协议)传播成员信息。 在N...

VSCode常用命令快捷键

目录 主命令框 常用快捷键 编辑器与窗口管理 代码编辑 格式调整 光标相关 重构代码 查找替换 显示相关 其他 修改默认快捷键 主命令框 F1 或 Ctrl+Shift+P : 打开命令面板。在打开的输入框内,可以输入任何命令,例如: 按一下 Backspace 会进入到 Ctrl+P 模式 在 Ctrl+P 下输入 > 可以进...

Winforms开发技巧大揭秘,DevExpress查找编辑器自动搜索模式

下载DevExpress v19.2完整版  DevExpress Winforms Controls 内置140多个UI控件和库,完美构建流畅、美观且易于使用的应用程序。在前面的教程文章中,技术团队宣传了针对DevExpress LookUpEdit和GridLookUpEdit控件新的AutoSuggest模式。 简而言之,AutoSuggest允许编...

vue-json-editor json编辑器

一、概述 现有一个vue项目,需要一个json编辑器,能够格式化json数据,同时也支持编辑功能。 vue-json-editor 插件就可以实现这个功能 二、vue-json-editor使用 安装插件 npm install vue-json-editor --save 使用 test.vue <template> <div s...

解读支付宝接口实现步骤

大家想必都有这种困惑——拿到支付宝的接口代码后,尽管里面的程序有注释,接口代码包中也附有开发说明,但还是不知道该如何入手。这不难想象是什么原因,因为自己并不了解这个接口的工作原理是什么?那么这篇文章就是要向大家全面展示关于支付宝接口的所有东西,以便大家能快速上手把接口接入自己的项目中,也能帮助那些已经对支付宝接口有所了解的程序开发者们更了解支付宝的一些通用...

HSF处理流程分析

一.HSF的基本概念 HSF全称为High-Speed Service Framework,旨在为淘系的应用提供一个分布式的服务框架,HSF从分布式应用层面以及统一的发布/调用方式层面为大家提供支持,从而可以很容易的开发分布式的应用以及提供或使用公用功能模块,而不用考虑分布式领域中的各种细节技术,例如远程通讯、性能损耗、调用的透明化、同步/异步调用方式的实...