veloren_common_net/sync/
sync_ext.rs1use super::{
2 packet::{CompPacket, CompSyncPackage, CompUpdateKind, EntityPackage, EntitySyncPackage},
3 track::UpdateTracker,
4};
5use common::{
6 resources::PlayerEntity,
7 uid::{IdMaps, Uid},
8};
9use specs::{WorldExt, world::Builder};
10use tracing::error;
11
12pub trait WorldSyncExt {
13 fn register_sync_marker(&mut self);
14 fn register_synced<C: specs::Component + Clone + Send + Sync>(&mut self)
15 where
16 C::Storage: Default + specs::storage::Tracked;
17 fn register_tracker<C: specs::Component + Clone + Send + Sync>(&mut self)
18 where
19 C::Storage: Default + specs::storage::Tracked;
20 fn create_entity_synced(&mut self) -> specs::EntityBuilder;
21 fn delete_entity_and_clear_uid_mapping(&mut self, uid: Uid);
22 fn uid_from_entity(&self, entity: specs::Entity) -> Option<Uid>;
23 fn entity_from_uid(&self, uid: Uid) -> Option<specs::Entity>;
24 fn apply_entity_package<P: CompPacket>(
25 &mut self,
26 entity_package: EntityPackage<P>,
27 ) -> specs::Entity;
28 fn apply_entity_sync_package(&mut self, package: EntitySyncPackage, client_uid: Option<Uid>);
29 fn apply_comp_sync_package<P: CompPacket>(&mut self, package: CompSyncPackage<P>);
30}
31
32impl WorldSyncExt for specs::World {
33 fn register_sync_marker(&mut self) {
34 self.register_synced::<Uid>();
35 self.insert(IdMaps::new());
36 }
37
38 fn register_synced<C: specs::Component + Clone + Send + Sync>(&mut self)
39 where
40 C::Storage: Default + specs::storage::Tracked,
41 {
42 self.register::<C>();
43 self.register_tracker::<C>();
44 }
45
46 fn register_tracker<C: specs::Component + Clone + Send + Sync>(&mut self)
47 where
48 C::Storage: Default + specs::storage::Tracked,
49 {
50 let tracker = UpdateTracker::<C>::new(self);
51 self.insert(tracker);
52 }
53
54 fn create_entity_synced(&mut self) -> specs::EntityBuilder {
55 let builder = self.create_entity();
60 let uid = builder
61 .world
62 .write_resource::<IdMaps>()
63 .allocate(builder.entity);
64 builder.with(uid)
65 }
66
67 fn delete_entity_and_clear_uid_mapping(&mut self, uid: Uid) {
72 let maybe_entity = self.write_resource::<IdMaps>()
74 .remove_entity(None, Some(uid), None, None);
78 if let Some(entity) = maybe_entity {
79 if let Err(e) = self.delete_entity(entity) {
80 error!(?e, "Failed to delete entity");
81 }
82 }
83 }
84
85 fn uid_from_entity(&self, entity: specs::Entity) -> Option<Uid> {
87 self.read_storage::<Uid>().get(entity).copied()
88 }
89
90 fn entity_from_uid(&self, uid: Uid) -> Option<specs::Entity> {
92 self.read_resource::<IdMaps>().uid_entity(uid)
93 }
94
95 fn apply_entity_package<P: CompPacket>(
96 &mut self,
97 entity_package: EntityPackage<P>,
98 ) -> specs::Entity {
99 let EntityPackage { uid, comps } = entity_package;
100
101 let entity = create_entity_with_uid(self, uid);
102 for packet in comps {
103 packet.apply_insert(entity, self, true)
104 }
105
106 entity
107 }
108
109 fn apply_entity_sync_package(&mut self, package: EntitySyncPackage, client_uid: Option<Uid>) {
110 let EntitySyncPackage {
112 created_entities,
113 deleted_entities,
114 } = package;
115
116 created_entities.into_iter().for_each(|uid| {
118 create_entity_with_uid(self, uid);
119 });
120
121 deleted_entities.into_iter().for_each(|uid| {
123 if client_uid != Some(uid) {
128 self.delete_entity_and_clear_uid_mapping(uid);
129 }
130 });
131 }
132
133 fn apply_comp_sync_package<P: CompPacket>(&mut self, package: CompSyncPackage<P>) {
134 let player_entity = self.read_resource::<PlayerEntity>().0;
136 package.comp_updates.into_iter().for_each(|(uid, update)| {
137 if let Some(entity) = self.read_resource::<IdMaps>().uid_entity(uid.into()) {
138 let force_update = player_entity == Some(entity);
139 match update {
140 CompUpdateKind::Inserted(packet) => {
141 packet.apply_insert(entity, self, force_update);
142 },
143 CompUpdateKind::Modified(packet) => {
144 packet.apply_modify(entity, self, force_update);
145 },
146 CompUpdateKind::Removed(phantom) => {
147 P::apply_remove(phantom, entity, self);
148 },
149 }
150 }
151 });
152 }
153}
154
155fn create_entity_with_uid(specs_world: &mut specs::World, entity_uid: Uid) -> specs::Entity {
159 let existing_entity = specs_world.read_resource::<IdMaps>().uid_entity(entity_uid);
160
161 match existing_entity {
165 Some(entity) => entity,
166 None => {
167 let entity_builder = specs_world.create_entity();
168 entity_builder
169 .world
170 .write_resource::<IdMaps>()
171 .add_entity(entity_uid, entity_builder.entity);
172 entity_builder.with(entity_uid).build()
173 },
174 }
175}