Skip to main content

pebble/ecs/
resources.rs

1use std::cell::{RefCell, RefMut};
2
3/// Container for singleton resources stored inside the ECS world.
4///
5/// All resources live on a single hidden entity so they participate in the
6/// same borrow-checking rules as regular components. [`Resources`] is passed
7/// to every system alongside the [`hecs::World`].
8pub struct Resources {
9    pub(crate) resource_entity: hecs::Entity,
10    cmds: RefCell<hecs::CommandBuffer>,
11}
12
13impl Resources {
14    /// Create a new `Resources` container, spawning the internal resource entity.
15    pub fn new(world: &mut hecs::World) -> Self {
16        Self {
17            resource_entity: world.spawn(()),
18            cmds: RefCell::new(hecs::CommandBuffer::default()),
19        }
20    }
21
22    /// Insert or replace a resource of type `T`.
23    pub fn insert_resource<T>(&mut self, world: &mut hecs::World, res: T)
24    where
25        T: hecs::Component,
26    {
27        world.insert_one(self.resource_entity, res).ok();
28    }
29
30    /// Borrow resource `T`, panicking if it is not present.
31    pub fn get_resource<'a, T>(&self, world: &'a hecs::World) -> hecs::Ref<'a, T>
32    where
33        T: hecs::Component,
34    {
35        world
36            .get::<&T>(self.resource_entity)
37            .unwrap_or_else(|_| panic!("Resource not found: {}", std::any::type_name::<T>()))
38    }
39
40    /// Mutably borrow resource `T`, panicking if it is not present.
41    pub fn get_resource_mut<'a, T>(&self, world: &'a hecs::World) -> hecs::RefMut<'a, T>
42    where
43        T: hecs::Component,
44    {
45        world
46            .get::<&mut T>(self.resource_entity)
47            .unwrap_or_else(|_| panic!("Resource not found: {}", std::any::type_name::<T>()))
48    }
49
50    /// Returns `true` if resource `T` is currently present.
51    pub fn has_resource<T>(&self, world: &hecs::World) -> bool
52    where
53        T: hecs::Component,
54    {
55        if let Ok(_) = world.get::<&T>(self.resource_entity) {
56            return true;
57        }
58
59        false
60    }
61
62    /// Borrow the shared command buffer used to defer world mutations.
63    pub fn get_command_buffer<'a>(&'a self) -> RefMut<'a, hecs::CommandBuffer> {
64        self.cmds.borrow_mut()
65    }
66
67    /// Insert resource `T` only if it is not already present.
68    ///
69    /// Returns `true` if the resource was inserted, `false` if it already existed.
70    pub fn try_insert<T>(&mut self, world: &mut hecs::World, res: T) -> bool
71    where
72        T: hecs::Component,
73    {
74        if self.has_resource::<T>(world) {
75            false
76        } else {
77            world.insert_one(self.resource_entity, res).ok();
78            true
79        }
80    }
81}