Skip to content

Commit

Permalink
change get_entity and remove panic from entity
Browse files Browse the repository at this point in the history
  • Loading branch information
JaySpruce committed Feb 26, 2025
1 parent 11db717 commit d8bdc0f
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 49 deletions.
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/relationship/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ pub trait Relationship: Component + Sized {
{
relationship_target.collection_mut_risky().remove(entity);
if relationship_target.len() == 0 {
if let Some(mut entity) = world.commands().get_entity(target_entity) {
if let Ok(mut entity) = world.commands().get_entity(target_entity) {
// this "remove" operation must check emptiness because in the event that an identical
// relationship is inserted on top, this despawn would result in the removal of that identical
// relationship ... not what we want!
Expand Down
74 changes: 35 additions & 39 deletions crates/bevy_ecs/src/system/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::{
bundle::{Bundle, InsertMode, NoBundleEffect},
change_detection::{MaybeLocation, Mut},
component::{Component, ComponentId, Mutable},
entity::{Entities, Entity, EntityClonerBuilder},
entity::{Entities, Entity, EntityClonerBuilder, EntityDoesNotExistError},
event::Event,
observer::{Observer, TriggerTargets},
resource::Resource,
Expand Down Expand Up @@ -404,13 +404,9 @@ impl<'w, 's> Commands<'w, 's> {

/// Returns the [`EntityCommands`] for the requested [`Entity`].
///
/// This method does not guarantee that commands queued by the `EntityCommands`
/// This method does not guarantee that commands queued by the returned `EntityCommands`
/// will be successful, since the entity could be despawned before they are executed.
///
/// # Panics
///
/// This method panics if the requested entity does not exist.
///
/// # Example
///
/// ```
Expand Down Expand Up @@ -442,63 +438,63 @@ impl<'w, 's> Commands<'w, 's> {
#[inline]
#[track_caller]
pub fn entity(&mut self, entity: Entity) -> EntityCommands {
#[inline(never)]
#[cold]
#[track_caller]
fn panic_no_entity(entities: &Entities, entity: Entity) -> ! {
panic!(
"Attempting to create an EntityCommands for entity {entity}, which {}",
entities.entity_does_not_exist_error_details(entity)
);
}

if self.get_entity(entity).is_some() {
EntityCommands {
entity,
commands: self.reborrow(),
}
} else {
panic_no_entity(self.entities, entity)
EntityCommands {
entity,
commands: self.reborrow(),
}
}

/// Returns the [`EntityCommands`] for the requested [`Entity`], if it exists.
///
/// Returns `None` if the entity does not exist.
///
/// This method does not guarantee that commands queued by the `EntityCommands`
/// This method does not guarantee that commands queued by the returned `EntityCommands`
/// will be successful, since the entity could be despawned before they are executed.
///
/// # Errors
///
/// Returns [`EntityDoesNotExistError`] if the requested entity does not exist.
///
/// # Example
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// #[derive(Component)]
/// struct Label(&'static str);
/// fn example_system(mut commands: Commands) {
/// // Create a new, empty entity
/// fn example_system(mut commands: Commands) -> Result {
/// // Create a new, empty entity.
/// let entity = commands.spawn_empty().id();
///
/// // Get the entity if it still exists, which it will in this case
/// if let Some(mut entity_commands) = commands.get_entity(entity) {
/// // adds a single component to the entity
/// entity_commands.insert(Label("hello world"));
/// }
/// // Get the entity if it still exists, which it will in this case.
/// // If it didn't, the `?` operator would propogate the returned error

Check warning on line 468 in crates/bevy_ecs/src/system/commands/mod.rs

View workflow job for this annotation

GitHub Actions / typos

"propogate" should be "propagate".
/// // to the system, and the system would pass it to an error handler.
/// entity_commands = commands.get_entity(entity)?;
///
/// // Add a single component to the entity.
/// entity_commands.insert(Label("hello world"));
///
/// // Return from the system with a success.
/// Ok(())
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
/// ```
///
/// # See also
///
/// - [`entity`](Self::entity) for the panicking version.
/// - [`entity`](Self::entity) for the infallible version.
#[inline]
#[track_caller]
pub fn get_entity(&mut self, entity: Entity) -> Option<EntityCommands> {
self.entities.contains(entity).then_some(EntityCommands {
entity,
commands: self.reborrow(),
})
pub fn get_entity(
&mut self,
entity: Entity,
) -> Result<EntityCommands, EntityDoesNotExistError> {
if self.entities.contains(entity) {
Ok(EntityCommands {
entity,
commands: self.reborrow(),
})
} else {
Err(EntityDoesNotExistError::new(entity, self.entities))
}
}

/// Pushes a [`Command`] to the queue for creating entities with a particular [`Bundle`] type.
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_input/src/gamepad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1460,7 +1460,7 @@ pub fn gamepad_connection_system(
vendor_id,
product_id,
} => {
let Some(mut gamepad) = commands.get_entity(id) else {
let Ok(mut gamepad) = commands.get_entity(id) else {
warn!("Gamepad {} removed before handling connection event.", id);
continue;
};
Expand All @@ -1475,7 +1475,7 @@ pub fn gamepad_connection_system(
info!("Gamepad {} connected.", id);
}
GamepadConnection::Disconnected => {
let Some(mut gamepad) = commands.get_entity(id) else {
let Ok(mut gamepad) = commands.get_entity(id) else {
warn!("Gamepad {} removed before handling disconnection event. You can ignore this if you manually removed it.", id);
continue;
};
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_pbr/src/render/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ pub(crate) fn add_light_view_entities(
trigger: Trigger<OnAdd, (ExtractedDirectionalLight, ExtractedPointLight)>,
mut commands: Commands,
) {
if let Some(mut v) = commands.get_entity(trigger.target()) {
if let Ok(mut v) = commands.get_entity(trigger.target()) {
v.insert(LightViewEntities::default());
}
}
Expand All @@ -535,7 +535,7 @@ pub(crate) fn extracted_light_removed(
trigger: Trigger<OnRemove, (ExtractedDirectionalLight, ExtractedPointLight)>,
mut commands: Commands,
) {
if let Some(mut v) = commands.get_entity(trigger.target()) {
if let Ok(mut v) = commands.get_entity(trigger.target()) {
v.try_remove::<LightViewEntities>();
}
}
Expand All @@ -548,7 +548,7 @@ pub(crate) fn remove_light_view_entities(
if let Ok(entities) = query.get(trigger.target()) {
for v in entities.0.values() {
for e in v.iter().copied() {
if let Some(mut v) = commands.get_entity(e) {
if let Ok(mut v) = commands.get_entity(e) {
v.despawn();
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/wireframe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ fn apply_wireframe_material(
global_material: Res<GlobalWireframeMaterial>,
) {
for e in removed_wireframes.read().chain(no_wireframes.iter()) {
if let Some(mut commands) = commands.get_entity(e) {
if let Ok(mut commands) = commands.get_entity(e) {
commands.remove::<MeshMaterial3d<WireframeMaterial>>();
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_picking/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ pub fn update_interactions(
for (hovered_entity, new_interaction) in new_interaction_state.drain() {
if let Ok(mut interaction) = interact.get_mut(hovered_entity) {
*interaction = new_interaction;
} else if let Some(mut entity_commands) = commands.get_entity(hovered_entity) {
} else if let Ok(mut entity_commands) = commands.get_entity(hovered_entity) {
entity_commands.try_insert(new_interaction);
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_sprite/src/mesh2d/wireframe2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ fn apply_wireframe_material(
global_material: Res<GlobalWireframe2dMaterial>,
) {
for e in removed_wireframes.read().chain(no_wireframes.iter()) {
if let Some(mut commands) = commands.get_entity(e) {
if let Ok(mut commands) = commands.get_entity(e) {
commands.remove::<MeshMaterial2d<Wireframe2dMaterial>>();
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/ecs/observers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ fn on_remove_mine(
fn explode_mine(trigger: Trigger<Explode>, query: Query<&Mine>, mut commands: Commands) {
// If a triggered event is targeting a specific entity you can access it with `.target()`
let id = trigger.target();
let Some(mut entity) = commands.get_entity(id) else {
let Ok(mut entity) = commands.get_entity(id) else {
return;
};
info!("Boom! {} exploded.", id.index());
Expand Down

0 comments on commit d8bdc0f

Please sign in to comment.