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

    一、问题

    在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;
    }

  • 相关阅读:
    kali Linux的 安装详细步骤
    kali linux与虚拟机Vmware安装vmware tools(主机与虚拟机的文件拖拽)
    利用locust进行压测,检验一下之前搭建的性能监控平台
    记一个比较有趣的缺陷
    使用soupUI模拟(mock)webservice接口
    python操作postgresql数据库
    python接口自动化(二)——封装需要用到的工具类
    Airtest之web自动化(二)——在本地环境运行airtest脚本
    python接口自动化()一)(设计一款自己的接口自动化框架)
    让http服务人类(python之requests做接口测试)
  • 原文地址:https://www.cnblogs.com/tsecer/p/15120587.html
Copyright © 2011-2022 走看看