Skip to main content

Crate bevy_archive

Crate bevy_archive 

Source
Expand description

§bevy_archive — Structured ECS World Serialization for Bevy

bevy_archive is a format-agnostic snapshot and serialization system built on Bevy ECS. It decomposes a World by archetype, stores component data in columnar form, and writes the result to one of several pluggable backends (JSON, TOML, CSV, MessagePack, Parquet).

§Design Principles

  1. Archetype-centric storage. Entities are grouped by their component signature (archetype). Each archetype is a table: rows = entities, columns = component values. This mirrors how Bevy lays out data internally and avoids the overhead of per-entity iteration.

  2. Format agnostic via the Archive trait. All backends implement the same five-method interface. Adding a new format requires only implementing Archive — no changes to the core save/load pipeline.

  3. User-controlled entity ID space during merge. When loading a snapshot into an existing world, apply_with_remap accepts a user-provided EntityRemapper so that the user, not the engine, decides how old IDs map to new ones. Bevy’s entity generations are transparent to this path.

  4. Zero-allocation writes via HarvardCommandBuffer. Deserialized component payloads are placed into a bumpalo::Bump arena and batched into a write-combining command stream before being flushed to the world in a single pass.

  5. Isolation from Bevy API churn. Volatile Bevy internals (EntityIndex, Entities, EntityAllocator) are touched only in a few strategic modules. Users interact with stable wrapper functions like entity_to_index and entity_from_index.

§Supported Formats

FormatStructFeatureBest For
MessagePack binaryMsgPackArchive(default)Savegames, network transfer
Aurora manifest (JSON/TOML + CSV + Parquet)AuroraWorldManifest(default)Modding, hand-editable assets, hybrid binary+text
JSON entity dumpWorldSnapshot(default)Debugging, introspection
Apache Arrow / ParquetWorldArrowSnapshot (in binary_archive)arrow_rsAnalytics, large worlds

Aurora + Arrow: When arrow_rs is enabled, the Aurora manifest format can embed Parquet blobs alongside CSV/JSON. The same load_world_manifest function dispatches to the Arrow loader automatically — no separate code path needed. See examples/hybrid_zip.rs.

§Quick Start

use bevy_archive::prelude::*;
use bevy_ecs::prelude::*;
use serde::{Serialize, Deserialize};

#[derive(Component, Serialize, Deserialize)]
struct Health(f32);

// 1. Register components
let mut registry = SnapshotRegistry::default();
registry.register::<Health>();

// 2. Populate the world
let mut world = World::new();
world.spawn(Health(100.0));
world.spawn(Health(60.0));

// 3. Save
let manifest = save_world_manifest(&world, &registry).unwrap();

// 4. Load into a fresh world
let mut new_world = World::new();
load_world_manifest(&mut new_world, &manifest, &registry).unwrap();

§Loading with ID Remapping (Entity Merging)

Use apply_with_remap when loading a snapshot into a world that already contains entities:

let mut target_world = World::new();
let mut id_registry = IDRemapRegistry::default();

// Pre-allocate slots for the incoming entities
let old_ids = archive.get_entities();
let mut mapper = HashMap::new();
for &old in &old_ids {
    mapper.insert(old, target_world.spawn_empty().id());
}

// Apply with remapping
archive.apply_with_remap(&mut target_world, &registry, &id_registry, &mapper).unwrap();

The mapper gives you total control over the new ID space. Bevy’s internal entity generations are never inspected or assumed.

§Entity Serialization Helpers

Bevy changes its entity API surface between versions. To insulate your code, use the two canonical conversion functions:

use bevy_archive::prelude::*;
use bevy_ecs::prelude::*;

// Entity → u32 (index only, drops generation)
let idx: u32 = entity_to_index(&entity);

// u32 → Entity (generation=0, suitable for deserialization)
let restored = entity_from_index(idx);

// Also usable via serde attribute:
// #[serde(with = "entity_serializer")]

Prefer entity_to_index / entity_from_index over raw .index_u32() or .from_raw_u32() in wrapper From impls and remap hooks — when the next Bevy release renames these again, only serde_utils.rs needs updating.

§Registering Custom Types (Wrappers)

When a Bevy component cannot be serialized directly (e.g. it contains an Entity handle), register a wrapper type that implements From<&Component>:

let mut registry = SnapshotRegistry::default();
registry.register_with::<ChildOf, ChildOfWrapper>();

§Bevy 0.19 Pitfalls

Bevy 0.19 introduced several changes that affect snapshot code. bevy_archive handles them internally, but awareness helps when extending the library.

§Resources are entities

In 0.19 every Resource is stored as a real Entity tagged with an IsResource marker. World::new() spawns one in bootstrap(). These entities and their archetypes leak into public iterators.

bevy_archive filters them out at the archetype level with !arch.contains(bevy_ecs::resource::IS_RESOURCE) in all four save paths.

§Entity allocation ≠ spawning

EntityAllocator::alloc_many(n) advances a counter but does not extend the entity metadata or spawn entities. EntityWorldMut silently returns Err for unspawned IDs.

bevy_archive provides reserve_entity_slots which wraps alloc_many + spawn_empty_at to make a contiguous ID range alive before loading.

§EntityIndex is a newtype (0.17→0.19)

Entity::index() now returns EntityIndex instead of a raw u32. Use .index_u32() for raw values, or better yet entity_to_index.

§Module Map

ModulePurpose
traitsThe Archive trait — the primary API surface
archetype_archiveCore save/load engine: ArchetypeSnapshot, WorldArchSnapshot
aurora_archiveAurora manifest format (JSON/TOML + CSV embedding)
entity_archiveLegacy per-entity JSON snapshot
bevy_registrySnapshotRegistry, IDRemapRegistry, reserve_entity_slots
serde_utilsentity_to_index, entity_from_index, serde helpers
bevy_cmdbufferHarvardCommandBuffer — low-level write engine
binary_archiveMessagePack and Arrow/Parquet backends

§Examples

See examples/ in the repository:

  • standard_api_example.rs — basic save/load with all formats
  • id_remap_example.rs — entity ID remapping (merge)
  • aurora_manifest_example.rs — Aurora manifest with ChildOf wrapper
  • hybrid_zip.rs — Parquet + CSV hybrid archive (requires arrow_rs)

Modules§

archetype_archive
aurora_archive
This module contains the full Aurora manifest system for BevyArchive.
bevy_cmdbuffer
bevy_registry
binary_archive
csv_archive
entity_archive
prelude
serde_utils
traits