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