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属于序列化/反序列化核心函数,通常在以下场景执行:
- 编辑器加载蓝图、资产时的后台序列化
- 数据导入/导出流程
- 蓝图编译阶段的静态数据处理
这些场景下:
- 函数可能运行在后台线程,而
AddOnScreenDebugMessage依赖主线程的渲染帧循环才能输出到屏幕 - 执行时机早于游戏窗口/渲染上下文初始化,屏幕渲染管线未就绪,无法显示调试消息
替代调试方案
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
相关产品推荐
相关产品推荐

