# Objective
Expand `track_change_detection` feature to also track entity spawns and
despawns. Use this to create better error messages.
# Solution
Adds `Entities::entity_get_spawned_or_despawned_by` as well as `{all
entity reference types}::spawned_by`.
This also removes the deprecated `get_many_entities_mut` & co (and
therefore can't land in 0.15) because we don't yet have no Polonius.
## Testing
Added a test that checks that the locations get updated and these
updates are ordered correctly vs hooks & observers.
---
## Showcase
Access location:
```rust
let mut world = World::new();
let entity = world.spawn_empty().id();
println!("spawned by: {}", world.entity(entity).spawned_by());
```
```
spawned by: src/main.rs:5:24
```
Error message (with `track_change_detection`):
```rust
world.despawn(entity);
world.entity(entity);
```
```
thread 'main' panicked at src/main.rs:11:11:
Entity 0v1#4294967296 was despawned by src/main.rs:10:11
```
and without:
```
thread 'main' panicked at src/main.rs:11:11:
Entity 0v1#4294967296 does not exist (enable `track_change_detection` feature for more details)
```
Similar error messages now also exists for `Query::get`,
`World::entity_mut`, `EntityCommands` creation and everything that
causes `B0003`, e.g.
```
error[B0003]: Could not insert a bundle (of type `MaterialMeshBundle<StandardMaterial>`) for entity Entity { index: 7, generation: 1 }, which was despawned by src/main.rs:10:11. See: https://bevyengine.org/learn/errors/#b0003
```
---------
Co-authored-by: kurk070ff <108901106+kurk070ff@users.noreply.github.com>
Co-authored-by: Freya Pines <freya@MacBookAir.lan>
Co-authored-by: Freya Pines <freya@Freyas-MacBook-Air.local>
Co-authored-by: Matty Weatherley <weatherleymatthew@gmail.com>
85 lines
3.0 KiB
Rust
85 lines
3.0 KiB
Rust
//! Contains error types returned by bevy's schedule.
|
|
|
|
use thiserror::Error;
|
|
|
|
use crate::{component::ComponentId, entity::Entity, schedule::InternedScheduleLabel};
|
|
|
|
use super::unsafe_world_cell::UnsafeWorldCell;
|
|
|
|
/// The error type returned by [`World::try_run_schedule`] if the provided schedule does not exist.
|
|
///
|
|
/// [`World::try_run_schedule`]: crate::world::World::try_run_schedule
|
|
#[derive(Error, Debug)]
|
|
#[error("The schedule with the label {0:?} was not found.")]
|
|
pub struct TryRunScheduleError(pub InternedScheduleLabel);
|
|
|
|
/// An error that occurs when dynamically retrieving components from an entity.
|
|
#[derive(Error, Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum EntityComponentError {
|
|
/// The component with the given [`ComponentId`] does not exist on the entity.
|
|
#[error("The component with ID {0:?} does not exist on the entity.")]
|
|
MissingComponent(ComponentId),
|
|
/// The component with the given [`ComponentId`] was requested mutably more than once.
|
|
#[error("The component with ID {0:?} was requested mutably more than once.")]
|
|
AliasedMutability(ComponentId),
|
|
}
|
|
|
|
/// An error that occurs when fetching entities mutably from a world.
|
|
#[derive(Clone, Copy)]
|
|
pub enum EntityFetchError<'w> {
|
|
/// The entity with the given ID does not exist.
|
|
NoSuchEntity(Entity, UnsafeWorldCell<'w>),
|
|
/// The entity with the given ID was requested mutably more than once.
|
|
AliasedMutability(Entity),
|
|
}
|
|
|
|
impl<'w> core::error::Error for EntityFetchError<'w> {}
|
|
|
|
impl<'w> core::fmt::Display for EntityFetchError<'w> {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
match *self {
|
|
Self::NoSuchEntity(entity, world) => {
|
|
write!(
|
|
f,
|
|
"Entity {entity} {}",
|
|
world
|
|
.entities()
|
|
.entity_does_not_exist_error_details_message(entity)
|
|
)
|
|
}
|
|
Self::AliasedMutability(entity) => {
|
|
write!(f, "Entity {entity} was requested mutably more than once")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'w> core::fmt::Debug for EntityFetchError<'w> {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
match *self {
|
|
Self::NoSuchEntity(entity, world) => {
|
|
write!(
|
|
f,
|
|
"NoSuchEntity({entity} {})",
|
|
world
|
|
.entities()
|
|
.entity_does_not_exist_error_details_message(entity)
|
|
)
|
|
}
|
|
Self::AliasedMutability(entity) => write!(f, "AliasedMutability({entity})"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'w> PartialEq for EntityFetchError<'w> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(Self::NoSuchEntity(e1, _), Self::NoSuchEntity(e2, _)) if e1 == e2 => true,
|
|
(Self::AliasedMutability(e1), Self::AliasedMutability(e2)) if e1 == e2 => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'w> Eq for EntityFetchError<'w> {}
|