use std::cell::{Cell, RefCell, RefMut};
thread_local! {
static CURRENT_SYSTEM: Cell<Option<&'static str>> = Cell::new(None);
}
pub(crate) struct CurrentSystemGuard(Option<&'static str>);
impl Drop for CurrentSystemGuard {
fn drop(&mut self) {
CURRENT_SYSTEM.with(|c| c.set(self.0));
}
}
pub(crate) fn set_current_system(name: &'static str) -> CurrentSystemGuard {
let previous = CURRENT_SYSTEM.with(|c| c.replace(Some(name)));
CurrentSystemGuard(previous)
}
fn current_system_suffix() -> String {
CURRENT_SYSTEM.with(|c| match c.get() {
Some(name) => format!(" (while running system `{name}`)"),
None => String::new(),
})
}
pub struct Resources {
pub(crate) resource_entity: hecs::Entity,
cmds: RefCell<hecs::CommandBuffer>,
generation: Cell<u64>,
}
impl Resources {
pub fn new(world: &mut hecs::World) -> Self {
Self {
resource_entity: world.spawn(()),
cmds: RefCell::new(hecs::CommandBuffer::default()),
generation: Cell::new(0),
}
}
pub fn insert_resource<T>(&mut self, world: &mut hecs::World, res: T)
where
T: hecs::Component,
{
world.insert_one(self.resource_entity, res).ok();
self.generation.set(self.generation.get() + 1);
}
pub fn get_resource<'a, T>(&self, world: &'a hecs::World) -> hecs::Ref<'a, T>
where
T: hecs::Component,
{
world.get::<&T>(self.resource_entity).unwrap_or_else(|_| {
panic!(
"Resource not found: {}{}",
std::any::type_name::<T>(),
current_system_suffix()
)
})
}
pub fn get_resource_mut<'a, T>(&self, world: &'a hecs::World) -> hecs::RefMut<'a, T>
where
T: hecs::Component,
{
world.get::<&mut T>(self.resource_entity).unwrap_or_else(|_| {
panic!(
"Resource not found: {}{}",
std::any::type_name::<T>(),
current_system_suffix()
)
})
}
pub fn has_resource<T>(&self, world: &hecs::World) -> bool
where
T: hecs::Component,
{
if let Ok(_) = world.get::<&T>(self.resource_entity) {
return true;
}
false
}
pub fn get_command_buffer<'a>(&'a self) -> RefMut<'a, hecs::CommandBuffer> {
self.cmds.borrow_mut()
}
pub fn try_insert<T>(&mut self, world: &mut hecs::World, res: T) -> bool
where
T: hecs::Component,
{
if self.has_resource::<T>(world) {
return false;
}
world.insert_one(self.resource_entity, res).ok();
self.generation.set(self.generation.get() + 1);
true
}
pub fn generation(&self) -> u64 {
self.generation.get()
}
pub(crate) fn bump_generation(&self) {
self.generation.set(self.generation.get() + 1);
}
}