Skip to content

Commit

Permalink
Make Commands and World apis consistent
Browse files Browse the repository at this point in the history
  • Loading branch information
cart committed Mar 20, 2021
1 parent c78b76b commit 7b64840
Show file tree
Hide file tree
Showing 54 changed files with 1,008 additions and 1,096 deletions.
187 changes: 91 additions & 96 deletions crates/bevy_ecs/src/system/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,27 @@ impl CommandQueue {
}

#[inline]
pub fn push(&mut self, command: Box<dyn Command>) {
pub fn push_boxed(&mut self, command: Box<dyn Command>) {
self.commands.push(command);
}

#[inline]
pub fn push<T: Command>(&mut self, command: T) {
self.push_boxed(Box::new(command));
}
}

/// A list of commands that will be run to modify a `World`
pub struct Commands<'a> {
queue: &'a mut CommandQueue,
entities: &'a Entities,
current_entity: Option<Entity>,
}

impl<'a> Commands<'a> {
pub fn new(queue: &'a mut CommandQueue, world: &'a World) -> Self {
Self {
queue,
entities: world.entities(),
current_entity: None,
}
}

Expand Down Expand Up @@ -84,84 +87,74 @@ impl<'a> Commands<'a> {
/// }
/// # example_system.system();
/// ```
pub fn spawn(&mut self, bundle: impl Bundle) -> &mut Self {
pub fn spawn(&mut self) -> EntityCommands<'a, '_> {
let entity = self.entities.reserve_entity();
self.set_current_entity(entity);
self.insert_bundle(entity, bundle);
self
EntityCommands {
entity,
commands: self,
}
}

pub fn spawn_bundle<'b, T: Bundle>(&'b mut self, bundle: T) -> EntityCommands<'a, 'b> {
let mut e = self.spawn();
e.insert_bundle(bundle);
e
}

pub fn entity(&mut self, entity: Entity) -> EntityCommands<'a, '_> {
EntityCommands {
entity,
commands: 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
pub fn spawn_batch<I>(&mut self, bundles_iter: I)
where
I: IntoIterator + Send + Sync + 'static,
I::Item: Bundle,
{
self.add_command(SpawnBatch { bundles_iter })
}

/// 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 [crate::world::EntityMut::insert_bundle].
pub fn insert_bundle(&mut self, entity: Entity, bundle: impl Bundle) -> &mut Self {
self.add_command(InsertBundle { entity, bundle })
self.queue.push(SpawnBatch { bundles_iter });
}

/// Inserts a single component into `entity`.
///
/// See [crate::world::EntityMut::insert].
pub fn insert(&mut self, entity: Entity, component: impl Component) -> &mut Self {
self.add_command(Insert { entity, component })
/// See [World::insert_resource].
pub fn insert_resource<T: Component>(&mut self, resource: T) {
self.queue.push(InsertResource { resource })
}

/// See [crate::world::EntityMut::remove].
pub fn remove<T>(&mut self, entity: Entity) -> &mut Self
where
T: Component,
{
self.add_command(Remove::<T> {
entity,
pub fn remove_resource<T: Component>(&mut self) {
self.queue.push(RemoveResource::<T> {
phantom: PhantomData,
})
});
}

/// See [World::insert_resource].
pub fn insert_resource<T: Component>(&mut self, resource: T) -> &mut Self {
self.add_command(InsertResource { resource })
/// 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<C: Command>(&mut self, command: C) {
self.queue.push(command);
}
}

/// See [crate::world::EntityMut::remove_bundle].
pub fn remove_bundle<T>(&mut self, entity: Entity) -> &mut Self
where
T: Bundle,
{
self.add_command(RemoveBundle::<T> {
entity,
phantom: PhantomData,
})
}
pub struct EntityCommands<'a, 'b> {
entity: Entity,
commands: &'b mut Commands<'a>,
}

pub fn remove_resource<T: Component>(&mut self) -> &mut Self {
self.add_command(RemoveResource::<T> {
phantom: PhantomData,
})
impl<'a, 'b> EntityCommands<'a, 'b> {
#[inline]
pub fn id(&self) -> Entity {
self.entity
}

/// Adds a bundle of components to the current entity.
///
/// See [`Self::with`], [`Self::current_entity`].
pub fn with_bundle(&mut self, bundle: impl Bundle) -> &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.queue.push(Box::new(InsertBundle {
entity: current_entity,
pub fn insert_bundle(&mut self, bundle: impl Bundle) -> &mut Self {
self.commands.add(InsertBundle {
entity: self.entity,
bundle,
}));
});
self
}

Expand Down Expand Up @@ -205,47 +198,47 @@ impl<'a> Commands<'a> {
/// }
/// # example_system.system();
/// ```
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.queue.push(Box::new(Insert {
entity: current_entity,
pub fn insert(&mut self, component: impl Component) -> &mut Self {
self.commands.add(Insert {
entity: self.entity,
component,
}));
});
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>(&mut self, command: C) -> &mut Self {
self.queue.push(Box::new(command));
/// See [crate::world::EntityMut::remove_bundle].
pub fn remove_bundle<T>(&mut self) -> &mut Self
where
T: Bundle,
{
self.commands.add(RemoveBundle::<T> {
entity: self.entity,
phantom: PhantomData,
});
self
}

/// See [`Self::add_command`].
pub fn add_command_boxed(&mut self, command: Box<dyn Command>) -> &mut Self {
self.queue.push(command);
/// See [crate::world::EntityMut::remove].
pub fn remove<T>(&mut self) -> &mut Self
where
T: Component,
{
self.commands.add(Remove::<T> {
entity: self.entity,
phantom: PhantomData,
});
self
}

/// Returns the current entity, set by [`Self::spawn`] or with [`Self::set_current_entity`].
pub fn current_entity(&self) -> Option<Entity> {
self.current_entity
}

pub fn set_current_entity(&mut self, entity: Entity) {
self.current_entity = Some(entity);
}

pub fn clear_current_entity(&mut self) {
self.current_entity = None;
/// Despawns only the specified entity, not including its children.
pub fn despawn(&mut self) {
self.commands.add(Despawn {
entity: self.entity,
})
}

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
pub fn commands(&mut self) -> &mut Commands<'a> {
self.commands
}
}

Expand Down Expand Up @@ -392,9 +385,8 @@ mod tests {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
let entity = Commands::new(&mut command_queue, &world)
.spawn((1u32, 2u64))
.current_entity()
.unwrap();
.spawn_bundle((1u32, 2u64))
.id();
command_queue.apply(&mut world);
assert!(world.entities().len() == 1);
let results = world
Expand All @@ -404,9 +396,11 @@ mod tests {
.collect::<Vec<_>>();
assert_eq!(results, vec![(1u32, 2u64)]);
// test entity despawn
Commands::new(&mut command_queue, &world)
.despawn(entity)
.despawn(entity); // double despawn shouldn't panic
{
let mut commands = Commands::new(&mut command_queue, &world);
commands.entity(entity).despawn();
commands.entity(entity).despawn(); // double despawn shouldn't panic
}
command_queue.apply(&mut world);
let results2 = world
.query::<(&u32, &u64)>()
Expand All @@ -421,9 +415,9 @@ mod tests {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
let entity = Commands::new(&mut command_queue, &world)
.spawn((1u32, 2u64))
.current_entity()
.unwrap();
.spawn()
.insert_bundle((1u32, 2u64))
.id();
command_queue.apply(&mut world);
let results_before = world
.query::<(&u32, &u64)>()
Expand All @@ -434,8 +428,9 @@ mod tests {

// test component removal
Commands::new(&mut command_queue, &world)
.remove::<u32>(entity)
.remove_bundle::<(u32, u64)>(entity);
.entity(entity)
.remove::<u32>()
.remove_bundle::<(u32, u64)>();
command_queue.apply(&mut world);
let results_after = world
.query::<(&u32, &u64)>()
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/system/exclusive_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ mod tests {
) {
for entity in query.iter() {
*counter += 1;
commands.remove::<f32>(entity);
commands.entity(entity).remove::<f32>();
}
}

Expand Down
16 changes: 8 additions & 8 deletions crates/bevy_gltf/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,18 +293,18 @@ fn load_node(
) -> Result<(), GltfError> {
let transform = gltf_node.transform();
let mut gltf_error = None;
let node = world_builder.spawn((
let mut node = world_builder.spawn_bundle((
Transform::from_matrix(Mat4::from_cols_array_2d(&transform.matrix())),
GlobalTransform::identity(),
));

if let Some(name) = gltf_node.name() {
node.with(Name::new(name.to_string()));
node.insert(Name::new(name.to_string()));
}

// create camera node
if let Some(camera) = gltf_node.camera() {
node.with(VisibleEntities {
node.insert(VisibleEntities {
..Default::default()
});

Expand All @@ -322,12 +322,12 @@ fn load_node(
..Default::default()
};

node.with(Camera {
node.insert(Camera {
name: Some(base::camera::CAMERA_2D.to_owned()),
projection_matrix: orthographic_projection.get_projection_matrix(),
..Default::default()
});
node.with(orthographic_projection);
node.insert(orthographic_projection);
}
gltf::camera::Projection::Perspective(perspective) => {
let mut perspective_projection: PerspectiveProjection = PerspectiveProjection {
Expand All @@ -341,12 +341,12 @@ fn load_node(
if let Some(aspect_ratio) = perspective.aspect_ratio() {
perspective_projection.aspect_ratio = aspect_ratio;
}
node.with(Camera {
node.insert(Camera {
name: Some(base::camera::CAMERA_3D.to_owned()),
projection_matrix: perspective_projection.get_projection_matrix(),
..Default::default()
});
node.with(perspective_projection);
node.insert(perspective_projection);
}
}
}
Expand All @@ -371,7 +371,7 @@ fn load_node(
let material_asset_path =
AssetPath::new_ref(load_context.path(), Some(&material_label));

parent.spawn(PbrBundle {
parent.spawn_bundle(PbrBundle {
mesh: load_context.get_handle(mesh_asset_path),
material: load_context.get_handle(material_asset_path),
..Default::default()
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_scene/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ impl Command for SpawnScene {
}

pub trait SpawnSceneCommands {
fn spawn_scene(&mut self, scene: Handle<Scene>) -> &mut Self;
fn spawn_scene(&mut self, scene: Handle<Scene>);
}

impl<'a> SpawnSceneCommands for Commands<'a> {
fn spawn_scene(&mut self, scene_handle: Handle<Scene>) -> &mut Self {
self.add_command(SpawnScene { scene_handle })
fn spawn_scene(&mut self, scene_handle: Handle<Scene>) {
self.add(SpawnScene { scene_handle });
}
}

Expand Down
Loading

0 comments on commit 7b64840

Please sign in to comment.