bones_lib/
reset.rs

1//! Conveniences for resetting a World to its' default state.
2use crate::prelude::*;
3
4/// Convenience type for selecting resources to keep before clearing the
5/// components, entities, and resources on a [`World`].
6///  ```ignore
7/// ResetWorld::standard()
8///     .keep::<Scoreboard>()
9///     .keep::<WritingRust>()
10///     .keep::<TheBugsAway>()
11///     .reset(world);
12/// ```
13/// Reseting the world should likely be the first call in your systems when
14/// applicable so that components are rendered continuously without disappearing
15/// for a frame before respawning world startup components.
16///
17/// You can create the type with [`Self::standard`], which is recommended for
18/// keeping certain special resources like [`SessionOptions`] & [`Entities`] on
19/// creation, or you can use [`Self::empty`] to create a new type that won't
20/// keep any resources on creation.
21///
22/// To add more resources to the list you can use [`self.keep`](Self::keep) with
23/// the specified type, no data needed, and chain the methods like the example
24/// above.
25///
26/// Uses a [`HashSet`] of [`SchemaId`] to determine the resources that will not
27/// be removed from the world on reset.
28#[derive(HasSchema, Default, Clone, Deref, DerefMut)]
29pub struct ResetWorld(pub HashSet<SchemaId>);
30
31impl ResetWorld {
32    /// Create a [`ResetWorld`] with no resources kept as opposed to the
33    /// [`Self::standard`] which keeps certain special resources on creation.
34    pub fn empty() -> Self {
35        Self(HashSet::default())
36    }
37    /// Create a [`ResetWorld`] that already keeps some basic special resources
38    /// that are usually needed like [`SessionOptions`] & [`Entities`].
39    pub fn standard() -> Self {
40        Self::empty()
41            // Even though Entities is completely cleared on reset, it is always
42            // expected everywhere so we can't remove it from the World.
43            .keep::<Entities>()
44            // SessionOptions is re-inserted every frame, but may still be
45            // wanted right after reset and is expected in `Game` right now.
46            .keep::<SessionOptions>()
47    }
48    /// Adds the [`SchemaId`] of the type given to the set of resources to keep
49    /// on reset.
50    ///
51    /// Returns `Self` to allow chaining the method:
52    /// ```ignore
53    /// Self::standard()
54    ///     .keep::<Scoreboard>()
55    ///     .keep::<WritingRust>()
56    ///     .keep::<TheBugsAway>()
57    ///     .reset(world);
58    /// ```
59    pub fn keep<T: HasSchema>(mut self) -> Self {
60        self.insert(T::schema().id());
61        self
62    }
63    /// Reset the given [`World`], clearing resources that are not included in
64    /// `self` as well as components and entities.
65    pub fn reset(self, world: &World) {
66        world.resource_mut::<Entities>().kill_all(); // `kill_all` for component clearing
67        world.maintain(); // clear components
68        *world.resource_mut::<Entities>() = Entities::default(); // fully reset entities
69        world.retain_owned_resources(|schema_id| self.contains(&schema_id));
70    }
71    /// Reset the given [`World`]'s resources that are not included in `self`.
72    pub fn reset_resources(self, world: &World) {
73        world.retain_owned_resources(|schema_id| self.contains(&schema_id));
74    }
75}