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}