Document part of bevy_ecs::Commands (#976)
Document part of bevy_ecs::Commands
This commit is contained in:
		
							parent
							
								
									71e2c7f4e4
								
							
						
					
					
						commit
						ff12f69233
					
				| @ -22,6 +22,8 @@ use std::{ | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// A dynamically typed collection of components
 | /// A dynamically typed collection of components
 | ||||||
|  | ///
 | ||||||
|  | /// See [Bundle]
 | ||||||
| pub trait DynamicBundle { | pub trait DynamicBundle { | ||||||
|     /// Invoke a callback on the fields' type IDs, sorted by descending alignment then id
 |     /// Invoke a callback on the fields' type IDs, sorted by descending alignment then id
 | ||||||
|     #[doc(hidden)] |     #[doc(hidden)] | ||||||
| @ -38,6 +40,8 @@ pub trait DynamicBundle { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// A statically typed collection of components
 | /// A statically typed collection of components
 | ||||||
|  | ///
 | ||||||
|  | /// See [DynamicBundle]
 | ||||||
| pub trait Bundle: DynamicBundle { | pub trait Bundle: DynamicBundle { | ||||||
|     #[doc(hidden)] |     #[doc(hidden)] | ||||||
|     fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T; |     fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T; | ||||||
|  | |||||||
| @ -76,16 +76,16 @@ impl World { | |||||||
|     /// let a = world.spawn((123, "abc"));
 |     /// let a = world.spawn((123, "abc"));
 | ||||||
|     /// let b = world.spawn((456, true));
 |     /// let b = world.spawn((456, true));
 | ||||||
|     /// ```
 |     /// ```
 | ||||||
|     pub fn spawn(&mut self, components: impl DynamicBundle) -> Entity { |     pub fn spawn(&mut self, bundle: impl DynamicBundle) -> Entity { | ||||||
|         // Ensure all entity allocations are accounted for so `self.entities` can realloc if
 |         // Ensure all entity allocations are accounted for so `self.entities` can realloc if
 | ||||||
|         // necessary
 |         // necessary
 | ||||||
|         self.flush(); |         self.flush(); | ||||||
| 
 | 
 | ||||||
|         let entity = self.entities.alloc(); |         let entity = self.entities.alloc(); | ||||||
|         let archetype_id = components.with_ids(|ids| { |         let archetype_id = bundle.with_ids(|ids| { | ||||||
|             self.index.get(ids).copied().unwrap_or_else(|| { |             self.index.get(ids).copied().unwrap_or_else(|| { | ||||||
|                 let x = self.archetypes.len() as u32; |                 let x = self.archetypes.len() as u32; | ||||||
|                 self.archetypes.push(Archetype::new(components.type_info())); |                 self.archetypes.push(Archetype::new(bundle.type_info())); | ||||||
|                 self.index.insert(ids.to_vec(), x); |                 self.index.insert(ids.to_vec(), x); | ||||||
|                 self.archetype_generation += 1; |                 self.archetype_generation += 1; | ||||||
|                 x |                 x | ||||||
| @ -95,7 +95,7 @@ impl World { | |||||||
|         let archetype = &mut self.archetypes[archetype_id as usize]; |         let archetype = &mut self.archetypes[archetype_id as usize]; | ||||||
|         unsafe { |         unsafe { | ||||||
|             let index = archetype.allocate(entity); |             let index = archetype.allocate(entity); | ||||||
|             components.put(|ptr, ty, size| { |             bundle.put(|ptr, ty, size| { | ||||||
|                 archetype.put_dynamic(ptr, ty, size, index, ComponentFlags::ADDED); |                 archetype.put_dynamic(ptr, ty, size, index, ComponentFlags::ADDED); | ||||||
|                 true |                 true | ||||||
|             }); |             }); | ||||||
| @ -566,7 +566,7 @@ impl World { | |||||||
|     pub fn insert( |     pub fn insert( | ||||||
|         &mut self, |         &mut self, | ||||||
|         entity: Entity, |         entity: Entity, | ||||||
|         components: impl DynamicBundle, |         bundle: impl DynamicBundle, | ||||||
|     ) -> Result<(), NoSuchEntity> { |     ) -> Result<(), NoSuchEntity> { | ||||||
|         use std::collections::hash_map::Entry; |         use std::collections::hash_map::Entry; | ||||||
| 
 | 
 | ||||||
| @ -576,7 +576,7 @@ impl World { | |||||||
|             // Assemble Vec<TypeInfo> for the final entity
 |             // Assemble Vec<TypeInfo> for the final entity
 | ||||||
|             let arch = &mut self.archetypes[loc.archetype as usize]; |             let arch = &mut self.archetypes[loc.archetype as usize]; | ||||||
|             let mut info = arch.types().to_vec(); |             let mut info = arch.types().to_vec(); | ||||||
|             for ty in components.type_info() { |             for ty in bundle.type_info() { | ||||||
|                 if let Some(ptr) = arch.get_dynamic(ty.id(), ty.layout().size(), loc.index) { |                 if let Some(ptr) = arch.get_dynamic(ty.id(), ty.layout().size(), loc.index) { | ||||||
|                     ty.drop(ptr.as_ptr()); |                     ty.drop(ptr.as_ptr()); | ||||||
|                 } else { |                 } else { | ||||||
| @ -601,7 +601,7 @@ impl World { | |||||||
|             if target == loc.archetype { |             if target == loc.archetype { | ||||||
|                 // Update components in the current archetype
 |                 // Update components in the current archetype
 | ||||||
|                 let arch = &mut self.archetypes[loc.archetype as usize]; |                 let arch = &mut self.archetypes[loc.archetype as usize]; | ||||||
|                 components.put(|ptr, ty, size| { |                 bundle.put(|ptr, ty, size| { | ||||||
|                     arch.put_dynamic(ptr, ty, size, loc.index, ComponentFlags::MUTATED); |                     arch.put_dynamic(ptr, ty, size, loc.index, ComponentFlags::MUTATED); | ||||||
|                     true |                     true | ||||||
|                 }); |                 }); | ||||||
| @ -625,7 +625,7 @@ impl World { | |||||||
|                 self.entities.get_mut(moved).unwrap().index = old_index; |                 self.entities.get_mut(moved).unwrap().index = old_index; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             components.put(|ptr, ty, size| { |             bundle.put(|ptr, ty, size| { | ||||||
|                 let had_component = source_arch.has_dynamic(ty); |                 let had_component = source_arch.has_dynamic(ty); | ||||||
|                 let flags = if had_component { |                 let flags = if had_component { | ||||||
|                     ComponentFlags::MUTATED |                     ComponentFlags::MUTATED | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ pub(crate) struct Spawn<T> | |||||||
| where | where | ||||||
|     T: DynamicBundle + Send + Sync + 'static, |     T: DynamicBundle + Send + Sync + 'static, | ||||||
| { | { | ||||||
|     components: T, |     bundle: T, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T> Command for Spawn<T> | impl<T> Command for Spawn<T> | ||||||
| @ -24,7 +24,7 @@ where | |||||||
|     T: DynamicBundle + Send + Sync + 'static, |     T: DynamicBundle + Send + Sync + 'static, | ||||||
| { | { | ||||||
|     fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) { |     fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) { | ||||||
|         world.spawn(self.components); |         world.spawn(self.bundle); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -33,7 +33,7 @@ where | |||||||
|     I: IntoIterator, |     I: IntoIterator, | ||||||
|     I::Item: Bundle, |     I::Item: Bundle, | ||||||
| { | { | ||||||
|     components_iter: I, |     bundles_iter: I, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<I> Command for SpawnBatch<I> | impl<I> Command for SpawnBatch<I> | ||||||
| @ -42,7 +42,7 @@ where | |||||||
|     I::Item: Bundle, |     I::Item: Bundle, | ||||||
| { | { | ||||||
|     fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) { |     fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) { | ||||||
|         world.spawn_batch(self.components_iter); |         world.spawn_batch(self.bundles_iter); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -64,7 +64,7 @@ where | |||||||
|     T: DynamicBundle + Send + Sync + 'static, |     T: DynamicBundle + Send + Sync + 'static, | ||||||
| { | { | ||||||
|     entity: Entity, |     entity: Entity, | ||||||
|     components: T, |     bundle: T, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<T> Command for Insert<T> | impl<T> Command for Insert<T> | ||||||
| @ -72,7 +72,7 @@ where | |||||||
|     T: DynamicBundle + Send + Sync + 'static, |     T: DynamicBundle + Send + Sync + 'static, | ||||||
| { | { | ||||||
|     fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) { |     fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) { | ||||||
|         world.insert(self.entity, self.components).unwrap(); |         world.insert(self.entity, self.bundle).unwrap(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -181,6 +181,7 @@ impl<T: Resource> Command for InsertLocalResource<T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// A list of commands that will be run to populate a `World` and `Resources`.
 | ||||||
| #[derive(Default)] | #[derive(Default)] | ||||||
| pub struct Commands { | pub struct Commands { | ||||||
|     commands: Vec<Box<dyn Command>>, |     commands: Vec<Box<dyn Command>>, | ||||||
| @ -189,38 +190,78 @@ pub struct Commands { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Commands { | impl Commands { | ||||||
|     pub fn spawn(&mut self, components: impl DynamicBundle + Send + Sync + 'static) -> &mut Self { |     /// 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
 | ||||||
|  |     ///
 | ||||||
|  |     /// ```
 | ||||||
|  |     /// use bevy_ecs::prelude::*;
 | ||||||
|  |     ///
 | ||||||
|  |     /// struct Component1;
 | ||||||
|  |     /// struct Component2;
 | ||||||
|  |     ///
 | ||||||
|  |     /// #[derive(Bundle)]
 | ||||||
|  |     /// struct ExampleBundle {
 | ||||||
|  |     ///     a: Component1,
 | ||||||
|  |     ///     b: Component2,
 | ||||||
|  |     /// }
 | ||||||
|  |     ///
 | ||||||
|  |     /// fn example_system(mut commands: Commands) {
 | ||||||
|  |     ///     // 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));
 | ||||||
|  |     /// }
 | ||||||
|  |     /// ```
 | ||||||
|  |     pub fn spawn(&mut self, bundle: impl DynamicBundle + Send + Sync + 'static) -> &mut Self { | ||||||
|         let entity = self |         let entity = self | ||||||
|             .entity_reserver |             .entity_reserver | ||||||
|             .as_ref() |             .as_ref() | ||||||
|             .expect("Entity reserver has not been set.") |             .expect("Entity reserver has not been set.") | ||||||
|             .reserve_entity(); |             .reserve_entity(); | ||||||
|         self.current_entity = Some(entity); |         self.set_current_entity(entity); | ||||||
|         self.commands.push(Box::new(Insert { entity, components })); |         self.insert(entity, bundle); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn spawn_batch<I>(&mut self, components_iter: I) -> &mut Self |     /// 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 | ||||||
|     where |     where | ||||||
|         I: IntoIterator + Send + Sync + 'static, |         I: IntoIterator + Send + Sync + 'static, | ||||||
|         I::Item: Bundle, |         I::Item: Bundle, | ||||||
|     { |     { | ||||||
|         self.add_command(SpawnBatch { components_iter }) |         self.add_command(SpawnBatch { bundles_iter }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Despawns only the specified entity, ignoring any other consideration.
 |     /// Despawns only the specified entity, not including its children.
 | ||||||
|     pub fn despawn(&mut self, entity: Entity) -> &mut Self { |     pub fn despawn(&mut self, entity: Entity) -> &mut Self { | ||||||
|         self.add_command(Despawn { entity }) |         self.add_command(Despawn { entity }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Inserts a bundle of components into `entity`.
 | ||||||
|  |     ///
 | ||||||
|  |     /// See [`World::insert`].
 | ||||||
|     pub fn insert( |     pub fn insert( | ||||||
|         &mut self, |         &mut self, | ||||||
|         entity: Entity, |         entity: Entity, | ||||||
|         components: impl DynamicBundle + Send + Sync + 'static, |         bundle: impl DynamicBundle + Send + Sync + 'static, | ||||||
|     ) -> &mut Self { |     ) -> &mut Self { | ||||||
|         self.add_command(Insert { entity, components }) |         self.add_command(Insert { entity, bundle }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Inserts a single component into `entity`.
 | ||||||
|  |     ///
 | ||||||
|  |     /// See [`World::insert_one`].
 | ||||||
|     pub fn insert_one(&mut self, entity: Entity, component: impl Component) -> &mut Self { |     pub fn insert_one(&mut self, entity: Entity, component: impl Component) -> &mut Self { | ||||||
|         self.add_command(InsertOne { entity, component }) |         self.add_command(InsertOne { entity, component }) | ||||||
|     } |     } | ||||||
| @ -229,6 +270,9 @@ impl Commands { | |||||||
|         self.add_command(InsertResource { resource }) |         self.add_command(InsertResource { resource }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Insert a resource that is local to a specific system.
 | ||||||
|  |     ///
 | ||||||
|  |     /// See [`crate::System::id`].
 | ||||||
|     pub fn insert_local_resource<T: Resource>( |     pub fn insert_local_resource<T: Resource>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         system_id: SystemId, |         system_id: SystemId, | ||||||
| @ -240,6 +284,7 @@ impl Commands { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// See [`World::remove_one`].
 | ||||||
|     pub fn remove_one<T>(&mut self, entity: Entity) -> &mut Self |     pub fn remove_one<T>(&mut self, entity: Entity) -> &mut Self | ||||||
|     where |     where | ||||||
|         T: Component, |         T: Component, | ||||||
| @ -250,6 +295,7 @@ impl Commands { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// See [`World::remove`].
 | ||||||
|     pub fn remove<T>(&mut self, entity: Entity) -> &mut Self |     pub fn remove<T>(&mut self, entity: Entity) -> &mut Self | ||||||
|     where |     where | ||||||
|         T: Bundle + Send + Sync + 'static, |         T: Bundle + Send + Sync + 'static, | ||||||
| @ -260,18 +306,54 @@ impl Commands { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn with_bundle( |     /// Adds a bundle of components to the current entity.
 | ||||||
|         &mut self, |     ///
 | ||||||
|         components: impl DynamicBundle + Send + Sync + 'static, |     /// See [`Self::with`], [`Self::current_entity`].
 | ||||||
|     ) -> &mut Self { |     pub fn with_bundle(&mut self, bundle: 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."); |         let current_entity =  self.current_entity.expect("Cannot add bundle because the 'current entity' is not set. You should spawn an entity first."); | ||||||
|         self.commands.push(Box::new(Insert { |         self.commands.push(Box::new(Insert { | ||||||
|             entity: current_entity, |             entity: current_entity, | ||||||
|             components, |             bundle, | ||||||
|         })); |         })); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// 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`].
 | ||||||
|  |     ///
 | ||||||
|  |     /// ```
 | ||||||
|  |     /// use bevy_ecs::prelude::*;
 | ||||||
|  |     ///
 | ||||||
|  |     /// struct Component1;
 | ||||||
|  |     /// struct Component2;
 | ||||||
|  |     ///
 | ||||||
|  |     /// fn example_system(mut commands: Commands) {
 | ||||||
|  |     ///     // 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,
 | ||||||
|  |     ///     });
 | ||||||
|  |     /// }
 | ||||||
|  |     /// ```
 | ||||||
|     pub fn with(&mut self, component: impl Component) -> &mut 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."); |         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 { |         self.commands.push(Box::new(InsertOne { | ||||||
| @ -281,22 +363,26 @@ impl Commands { | |||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Adds a command directly to the command list. Prefer this to [`Self::add_command_boxed`] if the type of `command` is statically known.
 | ||||||
|     pub fn add_command<C: Command + 'static>(&mut self, command: C) -> &mut Self { |     pub fn add_command<C: Command + 'static>(&mut self, command: C) -> &mut Self { | ||||||
|         self.commands.push(Box::new(command)); |         self.commands.push(Box::new(command)); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// See [`Self::add_command`].
 | ||||||
|     pub fn add_command_boxed(&mut self, command: Box<dyn Command>) -> &mut Self { |     pub fn add_command_boxed(&mut self, command: Box<dyn Command>) -> &mut Self { | ||||||
|         self.commands.push(command); |         self.commands.push(command); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Runs all the stored commands on `world` and `resources`. The command buffer is emptied as a part of this call.
 | ||||||
|     pub fn apply(&mut self, world: &mut World, resources: &mut Resources) { |     pub fn apply(&mut self, world: &mut World, resources: &mut Resources) { | ||||||
|         for command in self.commands.drain(..) { |         for command in self.commands.drain(..) { | ||||||
|             command.write(world, resources); |             command.write(world, resources); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Returns the current entity, set by [`Self::spawn`] or with [`Self::set_current_entity`].
 | ||||||
|     pub fn current_entity(&self) -> Option<Entity> { |     pub fn current_entity(&self) -> Option<Entity> { | ||||||
|         self.current_entity |         self.current_entity | ||||||
|     } |     } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Michael Tang
						Michael Tang