specs/saveload/marker.rs
1//! Provides `Marker` and `MarkerAllocator` traits
2
3use std::{
4 collections::HashMap,
5 fmt::{self, Debug},
6 hash::{Hash, Hasher},
7 marker::PhantomData,
8};
9
10use serde::{de::DeserializeOwned, Deserialize, Serialize};
11
12use crate::{
13 prelude::*,
14 storage::AccessMut,
15 world::{EntitiesRes, EntityResBuilder, LazyBuilder},
16};
17
18/// A common trait for `EntityBuilder` and `LazyBuilder` with a marker function,
19/// allowing either to be used.
20pub trait MarkedBuilder {
21 /// Add a `Marker` to the entity by fetching the associated allocator.
22 ///
23 /// ## Examples
24 ///
25 /// ```
26 /// use specs::{
27 /// prelude::*,
28 /// saveload::{MarkedBuilder, SimpleMarker, SimpleMarkerAllocator},
29 /// };
30 ///
31 /// struct NetworkSync;
32 ///
33 /// fn mark_entity<M: Builder + MarkedBuilder>(markable: M) -> Entity {
34 /// markable
35 /// /* .with(Component1) */
36 /// .marked::<SimpleMarker<NetworkSync>>()
37 /// .build()
38 /// }
39 ///
40 /// let mut world = World::new();
41 /// world.register::<SimpleMarker<NetworkSync>>();
42 /// world.insert(SimpleMarkerAllocator::<NetworkSync>::new());
43 ///
44 /// mark_entity(world.create_entity());
45 /// ```
46 fn marked<M: Marker>(self) -> Self;
47}
48
49impl<'a> MarkedBuilder for EntityBuilder<'a> {
50 fn marked<M>(self) -> Self
51 where
52 M: Marker,
53 {
54 let mut alloc = self.world.write_resource::<M::Allocator>();
55 alloc.mark(self.entity, &mut self.world.write_storage::<M>());
56
57 self
58 }
59}
60
61impl<'a> MarkedBuilder for LazyBuilder<'a> {
62 /// Add a `Marker` to the entity by fetching the associated allocator.
63 ///
64 /// This will be applied on the next `world.maintain()`.
65 ///
66 /// ## Examples
67 ///
68 /// ```rust
69 /// use specs::{
70 /// prelude::*,
71 /// saveload::{MarkedBuilder, SimpleMarker, SimpleMarkerAllocator},
72 /// };
73 ///
74 /// struct NetworkSync;
75 ///
76 /// let mut world = World::new();
77 /// world.register::<SimpleMarker<NetworkSync>>();
78 /// world.insert(SimpleMarkerAllocator::<NetworkSync>::new());
79 ///
80 /// # let lazy = world.read_resource::<LazyUpdate>();
81 /// # let entities = world.entities();
82 /// let my_entity = lazy
83 /// .create_entity(&entities)
84 /// /* .with(Component1) */
85 /// .marked::<SimpleMarker<NetworkSync>>()
86 /// .build();
87 /// ```
88 ///
89 /// ## Panics
90 ///
91 /// Panics during `world.maintain()` in case there's no allocator
92 /// added to the `World`.
93 fn marked<M>(self) -> Self
94 where
95 M: Marker,
96 {
97 let entity = self.entity;
98 self.lazy.exec(move |world| {
99 let mut alloc = world.write_resource::<M::Allocator>();
100 alloc.mark(entity, &mut world.write_storage::<M>());
101 });
102
103 self
104 }
105}
106
107impl<'a> EntityResBuilder<'a> {
108 /// Add a `Marker` to the entity with the associated allocator,
109 /// and component storage.
110 ///
111 /// ## Examples
112 ///
113 /// ```
114 /// use specs::{
115 /// prelude::*,
116 /// saveload::{SimpleMarker, SimpleMarkerAllocator},
117 /// };
118 ///
119 /// struct NetworkSync;
120 ///
121 /// let mut world = World::new();
122 /// world.register::<SimpleMarker<NetworkSync>>();
123 /// world.insert(SimpleMarkerAllocator::<NetworkSync>::new());
124 ///
125 /// let mut storage = world.write_storage::<SimpleMarker<NetworkSync>>();
126 /// let mut alloc = world.write_resource::<SimpleMarkerAllocator<NetworkSync>>();
127 ///
128 /// let entities = world.entities();
129 /// entities
130 /// .build_entity()
131 /// /* .with(Component1) */
132 /// .marked(&mut storage, &mut alloc)
133 /// .build();
134 /// ```
135 pub fn marked<M>(self, storage: &mut WriteStorage<M>, alloc: &mut M::Allocator) -> Self
136 where
137 M: Marker,
138 {
139 alloc.mark(self.entity, storage);
140 self
141 }
142}
143
144/// This trait should be implemented by a component which is going to be used as
145/// marker. This marker should be set to entity that should be serialized.
146/// If serialization strategy needs to set marker to some entity
147/// then it should use newly allocated marker from `Marker::Allocator`.
148///
149/// ## Example
150///
151/// ```rust
152/// extern crate specs;
153/// #[macro_use]
154/// extern crate serde;
155/// use std::{collections::HashMap, ops::Range};
156///
157/// use specs::{
158/// prelude::*,
159/// saveload::{MarkedBuilder, Marker, MarkerAllocator},
160/// world::EntitiesRes,
161/// };
162///
163/// // Marker for entities that should be synced over network
164/// #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
165/// struct NetMarker {
166/// id: u64,
167/// seq: u64,
168/// }
169///
170/// impl Component for NetMarker {
171/// type Storage = DenseVecStorage<Self>;
172/// }
173///
174/// impl Marker for NetMarker {
175/// type Allocator = NetNode;
176/// type Identifier = u64;
177///
178/// fn id(&self) -> u64 {
179/// self.id
180/// }
181///
182/// // Updates sequence id.
183/// // Entities with too old sequence id get deleted.
184/// fn update(&mut self, update: Self) {
185/// assert_eq!(self.id, update.id);
186/// self.seq = update.seq;
187/// }
188/// }
189///
190/// // Each client and server has one
191/// // Contains id range and `NetMarker -> Entity` mapping
192/// struct NetNode {
193/// range: Range<u64>,
194/// mapping: HashMap<u64, Entity>,
195/// }
196///
197/// impl MarkerAllocator<NetMarker> for NetNode {
198/// fn allocate(&mut self, entity: Entity, id: Option<u64>) -> NetMarker {
199/// let id = id.unwrap_or_else(|| {
200/// self.range
201/// .next()
202/// .expect("Id range must be virtually endless")
203/// });
204/// let marker = NetMarker { id, seq: 0 };
205/// self.mapping.insert(id, entity);
206/// marker
207/// }
208///
209/// fn retrieve_entity_internal(&self, id: u64) -> Option<Entity> {
210/// self.mapping.get(&id).cloned()
211/// }
212///
213/// fn maintain(&mut self, entities: &EntitiesRes, storage: &ReadStorage<NetMarker>) {
214/// self.mapping = (entities, storage)
215/// .join()
216/// .map(|(e, m)| (m.id(), e))
217/// .collect();
218/// }
219/// }
220///
221/// fn main() {
222/// let mut world = World::new();
223/// world.register::<NetMarker>();
224///
225/// world.insert(NetNode {
226/// range: 0..100,
227/// mapping: HashMap::new(),
228/// });
229///
230/// let entity = world.create_entity().marked::<NetMarker>().build();
231/// let storage = &mut world.write_storage::<NetMarker>();
232/// let marker = storage.get(entity).unwrap().clone();
233/// assert_eq!(
234/// world
235/// .write_resource::<NetNode>()
236/// .retrieve_entity(marker, storage, &world.entities()),
237/// entity
238/// );
239/// }
240/// ```
241pub trait Marker: Clone + Component + Debug + Eq + Hash + DeserializeOwned + Serialize {
242 /// Id of the marker
243 type Identifier;
244 /// Allocator for this `Marker`
245 type Allocator: MarkerAllocator<Self>;
246
247 /// Get this marker internal id.
248 /// The value of this method should be constant.
249 fn id(&self) -> Self::Identifier;
250
251 /// This gets called when an entity is deserialized by
252 /// `DeserializeComponents`. It can be used to update internal data that
253 /// is not used for identification.
254 ///
255 /// ## Contract
256 ///
257 /// This function may assume that `self.id() == new_revision.id()`.
258 /// However, it must not exhibit undefined behavior in such a case.
259 ///
260 /// ## Panics
261 ///
262 /// May panic if `self.id()` != `new_revision.id()`.
263 ///
264 /// ## Default implementation
265 ///
266 /// The default implementation just sets `self` to `new_revision`.
267 ///
268 /// ## Examples
269 ///
270 /// ```rust,ignore
271 /// #[derive(Clone, Debug, Deserialize, Eq, Hash, Serialize)]
272 /// struct MyMarker {
273 /// id: u64,
274 /// last_modified: String,
275 /// }
276 ///
277 /// impl Marker for MyMarker {
278 /// type Identifier = u64;
279 ///
280 /// fn id(&self) -> u64 {
281 /// self.id
282 /// }
283 ///
284 /// fn update(&self, new: Self) {
285 /// self.last_modified = new.last_modified;
286 /// }
287 /// }
288 /// ```
289 ///
290 /// Now, the marker always contains the name of the client who updated the
291 /// entity associated with this marker.
292 fn update(&mut self, new_revision: Self) {
293 *self = new_revision;
294 }
295}
296
297/// This allocator is used with the `Marker` trait.
298/// It provides a method for allocating new `Marker`s.
299/// It should also provide a `Marker -> Entity` mapping.
300/// The `maintain` method can be implemented for cleanup and actualization.
301/// See docs for `Marker` for an example.
302pub trait MarkerAllocator<M: Marker>: Resource {
303 /// Allocates a new marker for a given entity.
304 /// If you don't pass an id, a new unique id will be created.
305 fn allocate(&mut self, entity: Entity, id: Option<M::Identifier>) -> M;
306
307 /// Get an `Entity` by a marker identifier.
308 /// This function only accepts an id; it does not update the marker data.
309 ///
310 /// Implementors usually maintain a marker -> entity mapping
311 /// and use that to retrieve the entity.
312 fn retrieve_entity_internal(&self, id: M::Identifier) -> Option<Entity>;
313
314 /// Tries to retrieve an entity by the id of the marker;
315 /// if no entity has a marker with the same id, a new entity
316 /// will be created and `marker` will be inserted for it.
317 ///
318 /// In case the entity existed,
319 /// this method will update the marker data using `Marker::update`.
320 fn retrieve_entity(
321 &mut self,
322 marker: M,
323 storage: &mut WriteStorage<M>,
324 entities: &EntitiesRes,
325 ) -> Entity {
326 if let Some(entity) = self.retrieve_entity_internal(marker.id()) {
327 if let Some(mut marker_comp) = storage.get_mut(entity) {
328 marker_comp.access_mut().update(marker);
329
330 return entity;
331 }
332 }
333
334 let entity = entities.create();
335 let marker = self.allocate(entity, Some(marker.id()));
336
337 // It's not possible for this to fail, as there's no way a freshly
338 // created entity could be dead this fast.
339 storage.insert(entity, marker).unwrap();
340 entity
341 }
342
343 /// Create new unique marker `M` and attach it to entity.
344 /// Or get old marker if this entity is already marked.
345 /// If entity is dead then this will return `None`.
346 fn mark<'m>(
347 &mut self,
348 entity: Entity,
349 storage: &'m mut WriteStorage<M>,
350 ) -> Option<(&'m M, bool)> {
351 let new = if let Ok(entry) = storage.entry(entity) {
352 let mut new = false;
353 let _marker = entry.or_insert_with(|| {
354 new = true;
355 self.allocate(entity, None)
356 });
357
358 new
359 } else {
360 return None;
361 };
362 Some((storage.get(entity).unwrap(), new))
363 }
364
365 /// Maintain internal data. Cleanup if necessary.
366 fn maintain(&mut self, _entities: &EntitiesRes, _storage: &ReadStorage<M>);
367}
368
369/// Basic marker implementation usable for saving and loading, uses `u64` as
370/// identifier
371#[derive(Serialize, Deserialize)]
372#[repr(transparent)]
373pub struct SimpleMarker<T: ?Sized>(u64, #[serde(skip)] PhantomData<T>);
374
375impl<T: ?Sized> Clone for SimpleMarker<T> {
376 fn clone(&self) -> Self {
377 *self
378 }
379}
380
381impl<T: ?Sized> Copy for SimpleMarker<T> {}
382
383impl<T: ?Sized> PartialEq for SimpleMarker<T> {
384 fn eq(&self, other: &Self) -> bool {
385 self.0 == other.0
386 }
387}
388
389impl<T: ?Sized> Eq for SimpleMarker<T> {}
390
391impl<T: ?Sized> Hash for SimpleMarker<T> {
392 fn hash<H: Hasher>(&self, state: &mut H) {
393 self.0.hash(state);
394 }
395}
396
397impl<T: ?Sized> Debug for SimpleMarker<T> {
398 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
399 fmt.debug_tuple("SimpleMarker")
400 .field(&self.0)
401 .field(&self.1)
402 .finish()
403 }
404}
405
406impl<T> Component for SimpleMarker<T>
407where
408 T: 'static + ?Sized + Send + Sync,
409{
410 type Storage = DenseVecStorage<Self>;
411}
412
413impl<T> Marker for SimpleMarker<T>
414where
415 T: 'static + ?Sized + Send + Sync,
416{
417 type Allocator = SimpleMarkerAllocator<T>;
418 type Identifier = u64;
419
420 fn id(&self) -> u64 {
421 self.0
422 }
423}
424
425/// Basic marker allocator, uses `u64` as identifier
426pub struct SimpleMarkerAllocator<T: ?Sized> {
427 index: u64,
428 mapping: HashMap<u64, Entity>,
429 _phantom_data: PhantomData<T>,
430}
431
432impl<T: ?Sized> Debug for SimpleMarkerAllocator<T> {
433 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
434 fmt.debug_struct("SimpleMarkerAllocator")
435 .field("index", &self.index)
436 .field("mapping", &self.mapping)
437 .field("_phantom_data", &self._phantom_data)
438 .finish()
439 }
440}
441
442impl<T: ?Sized> Clone for SimpleMarkerAllocator<T> {
443 fn clone(&self) -> Self {
444 Self {
445 index: self.index,
446 mapping: self.mapping.clone(),
447 _phantom_data: PhantomData,
448 }
449 }
450}
451
452impl<T: ?Sized> Default for SimpleMarkerAllocator<T> {
453 fn default() -> Self {
454 Self::new()
455 }
456}
457
458impl<T: ?Sized> SimpleMarkerAllocator<T> {
459 /// Create new `SimpleMarkerAllocator` which will yield `SimpleMarker`s
460 /// starting with `0`
461 pub fn new() -> Self {
462 Self {
463 index: 0,
464 mapping: HashMap::new(),
465 _phantom_data: PhantomData,
466 }
467 }
468}
469
470impl<T> MarkerAllocator<SimpleMarker<T>> for SimpleMarkerAllocator<T>
471where
472 T: 'static + ?Sized + Send + Sync,
473{
474 fn allocate(&mut self, entity: Entity, id: Option<u64>) -> SimpleMarker<T> {
475 let marker = if let Some(id) = id {
476 if id >= self.index {
477 self.index = id + 1;
478 }
479 SimpleMarker(id, PhantomData)
480 } else {
481 self.index += 1;
482 SimpleMarker(self.index - 1, PhantomData)
483 };
484 self.mapping.insert(marker.id(), entity);
485
486 marker
487 }
488
489 fn retrieve_entity_internal(&self, id: u64) -> Option<Entity> {
490 self.mapping.get(&id).cloned()
491 }
492
493 fn maintain(&mut self, entities: &EntitiesRes, storage: &ReadStorage<SimpleMarker<T>>) {
494 // FIXME: may be too slow
495 self.mapping = (entities, storage)
496 .join()
497 .map(|(e, m)| (m.id(), e))
498 .collect();
499 }
500}