Skip to content

fix(unreal): guard TS blueprint gen against missing GeneratedClass - #2355

Open
ZhiruiLi wants to merge 1 commit into
Tencent:masterfrom
ZhiruiLi:fix/unreal-ts-blueprint-null-generated-class
Open

fix(unreal): guard TS blueprint gen against missing GeneratedClass#2355
ZhiruiLi wants to merge 1 commit into
Tencent:masterfrom
ZhiruiLi:fix/unreal-ts-blueprint-null-generated-class

Conversation

@ZhiruiLi

@ZhiruiLi ZhiruiLi commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

修复编辑器在生成 TypeScript 蓝图时,因 GeneratedClass 为空而在 UPEBlueprintAsset::AddFunction 中空指针崩溃的问题。

当磁盘上已有陈旧的 TS 蓝图资产,且其记录的父类已无法加载时,LoadOrCreate 仍会“成功”返回,随后 CodeAnalyze 继续调用 AddFunctionWithMetaData,最终在 GeneratedClass->GetSuperClass() 处以访问违例崩溃(读地址形如 0x38,对应 UStruct::SuperStruct 偏移)。

问题描述

CodeAnalyze 在编辑器启动或 TypeScript 源码变更时,会为继承 UE Native 类型的 TS 类生成/更新蓝图资产,流程大致为:

  1. LoadOrCreateWithMetaData(...)
  2. 遍历方法/属性,调用 AddFunctionWithMetaData / AddMemberVariableWithMetaData
  3. Save() → 编译并写回 .uasset

典型复现链:

  1. 开始为某个 TS 类生成蓝图
  2. Linker 报错:旧 .uasset 记录的父类加载失败,TypeScriptGeneratedClass 与其父类 “both will fail to load”
  3. 默认对象也无法加载,因为 generated class 不存在
  4. 紧接着崩溃:
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000038
UClass::GetSuperClass()
UPEBlueprintAsset::AddFunction()
UPEBlueprintAsset::execAddFunctionWithMetaData()

根因不是随机内存破坏,而是空指针未保护:

  1. .uasset 记录的父类(例如已被删除或重命名的 Native 类)加载失败
  2. Blueprint 可能半载成功,但 GeneratedClass 为空
  3. 旧版 LoadOrCreatereturn true
  4. JS 侧忽略返回值,继续调用 AddFunctionWithMetaData
  5. GeneratedClass->GetSuperClass() 对空指针解引用并崩溃

同一文件中,Save / RemoveNotExisted* 已有空指针判断,而 AddFunction / AddMemberVariable / SetupAttachment* 等生成路径缺少入口防护。

此外,即便勉强避免崩溃,用户把 TS 基类改到一个仍然有效的父类后,也会被坏掉的旧资产卡住,无法自动恢复。

解决方案

1. C++:UPEBlueprintAsset 入口防护

  • 新增 IsAssetReady():在 Blueprint / GeneratedClass 无效时打错误日志并早退
  • AddFunction / AddFunctionWithMetaData / AddMemberVariable* / SetupAttachments 等调用点统一检查
  • AddFunction 中对 SuperClass 做空判断
  • CanChangeCheck* 宏改用 GetNameSafe(GeneratedClass),避免保护逻辑自身二次崩溃

2. C++:LoadOrCreate 正确处理坏资产

  • GeneratedClass 无效时不再假装成功
  • 若调用方已提供有效的新 ParentClass(TS 已换到仍然可加载的基类):
    • 从 AssetRegistry 注销旧资产
    • 将坏对象 Rename 到 Transient,移出原 Package
    • 删除磁盘 .uasset
    • 落到创建路径,用新父类重建
  • 若没有可用父类,或处于 PIE:明确失败返回,而不是带着空 GeneratedClass 继续

这样既避免编辑器崩溃,也保留“修改 TS 基类即可恢复”的工作流,无需手动删除坏资产。

3. C++:Save() 编译后刷新缓存

CompileBlueprint 可能 reinstance 类,旧 UClass 会被标记为无效。
编译后重新从 Blueprint->GeneratedClass 刷新缓存指针,避免把失效类继续当作派生 TS 类的父类往下传。

4. JS/TS:CodeAnalyze 检查返回值

  • getUClassOfTypeLoadOrCreate 失败或 GeneratedClass 为空时跳过,不再把它当作基类使用
  • onBlueprintTypeAddOrChangeLoadOrCreateWithMetaData 失败时直接 return,不再继续 AddFunction

同步修改了源码与运行时产物:

  • PuertsEditor/CodeAnalyze.ts
  • Content/JavaScript/PuertsEditor/CodeAnalyze.js

修改文件

  • unreal/Puerts/Source/PuertsEditor/Public/PEBlueprintAsset.h
  • unreal/Puerts/Source/PuertsEditor/Private/PEBlueprintAsset.cpp
  • unreal/Puerts/PuertsEditor/CodeAnalyze.ts
  • unreal/Puerts/Content/JavaScript/PuertsEditor/CodeAnalyze.js

兼容性说明

  • MarkAsGarbage / MarkPendingKill 按 UE5 / UE4 分支处理
  • 未引入业务项目特有逻辑

LoadOrCreate used to succeed when a stale .uasset lost its parent class,
leaving GeneratedClass null; CodeAnalyze then called AddFunction and crashed
the editor. Bail out safely, recreate under a live TS parent when possible,
and check LoadOrCreate return values on the JS side.
@ZhiruiLi
ZhiruiLi force-pushed the fix/unreal-ts-blueprint-null-generated-class branch from 22832a5 to baa27bc Compare August 5, 2026 10:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant