bones_ecs/
world.rs

1//! Contains the ECS [`World`].
2
3use crate::prelude::*;
4
5/// The [`World`] is simply a collection of [`Resources`], and [`ComponentStores`].
6///
7/// Also stored in the world is the [`Entities`], but it is stored as a resource.
8///
9/// [`World`] is designed to be trivially [`Clone`]ed to allow for snapshotting the world state. The
10/// is especially useful in the context of rollback networking, which requires the ability to
11/// snapshot and restore state.
12#[derive(Clone)]
13pub struct World {
14    /// Stores the world resources.
15    pub resources: Resources,
16    /// Stores the world components.
17    pub components: ComponentStores,
18}
19impl std::fmt::Debug for World {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        f.debug_struct("World").finish()
22    }
23}
24
25impl Default for World {
26    fn default() -> Self {
27        let resources = Resources::new();
28
29        // Always initialize an Entities resource
30        resources.insert(Entities::default());
31
32        Self {
33            resources,
34            components: Default::default(),
35        }
36    }
37}
38
39impl World {
40    /// Create a new [`World`].
41    pub fn new() -> Self {
42        Self::default()
43    }
44
45    /// Create a new world that uses the provided entities resource.
46    ///
47    /// This allows multiple worlds to avoid allocating the same entity IDs.
48    pub fn with_entities(entities: AtomicResource<Entities>) -> Self {
49        let resources = Resources::new();
50        resources
51            .untyped()
52            .insert_cell(entities.into_untyped())
53            .unwrap();
54        World {
55            resources,
56            components: default(),
57        }
58    }
59
60    /// Remove the component info for dead entities.
61    ///
62    /// This should be called every game frame to cleanup entities that have been killed.
63    ///
64    /// This will remove the component storage for all killed entities, and allow their slots to be
65    /// re-used for any new entities.
66    pub fn maintain(&self) {
67        let mut entities = self.resource_mut::<Entities>();
68        for components in self.components.components.read_only_view().values() {
69            let mut components = components.borrow_mut();
70            let killed = entities.killed();
71            for &entity in killed {
72                // Safe: We don't provide an out pointer, so it doesn't overlap the component's
73                // internal storage.
74                unsafe {
75                    components.remove_raw(entity, None);
76                }
77            }
78        }
79        entities.clear_killed();
80    }
81
82    /// Run a system once.
83    ///
84    /// This is good for initializing the world with setup systems.
85    pub fn run_system<'system, R, In, Out, S>(&self, system: S, input: In) -> Out
86    where
87        In: 'system,
88        Out: 'system,
89        S: IntoSystem<R, In, Out>,
90        S::Sys: 'system,
91    {
92        let mut s = system.system();
93        s.run(self, input)
94    }
95
96    /// Get an entity's components.
97    ///
98    /// # Panics
99    ///
100    /// Panics if the entity does not have the required components from the query.
101    pub fn entity_components<Q: QueryItem>(
102        &self,
103        entity: Entity,
104        query: Q,
105    ) -> <Q::Iter as Iterator>::Item {
106        self.get_entity_components(entity, query).unwrap()
107    }
108
109    /// Get an entity's components.
110    pub fn get_entity_components<Q: QueryItem>(
111        &self,
112        entity: Entity,
113        query: Q,
114    ) -> Option<<Q::Iter as Iterator>::Item> {
115        let mut bitset = BitSetVec::default();
116        if self.resource::<Entities>().bitset().contains(entity) {
117            bitset.set(entity);
118        }
119        query.apply_bitset(&mut bitset);
120        match query.get_single_with_bitset(bitset.into()) {
121            Ok(components) => Some(components),
122            Err(QuerySingleError::NoEntities) => None,
123            Err(QuerySingleError::MultipleEntities) => {
124                panic!(
125                    "Query returned a MultipleEntities error for a bitset that \
126                    contains at most one enabled bit"
127                )
128            }
129        }
130    }
131
132    /// Initialize a resource of type `T` by inserting it's default value.
133    pub fn init_resource<R: HasSchema + FromWorld>(&self) -> RefMut<'_, R> {
134        if unlikely(!self.resources.contains::<R>()) {
135            let value = R::from_world(self);
136            self.resources.insert(value);
137        }
138        self.resource_mut()
139    }
140
141    /// Insert a resource, replacing it if it already exists.
142    pub fn insert_resource<R: HasSchema>(&self, resource: R) -> Option<R> {
143        self.resources.insert(resource)
144    }
145
146    /// Borrow a resource from the world.
147    /// # Panics
148    /// Panics if the resource does not exist in the store.
149    #[track_caller]
150    pub fn resource<T: HasSchema>(&self) -> Ref<'_, T> {
151        match self.resources.get::<T>() {
152            Some(r) => r,
153            None => panic!(
154                "Requested resource {} does not exist in the `World`. \
155                Did you forget to add it using `world.insert_resource` / `world.init_resource`?",
156                std::any::type_name::<T>()
157            ),
158        }
159    }
160
161    /// Borrow a resource from the world.
162    /// # Panics
163    /// Panics if the resource does not exist in the store.
164    #[track_caller]
165    pub fn resource_mut<T: HasSchema>(&self) -> RefMut<'_, T> {
166        match self.resources.get_mut::<T>() {
167            Some(r) => r,
168            None => panic!(
169                "Requested resource {} does not exist in the `World`. \
170                Did you forget to add it using `world.insert_resource` / `world.init_resource`?",
171                std::any::type_name::<T>()
172            ),
173        }
174    }
175
176    /// Borrow a resource from the world, if it exists.
177    pub fn get_resource<T: HasSchema>(&self) -> Option<Ref<'_, T>> {
178        self.resources.get()
179    }
180
181    /// Borrow a resource from the world, if it exists.
182    pub fn get_resource_mut<T: HasSchema>(&self) -> Option<RefMut<'_, T>> {
183        self.resources.get_mut()
184    }
185
186    /// Removes all resources that are not shared. Shared resources are preserved.
187    pub fn clear_owned_resources(&self) {
188        self.resources.clear_owned_resources();
189    }
190
191    /// Iterates through owned and shared resource cells removing them if the predicate returns `false`.
192    ///
193    /// See also: [`Self::retain_owned_resources`].
194    pub fn retain_resources<F>(&self, predicate: F)
195    where
196        F: FnMut(SchemaId) -> bool,
197    {
198        self.resources.untyped().retain_resources(predicate);
199    }
200
201    /// Iterates through resource cells removing them if the predicate returns `false`.
202    ///
203    /// Doesn't include shared resources. See also: [`Self::retain_resources`].
204    pub fn retain_owned_resources<F>(&self, predicate: F)
205    where
206        F: FnMut(SchemaId) -> bool,
207    {
208        self.resources.untyped().retain_owned_resources(predicate);
209    }
210
211    /// Borrow a component store from the world.
212    /// # Panics
213    /// Panics if the component store does not exist in the world.
214    #[track_caller]
215    pub fn component<T: HasSchema>(&self) -> Ref<'_, ComponentStore<T>> {
216        self.components.get::<T>().borrow()
217    }
218
219    /// Mutably borrow a component store from the world.
220    /// # Panics
221    /// Panics if the component store does not exist in the world.
222    #[track_caller]
223    pub fn component_mut<T: HasSchema>(&self) -> RefMut<'_, ComponentStore<T>> {
224        self.components.get::<T>().borrow_mut()
225    }
226
227    /// Load snapshot of [`World`] into self.
228    pub fn load_snapshot(&mut self, snapshot: World) {
229        self.components = snapshot.components;
230        self.resources = snapshot.resources;
231    }
232}
233
234/// Creates an instance of the type this trait is implemented for
235/// using data from the supplied [`World`].
236///
237/// This can be helpful for complex initialization or context-aware defaults.
238pub trait FromWorld {
239    /// Creates `Self` using data from the given [`World`].
240    fn from_world(world: &World) -> Self;
241}
242
243impl<T: Default> FromWorld for T {
244    fn from_world(_world: &World) -> Self {
245        T::default()
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    use crate::prelude::*;
252
253    use super::FromWorld;
254
255    #[derive(Clone, Copy, HasSchema, Debug, Eq, PartialEq, Default)]
256    #[repr(C)]
257    struct C(u32);
258
259    #[derive(Clone, HasSchema, Debug, Eq, PartialEq, Default)]
260    #[repr(C)]
261    struct Pos(i32, i32);
262
263    #[derive(Clone, HasSchema, Debug, Eq, PartialEq, Default)]
264    #[repr(C)]
265    struct Vel(i32, i32);
266
267    #[derive(Clone, HasSchema, Debug, Eq, PartialEq, Default)]
268    struct Marker;
269
270    // Sets up the world with a couple entities.
271    fn setup_world(
272        mut entities: ResMut<Entities>,
273        mut pos_comps: CompMut<Pos>,
274        mut vel_comps: CompMut<Vel>,
275        mut marker_comps: CompMut<Marker>,
276    ) {
277        let ent1 = entities.create();
278        pos_comps.insert(ent1, Pos(0, 100));
279        vel_comps.insert(ent1, Vel(0, -1));
280
281        let ent2 = entities.create();
282        pos_comps.insert(ent2, Pos(0, 0));
283        vel_comps.insert(ent2, Vel(1, 1));
284        marker_comps.insert(ent2, Marker);
285    }
286
287    /// Mutates the positions based on the velocities.
288    fn pos_vel_system(entities: Res<Entities>, mut pos: CompMut<Pos>, vel: Comp<Vel>) {
289        for (_, (pos, vel)) in entities.iter_with((&mut pos, &vel)) {
290            pos.0 += vel.0;
291            pos.1 += vel.1;
292        }
293    }
294
295    /// Tests that the world's components matches the state it should after running `setup_world`.
296    fn test_after_setup_state(
297        entities: Res<Entities>,
298        pos: Comp<Pos>,
299        vel: Comp<Vel>,
300        marker: Comp<Marker>,
301    ) {
302        let mut i = 0;
303        for (entity, (pos, vel)) in entities.iter_with((&pos, &vel)) {
304            let marker = marker.get(entity);
305            match (i, pos, vel, marker) {
306                (0, Pos(0, 100), Vel(0, -1), None) | (1, Pos(0, 0), Vel(1, 1), Some(Marker)) => (),
307                x => unreachable!("{:?}", x),
308            }
309            i += 1;
310        }
311        assert_eq!(i, 2);
312    }
313
314    /// Tests that the worlds components matches the state it should after running the
315    /// pos_vel_system one time.
316    fn test_pos_vel_1_run(
317        entities: Res<Entities>,
318        pos: Comp<Pos>,
319        vel: Comp<Vel>,
320        marker: Comp<Marker>,
321    ) {
322        let mut i = 0;
323        for (entity, (pos, vel)) in entities.iter_with((&pos, &vel)) {
324            let marker = marker.get(entity);
325            match (i, pos, vel, marker) {
326                (0, Pos(0, 99), Vel(0, -1), None) | (1, Pos(1, 1), Vel(1, 1), Some(Marker)) => (),
327                x => unreachable!("{:?}", x),
328            }
329            i += 1;
330        }
331        assert_eq!(i, 2);
332    }
333
334    #[test]
335    fn sanity_check() {
336        let world = World::new();
337
338        world.run_system(setup_world, ());
339
340        // Make sure our entities exist visit properly during iteration
341        let test = || {};
342        world.run_system(test, ());
343
344        // Mutate and read some components
345        world.run_system(pos_vel_system, ());
346
347        // Make sure the mutations were applied
348        world.run_system(test_pos_vel_1_run, ());
349    }
350
351    #[test]
352    fn snapshot() {
353        let world1 = World::new();
354        world1.run_system(setup_world, ());
355
356        // Snapshot world1
357        let snap = world1.clone();
358
359        // Make sure the snapshot represents world1's state
360        snap.run_system(test_after_setup_state, ());
361
362        // Run the pos_vel system on world1
363        world1.run_system(pos_vel_system, ());
364
365        // Make sure world1 has properly update
366        world1.run_system(test_pos_vel_1_run, ());
367
368        // Make sure the snapshot hasn't changed
369        snap.run_system(test_after_setup_state, ());
370
371        // Run the pos vel system once on the snapshot
372        snap.run_system(pos_vel_system, ());
373
374        // Make sure the snapshot has updated
375        world1.run_system(test_pos_vel_1_run, ());
376    }
377
378    #[test]
379    fn world_is_send() {
380        fn send<T: Send>(_: T) {}
381        send(World::new())
382    }
383
384    #[test]
385    fn get_entity_components() {
386        let w = World::default();
387
388        let (e1, e2) = {
389            let mut entities = w.resource_mut::<Entities>();
390            (entities.create(), entities.create())
391        };
392
393        let state = w.components.get::<C>();
394        let mut comp = state.borrow_mut();
395
396        let c2 = C(2);
397        comp.insert(e2, c2);
398
399        assert_eq!(w.get_entity_components(e1, &comp), None);
400        assert_eq!(w.get_entity_components(e2, &comp), Some(&c2));
401    }
402
403    // ============
404    //  From World
405    // ============
406
407    #[derive(Clone, HasSchema, Default)]
408    struct TestResource(u32);
409
410    #[derive(Clone, HasSchema)]
411    #[schema(opaque, no_default)]
412    struct TestFromWorld(u32);
413    impl FromWorld for TestFromWorld {
414        fn from_world(world: &World) -> Self {
415            let b = world.resource::<TestResource>();
416            Self(b.0)
417        }
418    }
419
420    #[test]
421    fn init_resource_does_not_overwrite() {
422        let w = World::default();
423        w.insert_resource(TestResource(0));
424        w.init_resource::<TestFromWorld>();
425        w.insert_resource(TestResource(1));
426
427        let resource = w.resource::<TestFromWorld>();
428        assert_eq!(resource.0, 0);
429    }
430}