fix(unreal): 修复生成蓝图的继承组件配置跨机器丢失 - #2353
Open
ZhiruiLi wants to merge 1 commit into
Open
Conversation
Derive generated SCS node GUIDs from the blueprint path and component variable name so inherited component overrides remain valid when generated blueprints are recreated on another machine. Normalize existing nodes on every generation pass before compilation and saving. This makes the migration idempotent and includes the default scene root while avoiding class layout changes during PIE.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题背景
PuerTS 会把组件类型的
uproperty生成为蓝图中的 SCS 节点。开发者可以在继承该生成蓝图的子蓝图里编辑组件属性,UE 会把这些属性覆写保存到子蓝图的UInheritableComponentHandler中。UInheritableComponentHandler使用FComponentKey{OwnerClass, AssociatedGuid}标识继承组件。其中AssociatedGuid来自父蓝图 SCS 节点的VariableGuid。匹配时只比较 GUID,不会在 GUID 不一致时按组件变量名回退匹配。问题在于,
USimpleConstructionScript::CreateNode通过FGuid::NewGuid()随机生成VariableGuid。当 TypeScript 生成蓝图被视为本地产物、没有加入版本管理时,不同用户会分别生成自己的父蓝图,得到不同的 SCS 节点 GUID:UInheritableComponentHandler::ValidateTemplates()会把这条记录判定为不再需要并删除;因此,即使生成蓝图的路径、类名、组件变量名和属性定义完全一致,内部 GUID 不同仍会导致继承组件配置跨机器丢失。
处理方式
1. 为 SCS 节点生成确定性 GUID
新增
MakeStableSCSNodeGuid(),根据以下内容派生 SCS 节点的 GUID:同时包含蓝图对象路径和组件变量名,可以避免不同生成类中存在同名组件时发生冲突。
这里使用 MD5 只是为了获得稳定的 128 位结果,不涉及安全用途。实现中显式按小端顺序把 digest 组装为
FGuid的四个uint32,避免结果依赖主机字节序。没有直接使用
FGuid::NewDeterministicGuid(),因为较旧的 UE 版本没有该接口,PuerTS 需要兼容这些版本。2. 每轮生成时幂等归一已有节点
新增
NormalizeSCSNodeGuids(),在每轮生成时检查并更新已有的 SCS 节点,而不是只在首次创建节点时设置 GUID。这样存量生成资产无需删除重建,只要重新执行一次完整生成,就会自动收敛到确定性 GUID。
处理范围包括:
USimpleConstructionScript::GetAllNodes()返回的全部节点;GetDefaultSceneRootNode(),因为默认根节点只有在实际作为根节点时才会出现在AllNodes中。只有节点 GUID 确实发生变化时才返回 changed 并触发保存;已经完成归一的蓝图不会在后续生成中被重复写盘。
3. 在编译前完成归一
在
UPEBlueprintAsset::Save()中、蓝图编译和保存之前执行归一。这个顺序很重要:继承组件覆写记录的校验发生在蓝图编译阶段。如果在编译之后才修改 GUID,旧记录可能已经被
ValidateTemplates()删除。PIE 期间不执行归一,因为此时 UE 不允许修改类布局;退出 PIE 后的下一轮生成会自动完成收敛。
兼容性与迁移说明
这次修改会让已有生成蓝图的 SCS 节点身份发生一次性变化。已有子蓝图中的覆写记录仍然引用旧的随机 GUID,因此第一次升级时无法自动迁移这些历史记录。
升级后建议执行:
完成这次迁移后,各机器会生成相同的 GUID,后续重新生成或跨机器同步都不会再导致覆写记录失效。
组件变量改名会改变派生 GUID,因此改名后同样需要一次性重新填写对应覆写。这与把“蓝图路径 + 组件变量名”作为组件稳定身份的设计一致。
验证情况
已在一个“TypeScript 生成蓝图不加入版本管理、子蓝图加入版本管理”的 UE/PuerTS 项目中完成验证:
PuertsEditor模块编译成功;*_GEN_VARIABLE组件都包含预期的确定性 GUID,没有遗漏节点;UInheritableComponentHandler的键与父蓝图 SCS 节点的确定性 GUID 一致;invalid或unnecessary而删除的记录。改动范围
本 PR 只修改一个 Unreal Editor 实现文件,没有新增或修改公共 API: