#serialization #bevy #serde #save #entity-component #serializer-deserializer

bevy_serde_project

bevy引擎的具有状态、结构化和可读性的序列化包

17次发布

0.3.2 2024年4月21日
0.3.1 2024年4月18日
0.2.3 2024年4月15日
0.1.11 2024年4月2日
0.1.6 2024年3月18日

#852 in 编码

Download history 42/week @ 2024-04-22 8/week @ 2024-04-29 1/week @ 2024-05-20 57/week @ 2024-07-29

每月下载量57次
用于 bevy_stat_query

MIT/Apache

96KB
2K SLoC

bevy_serde_project

Crates.io Docs Bevy tracking

bevy引擎的具有状态、结构化和可读性的序列化包。

功能

  • 具有世界访问权限的状态序列化和反序列化。
  • Entity、其 Component 和子项视为单个 serde 对象。
  • 序列化 Handle并提供通用数据合并接口。
  • 像智能指针一样序列化存储的 Entity
  • 将 trait 对象(如 Box<dyn T>)反序列化为序列化,作为 typetag 的替代方案。
  • 极其轻量级且模块化。无系统,无插件。
  • 支持几乎所有 serde 格式*

* 人体工程学可能取决于 SerializerDeserializerDeserializeSeed 特性支持

入门

序列化具有一些组件和子项的 Entity 角色,假设所有组件都是 SerializeDeserializeOwned

bind_object!(Character as "Character" {
    #[serde(flatten)]
    character: Character,
    position: Position,
    #[serde(default, skip_serializing_if="Option::is_none")]
    weapon: Maybe<Weapon>,
    shield: Maybe<Shield>,
    #[serde(default, skip_serializing_if="Vec::is_empty")]
    potions: ChildVec<Potion>,
})

然后调用 saveWorld 上,其中 serializer 是类似 serde_json::Serializer 的东西。

// Save
world.save::<Character>(serializer)
// Load
world.load::<Character>(deserializer)
// Delete
world.despawn_bound_objects::<Character>()

这将保存角色列表作为数组

[
    { .. },
    { .. },
    ..
]

要批量保存多种类型的对象,使用 batch! 宏创建批量序列化类型。

type SaveFile = batch!(
    Character, Monster, Terrain,
    // Use `BindResource` to serialize a resource.
    BindResource<MyResource>,
);
world.save::<SaveFile>(serializer)
world.load::<SaveFile>(serializer)
world.despawn_bound_objects::<SaveFile>()

这将按映射条目保存每个类型

{
    "Character": [ 
        { .. },
        { .. },
        ..
    ],
    "Monster": [ .. ],
    "Terrain": [ .. ],
    "MyResource": ..
}

常见问题解答

  • 如果我的类型不是 SerializeDeserializeOwned 呢?

我们可以使用 SerdeProject 派生或实现以将它们转换为 serde 类型。

  • 我不拥有该类型

使用 ConvertSerdeProject 宏将类型转换为所有权的 newtype。

  • 我有一个 ID 并且我想序列化其内容

SerdeProject 允许你在序列化过程中从世界中获取资源。

  • 我有一个 Box<dyn T>

如果你在一个非Wasm平台上,你可以尝试 typetag 包。如果不是,或者你想要更多控制,请查看此包中的 typetagged 模块。

特性和它们的作用

  • SerializeDeserializeOwned

任何 SerializeDeserializeOwned 类型都自动是 SerdeProject,而任何这样的 Component 都自动是 BevyObject

这的缺点是我们不能由于孤儿规则而在任何外部类型上实现 SerdeProject。这就是 ConvertSerdeProject 宏发挥作用的地方。

  • SerdeProject

SerdeProject 将非serde类型投影到具有世界访问权限的serde类型。

SerdeProject 宏在所有字段都实现 SerdeProject 或通过 Convert 特征转换为 SerdeProject 新类型的类型上实现了 SerdeProject

示例

Handle 序列化为它的路径,存储在 AssetServer 中。

#[derive(SerdeProject)]
struct MySprite {
    // implements serde, therefore is `SerdeProject`.
    pub name: String,
    // Calls `Convert` and `PathHandle<Image>` is `SerdeProject`.
    #[serde_project("PathHandle<Image>")]
    pub handle: Handle<Image>
}
  • Convert

Convert 允许你将不可序列化的类型 RefCast 为实现 SerdeProject 的新类型。

例如,PathHandle<Handle<T>>Handle 序列化为 String,而 UniqueHandle<Handle<T>>Handle 序列化为 T。这种零成本的转换可以通过 ref_cast 包来完成。

  • BevyObject

BevyObject 允许将 Entity 序列化。这可以是只是一个组件,或者组件的组合,子组件,子组件上的组件等。

所有 SerdeProject 组件都是 BevyObject

  • BindBevyObject

BindBevyObject 是一个 QueryFilter,通常是一个键组件,它确定序列化和反序列化的入口点。

任何具有 QueryFilter 但不满足绑定 BevyObject 布局的实体将导致错误。

使用 bind_object! 宏创建序列化条目。

  • Named

为资源提供序列化名称。

  • SaveLoad

表示批序列化类型,或单个保存文件的内容。

TypeTag

typetag 包允许你序列化像 Box<dyn T> 这样的特质对象,但使用 typetag 总是会拉入与你的构建相关联的所有实现,并且不适用于WASM。为了解决这些限制,此包允许你在bevy World 中手动注册反序列化器,并使用 TypeTagged 新类型进行序列化。

world.register_typetag::<Box<dyn Animal>, Cat>()

然后

#[derive(SerdeProject)]
struct MyComponent {
    #[serde_project("TypeTagged<Box<dyn Weapon>>")]
    weapon: Box<dyn Weapon>
}

为了拥有用户友好的配置文件,您可以使用 register_deserialize_anyAnyTagged 允许 deserialize_any,即使用 42 而不是在自描述格式中使用 {"int": 42}。请注意,在非自描述格式(如 postcard)中使用 AnyTagged 总会返回错误,因为这是 serde 规范的限制。

world.register_deserialize_any(|s: &str| 
    Ok(Box::new(s.parse::<Cat>()
        .map_err(|e| e.to_string())?
    ) as Box<dyn Animal>)
)

版本

bevy bevy-serde-project
0.13 最新版

许可证

许可协议为以下之一

由您选择。

贡献

除非您明确说明,否则任何有意提交以包含在您的工作中的贡献(根据 Apache-2.0 许可证定义),均应如上双许可,无需附加条款或条件。

依赖项

~18–53MB
~866K SLoC