2020-07-17 02:20:51 +00:00
use super ::SystemId ;
2020-11-16 04:32:23 +00:00
use crate ::{
resource ::{ Resource , Resources } ,
Bundle , Component , ComponentError , DynamicBundle , Entity , EntityReserver , World ,
} ;
2020-11-15 22:32:54 +00:00
use bevy_utils ::tracing ::{ debug , warn } ;
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 ,
{
2020-12-03 03:11:28 +00:00
bundle : T ,
2020-07-10 04:18:35 +00:00
}
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-12-03 03:11:28 +00:00
world . spawn ( self . bundle ) ;
2020-07-10 04:18:35 +00:00
}
}
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 ,
{
2020-12-03 03:11:28 +00:00
bundles_iter : I ,
2020-07-10 04:18:35 +00:00
}
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-12-03 03:11:28 +00:00
world . spawn_batch ( self . bundles_iter ) ;
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 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 ) {
2020-11-13 01:23:57 +00:00
debug! ( " Failed to despawn entity {:?}: {} " , self . entity , e ) ;
2020-10-08 23:58:19 +00:00
}
2020-07-10 04:18:35 +00:00
}
}
pub struct Insert < T >
where
T : DynamicBundle + Send + Sync + 'static ,
{
entity : Entity ,
2020-12-03 03:11:28 +00:00
bundle : T ,
2020-07-10 04:18:35 +00:00
}
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-12-03 03:11:28 +00:00
world . insert ( self . entity , self . bundle ) . unwrap ( ) ;
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 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-11-15 22:32:54 +00:00
match world . remove ::< T > ( self . entity ) {
Ok ( _ ) = > ( ) ,
2020-11-16 04:32:23 +00:00
Err ( ComponentError ::MissingComponent ( e ) ) = > {
2020-11-15 22:32:54 +00:00
warn! (
" Failed to remove components {:?} with error: {}. Falling back to inefficient one-by-one component removing. " ,
std ::any ::type_name ::< T > ( ) ,
e
) ;
if let Err ( e ) = world . remove_one_by_one ::< T > ( self . entity ) {
debug! (
" Failed to remove components {:?} with error: {} " ,
std ::any ::type_name ::< T > ( ) ,
e
) ;
}
}
Err ( e ) = > {
debug! (
" Failed to remove components {:?} with error: {} " ,
std ::any ::type_name ::< T > ( ) ,
e
) ;
}
}
2020-09-26 21:27:56 +00:00
}
}
2020-07-10 04:18:35 +00:00
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 ) ;
}
}
2021-02-22 03:43:26 +00:00
pub struct RemoveResource < T : Resource > {
phantom : PhantomData < T > ,
}
impl < T : Resource > Command for RemoveResource < T > {
fn write ( self : Box < Self > , _world : & mut World , resources : & mut Resources ) {
resources . remove ::< T > ( ) ;
}
}
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-12-03 03:11:28 +00:00
/// A list of commands that will be run to populate a `World` and `Resources`.
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-12-03 03:11:28 +00:00
/// Creates a new entity with the components contained in `bundle`.
///
/// Note that `bundle` is a [DynamicBundle], which is a collection of components. [DynamicBundle] is automatically implemented for tuples of components. You can also create your own bundle types by deriving [`derive@Bundle`]. If you would like to spawn an entity with a single component, consider wrapping the component in a tuple (which [DynamicBundle] is implemented for).
///
/// See [`Self::set_current_entity`], [`Self::insert`].
///
/// # Example
///
/// ```
2021-02-06 01:44:34 +00:00
/// # use bevy_ecs::prelude::*;
2020-12-03 03:11:28 +00:00
///
/// struct Component1;
/// struct Component2;
///
/// #[derive(Bundle)]
/// struct ExampleBundle {
/// a: Component1,
/// b: Component2,
/// }
///
2021-02-06 01:44:34 +00:00
/// fn example_system(commands: &mut Commands) {
2020-12-03 03:11:28 +00:00
/// // Create a new entity with a component bundle.
/// commands.spawn(ExampleBundle {
/// a: Component1,
/// b: Component2,
/// });
///
/// // Create a new entity with a single component.
/// commands.spawn((Component1,));
/// // Create a new entity with two components.
/// commands.spawn((Component1, Component2));
/// }
2021-02-06 01:44:34 +00:00
///
/// # example_system.system();
2020-12-03 03:11:28 +00:00
/// ```
pub fn spawn ( & mut self , bundle : impl DynamicBundle + Send + Sync + 'static ) -> & mut Self {
2020-09-18 00:16:38 +00:00
let entity = self
. entity_reserver
. as_ref ( )
2020-12-02 19:31:16 +00:00
. expect ( " Entity reserver has not been set. " )
2020-09-18 00:16:38 +00:00
. reserve_entity ( ) ;
2020-12-03 03:11:28 +00:00
self . set_current_entity ( entity ) ;
self . insert ( entity , bundle ) ;
2020-07-10 04:18:35 +00:00
self
}
2020-12-03 03:11:28 +00:00
/// Equivalent to iterating `bundles_iter` and calling [`Self::spawn`] on each bundle, but slightly more performant.
pub fn spawn_batch < I > ( & mut self , bundles_iter : I ) -> & mut Self
2020-07-10 04:18:35 +00:00
where
I : IntoIterator + Send + Sync + 'static ,
I ::Item : Bundle ,
{
2020-12-03 03:11:28 +00:00
self . add_command ( SpawnBatch { bundles_iter } )
2020-07-10 04:18:35 +00:00
}
2020-12-03 03:11:28 +00:00
/// Despawns only the specified entity, not including its children.
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
}
2020-12-03 03:11:28 +00:00
/// Inserts a bundle of components into `entity`.
///
/// See [`World::insert`].
2020-07-10 04:18:35 +00:00
pub fn insert (
& mut self ,
entity : Entity ,
2020-12-03 03:11:28 +00:00
bundle : impl DynamicBundle + Send + Sync + 'static ,
2020-07-10 04:18:35 +00:00
) -> & mut Self {
2020-12-03 03:11:28 +00:00
self . add_command ( Insert { entity , bundle } )
2020-07-10 04:18:35 +00:00
}
2020-12-03 03:11:28 +00:00
/// Inserts a single component into `entity`.
///
/// See [`World::insert_one`].
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
}
2020-12-03 03:11:28 +00:00
/// Insert a resource that is local to a specific system.
///
/// See [`crate::System::id`].
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-12-03 03:11:28 +00:00
/// See [`World::remove_one`].
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 ,
} )
}
2020-12-03 03:11:28 +00:00
/// See [`World::remove`].
2020-11-08 20:34:05 +00:00
pub fn remove < T > ( & mut self , entity : Entity ) -> & mut Self
where
T : Bundle + Send + Sync + 'static ,
{
self . add_command ( Remove ::< T > {
entity ,
phantom : PhantomData ,
} )
}
2021-02-22 03:43:26 +00:00
pub fn remove_resource < T : Resource > ( & mut self ) -> & mut Self {
self . add_command ( RemoveResource ::< T > {
phantom : PhantomData ,
} )
}
2020-12-03 03:11:28 +00:00
/// Adds a bundle of components to the current entity.
///
/// See [`Self::with`], [`Self::current_entity`].
pub fn with_bundle ( & mut self , bundle : impl DynamicBundle + Send + Sync + 'static ) -> & mut Self {
let current_entity = self . current_entity . expect ( " Cannot add bundle because the 'current entity' is not set. You should spawn an entity first. " ) ;
2020-11-08 20:34:05 +00:00
self . commands . push ( Box ::new ( Insert {
entity : current_entity ,
2020-12-03 03:11:28 +00:00
bundle ,
2020-11-08 20:34:05 +00:00
} ) ) ;
self
}
2020-12-03 03:11:28 +00:00
/// Adds a single component to the current entity.
///
/// See [`Self::with_bundle`], [`Self::current_entity`].
///
/// # Warning
///
/// It's possible to call this with a bundle, but this is likely not intended and [`Self::with_bundle`] should be used instead. If `with` is called with a bundle, the bundle itself will be added as a component instead of the bundles' inner components each being added.
///
/// # Example
///
/// `with` can be chained with [`Self::spawn`].
///
/// ```
2021-02-06 01:44:34 +00:00
/// # use bevy_ecs::prelude::*;
2020-12-03 03:11:28 +00:00
///
/// struct Component1;
/// struct Component2;
///
2021-02-06 01:44:34 +00:00
/// fn example_system(commands: &mut Commands) {
2020-12-03 03:11:28 +00:00
/// // Create a new entity with a `Component1` and `Component2`.
/// commands.spawn((Component1,)).with(Component2);
///
/// // Psst! These are also equivalent to the line above!
/// commands.spawn((Component1, Component2));
/// commands.spawn(()).with(Component1).with(Component2);
/// #[derive(Bundle)]
/// struct ExampleBundle {
/// a: Component1,
/// b: Component2,
/// }
/// commands.spawn(()).with_bundle(ExampleBundle {
/// a: Component1,
/// b: Component2,
/// });
/// }
2021-02-06 01:44:34 +00:00
///
/// # example_system.system();
2020-12-03 03:11:28 +00:00
/// ```
2020-11-08 20:34:05 +00:00
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-12-03 03:11:28 +00:00
/// Adds a command directly to the command list. Prefer this to [`Self::add_command_boxed`] if the type of `command` is statically known.
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-12-03 03:11:28 +00:00
/// See [`Self::add_command`].
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-12-03 03:11:28 +00:00
/// Runs all the stored commands on `world` and `resources`. The command buffer is emptied as a part of this call.
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
2020-12-03 03:11:28 +00:00
/// Returns the current entity, set by [`Self::spawn`] or with [`Self::set_current_entity`].
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) ]
2021-02-22 08:42:19 +00:00
#[ allow(clippy::float_cmp, clippy::approx_constant) ]
2020-07-10 04:18:35 +00:00
mod tests {
2020-11-16 04:32:23 +00:00
use crate ::{ resource ::Resources , Commands , World } ;
2021-02-22 03:43:26 +00:00
use core ::any ::TypeId ;
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 ( ( 1 u32 , 2 u64 ) ) ;
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.14 f32 ) ;
command_buffer . apply ( & mut world , & mut resources ) ;
let results = world
. query ::< ( & u32 , & u64 ) > ( )
. map ( | ( a , b ) | ( * a , * b ) )
. collect ::< Vec < _ > > ( ) ;
assert_eq! ( results , vec! [ ( 1 u32 , 2 u64 ) ] ) ;
assert_eq! ( * resources . get ::< f32 > ( ) . unwrap ( ) , 3.14 f32 ) ;
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
}
2020-11-15 22:32:54 +00:00
#[ test ]
fn remove_components ( ) {
let mut world = World ::default ( ) ;
let mut resources = Resources ::default ( ) ;
let mut command_buffer = Commands ::default ( ) ;
command_buffer . set_entity_reserver ( world . get_entity_reserver ( ) ) ;
command_buffer . spawn ( ( 1 u32 , 2 u64 ) ) ;
let entity = command_buffer . current_entity ( ) . unwrap ( ) ;
command_buffer . apply ( & mut world , & mut resources ) ;
let results_before = world
. query ::< ( & u32 , & u64 ) > ( )
. map ( | ( a , b ) | ( * a , * b ) )
. collect ::< Vec < _ > > ( ) ;
assert_eq! ( results_before , vec! [ ( 1 u32 , 2 u64 ) ] ) ;
// test component removal
command_buffer . remove_one ::< u32 > ( entity ) ;
command_buffer . remove ::< ( u32 , u64 ) > ( entity ) ;
command_buffer . apply ( & mut world , & mut resources ) ;
let results_after = world
. query ::< ( & u32 , & u64 ) > ( )
. map ( | ( a , b ) | ( * a , * b ) )
. collect ::< Vec < _ > > ( ) ;
assert_eq! ( results_after , vec! [ ] ) ;
2021-02-22 08:42:19 +00:00
let results_after_u64 = world . query ::< & u64 > ( ) . copied ( ) . collect ::< Vec < _ > > ( ) ;
2020-11-15 22:32:54 +00:00
assert_eq! ( results_after_u64 , vec! [ ] ) ;
}
2021-02-22 03:43:26 +00:00
#[ test ]
fn remove_resources ( ) {
let mut world = World ::default ( ) ;
let mut resources = Resources ::default ( ) ;
let mut command_buffer = Commands ::default ( ) ;
command_buffer . insert_resource ( 123 ) ;
command_buffer . insert_resource ( 456.0 ) ;
command_buffer . apply ( & mut world , & mut resources ) ;
assert_eq! (
resources . resource_data . contains_key ( & TypeId ::of ::< i32 > ( ) ) ,
true
) ;
assert_eq! (
resources . resource_data . contains_key ( & TypeId ::of ::< f64 > ( ) ) ,
true
) ;
// test resource removal
command_buffer . remove_resource ::< i32 > ( ) ;
command_buffer . apply ( & mut world , & mut resources ) ;
assert_eq! (
resources . resource_data . contains_key ( & TypeId ::of ::< i32 > ( ) ) ,
false
) ;
assert_eq! (
resources . resource_data . contains_key ( & TypeId ::of ::< f64 > ( ) ) ,
true
) ;
}
2020-07-10 04:18:35 +00:00
}