veloren_common_net/sync/
track.rs1use super::packet::{CompPacket, CompUpdateKind};
2use common::uid::Uid;
3use specs::{BitSet, Component, Entity, Join, ReadStorage, World, WorldExt};
4use std::{
5 convert::{TryFrom, TryInto},
6 marker::PhantomData,
7};
8
9pub struct UpdateTracker<C: Component> {
10 reader_id: specs::ReaderId<specs::storage::ComponentEvent>,
11 inserted: BitSet,
12 modified: BitSet,
13 removed: BitSet,
14 phantom: PhantomData<C>,
15}
16impl<C: Component> UpdateTracker<C>
17where
18 C::Storage: specs::storage::Tracked,
19{
20 pub fn new(specs_world: &World) -> Self {
21 Self {
22 reader_id: specs_world.write_storage::<C>().register_reader(),
23 inserted: BitSet::new(),
24 modified: BitSet::new(),
25 removed: BitSet::new(),
26 phantom: PhantomData,
27 }
28 }
29
30 pub fn inserted(&self) -> &BitSet { &self.inserted }
31
32 pub fn modified(&self) -> &BitSet { &self.modified }
33
34 pub fn removed(&self) -> &BitSet { &self.removed }
35
36 pub fn record_changes(&mut self, storage: &ReadStorage<'_, C>) {
37 self.inserted.clear();
38 self.modified.clear();
39 self.removed.clear();
40
41 for event in storage.channel().read(&mut self.reader_id) {
42 match event {
43 specs::storage::ComponentEvent::Inserted(id) => {
44 self.removed.remove(*id);
46 self.modified.remove(*id);
47 self.inserted.add(*id);
48 },
49 specs::storage::ComponentEvent::Modified(id) => {
50 if !self.inserted.contains(*id) {
52 debug_assert!(!self.removed.contains(*id)); self.modified.add(*id);
54 }
55 },
56 specs::storage::ComponentEvent::Removed(id) => {
57 self.inserted.remove(*id);
60 self.modified.remove(*id);
61 self.removed.add(*id);
62 },
63 };
64 }
65 }
66}
67
68impl<C: Component + Clone + Send + Sync> UpdateTracker<C> {
69 pub fn add_packet_for<P>(
70 &self,
71 storage: &ReadStorage<'_, C>,
72 entity: Entity,
73 packets: &mut Vec<P>,
74 ) where
75 P: CompPacket,
76 P: From<C>,
77 C: TryFrom<P>,
78 P::Phantom: From<PhantomData<C>>,
79 P::Phantom: TryInto<PhantomData<C>>,
80 C::Storage: specs::storage::Tracked,
81 {
82 if let Some(comp) = storage.get(entity) {
83 packets.push(P::from(comp.clone()));
84 }
85 }
86
87 pub fn get_updates_for<P>(
88 &self,
89 uids: &ReadStorage<'_, Uid>,
90 storage: &ReadStorage<'_, C>,
91 entity_filter: impl Join + Copy,
92 buf: &mut Vec<(u64, CompUpdateKind<P>)>,
93 ) where
94 P: CompPacket,
95 P: From<C>,
96 C: TryFrom<P>,
97 P::Phantom: From<PhantomData<C>>,
98 P::Phantom: TryInto<PhantomData<C>>,
99 C::Storage: specs::storage::Tracked,
100 {
101 for (uid, comp, _, _) in (uids, storage, &self.inserted, entity_filter).join() {
103 buf.push((
104 (*uid).into(),
105 CompUpdateKind::Inserted(P::from(comp.clone())),
106 ));
107 }
108
109 for (uid, comp, _, _) in (uids, storage, &self.modified, entity_filter).join() {
111 buf.push((
112 (*uid).into(),
113 CompUpdateKind::Modified(P::from(comp.clone())),
114 ));
115 }
116
117 for (uid, _, _) in (uids, &self.removed, entity_filter).join() {
119 buf.push((
120 (*uid).into(),
121 CompUpdateKind::Removed(P::Phantom::from(PhantomData::<C>)),
122 ));
123 }
124 }
125
126 pub fn get_update<P>(
129 &self,
130 storage: &ReadStorage<'_, C>,
131 entity: Entity,
132 ) -> Option<CompUpdateKind<P>>
133 where
134 P: CompPacket,
135 P: From<C>,
136 C: TryFrom<P>,
137 P::Phantom: From<PhantomData<C>>,
138 P::Phantom: TryInto<PhantomData<C>>,
139 C::Storage: specs::storage::Tracked,
140 {
141 let id = entity.id();
142 if self.modified.contains(id) {
146 storage
147 .get(entity)
148 .map(|comp| CompUpdateKind::Modified(P::from(comp.clone())))
149 } else if self.inserted.contains(id) {
150 storage
151 .get(entity)
152 .map(|comp| CompUpdateKind::Inserted(P::from(comp.clone())))
153 } else if self.removed.contains(id) {
154 Some(CompUpdateKind::Removed(P::Phantom::from(PhantomData::<C>)))
155 } else {
156 None
157 }
158 }
159}