🔁 使用 Bevy 反射序列化组件
2025-06-05
(反/)序列化 Entity 的所有 Component
#[cfg(test)]
mod test {
fn test_reflect() {
todo!();
}
}
获得 Entity 的 Component 信息
#[cfg(test)]
mod test {
#[derive(Reflect, Component)]
struct Foo {
a: f32
b: i32
}
fn test_reflect() {
let mut app = App::new();
app.register_type::<Foo>();
let world = app.world_mut();
let registry_arc: TypeRegistryArc = world.resource::<AppTypeRegistry>().0.clone();
let registry = registry_arc.read();
todo!();
}
}
-
AppTypeRegistry # 0 是一个原子引用计数,所以我们可以克隆它来避免占用世界的所有权
我们声明一个 App 是为了后续 Component 的测试。如果只想测试反射,不需要用到 World ,也可以使用构造函数实例化一个 TypeRegistry 。如: - let registry = TypeRegistry::new();
// test_reflect()
let id = world.spawn(Foo { a: 0, b: 0 });
if world.entities().contains(id) { // 检查实体存在
for component_info in world.inspect_entity(id) {
todo!();
}
}
序列化反射
// 在 for loop 中
let component_reflect: &dyn Reflect = world.get_reflect(id, component_info.type_id().unwrap()).unwrap();
let serialzier =
ReflectSerializer::new(component_reflect.as_partial_reflect(), ®istry);
let str = toml::to_string_pretty(&serialzier).unwrap();
println!("{}", &str); // Debug
-
ReflectSerializer 反射内容的序列化器,可以被各类基于 serde 的序列化方法序列化 -
在 toml 中,反射的 Foo 的序列化的结果是一个 toml::Table 里包含了一个键值,其键是 Foo 的类型路径,值还是一个 Table ,包含了 Foo 的字段。
反序列化反射
// 这是 toml 格式的 Table
let table = toml::from_str::<toml::Table>(&str).unwrap();
let key = table.iter().last().unzip().0.unwrap().clone();
// 重要的地方!
let reflect_deserializer = ReflectDeserializer::new(®istry);
let partial_reflect: Box<dyn PartialReflect> =
reflect_deserializer.deserialize(table).unwrap();
assert!(partial_reflect.represents::<Foo>()); // 检查部分反射代表的是否是类型 Foo
-
key :这里获得的 key 是 Foo 的完整类型路径。后面插入 Component 时会用到。 -
ReflectDeserializer :反序列化器,其 # deserialize 方法来自对 serde 的 DeserializeSeed trait 实现,如果 rust analyzer 无法找到 # deserialize 方法,需要手动 use DeserializeSeed .
插入反射组件到实体中
let type_registration: &TypeRegistration = registry.get_with_type_path(&key).unwrap();
let type_id: TypeId = TypeRegistration::type_id(type_registration);
-
type_registration :我们使用上面得到的类型路径(key)获取类型的注册信息,为了获取类型的 TypeId -
type_id :通过 TypeRegistration # type_id 来获取注册类型的 TypeId,这里使用显式的方法调用是为了与标准库原有的 Any # type_id 函数区分。
#[derive(Reflect, Component)]
#[reflect(Component, from_reflect = true)] // new!
struct Foo {
a: f32,
b: i32,
}
if let Some(reflect_component) =
registry.get_type_data::<ReflectComponent>(type_id) // -> Option<&ReflectComponent>
{
info!("Successfully insert reflect component!");
reflect_component.insert(
&mut world.entity_mut(id),
partial_reflect.as_ref(),
®istry,
);
}
type_registration.data::<ReflectComponent>(); // -> Option<&ReflectComponent>
运行时检查类型是否实现了某个 trait
#[derive(Reflect, Component)]
#[reflect(FooTrait, Component, from_reflect = true)] // new!
struct Foo {
a: f32,
b: i32,
}
#[reflect_trait] // new!
trait FooTrait {}
impl FooTrait for Foo {}
- reflect_trait
宏会自动生成 trait 的数据,既 Reflect{trait_ident} 结构体。
let is_impl_foo_trait =
type_registration.data::<ReflectFooTrait>().is_some();
// or
registry.get_type_data::<ReflectComponent>(type_id).is_some();