1use std::any::TypeId;
2use std::collections::HashMap;
3use std::marker::PhantomData;
4
5use anyhow::{anyhow, Result};
6use bevy_ecs::component::Mutable;
7use bevy_ecs::prelude::{Component, Entity, World};
8use codec::{ComponentSnapshot, DeltaUpdateComponent, DeltaUpdateEntity, FieldValue};
9use schema::{ChangePolicy, ComponentDef, ComponentId, FieldCodec, FieldDef, FieldId, Schema};
10
11#[derive(Debug, Clone)]
12pub struct ReplicatedField {
13 pub id: u16,
14 pub codec: FieldCodec,
15 pub change: Option<ChangePolicy>,
16}
17
18pub trait ReplicatedComponent: Component<Mutability = Mutable> {
19 const COMPONENT_ID: u16;
20
21 fn fields() -> Vec<ReplicatedField>;
22
23 fn read_fields(&self) -> Vec<FieldValue>;
24
25 fn apply_field(&mut self, index: usize, value: FieldValue) -> Result<()>;
26
27 fn from_fields(fields: &[FieldValue]) -> Result<Self>
28 where
29 Self: Sized;
30}
31
32pub(crate) trait ComponentAdapter {
33 fn type_id(&self) -> TypeId;
34 fn component_id(&self) -> ComponentId;
35 fn schema_def(&self) -> ComponentDef;
36 fn snapshot_component(&self, world: &World, entity: Entity) -> Option<ComponentSnapshot>;
37 fn update_component(&self, world: &World, entity: Entity) -> Option<DeltaUpdateComponent>;
38 fn apply_update(
39 &self,
40 world: &mut World,
41 entity: Entity,
42 fields: &[(usize, FieldValue)],
43 ) -> Result<()>;
44 fn insert_component(
45 &self,
46 world: &mut World,
47 entity: Entity,
48 fields: &[FieldValue],
49 ) -> Result<()>;
50 fn added_entities(&self, world: &mut World) -> Vec<Entity>;
51 fn changed_entities(&self, world: &mut World) -> Vec<Entity>;
52 fn removed_entities(&self, world: &World) -> Vec<Entity>;
53}
54
55struct ComponentAdapterImpl<T: ReplicatedComponent> {
56 component_id: ComponentId,
57 fields: Vec<ReplicatedField>,
58 _marker: PhantomData<T>,
59}
60
61impl<T: ReplicatedComponent> ComponentAdapterImpl<T> {
62 fn new() -> Self {
63 Self {
64 component_id: ComponentId::new(T::COMPONENT_ID).expect("component id must be non-zero"),
65 fields: T::fields(),
66 _marker: PhantomData,
67 }
68 }
69
70 fn snapshot_fields(&self, component: &T) -> Vec<FieldValue> {
71 component.read_fields()
72 }
73
74 fn build_field_defs(&self) -> Vec<FieldDef> {
75 self.fields
76 .iter()
77 .map(|field| {
78 let mut def = FieldDef::new(
79 FieldId::new(field.id).expect("field id must be non-zero"),
80 field.codec,
81 );
82 if let Some(change) = field.change {
83 def = def.change(change);
84 }
85 def
86 })
87 .collect()
88 }
89}
90
91impl<T: ReplicatedComponent> ComponentAdapter for ComponentAdapterImpl<T> {
92 fn type_id(&self) -> TypeId {
93 TypeId::of::<T>()
94 }
95
96 fn component_id(&self) -> ComponentId {
97 self.component_id
98 }
99
100 fn schema_def(&self) -> ComponentDef {
101 let mut def = ComponentDef::new(self.component_id);
102 for field in self.build_field_defs() {
103 def = def.field(field);
104 }
105 def
106 }
107
108 fn snapshot_component(&self, world: &World, entity: Entity) -> Option<ComponentSnapshot> {
109 let component = world.get::<T>(entity)?;
110 let fields = self.snapshot_fields(component);
111 Some(ComponentSnapshot {
112 id: self.component_id,
113 fields,
114 })
115 }
116
117 fn update_component(&self, world: &World, entity: Entity) -> Option<DeltaUpdateComponent> {
118 let component = world.get::<T>(entity)?;
119 let fields = self.snapshot_fields(component);
120 let updates = fields.into_iter().enumerate().collect();
121 Some(DeltaUpdateComponent {
122 id: self.component_id,
123 fields: updates,
124 })
125 }
126
127 fn apply_update(
128 &self,
129 world: &mut World,
130 entity: Entity,
131 fields: &[(usize, FieldValue)],
132 ) -> Result<()> {
133 let mut component = world
134 .get_mut::<T>(entity)
135 .ok_or_else(|| anyhow!("missing component {:?}", self.component_id))?;
136 for (index, value) in fields {
137 component.apply_field(*index, *value)?;
138 }
139 Ok(())
140 }
141
142 fn insert_component(
143 &self,
144 world: &mut World,
145 entity: Entity,
146 fields: &[FieldValue],
147 ) -> Result<()> {
148 let component = T::from_fields(fields)?;
149 world.entity_mut(entity).insert(component);
150 Ok(())
151 }
152
153 fn added_entities(&self, world: &mut World) -> Vec<Entity> {
154 let mut query = world.query_filtered::<Entity, bevy_ecs::query::Added<T>>();
155 query.iter(world).collect()
156 }
157
158 fn changed_entities(&self, world: &mut World) -> Vec<Entity> {
159 let mut query = world.query_filtered::<Entity, bevy_ecs::query::Changed<T>>();
160 query.iter(world).collect()
161 }
162
163 fn removed_entities(&self, world: &World) -> Vec<Entity> {
164 world.removed::<T>().collect()
165 }
166}
167
168pub struct BevySchema {
169 pub schema: Schema,
170 adapters: Vec<Box<dyn ComponentAdapter>>,
171 adapter_by_component: HashMap<ComponentId, usize>,
172}
173
174impl BevySchema {
175 #[must_use]
176 pub fn schema(&self) -> &Schema {
177 &self.schema
178 }
179
180 pub(crate) fn adapters(&self) -> &[Box<dyn ComponentAdapter>] {
181 &self.adapters
182 }
183
184 pub(crate) fn adapter_by_component(
185 &self,
186 component_id: ComponentId,
187 ) -> Option<&dyn ComponentAdapter> {
188 let index = self.adapter_by_component.get(&component_id).copied()?;
189 self.adapters.get(index).map(|adapter| adapter.as_ref())
190 }
191
192 pub fn snapshot_entity(&self, world: &World, entity: Entity) -> Vec<ComponentSnapshot> {
193 self.adapters
194 .iter()
195 .filter_map(|adapter| adapter.snapshot_component(world, entity))
196 .collect()
197 }
198
199 pub fn apply_component_fields(
200 &self,
201 world: &mut World,
202 entity: Entity,
203 component_id: ComponentId,
204 fields: &[(usize, FieldValue)],
205 ) -> Result<()> {
206 let adapter = self
207 .adapter_by_component(component_id)
208 .ok_or_else(|| anyhow!("unknown component {:?}", component_id))?;
209 adapter.apply_update(world, entity, fields)
210 }
211
212 pub fn insert_component_fields(
213 &self,
214 world: &mut World,
215 entity: Entity,
216 component_id: ComponentId,
217 fields: &[FieldValue],
218 ) -> Result<()> {
219 let adapter = self
220 .adapter_by_component(component_id)
221 .ok_or_else(|| anyhow!("unknown component {:?}", component_id))?;
222 adapter.insert_component(world, entity, fields)
223 }
224
225 pub fn build_delta_update(
226 &self,
227 world: &World,
228 entity: Entity,
229 entity_id: codec::EntityId,
230 component_ids: &[ComponentId],
231 ) -> Option<DeltaUpdateEntity> {
232 let mut components = Vec::with_capacity(component_ids.len());
233 for component_id in component_ids {
234 let adapter = self.adapter_by_component(*component_id)?;
235 if let Some(update) = adapter.update_component(world, entity) {
236 components.push(update);
237 }
238 }
239 if components.is_empty() {
240 None
241 } else {
242 Some(DeltaUpdateEntity {
243 id: entity_id,
244 components,
245 })
246 }
247 }
248}
249
250#[derive(Default)]
251pub struct BevySchemaBuilder {
252 adapters: Vec<Box<dyn ComponentAdapter>>,
253}
254
255impl BevySchemaBuilder {
256 #[must_use]
257 pub fn new() -> Self {
258 Self::default()
259 }
260
261 pub fn component<T: ReplicatedComponent + 'static>(&mut self) -> &mut Self {
262 let adapter = ComponentAdapterImpl::<T>::new();
263 if self
264 .adapters
265 .iter()
266 .any(|existing| existing.type_id() == adapter.type_id())
267 {
268 return self;
269 }
270 self.adapters.push(Box::new(adapter));
271 self
272 }
273
274 pub fn build(self) -> Result<BevySchema> {
275 let mut components = Vec::with_capacity(self.adapters.len());
276 for adapter in &self.adapters {
277 components.push(adapter.schema_def());
278 }
279 let schema = Schema::new(components).map_err(|err| anyhow!("{err:?}"))?;
280 let adapter_by_component = self
281 .adapters
282 .iter()
283 .enumerate()
284 .map(|(index, adapter)| (adapter.component_id(), index))
285 .collect();
286 Ok(BevySchema {
287 schema,
288 adapters: self.adapters,
289 adapter_by_component,
290 })
291 }
292}