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
 | ||||
| ///
 | ||||
| /// See [Bundle]
 | ||||
| pub trait DynamicBundle { | ||||
|     /// Invoke a callback on the fields' type IDs, sorted by descending alignment then id
 | ||||
|     #[doc(hidden)] | ||||
| @ -38,6 +40,8 @@ pub trait DynamicBundle { | ||||
| } | ||||
| 
 | ||||
| /// A statically typed collection of components
 | ||||
| ///
 | ||||
| /// See [DynamicBundle]
 | ||||
| pub trait Bundle: DynamicBundle { | ||||
|     #[doc(hidden)] | ||||
|     fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T; | ||||
|  | ||||
| @ -76,16 +76,16 @@ impl World { | ||||
|     /// let a = world.spawn((123, "abc"));
 | ||||
|     /// 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
 | ||||
|         // necessary
 | ||||
|         self.flush(); | ||||
| 
 | ||||
|         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(|| { | ||||
|                 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.archetype_generation += 1; | ||||
|                 x | ||||
| @ -95,7 +95,7 @@ impl World { | ||||
|         let archetype = &mut self.archetypes[archetype_id as usize]; | ||||
|         unsafe { | ||||
|             let index = archetype.allocate(entity); | ||||
|             components.put(|ptr, ty, size| { | ||||
|             bundle.put(|ptr, ty, size| { | ||||
|                 archetype.put_dynamic(ptr, ty, size, index, ComponentFlags::ADDED); | ||||
|                 true | ||||
|             }); | ||||
| @ -566,7 +566,7 @@ impl World { | ||||
|     pub fn insert( | ||||
|         &mut self, | ||||
|         entity: Entity, | ||||
|         components: impl DynamicBundle, | ||||
|         bundle: impl DynamicBundle, | ||||
|     ) -> Result<(), NoSuchEntity> { | ||||
|         use std::collections::hash_map::Entry; | ||||
| 
 | ||||
| @ -576,7 +576,7 @@ impl World { | ||||
|             // Assemble Vec<TypeInfo> for the final entity
 | ||||
|             let arch = &mut self.archetypes[loc.archetype as usize]; | ||||
|             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) { | ||||
|                     ty.drop(ptr.as_ptr()); | ||||
|                 } else { | ||||
| @ -601,7 +601,7 @@ impl World { | ||||
|             if target == loc.archetype { | ||||
|                 // Update components in the current archetype
 | ||||
|                 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); | ||||
|                     true | ||||
|                 }); | ||||
| @ -625,7 +625,7 @@ impl World { | ||||
|                 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 flags = if had_component { | ||||
|                     ComponentFlags::MUTATED | ||||
|  | ||||
| @ -16,7 +16,7 @@ pub(crate) struct Spawn<T> | ||||
| where | ||||
|     T: DynamicBundle + Send + Sync + 'static, | ||||
| { | ||||
|     components: T, | ||||
|     bundle: T, | ||||
| } | ||||
| 
 | ||||
| impl<T> Command for Spawn<T> | ||||
| @ -24,7 +24,7 @@ where | ||||
|     T: DynamicBundle + Send + Sync + 'static, | ||||
| { | ||||
|     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::Item: Bundle, | ||||
| { | ||||
|     components_iter: I, | ||||
|     bundles_iter: I, | ||||
| } | ||||
| 
 | ||||
| impl<I> Command for SpawnBatch<I> | ||||
| @ -42,7 +42,7 @@ where | ||||
|     I::Item: Bundle, | ||||
| { | ||||
|     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, | ||||
| { | ||||
|     entity: Entity, | ||||
|     components: T, | ||||
|     bundle: T, | ||||
| } | ||||
| 
 | ||||
| impl<T> Command for Insert<T> | ||||
| @ -72,7 +72,7 @@ where | ||||
|     T: DynamicBundle + Send + Sync + 'static, | ||||
| { | ||||
|     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)] | ||||
| pub struct Commands { | ||||
|     commands: Vec<Box<dyn Command>>, | ||||
| @ -189,38 +190,78 @@ pub struct 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 | ||||
|             .entity_reserver | ||||
|             .as_ref() | ||||
|             .expect("Entity reserver has not been set.") | ||||
|             .reserve_entity(); | ||||
|         self.current_entity = Some(entity); | ||||
|         self.commands.push(Box::new(Insert { entity, components })); | ||||
|         self.set_current_entity(entity); | ||||
|         self.insert(entity, bundle); | ||||
|         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 | ||||
|         I: IntoIterator + Send + Sync + 'static, | ||||
|         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 { | ||||
|         self.add_command(Despawn { entity }) | ||||
|     } | ||||
| 
 | ||||
|     /// Inserts a bundle of components into `entity`.
 | ||||
|     ///
 | ||||
|     /// See [`World::insert`].
 | ||||
|     pub fn insert( | ||||
|         &mut self, | ||||
|         entity: Entity, | ||||
|         components: impl DynamicBundle + Send + Sync + 'static, | ||||
|         bundle: impl DynamicBundle + Send + Sync + 'static, | ||||
|     ) -> &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 { | ||||
|         self.add_command(InsertOne { entity, component }) | ||||
|     } | ||||
| @ -229,6 +270,9 @@ impl Commands { | ||||
|         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>( | ||||
|         &mut self, | ||||
|         system_id: SystemId, | ||||
| @ -240,6 +284,7 @@ impl Commands { | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     /// See [`World::remove_one`].
 | ||||
|     pub fn remove_one<T>(&mut self, entity: Entity) -> &mut Self | ||||
|     where | ||||
|         T: Component, | ||||
| @ -250,6 +295,7 @@ impl Commands { | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     /// See [`World::remove`].
 | ||||
|     pub fn remove<T>(&mut self, entity: Entity) -> &mut Self | ||||
|     where | ||||
|         T: Bundle + Send + Sync + 'static, | ||||
| @ -260,18 +306,54 @@ impl Commands { | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     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."); | ||||
|     /// 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."); | ||||
|         self.commands.push(Box::new(Insert { | ||||
|             entity: current_entity, | ||||
|             components, | ||||
|             bundle, | ||||
|         })); | ||||
|         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 { | ||||
|         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 { | ||||
| @ -281,22 +363,26 @@ impl Commands { | ||||
|         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 { | ||||
|         self.commands.push(Box::new(command)); | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     /// See [`Self::add_command`].
 | ||||
|     pub fn add_command_boxed(&mut self, command: Box<dyn Command>) -> &mut Self { | ||||
|         self.commands.push(command); | ||||
|         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) { | ||||
|         for command in self.commands.drain(..) { | ||||
|             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> { | ||||
|         self.current_entity | ||||
|     } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Michael Tang
						Michael Tang