Skip to main content

sdec_bevy/
extract.rs

1use std::collections::{HashMap, HashSet};
2
3use bevy_ecs::prelude::{Entity, World};
4use codec::{DeltaUpdateEntity, EntityId, EntitySnapshot};
5use schema::ComponentId;
6
7use crate::mapping::EntityMap;
8use crate::schema::BevySchema;
9
10#[derive(Debug, Default)]
11pub struct BevyChangeSet {
12    pub creates: Vec<EntitySnapshot>,
13    pub destroys: Vec<EntityId>,
14    pub updates: Vec<DeltaUpdateEntity>,
15}
16
17#[derive(Debug, Default)]
18pub(crate) struct ExtractScratch {
19    create_entities: HashSet<Entity>,
20    update_entities: HashMap<Entity, Vec<ComponentId>>,
21    destroys: HashSet<EntityId>,
22}
23
24pub fn extract_changes(
25    schema: &BevySchema,
26    world: &mut World,
27    entities: &mut EntityMap,
28) -> BevyChangeSet {
29    let mut scratch = ExtractScratch::default();
30    let mut changes = BevyChangeSet::default();
31    extract_changes_with_scratch(schema, world, entities, &mut scratch, &mut changes);
32    changes
33}
34
35pub(crate) fn extract_changes_with_scratch(
36    schema: &BevySchema,
37    world: &mut World,
38    entities: &mut EntityMap,
39    scratch: &mut ExtractScratch,
40    out: &mut BevyChangeSet,
41) {
42    scratch.create_entities.clear();
43    scratch.update_entities.clear();
44    scratch.destroys.clear();
45    out.creates.clear();
46    out.updates.clear();
47    out.destroys.clear();
48
49    for adapter in schema.adapters() {
50        for entity in adapter.added_entities(world) {
51            scratch.create_entities.insert(entity);
52        }
53        for entity in adapter.changed_entities(world) {
54            scratch
55                .update_entities
56                .entry(entity)
57                .or_default()
58                .push(adapter.component_id());
59        }
60        for entity in adapter.removed_entities(world) {
61            if let Some(id) = entities.entity_id_known(entity) {
62                scratch.destroys.insert(id);
63            }
64        }
65    }
66
67    out.creates.reserve(scratch.create_entities.len());
68    for entity in scratch.create_entities.iter().copied() {
69        let id = entities.entity_id(entity);
70        let components = schema.snapshot_entity(world, entity);
71        if components.is_empty() {
72            continue;
73        }
74        out.creates.push(EntitySnapshot { id, components });
75    }
76
77    out.updates.reserve(scratch.update_entities.len());
78    for (entity, components) in scratch.update_entities.iter() {
79        if scratch.create_entities.contains(entity) {
80            continue;
81        }
82        let id = entities.entity_id(*entity);
83        let mut delta_components = Vec::new();
84        for component_id in components {
85            if let Some(adapter) = schema.adapter_by_component(*component_id) {
86                if let Some(component_update) = adapter.update_component(world, *entity) {
87                    delta_components.push(component_update);
88                }
89            }
90        }
91        if !delta_components.is_empty() {
92            out.updates.push(DeltaUpdateEntity {
93                id,
94                components: delta_components,
95            });
96        }
97    }
98
99    out.destroys.reserve(scratch.destroys.len());
100    out.destroys.extend(scratch.destroys.iter().copied());
101    out.destroys.sort_by_key(|id| id.raw());
102    out.creates.sort_by_key(|entity| entity.id.raw());
103    out.updates.sort_by_key(|entity| entity.id.raw());
104}