You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UE4修改引擎函数时AddOnScreenDebugMessage失效问题求助

FMapProperty::ImportText_Internal 屏幕调试消息无输出的解决方法

问题背景

研究FMapProperty::ImportText_Internal运行机制时,在函数内添加GEngine->AddOnScreenDebugMessage后无屏幕输出,已确认GEngine可正常访问,其他引擎源码调试也遇此问题。

示例代码:

const TCHAR* FMapProperty::ImportText_Internal(const TCHAR* Buffer, void* Data, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText) const
{
    //Not working
    if (GEngine)
        GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, TEXT("Some debug message!"));

    checkSlow(KeyProp);
    checkSlow(ValueProp);

    FScriptMapHelper MapHelper(this, Data);
    MapHelper.EmptyValues();

    // If we export an empty array we export an empty string, so ensure that if we're passed an empty string
    // we interpret it as an empty array.
    if (*Buffer++ != TCHAR('('))
    {
        return nullptr;
    } 

    SkipWhitespace(Buffer);
    if (*Buffer == TCHAR(')'))
    {
        return Buffer + 1;
    }

    uint8* TempPairStorage   = (uint8*)FMemory::Malloc(MapLayout.ValueOffset + ValueProp->ElementSize);

    bool bSuccess = false;
    ON_SCOPE_EXIT
    {
        FMemory::Free(TempPairStorage);

        // If we are returning because of an error, remove any already-added elements from the map before returning
        // to ensure we're not left with a partial state.
        if (!bSuccess)
        {
            MapHelper.EmptyValues();
        }
    };

    for (;;)
    {
        KeyProp->InitializeValue(TempPairStorage);
        ValueProp->InitializeValue(TempPairStorage + MapLayout.ValueOffset);
        ON_SCOPE_EXIT
        {
            ValueProp->DestroyValue(TempPairStorage + MapLayout.ValueOffset);
            KeyProp->DestroyValue(TempPairStorage);
        };

        if (*Buffer++ != TCHAR('('))
        {
            return nullptr;
        }

        // Parse the key
        SkipWhitespace(Buffer);
        Buffer = KeyProp->ImportText(Buffer, TempPairStorage, PortFlags | PPF_Delimited, Parent, ErrorText);
        if (!Buffer)
        {
            return nullptr;
        }

        // Skip this element if it's already in the map
        bool bSkip = MapHelper.FindMapIndexWithKey(TempPairStorage) != INDEX_NONE;

        SkipWhitespace(Buffer);
        if (*Buffer++ != TCHAR(','))
        {
            return nullptr;
        }

        // Parse the value
        SkipWhitespace(Buffer);
        Buffer = ValueProp->ImportText(Buffer, TempPairStorage + MapLayout.ValueOffset, PortFlags | PPF_Delimited, Parent, ErrorText);
        if (!Buffer)
        {
            return nullptr;
        }

        SkipWhitespace(Buffer);
        if (*Buffer++ != TCHAR(')'))
        {
            return nullptr;
        }

        if (!bSkip)
        {
            int32  Index   = MapHelper.AddDefaultValue_Invalid_NeedsRehash();
            uint8* PairPtr = MapHelper.GetPairPtrWithoutCheck(Index);

            // Copy over imported key and value from temporary storage
            KeyProp  ->CopyCompleteValue_InContainer(PairPtr, TempPairStorage);
            ValueProp->CopyCompleteValue_InContainer(PairPtr, TempPairStorage);
        }

        SkipWhitespace(Buffer);
        switch (*Buffer++)
        {
            case TCHAR(')'):
                MapHelper.Rehash();
                bSuccess = true;
                return Buffer;

            case TCHAR(','):
                SkipWhitespace(Buffer);
                break;

            default:
                return nullptr;
        }
    }
}

问题原因

FMapProperty::ImportText_Internal属于序列化/反序列化核心函数,通常在以下场景执行:

  • 编辑器加载蓝图、资产时的后台序列化
  • 数据导入/导出流程
  • 蓝图编译阶段的静态数据处理

这些场景下:

  1. 函数可能运行在后台线程,而AddOnScreenDebugMessage依赖主线程的渲染帧循环才能输出到屏幕
  2. 执行时机早于游戏窗口/渲染上下文初始化,屏幕渲染管线未就绪,无法显示调试消息

替代调试方案

1. 使用UE日志系统(最可靠)

替换屏幕消息为日志输出,支持所有线程,可在编辑器输出日志或本地日志文件查看:

UE_LOG(LogTemp, Warning, TEXT("FMapProperty::ImportText_Internal 触发,Buffer起始内容:%s"), Buffer);

查看路径:编辑器顶部菜单栏 Window > Developer Tools > Output Log,或项目目录下 Saved/Logs/ 文件夹。

2. 断点调试

直接在函数开头设置断点,调试时检查:

  • 函数是否真的被调用
  • Buffer、PortFlags等参数值是否符合预期
  • 函数是否提前返回(比如开头的括号检查失败)

3. 编辑器通知(编辑器场景可见)

如果需要在编辑器界面得到反馈,使用编辑器通知API:

if (GEditor)
{
    FNotificationInfo NotifyInfo(FText::FromString("FMapProperty::ImportText_Internal 已执行"));
    NotifyInfo.ExpireDuration = 5.0f; // 显示5秒
    NotifyInfo.bUseLargeFont = false;
    GEditor->AddNotification(NotifyInfo);
}

额外验证步骤

  • 确认函数执行:在函数开头添加check(0),若触发编辑器崩溃,说明函数确实被调用;若无崩溃,说明当前流程未走到该函数
  • 检查PortFlags:某些标志(如PPF_Silent)会抑制输出或改变执行逻辑,可打印PortFlags值确认

内容的提问来源于stack exchange,提问作者The Darkest Edge Lord

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 20:07:02