use bevy::prelude::*;
use crossbeam::channel::{Receiver, Sender};
use std::sync::Arc;
struct AutoDespawnSignalInner
{
entity: Entity,
sender: Sender<Entity>,
}
impl Drop for AutoDespawnSignalInner
{
fn drop(&mut self)
{
let _ = self.sender.send(self.entity);
}
}
pub fn garbage_collect_entities(world: &mut World)
{
while let Some(entity) = world.resource::<AutoDespawner>().try_recv()
{
world.get_entity_mut(entity).ok().map(|e| e.despawn_recursive());
}
}
#[derive(Resource, Clone)]
pub struct AutoDespawner
{
sender: Sender<Entity>,
receiver: Receiver<Entity>,
}
impl AutoDespawner
{
fn new() -> Self
{
let (sender, receiver) = crossbeam::channel::unbounded();
Self{ sender, receiver }
}
pub fn prepare(&self, entity: Entity) -> AutoDespawnSignal
{
AutoDespawnSignal::new(entity, self.sender.clone())
}
pub(crate) fn try_recv(&self) -> Option<Entity>
{
self.receiver.try_recv().ok()
}
}
pub struct AutoDespawnSignal(Arc<AutoDespawnSignalInner>);
impl AutoDespawnSignal
{
fn new(entity: Entity, sender: Sender<Entity>) -> Self
{
Self(Arc::new(AutoDespawnSignalInner{ entity, sender }))
}
pub fn entity(&self) -> Entity
{
self.0.entity
}
}
impl Clone for AutoDespawnSignal
{
fn clone(&self) -> Self { Self(self.0.clone()) }
}
#[derive(SystemSet, Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct AutoDespawnSet;
pub trait AutoDespawnAppExt
{
fn setup_auto_despawn(&mut self) -> &mut Self;
}
impl AutoDespawnAppExt for App
{
fn setup_auto_despawn(&mut self) -> &mut Self
{
if self.world().contains_resource::<AutoDespawner>() { return self; }
self.insert_resource(AutoDespawner::new())
.add_systems(Last, garbage_collect_entities.in_set(AutoDespawnSet))
}
}