Files
XCEngine/docs/api/XCEngine/Components/ComponentFactoryRegistry/ComponentFactoryRegistry.md

3.9 KiB
Raw Blame History

ComponentFactoryRegistry

命名空间: XCEngine::Components

类型: class

头文件: XCEngine/Components/ComponentFactoryRegistry.h

描述: 维护“组件类型名 -> 创建函数”的全局注册表,供场景反序列化按类型名恢复组件实例。

角色概述

ComponentFactoryRegistryComponents 模块和场景文本反序列化之间的桥梁。

Scene::DeserializeFromString 读到类似下面的记录时:

component=Camera;projection=0;fov=60;...

它需要先回答一个问题: "Camera" 应该创建成什么 C++ 类型?

当前答案就是交给 ComponentFactoryRegistry。它保存组件类型名与工厂函数的映射,并按需调用 GameObject::AddComponent<T>() 创建实例。

当前实现行为

1. 这是一个单例式全局注册表

  • 使用 Get 获取全局唯一实例
  • 构造函数里完成内建组件的预注册
  • 存储结构是 unordered_map<string, CreateComponentFn> 加一个注册顺序数组

2. 当前预注册组件

engine/src/Components/ComponentFactoryRegistry.cpp 当前实现,默认注册了:

  • Camera
  • Light
  • AudioSource
  • AudioListener
  • MeshFilter
  • MeshRenderer
  • ScriptComponent

Transform 没有注册,这不是遗漏,而是当前设计决定:TransformComponentGameObject 构造时内建创建,不通过工厂补建。

3. 工厂真正做的事情

内建工厂函数最终调用的是:

gameObject->AddComponent<T>()

所以它继承了 GameObject::AddComponent<T>() 的所有现实语义,包括:

  • 只负责创建并挂接组件
  • 不会自动补发 Awake()Start()OnEnable()

这一点对理解场景加载后的生命周期非常关键。

注册顺序语义

RegisterFactory() 当前使用 insert_or_assign

  • 新类型会加入 m_registrationOrder
  • 已存在类型会被替换工厂函数
  • 替换已有类型时不会重复追加到顺序数组

因此 GetRegisteredTypes 返回的是“首次注册顺序”,不是 map key 的排序结果。

与 Scene 反序列化的关系

当前 Scene::DeserializeFromString() 的流程大致是:

  1. 创建 GameObject
  2. 读出 transform payload恢复内建 Transform
  3. 对每条 component=<type>;payload 记录调用 ComponentFactoryRegistry::CreateComponent()
  4. 让新组件执行各自的 Deserialize()
  5. 最后再恢复父子关系

这条链路解释了两个常见现象:

  • 只有已注册组件类型才能从场景文本成功还原
  • 反序列化路径并不会自动把组件送入完整运行时生命周期

线程语义

  • 当前实现没有加锁。
  • 注册和查询都应视为非线程安全操作。
  • 典型使用方式是在初始化阶段完成注册,在场景加载阶段只读查询。

当前实现限制

  • 只支持基于字符串类型名的简单工厂映射,没有版本迁移、字段升级或 schema 管理层。
  • 反序列化后不会自动补发 Awake()/Start()
  • 没有发现针对自定义组件热注册冲突、卸载或线程安全的额外保护。

推荐使用方式

  1. 内建组件依赖默认注册即可。
  2. 自定义组件如果要参与场景反序列化,必须在加载前完成注册。
  3. 不要把它当成完整反射系统;它只是“名字到构造函数”的桥接层。

相关方法

相关指南

相关文档