Crate bevy_serde_lens

Source
Expand description

§bevy_serde_lens

Crates.io Docs Bevy tracking

Blazingly fast, stateful, structural and human-readable serialization crate for the bevy engine.

§Features

  • Stateful serialization and deserialization with world access.
  • No systems, no plugins.
  • Blazingly fast (compared to DynamicScene).
  • Treat an Entity, its Components and children as a single serde object.
  • Deserialize trait objects like Box<dyn T>, as an alternative to typetag.
  • Supports every serde format using familiar syntax.
  • Serialize Handles and provide a generalized data interning interface.
  • No reflection needed.

§Getting Started

Imagine we have a typical Character bundle.

First we derive BevyObject:

#[derive(Bundle, BevyObject)]
#[bevy_object(query)]
pub struct Character {
    pub transform: Transform,
    pub name: Name,
    pub position: Position,
    pub hp: Hp,
}
  • #[bevy_object(query)]

This indicates we are serializing a query instead of a hierarchical tree, which improves performance.

To serialize we simply do:

serde_json::to_string(&world.serialize_lens::<Character>());

This finds all entities that fits the QueryFilter of the bundle and serializes them in an array.

To deserialize we use deserialize_scope:

world.deserialize_scope(|| {
    // Returned object doesn't matter, data is stored in the world.
    let _ = serde_json::from_str::<InWorld<Character>>(&json_string);
})

This statement spawns new entities in the world and fills them with deserialized data.

You might want to delete current entities before loading new ones, to delete all associated entities of a serialization:

// Despawn all character.
world.despawn_bound_objects::<Character>()

To save multiple types of objects in a batch, create a batch serialization type with the batch! macro.

type SaveFile = batch!(
    Character, Monster,
    // Use `SerializeResource` to serialize a resource.
    SerializeResource<Terrain>,
);
world.serialize_lens::<SaveFile>()
world.deserialize_scope(|| {
    let _ = serde_json::from_str::<InWorld<SaveFile>>(&json_string);
})
world.despawn_bound_objects::<SaveFile>()

This saves each type in a map entry:

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

§Advanced Serialization

BevyObject is not just a clone of Bundle, we support additional types.

  • impl BevyObject: Components are automatically BevyObject and BevyObject can contain multiple other BevyObjects.
  • Maybe<T> can be used if an item may or may not exist.
  • DefaultInit initializes a non-serialize component with FromWorld.
  • Child<T> finds and serializes a single BevyObject in children.
  • ChildVec<T> finds and serializes multiple BevyObjects in children.

New in 0.5:

  • Child<T, C> finds and serializes a single BevyObject from a custom children component.
  • ChildVec<T, C> finds and serializes multiple BevyObjects from a custom children component.

See the BevyObject derive macro for more details.

// Note we cannot derive bundle anymore.
// #[bevy_object(query)] also cannot be used due to children being serialized.
#[derive(BevyObject)]
#[bevy_object(rename = "character")]
pub struct Character {
    pub transform: Transform,
    pub name: Name,
    pub position: Position,
    pub hp: Hp,
    #[serde(default)]
    pub weapon: Maybe<Weapon>
    #[serde(skip)]
    pub cache: DefaultInit<Cache>,
    pub potions: ChildVec<Potion>
}

§Stateful Serialization

When using bevy_serde_lens you can use with_world to access &World in Serialize implementations and with_world_mut to access &mut World in Deserialize implementations.

These functions actually comes from bevy_serde_lens_core which is more semver stable and more suited as a dependency for library authors.

§Serialize Handles

To serialize a Handle as its string path, you can use #[serde(with = "PathHandle")]. To serialize its content, use #[serde(with = "UniqueHandle")].

#[derive(Component, Serialize, Deserialize)]
struct MySprite {
    #[serde(with = "PathHandle")]
    image: Handle<Image>
}

Or use the newtype directly.

#[derive(Component, Serialize, Deserialize)]
struct MySprite {
    image: PathHandle<Image>
}

§TypeTag

The typetag crate allows you to serialize trait objects like Box<dyn T>, but using typetag will always pull in all implementations linked to your build and does not work on WASM. To address these limitations this crate allows you to register deserializers manually in the bevy World and use the TypeTagged projection type for serialization.

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

then

#[derive(Serialize, Deserialize)]
struct MyComponent {
    #[serde(with = "TypeTagged")]
    weapon: Box<dyn Animal>
}

To have user friendly configuration files, you can use register_deserialize_any and AnyTagged to allow deserialize_any, i.e. deserialize 42 instead of {"int": 42} in self-describing formats. Keep in mind using AnyTagged in a non-self-describing format like postcard will always return an error as this is a limitation of the serde specification.

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

§Versions

bevybevy-serde-lens-corebevy-serde-lens
0.13-0.1-0.3
0.140.140.4
0.150.150.5-latest

§License

Licensed under either of

at your option.

§Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Re-exports§

pub use batch::Join;
pub use entity::EntityId;
pub use entity::Parented;

Modules§

asset
Module for serializing Handles and Assets.
entity
Module for serializing Entity and hierarchy.
interning
Module for interning data in a Resource.
typetagged
Module for serializing trait objects.

Macros§

batch
Batches multiple SerializeWorld types to be serialized together as a map.

Structs§

AdaptedComponent
Apply a SerdeAdaptor to a SerializeComponent<T> to change how a component is serialized.
AdditionalFilter
Add an additional dummy QueryFilter to the BevyObject derive macro.
Child
Extractor for a single BevyObject in Children or entities referenced by a custom ChildrenLike type.
ChildVec
Extractor for multiple BevyObjects in Children or entities referenced by a custom ChildrenLike type.
DefaultInit
Convert a Default or FromWorld component to BevyObject using default initialization.
DeserializeLens
A DeserializeSeed type from a World reference and a BatchSerialization type.
InWorld
A Deserialize type from a BatchSerialization type.
Maybe
Extractor that allows a BevyObject to be missing.
Root
Make a BevyObject Deserialize by providing a root level entity in the world.
SerializeComponent
Serialize a component on the active entity.
SerializeLens
A Serialize type from a World reference and a BatchSerialization type.
SerializeNonSend
Serialize a non-send resource on the active world.
SerializeResource
Serialize a resource on the active world.

Traits§

BatchSerialization
A batch serialization type.
BevyObject
Associate a BevyObject to a EntityFilter, usually a component as With<Component>.
BindProject
Make a type usable in in the BevyObject macro.
BindProjectQuery
Make a type usable in in the BevyObject macro in query mode.
ChildrenLike
Types that references one or many entities similar to Children.
EntityFilter
A subset of QueryFilter that works on EntityRef. Supports tuples, With, Without and Or.
SerdeAdaptor
A trait that enables AdaptedComponent to change the behavior of serialization and add serialization support to non-serialize types.
SerializeWorld
A Single item in BatchSerialization.
WorldExtension
Extension methods on World.
ZstInit
Equivalent to Default, indicates the type should be a marker ZST, not a concrete type.

Functions§

current_entity
Obtain the current Entity in bevy_serde_lens.
with_world
Run a function on a read only reference to World.
with_world_mut
Run a function on a mutable only reference to World.

Derive Macros§

BevyObject
Derive macro for BevyObject. This largely mirrors Bundle but supports additional types of fields.