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