2020-07-17 02:20:51 +00:00
|
|
|
use super::SystemId;
|
|
|
|
use crate::resource::{Resource, Resources};
|
2020-09-18 00:16:38 +00:00
|
|
|
use bevy_hecs::{Bundle, Component, DynamicBundle, Entity, EntityReserver, World};
|
2020-11-08 20:34:05 +00:00
|
|
|
use std::marker::PhantomData;
|
2020-10-08 18:43:01 +00:00
|
|
|
|
2020-08-09 23:13:04 +00:00
|
|
|
/// A [World] mutation
|
2020-10-18 20:48:15 +00:00
|
|
|
pub trait Command: Send + Sync {
|
|
|
|
fn write(self: Box<Self>, world: &mut World, resources: &mut Resources);
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
2020-10-08 18:43:01 +00:00
|
|
|
#[derive(Debug)]
|
2020-08-09 23:13:04 +00:00
|
|
|
pub(crate) struct Spawn<T>
|
2020-07-10 04:18:35 +00:00
|
|
|
where
|
|
|
|
T: DynamicBundle + Send + Sync + 'static,
|
|
|
|
{
|
|
|
|
components: T,
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
impl<T> Command for Spawn<T>
|
2020-07-10 04:18:35 +00:00
|
|
|
where
|
|
|
|
T: DynamicBundle + Send + Sync + 'static,
|
|
|
|
{
|
2020-10-18 20:48:15 +00:00
|
|
|
fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) {
|
2020-07-10 04:18:35 +00:00
|
|
|
world.spawn(self.components);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-09 23:13:04 +00:00
|
|
|
pub(crate) struct SpawnBatch<I>
|
2020-07-10 04:18:35 +00:00
|
|
|
where
|
|
|
|
I: IntoIterator,
|
|
|
|
I::Item: Bundle,
|
|
|
|
{
|
|
|
|
components_iter: I,
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
impl<I> Command for SpawnBatch<I>
|
2020-07-10 04:18:35 +00:00
|
|
|
where
|
|
|
|
I: IntoIterator + Send + Sync,
|
|
|
|
I::Item: Bundle,
|
|
|
|
{
|
2020-10-18 20:48:15 +00:00
|
|
|
fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) {
|
2020-07-10 04:18:35 +00:00
|
|
|
world.spawn_batch(self.components_iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-08 18:43:01 +00:00
|
|
|
#[derive(Debug)]
|
2020-08-09 23:13:04 +00:00
|
|
|
pub(crate) struct Despawn {
|
2020-07-10 04:18:35 +00:00
|
|
|
entity: Entity,
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
impl Command for Despawn {
|
|
|
|
fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) {
|
2020-10-08 23:58:19 +00:00
|
|
|
if let Err(e) = world.despawn(self.entity) {
|
|
|
|
log::debug!("Failed to despawn entity {:?}: {}", self.entity, e);
|
|
|
|
}
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Insert<T>
|
|
|
|
where
|
|
|
|
T: DynamicBundle + Send + Sync + 'static,
|
|
|
|
{
|
|
|
|
entity: Entity,
|
|
|
|
components: T,
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
impl<T> Command for Insert<T>
|
2020-07-10 04:18:35 +00:00
|
|
|
where
|
|
|
|
T: DynamicBundle + Send + Sync + 'static,
|
|
|
|
{
|
2020-10-18 20:48:15 +00:00
|
|
|
fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) {
|
2020-07-10 04:18:35 +00:00
|
|
|
world.insert(self.entity, self.components).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-08 18:43:01 +00:00
|
|
|
#[derive(Debug)]
|
2020-08-09 23:13:04 +00:00
|
|
|
pub(crate) struct InsertOne<T>
|
2020-07-10 04:18:35 +00:00
|
|
|
where
|
|
|
|
T: Component,
|
|
|
|
{
|
|
|
|
entity: Entity,
|
|
|
|
component: T,
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
impl<T> Command for InsertOne<T>
|
2020-07-10 04:18:35 +00:00
|
|
|
where
|
|
|
|
T: Component,
|
|
|
|
{
|
2020-10-18 20:48:15 +00:00
|
|
|
fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) {
|
2020-07-10 04:18:35 +00:00
|
|
|
world.insert(self.entity, (self.component,)).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-08 18:43:01 +00:00
|
|
|
#[derive(Debug)]
|
2020-08-13 23:38:38 +00:00
|
|
|
pub(crate) struct RemoveOne<T>
|
|
|
|
where
|
|
|
|
T: Component,
|
|
|
|
{
|
|
|
|
entity: Entity,
|
|
|
|
phantom: PhantomData<T>,
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
impl<T> Command for RemoveOne<T>
|
2020-08-13 23:38:38 +00:00
|
|
|
where
|
|
|
|
T: Component,
|
|
|
|
{
|
2020-10-18 20:48:15 +00:00
|
|
|
fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) {
|
2020-08-13 23:38:38 +00:00
|
|
|
if world.get::<T>(self.entity).is_ok() {
|
|
|
|
world.remove_one::<T>(self.entity).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-08 18:43:01 +00:00
|
|
|
#[derive(Debug)]
|
2020-09-26 21:27:56 +00:00
|
|
|
pub(crate) struct Remove<T>
|
|
|
|
where
|
|
|
|
T: Bundle + Send + Sync + 'static,
|
|
|
|
{
|
|
|
|
entity: Entity,
|
|
|
|
phantom: PhantomData<T>,
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
impl<T> Command for Remove<T>
|
2020-09-26 21:27:56 +00:00
|
|
|
where
|
|
|
|
T: Bundle + Send + Sync + 'static,
|
|
|
|
{
|
2020-10-18 20:48:15 +00:00
|
|
|
fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) {
|
2020-09-26 21:27:56 +00:00
|
|
|
world.remove::<T>(self.entity).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 04:18:35 +00:00
|
|
|
pub trait ResourcesWriter: Send + Sync {
|
|
|
|
fn write(self: Box<Self>, resources: &mut Resources);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct InsertResource<T: Resource> {
|
|
|
|
resource: T,
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
impl<T: Resource> Command for InsertResource<T> {
|
|
|
|
fn write(self: Box<Self>, _world: &mut World, resources: &mut Resources) {
|
2020-07-10 04:18:35 +00:00
|
|
|
resources.insert(self.resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-08 18:43:01 +00:00
|
|
|
#[derive(Debug)]
|
2020-08-09 23:13:04 +00:00
|
|
|
pub(crate) struct InsertLocalResource<T: Resource> {
|
2020-07-10 04:18:35 +00:00
|
|
|
resource: T,
|
|
|
|
system_id: SystemId,
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
impl<T: Resource> Command for InsertLocalResource<T> {
|
|
|
|
fn write(self: Box<Self>, _world: &mut World, resources: &mut Resources) {
|
2020-07-10 04:18:35 +00:00
|
|
|
resources.insert_local(self.system_id, self.resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
#[derive(Default)]
|
2020-11-08 20:34:05 +00:00
|
|
|
pub struct Commands {
|
|
|
|
commands: Vec<Box<dyn Command>>,
|
|
|
|
current_entity: Option<Entity>,
|
|
|
|
entity_reserver: Option<EntityReserver>,
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
impl Commands {
|
2020-07-10 04:18:35 +00:00
|
|
|
pub fn spawn(&mut self, components: impl DynamicBundle + Send + Sync + 'static) -> &mut Self {
|
2020-09-18 00:16:38 +00:00
|
|
|
let entity = self
|
|
|
|
.entity_reserver
|
|
|
|
.as_ref()
|
|
|
|
.expect("entity reserver has not been set")
|
|
|
|
.reserve_entity();
|
2020-07-10 04:18:35 +00:00
|
|
|
self.current_entity = Some(entity);
|
2020-10-18 20:48:15 +00:00
|
|
|
self.commands.push(Box::new(Insert { entity, components }));
|
2020-07-10 04:18:35 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn spawn_batch<I>(&mut self, components_iter: I) -> &mut Self
|
|
|
|
where
|
|
|
|
I: IntoIterator + Send + Sync + 'static,
|
|
|
|
I::Item: Bundle,
|
|
|
|
{
|
2020-10-18 20:48:15 +00:00
|
|
|
self.add_command(SpawnBatch { components_iter })
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
2020-07-27 22:10:32 +00:00
|
|
|
/// Despawns only the specified entity, ignoring any other consideration.
|
2020-07-10 04:18:35 +00:00
|
|
|
pub fn despawn(&mut self, entity: Entity) -> &mut Self {
|
2020-10-18 20:48:15 +00:00
|
|
|
self.add_command(Despawn { entity })
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert(
|
|
|
|
&mut self,
|
|
|
|
entity: Entity,
|
|
|
|
components: impl DynamicBundle + Send + Sync + 'static,
|
|
|
|
) -> &mut Self {
|
2020-10-18 20:48:15 +00:00
|
|
|
self.add_command(Insert { entity, components })
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert_one(&mut self, entity: Entity, component: impl Component) -> &mut Self {
|
2020-10-18 20:48:15 +00:00
|
|
|
self.add_command(InsertOne { entity, component })
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert_resource<T: Resource>(&mut self, resource: T) -> &mut Self {
|
2020-10-18 20:48:15 +00:00
|
|
|
self.add_command(InsertResource { resource })
|
2020-07-23 20:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert_local_resource<T: Resource>(
|
|
|
|
&mut self,
|
|
|
|
system_id: SystemId,
|
|
|
|
resource: T,
|
|
|
|
) -> &mut Self {
|
2020-10-18 20:48:15 +00:00
|
|
|
self.add_command(InsertLocalResource {
|
2020-07-23 20:07:45 +00:00
|
|
|
system_id,
|
|
|
|
resource,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
pub fn remove_one<T>(&mut self, entity: Entity) -> &mut Self
|
|
|
|
where
|
|
|
|
T: Component,
|
|
|
|
{
|
|
|
|
self.add_command(RemoveOne::<T> {
|
|
|
|
entity,
|
|
|
|
phantom: PhantomData,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove<T>(&mut self, entity: Entity) -> &mut Self
|
|
|
|
where
|
|
|
|
T: Bundle + Send + Sync + 'static,
|
|
|
|
{
|
|
|
|
self.add_command(Remove::<T> {
|
|
|
|
entity,
|
|
|
|
phantom: PhantomData,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn with_bundle(
|
|
|
|
&mut self,
|
|
|
|
components: impl DynamicBundle + Send + Sync + 'static,
|
|
|
|
) -> &mut Self {
|
|
|
|
let current_entity = self.current_entity.expect("Cannot add components because the 'current entity' is not set. You should spawn an entity first.");
|
|
|
|
self.commands.push(Box::new(Insert {
|
|
|
|
entity: current_entity,
|
|
|
|
components,
|
|
|
|
}));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn with(&mut self, component: impl Component) -> &mut Self {
|
|
|
|
let current_entity = self.current_entity.expect("Cannot add component because the 'current entity' is not set. You should spawn an entity first.");
|
|
|
|
self.commands.push(Box::new(InsertOne {
|
|
|
|
entity: current_entity,
|
|
|
|
component,
|
|
|
|
}));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
pub fn add_command<C: Command + 'static>(&mut self, command: C) -> &mut Self {
|
2020-11-08 20:34:05 +00:00
|
|
|
self.commands.push(Box::new(command));
|
2020-07-10 04:18:35 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:48:15 +00:00
|
|
|
pub fn add_command_boxed(&mut self, command: Box<dyn Command>) -> &mut Self {
|
2020-11-08 20:34:05 +00:00
|
|
|
self.commands.push(command);
|
2020-07-10 04:18:35 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
pub fn apply(&mut self, world: &mut World, resources: &mut Resources) {
|
|
|
|
for command in self.commands.drain(..) {
|
2020-10-18 20:48:15 +00:00
|
|
|
command.write(world, resources);
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-24 00:32:53 +00:00
|
|
|
|
|
|
|
pub fn current_entity(&self) -> Option<Entity> {
|
2020-11-08 20:34:05 +00:00
|
|
|
self.current_entity
|
2020-07-24 00:32:53 +00:00
|
|
|
}
|
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
pub fn set_current_entity(&mut self, entity: Entity) {
|
|
|
|
self.current_entity = Some(entity);
|
2020-07-24 00:32:53 +00:00
|
|
|
}
|
2020-08-13 23:38:38 +00:00
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
pub fn clear_current_entity(&mut self) {
|
|
|
|
self.current_entity = None;
|
2020-09-26 21:27:56 +00:00
|
|
|
}
|
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
pub fn for_current_entity(&mut self, f: impl FnOnce(Entity)) -> &mut Self {
|
|
|
|
let current_entity = self
|
|
|
|
.current_entity
|
|
|
|
.expect("The 'current entity' is not set. You should spawn an entity first.");
|
|
|
|
f(current_entity);
|
|
|
|
self
|
2020-08-13 23:38:38 +00:00
|
|
|
}
|
2020-09-18 00:16:38 +00:00
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
pub fn set_entity_reserver(&mut self, entity_reserver: EntityReserver) {
|
|
|
|
self.entity_reserver = Some(entity_reserver);
|
2020-09-18 00:16:38 +00:00
|
|
|
}
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2020-07-17 02:20:51 +00:00
|
|
|
use super::Commands;
|
|
|
|
use crate::resource::Resources;
|
2020-08-10 00:58:56 +00:00
|
|
|
use bevy_hecs::World;
|
2020-07-10 04:18:35 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn command_buffer() {
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
let mut command_buffer = Commands::default();
|
2020-09-18 00:16:38 +00:00
|
|
|
command_buffer.set_entity_reserver(world.get_entity_reserver());
|
2020-07-10 04:18:35 +00:00
|
|
|
command_buffer.spawn((1u32, 2u64));
|
2020-10-08 23:58:19 +00:00
|
|
|
let entity = command_buffer.current_entity().unwrap();
|
2020-07-10 04:18:35 +00:00
|
|
|
command_buffer.insert_resource(3.14f32);
|
|
|
|
command_buffer.apply(&mut world, &mut resources);
|
|
|
|
let results = world
|
|
|
|
.query::<(&u32, &u64)>()
|
|
|
|
.map(|(a, b)| (*a, *b))
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
assert_eq!(results, vec![(1u32, 2u64)]);
|
|
|
|
assert_eq!(*resources.get::<f32>().unwrap(), 3.14f32);
|
2020-10-08 23:58:19 +00:00
|
|
|
// test entity despawn
|
|
|
|
command_buffer.despawn(entity);
|
|
|
|
command_buffer.despawn(entity); // double despawn shouldn't panic
|
|
|
|
command_buffer.apply(&mut world, &mut resources);
|
|
|
|
let results2 = world
|
|
|
|
.query::<(&u32, &u64)>()
|
|
|
|
.map(|(a, b)| (*a, *b))
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
assert_eq!(results2, vec![]);
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
}
|