1use super::track::UpdateTracker;
2use common::{resources::Time, uid::Uid};
3use serde::{Deserialize, Serialize, de::DeserializeOwned};
4use specs::{Component, Entity, Join, ReadStorage, World, WorldExt, storage::AccessMut};
5use std::{
6 convert::{TryFrom, TryInto},
7 fmt::Debug,
8 marker::PhantomData,
9};
10use tracing::error;
11
12pub trait CompPacket: Clone + Debug + Send + 'static {
20 type Phantom: Clone + Debug + Serialize + DeserializeOwned;
21
22 fn apply_insert(self, entity: Entity, world: &World, force_update: bool);
23 fn apply_modify(self, entity: Entity, world: &World, force_update: bool);
24 fn apply_remove(phantom: Self::Phantom, entity: Entity, world: &World);
25}
26
27pub fn handle_insert<C: Component>(comp: C, entity: Entity, world: &World) {
29 if let Err(e) = world.write_storage::<C>().insert(entity, comp) {
30 error!(?e, "Error inserting");
31 }
32}
33pub fn handle_modify<C: Component + Debug>(comp: C, entity: Entity, world: &World) {
35 if let Some(mut c) = world.write_storage::<C>().get_mut(entity) {
36 *c.access_mut() = comp
37 } else {
38 error!(
39 ?comp,
40 "Error modifying synced component, it doesn't seem to exist"
41 );
42 }
43}
44pub fn handle_remove<C: Component>(entity: Entity, world: &World) {
46 world.write_storage::<C>().remove(entity);
47}
48
49pub trait InterpolatableComponent: Component {
50 type InterpData: Component;
51 type ReadData;
52
53 fn new_data(x: Self) -> Self::InterpData;
54 fn update_component(&self, data: &mut Self::InterpData, time: f64, force_update: bool);
55 #[must_use]
56 fn interpolate(self, data: &Self::InterpData, time: f64, read_data: &Self::ReadData) -> Self;
57}
58
59pub fn handle_interp_insert<C: InterpolatableComponent + Clone>(
60 comp: C,
61 entity: Entity,
62 world: &World,
63 force_update: bool,
64) {
65 let mut interp_data = C::new_data(comp.clone());
66 let time = world.read_resource::<Time>().0;
67 comp.update_component(&mut interp_data, time, force_update);
68 handle_insert(comp, entity, world);
69 handle_insert(interp_data, entity, world);
70}
71
72pub fn handle_interp_modify<C: InterpolatableComponent + Debug>(
73 comp: C,
74 entity: Entity,
75 world: &World,
76 force_update: bool,
77) {
78 if let Some(mut interp_data) = world.write_storage::<C::InterpData>().get_mut(entity) {
79 let time = world.read_resource::<Time>().0;
80 comp.update_component(interp_data.access_mut(), time, force_update);
81 handle_modify(comp, entity, world);
82 } else {
83 error!(
84 ?comp,
85 "Error modifying interpolation data for synced component, it doesn't seem to exist"
86 );
87 }
88}
89
90pub fn handle_interp_remove<C: InterpolatableComponent>(entity: Entity, world: &World) {
91 handle_remove::<C>(entity, world);
92 handle_remove::<C::InterpData>(entity, world);
93}
94
95#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
96pub enum CompUpdateKind<P: CompPacket> {
97 Inserted(P),
98 Modified(P),
99 Removed(P::Phantom),
100}
101
102#[derive(Clone, Debug, Serialize, Deserialize)]
103pub struct EntityPackage<P: CompPacket> {
104 pub uid: Uid,
105 pub comps: Vec<P>,
106}
107
108#[derive(Clone, Debug, Serialize, Deserialize)]
109pub struct EntitySyncPackage {
110 pub created_entities: Vec<Uid>,
111 pub deleted_entities: Vec<Uid>,
112}
113impl EntitySyncPackage {
114 pub fn new(
115 uids: &ReadStorage<'_, Uid>,
116 uid_tracker: &UpdateTracker<Uid>,
117 filter: impl Join + Copy,
118 deleted_entities: Vec<Uid>,
119 ) -> Self {
120 let created_entities = (uids, filter, uid_tracker.inserted())
122 .join()
123 .map(|(uid, _, _)| *uid)
124 .collect();
125
126 Self {
127 created_entities,
128 deleted_entities,
129 }
130 }
131}
132
133#[derive(Clone, Debug, Serialize, Deserialize)]
134pub struct CompSyncPackage<P: CompPacket> {
135 pub comp_updates: Vec<(u64, CompUpdateKind<P>)>,
137}
138
139impl<P: CompPacket> CompSyncPackage<P> {
140 #[expect(clippy::new_without_default)]
141 pub fn new() -> Self {
142 Self {
143 comp_updates: Vec::new(),
144 }
145 }
146
147 pub fn comp_inserted<C>(&mut self, uid: Uid, comp: C)
148 where
149 P: From<C>,
150 {
151 self.comp_updates
152 .push((uid.into(), CompUpdateKind::Inserted(comp.into())));
153 }
154
155 pub fn comp_modified<C>(&mut self, uid: Uid, comp: C)
156 where
157 P: From<C>,
158 {
159 self.comp_updates
160 .push((uid.into(), CompUpdateKind::Modified(comp.into())));
161 }
162
163 pub fn comp_removed<C>(&mut self, uid: Uid)
164 where
165 P::Phantom: From<PhantomData<C>>,
166 {
167 self.comp_updates
168 .push((uid.into(), CompUpdateKind::Removed(PhantomData::<C>.into())));
169 }
170
171 pub fn add_component_updates<'a, C>(
172 &mut self,
173 uids: &ReadStorage<'a, Uid>,
174 tracker: &UpdateTracker<C>,
175 storage: &ReadStorage<'a, C>,
176 filter: impl Join + Copy,
177 ) where
178 P: From<C>,
179 C: Component + Clone + Send + Sync + TryFrom<P>,
180 P::Phantom: From<PhantomData<C>>,
181 P::Phantom: TryInto<PhantomData<C>>,
182 C::Storage: specs::storage::Tracked,
183 {
184 tracker.get_updates_for(uids, storage, filter, &mut self.comp_updates);
185 }
186
187 pub fn add_component_update<C>(
190 &mut self,
191 tracker: &UpdateTracker<C>,
192 storage: &ReadStorage<'_, C>,
193 uid: u64,
194 entity: Entity,
195 ) where
196 P: From<C>,
197 C: Component + Clone + Send + Sync + TryFrom<P>,
198 P::Phantom: From<PhantomData<C>>,
199 P::Phantom: TryInto<PhantomData<C>>,
200 C::Storage: specs::storage::Tracked,
201 {
202 if let Some(comp_update) = tracker.get_update(storage, entity) {
203 self.comp_updates.push((uid, comp_update))
204 }
205 }
206
207 pub fn is_empty(&self) -> bool { self.comp_updates.is_empty() }
210}