Remove APIs deprecated in 0.13 (#11974)

# Objective
We deprecated quite a few APIs in 0.13. 0.13 has shipped already. It
should be OK to remove them in 0.14's release. Fixes #4059. Fixes #9011.

## Solution
Remove them.
This commit is contained in:
James Liu 2024-02-19 11:04:47 -08:00 committed by GitHub
parent f77618eccb
commit bc82749012
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 74 additions and 1442 deletions

View file

@ -1,4 +1,4 @@
use bevy_ecs::entity::{Entity, EntityHashMap, EntityHashSet};
use bevy_ecs::entity::{Entity, EntityHashSet};
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;

View file

@ -28,8 +28,6 @@ criterion_group!(
world_query_iter,
world_query_for_each,
world_spawn,
query_get_component_simple,
query_get_component,
query_get,
query_get_many::<2>,
query_get_many::<5>,

View file

@ -2,7 +2,6 @@ use bevy_ecs::{
bundle::Bundle,
component::Component,
entity::Entity,
prelude::*,
system::{Query, SystemState},
world::World,
};
@ -257,104 +256,6 @@ pub fn world_query_for_each(criterion: &mut Criterion) {
group.finish();
}
pub fn query_get_component_simple(criterion: &mut Criterion) {
#[derive(Component)]
struct A(f32);
let mut group = criterion.benchmark_group("query_get_component_simple");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("unchecked", |bencher| {
let mut world = World::new();
let entity = world.spawn(A(0.0)).id();
let mut query = world.query::<&mut A>();
let world_cell = world.as_unsafe_world_cell();
bencher.iter(|| {
for _x in 0..100000 {
let mut a = unsafe { query.get_unchecked(world_cell, entity).unwrap() };
a.0 += 1.0;
}
});
});
group.bench_function("system", |bencher| {
let mut world = World::new();
let entity = world.spawn(A(0.0)).id();
fn query_system(In(entity): In<Entity>, mut query: Query<&mut A>) {
for _ in 0..100_000 {
let mut a = query.get_mut(entity).unwrap();
a.0 += 1.0;
}
}
let mut system = IntoSystem::into_system(query_system);
system.initialize(&mut world);
system.update_archetype_component_access(world.as_unsafe_world_cell());
bencher.iter(|| system.run(entity, &mut world));
});
group.finish();
}
pub fn query_get_component(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("query_get_component");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
let mut world = World::default();
let mut entities: Vec<_> = world
.spawn_batch((0..entity_count).map(|_| Table::default()))
.collect();
entities.shuffle(&mut deterministic_rand());
let mut query = SystemState::<Query<&Table>>::new(&mut world);
let query = query.get(&world);
bencher.iter(|| {
let mut count = 0;
for comp in entities
.iter()
.flat_map(|&e| query.get_component::<Table>(e))
{
black_box(comp);
count += 1;
black_box(count);
}
assert_eq!(black_box(count), entity_count);
});
});
group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
let mut world = World::default();
let mut entities: Vec<_> = world
.spawn_batch((0..entity_count).map(|_| Sparse::default()))
.collect();
entities.shuffle(&mut deterministic_rand());
let mut query = SystemState::<Query<&Sparse>>::new(&mut world);
let query = query.get(&world);
bencher.iter(|| {
let mut count = 0;
for comp in entities
.iter()
.flat_map(|&e| query.get_component::<Sparse>(e))
{
black_box(comp);
count += 1;
black_box(count);
}
assert_eq!(black_box(count), entity_count);
});
});
}
group.finish();
}
pub fn query_get(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("query_get");
group.warm_up_time(std::time::Duration::from_millis(500));

View file

@ -121,15 +121,6 @@ pub struct SceneEntityMapper<'m> {
}
impl<'m> SceneEntityMapper<'m> {
#[deprecated(
since = "0.13.0",
note = "please use `EntityMapper::map_entity` instead"
)]
/// Returns the corresponding mapped entity or reserves a new dead entity ID in the current world if it is absent.
pub fn get_or_reserve(&mut self, entity: Entity) -> Entity {
self.map_entity(entity)
}
/// Gets a reference to the underlying [`EntityHashMap<Entity>`].
pub fn get_map(&'m self) -> &'m EntityHashMap<Entity> {
self.map

View file

@ -21,76 +21,6 @@ pub enum QueryEntityError {
AliasedMutability(Entity),
}
/// An error that occurs when retrieving a specific [`Entity`]'s component from a [`Query`](crate::system::Query).
#[derive(Debug, PartialEq, Eq, Error)]
pub enum QueryComponentError {
/// The [`Query`](crate::system::Query) does not have read access to the requested component.
///
/// This error occurs when the requested component is not included in the original query.
///
/// # Example
///
/// ```
/// # use bevy_ecs::{prelude::*, query::QueryComponentError};
/// #
/// # #[derive(Component)]
/// # struct OtherComponent;
/// #
/// # #[derive(Component, PartialEq, Debug)]
/// # struct RequestedComponent;
/// #
/// # #[derive(Resource)]
/// # struct SpecificEntity {
/// # entity: Entity,
/// # }
/// #
/// fn get_missing_read_access_error(query: Query<&OtherComponent>, res: Res<SpecificEntity>) {
/// assert_eq!(
/// query.get_component::<RequestedComponent>(res.entity),
/// Err(QueryComponentError::MissingReadAccess),
/// );
/// println!("query doesn't have read access to RequestedComponent because it does not appear in Query<&OtherComponent>");
/// }
/// # bevy_ecs::system::assert_is_system(get_missing_read_access_error);
/// ```
#[error("This query does not have read access to the requested component")]
MissingReadAccess,
/// The [`Query`](crate::system::Query) does not have write access to the requested component.
///
/// This error occurs when the requested component is not included in the original query, or the mutability of the requested component is mismatched with the original query.
///
/// # Example
///
/// ```
/// # use bevy_ecs::{prelude::*, query::QueryComponentError};
/// #
/// # #[derive(Component, PartialEq, Debug)]
/// # struct RequestedComponent;
/// #
/// # #[derive(Resource)]
/// # struct SpecificEntity {
/// # entity: Entity,
/// # }
/// #
/// fn get_missing_write_access_error(mut query: Query<&RequestedComponent>, res: Res<SpecificEntity>) {
/// assert_eq!(
/// query.get_component::<RequestedComponent>(res.entity),
/// Err(QueryComponentError::MissingWriteAccess),
/// );
/// println!("query doesn't have write access to RequestedComponent because it doesn't have &mut in Query<&RequestedComponent>");
/// }
/// # bevy_ecs::system::assert_is_system(get_missing_write_access_error);
/// ```
#[error("This query does not have write access to the requested component")]
MissingWriteAccess,
/// The given [`Entity`] does not have the requested component.
#[error("The given entity does not have the requested component")]
MissingComponent,
/// The requested [`Entity`] does not exist.
#[error("The requested entity does not exist")]
NoSuchEntity,
}
/// An error that occurs when evaluating a [`Query`](crate::system::Query) or [`QueryState`](crate::query::QueryState) as a single expected result via
/// [`get_single`](crate::system::Query::get_single) or [`get_single_mut`](crate::system::Query::get_single_mut).
#[derive(Debug, Error)]

View file

@ -739,7 +739,6 @@ mod tests {
}
}
#[allow(deprecated)]
#[test]
fn mut_to_immut_query_methods_have_immut_item() {
#[derive(Component)]
@ -771,7 +770,6 @@ mod tests {
q.iter().for_each(|_: &Foo| ());
let _: Option<&Foo> = q.get(e).ok();
let _: Option<&Foo> = q.get_component(e).ok();
let _: Option<[&Foo; 1]> = q.get_many([e]).ok();
let _: Option<&Foo> = q.get_single().ok();
let _: [&Foo; 1] = q.many([e]);

View file

@ -1,9 +1,8 @@
use crate::{
archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration, ArchetypeId},
change_detection::Mut,
component::{ComponentId, Tick},
entity::Entity,
prelude::{Component, FromWorld},
prelude::FromWorld,
query::{
Access, BatchingStrategy, DebugCheckedUnwrap, FilteredAccess, QueryCombinationIter,
QueryIter, QueryParIter,
@ -14,7 +13,7 @@ use crate::{
#[cfg(feature = "trace")]
use bevy_utils::tracing::Span;
use fixedbitset::FixedBitSet;
use std::{any::TypeId, borrow::Borrow, fmt, mem::MaybeUninit, ptr};
use std::{borrow::Borrow, fmt, mem::MaybeUninit, ptr};
use super::{
NopWorldQuery, QueryBuilder, QueryData, QueryEntityError, QueryFilter, QueryManyIter,
@ -646,118 +645,6 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
}
}
/// Returns a shared reference to the component `T` of the given [`Entity`].
///
/// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead.
#[deprecated(
since = "0.13.0",
note = "Please use `get` and select for the exact component based on the structure of the exact query as required."
)]
#[allow(deprecated)]
#[inline]
pub(crate) fn get_component<'w, T: Component>(
&self,
world: UnsafeWorldCell<'w>,
entity: Entity,
) -> Result<&'w T, super::QueryComponentError> {
let entity_ref = world
.get_entity(entity)
.ok_or(super::QueryComponentError::NoSuchEntity)?;
let component_id = world
.components()
.get_id(TypeId::of::<T>())
.ok_or(super::QueryComponentError::MissingComponent)?;
let archetype_component = entity_ref
.archetype()
.get_archetype_component_id(component_id)
.ok_or(super::QueryComponentError::MissingComponent)?;
if self
.archetype_component_access
.has_read(archetype_component)
{
// SAFETY: `world` must have access to the component `T` for this entity,
// since it was registered in `self`'s archetype component access set.
unsafe { entity_ref.get::<T>() }.ok_or(super::QueryComponentError::MissingComponent)
} else {
Err(super::QueryComponentError::MissingReadAccess)
}
}
/// Returns a shared reference to the component `T` of the given [`Entity`].
///
/// # Panics
///
/// If given a nonexisting entity or mismatched component, this will panic.
#[deprecated(
since = "0.13.0",
note = "Please use `get` and select for the exact component based on the structure of the exact query as required."
)]
#[allow(deprecated)]
#[inline]
pub(crate) fn component<'w, T: Component>(
&self,
world: UnsafeWorldCell<'w>,
entity: Entity,
) -> &'w T {
match self.get_component(world, entity) {
Ok(component) => component,
Err(error) => {
panic!(
"Cannot get component `{:?}` from {entity:?}: {error}",
TypeId::of::<T>()
)
}
}
}
/// Returns a mutable reference to the component `T` of the given entity.
///
/// In case of a nonexisting entity or mismatched component, a [`QueryComponentError`] is returned instead.
///
/// # Safety
///
/// This function makes it possible to violate Rust's aliasing guarantees.
/// You must make sure this call does not result in multiple mutable references to the same component.
///
/// [`QueryComponentError`]: super::QueryComponentError
#[deprecated(
since = "0.13.0",
note = "Please use QueryState::get_unchecked_manual and select for the exact component based on the structure of the exact query as required."
)]
#[allow(deprecated)]
#[inline]
pub unsafe fn get_component_unchecked_mut<'w, T: Component>(
&self,
world: UnsafeWorldCell<'w>,
entity: Entity,
last_run: Tick,
this_run: Tick,
) -> Result<Mut<'w, T>, super::QueryComponentError> {
let entity_ref = world
.get_entity(entity)
.ok_or(super::QueryComponentError::NoSuchEntity)?;
let component_id = world
.components()
.get_id(TypeId::of::<T>())
.ok_or(super::QueryComponentError::MissingComponent)?;
let archetype_component = entity_ref
.archetype()
.get_archetype_component_id(component_id)
.ok_or(super::QueryComponentError::MissingComponent)?;
if self
.archetype_component_access
.has_write(archetype_component)
{
// SAFETY: It is the responsibility of the caller to ensure it is sound to get a
// mutable reference to this entity's component `T`.
let result = unsafe { entity_ref.get_mut_using_ticks::<T>(last_run, this_run) };
result.ok_or(super::QueryComponentError::MissingComponent)
} else {
Err(super::QueryComponentError::MissingWriteAccess)
}
}
/// Gets the read-only query results for the given [`World`] and array of [`Entity`], where the last change and
/// the current change tick are given.
///
@ -1133,56 +1020,6 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
QueryCombinationIter::new(world, self, last_run, this_run)
}
/// Runs `func` on each query result for the given [`World`]. This is faster than the equivalent
/// `iter()` method, but cannot be chained like a normal [`Iterator`].
///
/// This can only be called for read-only queries, see [`Self::for_each_mut`] for write-queries.
///
/// Shorthand for `query.iter(world).for_each(..)`.
#[inline]
#[deprecated(
since = "0.13.0",
note = "QueryState::for_each was not idiomatic Rust and has been moved to query.iter().for_each()"
)]
pub fn for_each<'w, FN: FnMut(ROQueryItem<'w, D>)>(&mut self, world: &'w World, func: FN) {
self.iter(world).for_each(func);
}
/// Runs `func` on each query result for the given [`World`]. This is faster than the equivalent
/// `iter_mut()` method, but cannot be chained like a normal [`Iterator`].
///
/// Shorthand for `query.iter_mut(world).for_each(..)`.
#[inline]
#[deprecated(
since = "0.13.0",
note = "QueryState::for_each_mut was not idiomatic Rust and has been moved to query.iter_mut().for_each()"
)]
pub fn for_each_mut<'w, FN: FnMut(D::Item<'w>)>(&mut self, world: &'w mut World, func: FN) {
self.iter_mut(world).for_each(func);
}
/// Runs `func` on each query result for the given [`World`]. This is faster than the equivalent
/// `iter()` method, but cannot be chained like a normal [`Iterator`].
///
/// # Safety
///
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query.
#[inline]
#[deprecated(
since = "0.13.0",
note = "QueryState::for_each_unchecked was not idiomatic Rust and has been moved to query.iter_unchecked_manual().for_each()"
)]
pub unsafe fn for_each_unchecked<'w, FN: FnMut(D::Item<'w>)>(
&mut self,
world: UnsafeWorldCell<'w>,
func: FN,
) {
self.update_archetypes_unsafe_world_cell(world);
self.iter_unchecked_manual(world, world.last_change_tick(), world.change_tick())
.for_each(func);
}
/// Returns a parallel iterator over the query results for the given [`World`].
///
/// This can only be called for read-only queries, see [`par_iter_mut`] for write-queries.

View file

@ -766,67 +766,6 @@ pub mod common_conditions {
}
}
/// Identical to [`in_state`] - use that instead.
///
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// if the state machine exists and is currently in `state`.
///
/// The condition will return `false` if the state does not exist.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Resource, Default)]
/// # struct Counter(u8);
/// # let mut app = Schedule::default();
/// # let mut world = World::new();
/// # world.init_resource::<Counter>();
/// #[derive(States, Clone, Copy, Default, Eq, PartialEq, Hash, Debug)]
/// enum GameState {
/// #[default]
/// Playing,
/// Paused,
/// }
///
/// app.add_systems((
/// // `state_exists_and_equals` will only return true if the
/// // given state exists and equals the given value
/// play_system.run_if(state_exists_and_equals(GameState::Playing)),
/// pause_system.run_if(state_exists_and_equals(GameState::Paused)),
/// ));
///
/// fn play_system(mut counter: ResMut<Counter>) {
/// counter.0 += 1;
/// }
///
/// fn pause_system(mut counter: ResMut<Counter>) {
/// counter.0 -= 1;
/// }
///
/// // `GameState` does not yet exists so neither system will run
/// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 0);
///
/// world.init_resource::<State<GameState>>();
///
/// // We default to `GameState::Playing` so `play_system` runs
/// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1);
///
/// *world.resource_mut::<State<GameState>>() = State::new(GameState::Paused);
///
/// // Now that we are in `GameState::Pause`, `pause_system` will run
/// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 0);
/// ```
#[deprecated(since = "0.13.0", note = "use `in_state` instead.")]
pub fn state_exists_and_equals<S: States>(
state: S,
) -> impl FnMut(Option<Res<State<S>>>) -> bool + Clone {
in_state(state)
}
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
/// if the state machine changed state.
///

View file

@ -401,65 +401,6 @@ mod tests {
schedule.run(world);
}
#[allow(deprecated)]
#[test]
fn query_system_gets() {
fn query_system(
mut ran: ResMut<SystemRan>,
entity_query: Query<Entity, With<A>>,
b_query: Query<&B>,
a_c_query: Query<(&A, &C)>,
d_query: Query<&D>,
) {
let entities = entity_query.iter().collect::<Vec<Entity>>();
assert!(
b_query.get_component::<B>(entities[0]).is_err(),
"entity 0 should not have B"
);
assert!(
b_query.get_component::<B>(entities[1]).is_ok(),
"entity 1 should have B"
);
assert!(
b_query.get_component::<A>(entities[1]).is_err(),
"entity 1 should have A, but b_query shouldn't have access to it"
);
assert!(
b_query.get_component::<D>(entities[3]).is_err(),
"entity 3 should have D, but it shouldn't be accessible from b_query"
);
assert!(
b_query.get_component::<C>(entities[2]).is_err(),
"entity 2 has C, but it shouldn't be accessible from b_query"
);
assert!(
a_c_query.get_component::<C>(entities[2]).is_ok(),
"entity 2 has C, and it should be accessible from a_c_query"
);
assert!(
a_c_query.get_component::<D>(entities[3]).is_err(),
"entity 3 should have D, but it shouldn't be accessible from b_query"
);
assert!(
d_query.get_component::<D>(entities[3]).is_ok(),
"entity 3 should have D"
);
*ran = SystemRan::Yes;
}
let mut world = World::default();
world.insert_resource(SystemRan::No);
world.spawn(A);
world.spawn((A, B));
world.spawn((A, C));
world.spawn((A, D));
run_system(&mut world, query_system);
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
}
#[test]
fn get_many_is_ordered() {
use crate::system::Resource;
@ -1561,22 +1502,6 @@ mod tests {
});
}
#[allow(deprecated)]
#[test]
fn readonly_query_get_mut_component_fails() {
use crate::query::QueryComponentError;
let mut world = World::new();
let entity = world.spawn(W(42u32)).id();
run_system(&mut world, move |q: Query<&mut W<u32>>| {
let mut rq = q.to_readonly();
assert_eq!(
QueryComponentError::MissingWriteAccess,
rq.get_component_mut::<W<u32>>(entity).unwrap_err(),
);
});
}
#[test]
#[should_panic = "Encountered a mismatched World."]
fn query_validates_world_id() {
@ -1590,7 +1515,6 @@ mod tests {
&qstate,
Tick::new(0),
Tick::new(0),
false,
)
};
query.iter();

View file

@ -1,14 +1,14 @@
use crate::{
component::{Component, Tick},
component::Tick,
entity::Entity,
query::{
BatchingStrategy, QueryCombinationIter, QueryData, QueryEntityError, QueryFilter,
QueryIter, QueryManyIter, QueryParIter, QuerySingleError, QueryState, ROQueryItem,
ReadOnlyQueryData,
},
world::{unsafe_world_cell::UnsafeWorldCell, Mut},
world::unsafe_world_cell::UnsafeWorldCell,
};
use std::{any::TypeId, borrow::Borrow};
use std::borrow::Borrow;
/// [System parameter] that provides selective access to the [`Component`] data stored in a [`World`].
///
@ -239,7 +239,7 @@ use std::{any::TypeId, borrow::Borrow};
/// |Query methods|Effect|
/// |:---:|---|
/// |[`iter`]\[[`_mut`][`iter_mut`]]|Returns an iterator over all query items.|
/// |[`for_each`]\[[`_mut`][`for_each_mut`]],<br>[`par_iter`]\[[`_mut`][`par_iter_mut`]]|Runs a specified function for each query item.|
/// |[[`iter().for_each()`][`for_each`]\[[`iter_mut().for_each()`][`for_each`]],<br>[`par_iter`]\[[`_mut`][`par_iter_mut`]]|Runs a specified function for each query item.|
/// |[`iter_many`]\[[`_mut`][`iter_many_mut`]]|Iterates or runs a specified function over query items generated by a list of entities.|
/// |[`iter_combinations`]\[[`_mut`][`iter_combinations_mut`]]|Returns an iterator over all combinations of a specified number of query items.|
/// |[`get`]\[[`_mut`][`get_mut`]]|Returns the query item for the specified entity.|
@ -275,7 +275,7 @@ use std::{any::TypeId, borrow::Borrow};
/// |Query operation|Computational complexity|
/// |:---:|:---:|
/// |[`iter`]\[[`_mut`][`iter_mut`]]|O(n)|
/// |[`for_each`]\[[`_mut`][`for_each_mut`]],<br>[`par_iter`]\[[`_mut`][`par_iter_mut`]]|O(n)|
/// |[[`iter().for_each()`][`for_each`]\[[`iter_mut().for_each()`][`for_each`]],<br>[`par_iter`]\[[`_mut`][`par_iter_mut`]]|O(n)|
/// |[`iter_many`]\[[`_mut`][`iter_many_mut`]]|O(k)|
/// |[`iter_combinations`]\[[`_mut`][`iter_combinations_mut`]]|O(<sub>n</sub>C<sub>r</sub>)|
/// |[`get`]\[[`_mut`][`get_mut`]]|O(1)|
@ -285,12 +285,34 @@ use std::{any::TypeId, borrow::Borrow};
/// |Archetype based filtering ([`With`], [`Without`], [`Or`])|O(a)|
/// |Change detection filtering ([`Added`], [`Changed`])|O(a + n)|
///
/// `for_each` methods are seen to be generally faster than their `iter` version on worlds with high archetype fragmentation.
/// As iterators are in general more flexible and better integrated with the rest of the Rust ecosystem,
/// it is advised to use `iter` methods over `for_each`.
/// It is strongly advised to only use `for_each` if it tangibly improves performance:
/// be sure profile or benchmark both before and after the change.
/// # `Iterator::for_each`
///
/// `for_each` methods are seen to be generally faster than directly iterating through `iter` on worlds with high archetype
/// fragmentation, and may enable additional optimizations like [autovectorization]. It is strongly advised to only use
/// [`Iterator::for_each`] if it tangibly improves performance. *Always* be sure profile or benchmark both before and
/// after the change!
///
/// ```rust
/// # use bevy_ecs::prelude::*;
/// # #[derive(Component)]
/// # struct ComponentA;
/// # fn system(
/// # query: Query<&ComponentA>,
/// # ) {
/// // This might be result in better performance...
/// query.iter().for_each(|component| {
/// // do things with the component
/// });
/// // ...than this. Always be sure to benchmark to validate the difference!
/// for component in query.iter() {
/// // do things with the component
/// }
/// # }
/// # bevy_ecs::system::assert_system_does_not_conflict(system);
/// ```
///
/// [`Component`]: crate::component::Component
/// [autovectorization]: https://en.wikipedia.org/wiki/Automatic_vectorization
/// [`Added`]: crate::query::Added
/// [`AnyOf`]: crate::query::AnyOf
/// [binomial coefficient]: https://en.wikipedia.org/wiki/Binomial_coefficient
@ -298,8 +320,7 @@ use std::{any::TypeId, borrow::Borrow};
/// [components]: crate::component::Component
/// [entity identifiers]: Entity
/// [`EntityRef`]: crate::world::EntityRef
/// [`for_each`]: Self::for_each
/// [`for_each_mut`]: Self::for_each_mut
/// [`for_each`]: #iterator-for-each
/// [`get`]: Self::get
/// [`get_many`]: Self::get_many
/// [`get_many_mut`]: Self::get_many_mut
@ -331,12 +352,6 @@ pub struct Query<'world, 'state, D: QueryData, F: QueryFilter = ()> {
state: &'state QueryState<D, F>,
last_run: Tick,
this_run: Tick,
// SAFETY: This is used to ensure that `get_component_mut::<C>` properly fails when a Query writes C
// and gets converted to a read-only query using `to_readonly`. Without checking this, `get_component_mut` relies on
// QueryState's archetype_component_access, which will continue allowing write access to C after being cast to
// the read-only variant. This whole situation is confusing and error prone. Ideally this is a temporary hack
// until we sort out a cleaner alternative.
force_read_only_component_access: bool,
}
impl<D: QueryData, F: QueryFilter> std::fmt::Debug for Query<'_, '_, D, F> {
@ -368,12 +383,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
state: &'s QueryState<D, F>,
last_run: Tick,
this_run: Tick,
force_read_only_component_access: bool,
) -> Self {
state.validate_world(world.id());
Self {
force_read_only_component_access,
world,
state,
last_run,
@ -389,17 +402,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
pub fn to_readonly(&self) -> Query<'_, 's, D::ReadOnly, F> {
let new_state = self.state.as_readonly();
// SAFETY: This is memory safe because it turns the query immutable.
unsafe {
Query::new(
self.world,
new_state,
self.last_run,
self.this_run,
// SAFETY: this must be set to true or `get_component_mut` will be unsound. See the comments
// on this field for more details
true,
)
}
unsafe { Query::new(self.world, new_state, self.last_run, self.this_run) }
}
/// Returns an [`Iterator`] over the read-only query items.
@ -424,8 +427,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
///
/// # See also
///
/// - [`iter_mut`](Self::iter_mut) for mutable query items.
/// - [`for_each`](Self::for_each) for the closure based alternative.
/// [`iter_mut`](Self::iter_mut) for mutable query items.
#[inline]
pub fn iter(&self) -> QueryIter<'_, 's, D::ReadOnly, F> {
// SAFETY:
@ -460,8 +462,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
///
/// # See also
///
/// - [`iter`](Self::iter) for read-only query items.
/// - [`for_each_mut`](Self::for_each_mut) for the closure based alternative.
/// [`iter`](Self::iter) for read-only query items.
#[inline]
pub fn iter_mut(&mut self) -> QueryIter<'_, 's, D, F> {
// SAFETY: `self.world` has permission to access the required components.
@ -710,89 +711,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
.iter_many_unchecked_manual(entities, self.world, self.last_run, self.this_run)
}
/// Runs `f` on each read-only query item.
///
/// Shorthand for `query.iter().for_each(..)`.
///
/// # Example
///
/// Here, the `report_names_system` iterates over the `Player` component of every entity that contains it:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Component)]
/// # struct Player { name: String }
/// #
/// fn report_names_system(query: Query<&Player>) {
/// query.for_each(|player| {
/// println!("Say hello to {}!", player.name);
/// });
/// }
/// # bevy_ecs::system::assert_is_system(report_names_system);
/// ```
///
/// # See also
///
/// - [`for_each_mut`](Self::for_each_mut) to operate on mutable query items.
/// - [`iter`](Self::iter) for the iterator based alternative.
#[inline]
#[deprecated(
since = "0.13.0",
note = "Query::for_each was not idiomatic Rust and has been moved to query.iter().for_each()"
)]
pub fn for_each<'this>(&'this self, f: impl FnMut(ROQueryItem<'this, D>)) {
// SAFETY:
// - `self.world` has permission to access the required components.
// - The query is read-only, so it can be aliased even if it was originally mutable.
unsafe {
self.state
.as_readonly()
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
.for_each(f);
};
}
/// Runs `f` on each query item.
///
/// Shorthand for `query.iter_mut().for_each(..)`.
///
/// # Example
///
/// Here, the `gravity_system` updates the `Velocity` component of every entity that contains it:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Component)]
/// # struct Velocity { x: f32, y: f32, z: f32 }
/// fn gravity_system(mut query: Query<&mut Velocity>) {
/// const DELTA: f32 = 1.0 / 60.0;
/// query.for_each_mut(|mut velocity| {
/// velocity.y -= 9.8 * DELTA;
/// });
/// }
/// # bevy_ecs::system::assert_is_system(gravity_system);
/// ```
///
/// # See also
///
/// - [`for_each`](Self::for_each) to operate on read-only query items.
/// - [`iter_mut`](Self::iter_mut) for the iterator based alternative.
#[inline]
#[deprecated(
since = "0.13.0",
note = "Query::for_each_mut was not idiomatic Rust and has been moved to query.iter_mut().for_each()"
)]
pub fn for_each_mut<'a>(&'a mut self, f: impl FnMut(D::Item<'a>)) {
// SAFETY: `self.world` has permission to access the required components.
unsafe {
self.state
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
.for_each(f);
};
}
/// Returns a parallel iterator over the query results for the given [`World`].
///
/// This can only be called for read-only queries, see [`par_iter_mut`] for write-queries.
@ -1100,183 +1018,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
.get_unchecked_manual(self.world, entity, self.last_run, self.this_run)
}
/// Returns a shared reference to the component `T` of the given [`Entity`].
///
/// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead.
///
/// # Example
///
/// Here, `get_component` is used to retrieve the `Character` component of the entity specified by the `SelectedCharacter` resource.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Resource)]
/// # struct SelectedCharacter { entity: Entity }
/// # #[derive(Component)]
/// # struct Character { name: String }
/// #
/// fn print_selected_character_name_system(
/// query: Query<&Character>,
/// selection: Res<SelectedCharacter>
/// )
/// {
/// if let Ok(selected_character) = query.get_component::<Character>(selection.entity) {
/// println!("{}", selected_character.name);
/// }
/// }
/// # bevy_ecs::system::assert_is_system(print_selected_character_name_system);
/// ```
///
/// # See also
///
/// - [`component`](Self::component) a panicking version of this function.
/// - [`get_component_mut`](Self::get_component_mut) to get a mutable reference of a component.
#[deprecated(
since = "0.13.0",
note = "Please use `get` and select for the exact component based on the structure of the exact query as required."
)]
#[allow(deprecated)]
#[inline]
pub fn get_component<T: Component>(
&self,
entity: Entity,
) -> Result<&T, crate::query::QueryComponentError> {
self.state.get_component(self.world, entity)
}
/// Returns a mutable reference to the component `T` of the given entity.
///
/// In case of a nonexisting entity, mismatched component or missing write access, a [`QueryComponentError`] is returned instead.
///
/// # Example
///
/// Here, `get_component_mut` is used to retrieve the `Health` component of the entity specified by the `PoisonedCharacter` resource.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Resource)]
/// # struct PoisonedCharacter { character_id: Entity }
/// # #[derive(Component)]
/// # struct Health(u32);
/// #
/// fn poison_system(mut query: Query<&mut Health>, poisoned: Res<PoisonedCharacter>) {
/// if let Ok(mut health) = query.get_component_mut::<Health>(poisoned.character_id) {
/// health.0 -= 1;
/// }
/// }
/// # bevy_ecs::system::assert_is_system(poison_system);
/// ```
///
/// # See also
///
/// - [`component_mut`](Self::component_mut) a panicking version of this function.
/// - [`get_component`](Self::get_component) to get a shared reference of a component.
///
/// [`QueryComponentError`]: crate::query::QueryComponentError
#[deprecated(
since = "0.13.0",
note = "Please use `get_mut` and select for the exact component based on the structure of the exact query as required."
)]
#[allow(deprecated)]
#[inline]
pub fn get_component_mut<T: Component>(
&mut self,
entity: Entity,
) -> Result<Mut<'_, T>, crate::query::QueryComponentError> {
// SAFETY: unique access to query (preventing aliased access)
unsafe { self.get_component_unchecked_mut(entity) }
}
/// Returns a shared reference to the component `T` of the given [`Entity`].
///
/// # Panics
///
/// Panics in case of a nonexisting entity or mismatched component.
///
/// # See also
///
/// - [`get_component`](Self::get_component) a non-panicking version of this function.
/// - [`component_mut`](Self::component_mut) to get a mutable reference of a component.
#[deprecated(
since = "0.13.0",
note = "Please use `get` and select for the exact component based on the structure of the exact query as required."
)]
#[allow(deprecated)]
#[inline]
#[track_caller]
pub fn component<T: Component>(&self, entity: Entity) -> &T {
self.state.component(self.world, entity)
}
/// Returns a mutable reference to the component `T` of the given entity.
///
/// # Panics
///
/// Panics in case of a nonexisting entity, mismatched component or missing write access.
///
/// # See also
///
/// - [`get_component_mut`](Self::get_component_mut) a non-panicking version of this function.
/// - [`component`](Self::component) to get a shared reference of a component.
#[deprecated(
since = "0.13.0",
note = "Please use `get_mut` and select for the exact component based on the structure of the exact query as required."
)]
#[allow(deprecated)]
#[inline]
#[track_caller]
pub fn component_mut<T: Component>(&mut self, entity: Entity) -> Mut<'_, T> {
match self.get_component_mut(entity) {
Ok(component) => component,
Err(error) => {
panic!(
"Cannot get component `{:?}` from {entity:?}: {error}",
TypeId::of::<T>()
)
}
}
}
/// Returns a mutable reference to the component `T` of the given entity.
///
/// In case of a nonexisting entity or mismatched component, a [`QueryComponentError`] is returned instead.
///
/// # Safety
///
/// This function makes it possible to violate Rust's aliasing guarantees.
/// You must make sure this call does not result in multiple mutable references to the same component.
///
/// # See also
///
/// - [`get_component_mut`](Self::get_component_mut) for the safe version.
///
/// [`QueryComponentError`]: crate::query::QueryComponentError
#[deprecated(
since = "0.13.0",
note = "Please use `get_unchecked` and select for the exact component based on the structure of the exact query as required."
)]
#[allow(deprecated)]
#[inline]
pub unsafe fn get_component_unchecked_mut<T: Component>(
&self,
entity: Entity,
) -> Result<Mut<'_, T>, crate::query::QueryComponentError> {
// This check is required to ensure soundness in the case of `to_readonly().get_component_mut()`
// See the comments on the `force_read_only_component_access` field for more info.
if self.force_read_only_component_access {
return Err(crate::query::QueryComponentError::MissingWriteAccess);
}
// SAFETY: The above check ensures we are not a readonly query.
// It is the callers responsibility to ensure multiple mutable access is not provided.
unsafe {
self.state
.get_component_unchecked_mut(self.world, entity, self.last_run, self.this_run)
}
}
/// Returns a single read-only query item when there is exactly one entity matching the query.
///
/// # Panics
@ -1566,7 +1307,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
state,
last_run: self.last_run,
this_run: self.this_run,
force_read_only_component_access: self.force_read_only_component_access,
}
}
@ -1684,7 +1424,6 @@ pub struct QueryLens<'w, Q: QueryData, F: QueryFilter = ()> {
state: QueryState<Q, F>,
last_run: Tick,
this_run: Tick,
force_read_only_component_access: bool,
}
impl<'w, Q: QueryData, F: QueryFilter> QueryLens<'w, Q, F> {
@ -1695,7 +1434,6 @@ impl<'w, Q: QueryData, F: QueryFilter> QueryLens<'w, Q, F> {
state: &self.state,
last_run: self.last_run,
this_run: self.this_run,
force_read_only_component_access: self.force_read_only_component_access,
}
}
}

View file

@ -228,7 +228,7 @@ unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Qu
// SAFETY: We have registered all of the query's world accesses,
// so the caller ensures that `world` has permission to access any
// world data that the query needs.
Query::new(world, state, system_meta.last_run, change_tick, false)
Query::new(world, state, system_meta.last_run, change_tick)
}
}

View file

@ -24,20 +24,6 @@ fn main() {
assert_eq!(data, &mut *data2); // oops UB
}
#[allow(deprecated)]
{
let data: &Foo = query.get_component::<Foo>(e).unwrap();
let mut data2: Mut<Foo> = query.get_component_mut(e).unwrap();
assert_eq!(data, &mut *data2); // oops UB
}
#[allow(deprecated)]
{
let mut data2: Mut<Foo> = query.get_component_mut(e).unwrap();
let data: &Foo = query.get_component::<Foo>(e).unwrap();
assert_eq!(data, &mut *data2); // oops UB
}
{
let data: &Foo = query.single();
let mut data2: Mut<Foo> = query.single_mut();

View file

@ -19,101 +19,81 @@ error[E0502]: cannot borrow `query` as immutable because it is also borrowed as
| ----- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_lifetime_safety.rs:30:39
--> tests/ui/query_lifetime_safety.rs:29:39
|
29 | let data: &Foo = query.get_component::<Foo>(e).unwrap();
28 | let data: &Foo = query.single();
| ----- immutable borrow occurs here
30 | let mut data2: Mut<Foo> = query.get_component_mut(e).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
31 | assert_eq!(data, &mut *data2); // oops UB
| ----------------------------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:37:30
|
36 | let mut data2: Mut<Foo> = query.get_component_mut(e).unwrap();
| ----- mutable borrow occurs here
37 | let data: &Foo = query.get_component::<Foo>(e).unwrap();
| ^^^^^ immutable borrow occurs here
38 | assert_eq!(data, &mut *data2); // oops UB
| ----- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_lifetime_safety.rs:43:39
|
42 | let data: &Foo = query.single();
| ----- immutable borrow occurs here
43 | let mut data2: Mut<Foo> = query.single_mut();
29 | let mut data2: Mut<Foo> = query.single_mut();
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
44 | assert_eq!(data, &mut *data2); // oops UB
30 | assert_eq!(data, &mut *data2); // oops UB
| ----------------------------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:49:30
--> tests/ui/query_lifetime_safety.rs:35:30
|
48 | let mut data2: Mut<Foo> = query.single_mut();
34 | let mut data2: Mut<Foo> = query.single_mut();
| ----- mutable borrow occurs here
49 | let data: &Foo = query.single();
35 | let data: &Foo = query.single();
| ^^^^^ immutable borrow occurs here
50 | assert_eq!(data, &mut *data2); // oops UB
36 | assert_eq!(data, &mut *data2); // oops UB
| ----- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_lifetime_safety.rs:55:39
--> tests/ui/query_lifetime_safety.rs:41:39
|
54 | let data: &Foo = query.get_single().unwrap();
40 | let data: &Foo = query.get_single().unwrap();
| ----- immutable borrow occurs here
55 | let mut data2: Mut<Foo> = query.get_single_mut().unwrap();
41 | let mut data2: Mut<Foo> = query.get_single_mut().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
56 | assert_eq!(data, &mut *data2); // oops UB
42 | assert_eq!(data, &mut *data2); // oops UB
| ----------------------------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:61:30
--> tests/ui/query_lifetime_safety.rs:47:30
|
60 | let mut data2: Mut<Foo> = query.get_single_mut().unwrap();
46 | let mut data2: Mut<Foo> = query.get_single_mut().unwrap();
| ----- mutable borrow occurs here
61 | let data: &Foo = query.get_single().unwrap();
47 | let data: &Foo = query.get_single().unwrap();
| ^^^^^ immutable borrow occurs here
62 | assert_eq!(data, &mut *data2); // oops UB
48 | assert_eq!(data, &mut *data2); // oops UB
| ----- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_lifetime_safety.rs:67:39
--> tests/ui/query_lifetime_safety.rs:53:39
|
66 | let data: &Foo = query.iter().next().unwrap();
52 | let data: &Foo = query.iter().next().unwrap();
| ----- immutable borrow occurs here
67 | let mut data2: Mut<Foo> = query.iter_mut().next().unwrap();
53 | let mut data2: Mut<Foo> = query.iter_mut().next().unwrap();
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
68 | assert_eq!(data, &mut *data2); // oops UB
54 | assert_eq!(data, &mut *data2); // oops UB
| ----------------------------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:73:30
--> tests/ui/query_lifetime_safety.rs:59:30
|
72 | let mut data2: Mut<Foo> = query.iter_mut().next().unwrap();
58 | let mut data2: Mut<Foo> = query.iter_mut().next().unwrap();
| ----- mutable borrow occurs here
73 | let data: &Foo = query.iter().next().unwrap();
59 | let data: &Foo = query.iter().next().unwrap();
| ^^^^^ immutable borrow occurs here
74 | assert_eq!(data, &mut *data2); // oops UB
60 | assert_eq!(data, &mut *data2); // oops UB
| ----- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_lifetime_safety.rs:81:13
--> tests/ui/query_lifetime_safety.rs:67:13
|
80 | query.iter().for_each(|data| opt_data = Some(data));
66 | query.iter().for_each(|data| opt_data = Some(data));
| ----- immutable borrow occurs here
81 | query.iter_mut().for_each(|data| opt_data_2 = Some(data));
67 | query.iter_mut().for_each(|data| opt_data_2 = Some(data));
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
82 | assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB
68 | assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB
| -------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:89:13
--> tests/ui/query_lifetime_safety.rs:75:13
|
88 | query.iter_mut().for_each(|data| opt_data_2 = Some(data));
74 | query.iter_mut().for_each(|data| opt_data_2 = Some(data));
| ----- mutable borrow occurs here
89 | query.iter().for_each(|data| opt_data = Some(data));
75 | query.iter().for_each(|data| opt_data = Some(data));
| ^^^^^ immutable borrow occurs here
90 | assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB
76 | assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB
| ---------- mutable borrow later used here

View file

@ -37,7 +37,7 @@ pub mod prelude {
Projection,
},
color::Color,
mesh::{morph::MorphWeights, primitives::Meshable, shape, Mesh},
mesh::{morph::MorphWeights, primitives::Meshable, Mesh},
render_resource::Shader,
spatial_bundle::SpatialBundle,
texture::{Image, ImagePlugin},

View file

@ -32,7 +32,7 @@ pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
/// with "attribute" values for each vertex.
///
/// Meshes can be automatically generated by a bevy `AssetLoader` (generally by loading a `Gltf` file),
/// or by converting a primitive [`shape`](crate::mesh::shape) using [`into`](Into).
/// or by converting a [primitive](bevy_math::primitives) using [`into`](Into).
/// It is also possible to create one manually.
/// They can be edited after creation.
///

View file

@ -2,8 +2,6 @@
mod mesh;
pub mod morph;
pub mod primitives;
/// Generation for some primitive shape meshes.
pub mod shape;
pub use mesh::*;
pub use primitives::*;

View file

@ -1,49 +0,0 @@
use crate::mesh::{Capsule3dMeshBuilder, CapsuleUvProfile, Mesh};
/// A cylinder with hemispheres at the top and bottom
#[deprecated(
since = "0.13.0",
note = "please use the `Capsule3d` primitive in `bevy_math` instead"
)]
#[derive(Debug, Copy, Clone)]
pub struct Capsule {
/// Radius on the `XZ` plane.
pub radius: f32,
/// Number of sections in cylinder between hemispheres.
pub rings: usize,
/// Height of the middle cylinder on the `Y` axis, excluding the hemispheres.
pub depth: f32,
/// Number of latitudes, distributed by inclination. Must be even.
pub latitudes: usize,
/// Number of longitudes, or meridians, distributed by azimuth.
pub longitudes: usize,
/// Manner in which UV coordinates are distributed vertically.
pub uv_profile: CapsuleUvProfile,
}
impl Default for Capsule {
fn default() -> Self {
Capsule {
radius: 0.5,
rings: 0,
depth: 1.0,
latitudes: 16,
longitudes: 32,
uv_profile: CapsuleUvProfile::Aspect,
}
}
}
impl From<Capsule> for Mesh {
#[allow(clippy::needless_range_loop)]
fn from(capsule: Capsule) -> Self {
Capsule3dMeshBuilder::new(
capsule.radius,
capsule.depth,
capsule.longitudes,
capsule.latitudes,
)
.rings(capsule.rings)
.uv_profile(capsule.uv_profile)
.build()
}
}

View file

@ -1,41 +0,0 @@
use crate::mesh::{CylinderMeshBuilder, Mesh};
/// A cylinder which stands on the XZ plane
#[deprecated(
since = "0.13.0",
note = "please use the `Cylinder` primitive in `bevy_math` instead"
)]
#[derive(Clone, Copy, Debug)]
pub struct Cylinder {
/// Radius in the XZ plane.
pub radius: f32,
/// Height of the cylinder in the Y axis.
pub height: f32,
/// The number of vertices around each horizontal slice of the cylinder. If you are looking at the cylinder from
/// above, this is the number of points you will see on the circle.
/// A higher number will make it appear more circular.
pub resolution: u32,
/// The number of segments between the two ends. Setting this to 1 will have triangles spanning the full
/// height of the cylinder. Setting it to 2 will have two sets of triangles with a horizontal slice in the middle of
/// cylinder. Greater numbers increase triangles/slices in the same way.
pub segments: u32,
}
impl Default for Cylinder {
fn default() -> Self {
Self {
radius: 0.5,
height: 1.0,
resolution: 16,
segments: 1,
}
}
}
impl From<Cylinder> for Mesh {
fn from(c: Cylinder) -> Self {
CylinderMeshBuilder::new(c.radius, c.height, c.resolution)
.segments(c.segments)
.build()
}
}

View file

@ -1,32 +0,0 @@
use crate::mesh::{IcosphereError, Mesh, Meshable};
use bevy_math::primitives::Sphere;
/// A sphere made from a subdivided Icosahedron.
#[deprecated(
since = "0.13.0",
note = "please use the `Sphere` primitive in `bevy_math` instead"
)]
#[derive(Debug, Clone, Copy)]
pub struct Icosphere {
/// The radius of the sphere.
pub radius: f32,
/// The number of subdivisions applied.
pub subdivisions: usize,
}
impl Default for Icosphere {
fn default() -> Self {
Self {
radius: 1.0,
subdivisions: 5,
}
}
}
impl TryFrom<Icosphere> for Mesh {
type Error = IcosphereError;
fn try_from(sphere: Icosphere) -> Result<Self, Self::Error> {
Sphere::new(sphere.radius).mesh().ico(sphere.subdivisions)
}
}

View file

@ -1,306 +0,0 @@
#![allow(deprecated)]
use crate::render_asset::RenderAssetUsages;
use super::{Indices, Mesh};
use bevy_math::*;
#[deprecated(
since = "0.13.0",
note = "please use the `Cuboid` primitive for meshing or `Aabb2d` for a bounding volume"
)]
#[derive(Debug, Copy, Clone)]
pub struct Cube {
pub size: f32,
}
impl Cube {
pub fn new(size: f32) -> Cube {
Cube { size }
}
}
impl Default for Cube {
fn default() -> Self {
Cube { size: 1.0 }
}
}
impl From<Cube> for Mesh {
fn from(cube: Cube) -> Self {
Box::new(cube.size, cube.size, cube.size).into()
}
}
/// An axis-aligned box defined by its minimum and maximum point.
#[deprecated(
since = "0.13.0",
note = "please use the `Cuboid` primitive for meshing or `Aabb3d` for a bounding volume"
)]
#[derive(Debug, Copy, Clone)]
pub struct Box {
pub min_x: f32,
pub max_x: f32,
pub min_y: f32,
pub max_y: f32,
pub min_z: f32,
pub max_z: f32,
}
impl Box {
/// Creates a new box centered at the origin with the supplied side lengths.
pub fn new(x_length: f32, y_length: f32, z_length: f32) -> Box {
Box {
max_x: x_length / 2.0,
min_x: -x_length / 2.0,
max_y: y_length / 2.0,
min_y: -y_length / 2.0,
max_z: z_length / 2.0,
min_z: -z_length / 2.0,
}
}
/// Creates a new box given the coordinates of two opposing corners.
pub fn from_corners(a: Vec3, b: Vec3) -> Box {
let max = a.max(b);
let min = a.min(b);
Box {
max_x: max.x,
min_x: min.x,
max_y: max.y,
min_y: min.y,
max_z: max.z,
min_z: min.z,
}
}
}
impl Default for Box {
fn default() -> Self {
Box::new(2.0, 1.0, 1.0)
}
}
impl From<Box> for Mesh {
fn from(sp: Box) -> Self {
// suppose Y-up right hand, and camera look from +z to -z
let vertices = &[
// Front
([sp.min_x, sp.min_y, sp.max_z], [0., 0., 1.0], [0., 0.]),
([sp.max_x, sp.min_y, sp.max_z], [0., 0., 1.0], [1.0, 0.]),
([sp.max_x, sp.max_y, sp.max_z], [0., 0., 1.0], [1.0, 1.0]),
([sp.min_x, sp.max_y, sp.max_z], [0., 0., 1.0], [0., 1.0]),
// Back
([sp.min_x, sp.max_y, sp.min_z], [0., 0., -1.0], [1.0, 0.]),
([sp.max_x, sp.max_y, sp.min_z], [0., 0., -1.0], [0., 0.]),
([sp.max_x, sp.min_y, sp.min_z], [0., 0., -1.0], [0., 1.0]),
([sp.min_x, sp.min_y, sp.min_z], [0., 0., -1.0], [1.0, 1.0]),
// Right
([sp.max_x, sp.min_y, sp.min_z], [1.0, 0., 0.], [0., 0.]),
([sp.max_x, sp.max_y, sp.min_z], [1.0, 0., 0.], [1.0, 0.]),
([sp.max_x, sp.max_y, sp.max_z], [1.0, 0., 0.], [1.0, 1.0]),
([sp.max_x, sp.min_y, sp.max_z], [1.0, 0., 0.], [0., 1.0]),
// Left
([sp.min_x, sp.min_y, sp.max_z], [-1.0, 0., 0.], [1.0, 0.]),
([sp.min_x, sp.max_y, sp.max_z], [-1.0, 0., 0.], [0., 0.]),
([sp.min_x, sp.max_y, sp.min_z], [-1.0, 0., 0.], [0., 1.0]),
([sp.min_x, sp.min_y, sp.min_z], [-1.0, 0., 0.], [1.0, 1.0]),
// Top
([sp.max_x, sp.max_y, sp.min_z], [0., 1.0, 0.], [1.0, 0.]),
([sp.min_x, sp.max_y, sp.min_z], [0., 1.0, 0.], [0., 0.]),
([sp.min_x, sp.max_y, sp.max_z], [0., 1.0, 0.], [0., 1.0]),
([sp.max_x, sp.max_y, sp.max_z], [0., 1.0, 0.], [1.0, 1.0]),
// Bottom
([sp.max_x, sp.min_y, sp.max_z], [0., -1.0, 0.], [0., 0.]),
([sp.min_x, sp.min_y, sp.max_z], [0., -1.0, 0.], [1.0, 0.]),
([sp.min_x, sp.min_y, sp.min_z], [0., -1.0, 0.], [1.0, 1.0]),
([sp.max_x, sp.min_y, sp.min_z], [0., -1.0, 0.], [0., 1.0]),
];
let positions: Vec<_> = vertices.iter().map(|(p, _, _)| *p).collect();
let normals: Vec<_> = vertices.iter().map(|(_, n, _)| *n).collect();
let uvs: Vec<_> = vertices.iter().map(|(_, _, uv)| *uv).collect();
let indices = Indices::U32(vec![
0, 1, 2, 2, 3, 0, // front
4, 5, 6, 6, 7, 4, // back
8, 9, 10, 10, 11, 8, // right
12, 13, 14, 14, 15, 12, // left
16, 17, 18, 18, 19, 16, // top
20, 21, 22, 22, 23, 20, // bottom
]);
Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
)
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
.with_inserted_indices(indices)
}
}
/// A rectangle on the `XY` plane centered at the origin.
#[deprecated(
since = "0.13.0",
note = "please use the `Rectangle` primitive in `bevy_math` instead"
)]
#[derive(Debug, Copy, Clone)]
pub struct Quad {
/// Full width and height of the rectangle.
pub size: Vec2,
/// Horizontally-flip the texture coordinates of the resulting mesh.
pub flip: bool,
}
impl Default for Quad {
fn default() -> Self {
Quad::new(Vec2::ONE)
}
}
impl Quad {
pub fn new(size: Vec2) -> Self {
Self { size, flip: false }
}
pub fn flipped(size: Vec2) -> Self {
Self { size, flip: true }
}
}
impl From<Quad> for Mesh {
fn from(quad: Quad) -> Self {
let extent_x = quad.size.x / 2.0;
let extent_y = quad.size.y / 2.0;
let (u_left, u_right) = if quad.flip { (1.0, 0.0) } else { (0.0, 1.0) };
let vertices = [
([-extent_x, -extent_y, 0.0], [0.0, 0.0, 1.0], [u_left, 1.0]),
([-extent_x, extent_y, 0.0], [0.0, 0.0, 1.0], [u_left, 0.0]),
([extent_x, extent_y, 0.0], [0.0, 0.0, 1.0], [u_right, 0.0]),
([extent_x, -extent_y, 0.0], [0.0, 0.0, 1.0], [u_right, 1.0]),
];
let indices = Indices::U32(vec![0, 2, 1, 0, 3, 2]);
let positions: Vec<_> = vertices.iter().map(|(p, _, _)| *p).collect();
let normals: Vec<_> = vertices.iter().map(|(_, n, _)| *n).collect();
let uvs: Vec<_> = vertices.iter().map(|(_, _, uv)| *uv).collect();
Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
)
.with_inserted_indices(indices)
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
}
}
/// A square on the `XZ` plane centered at the origin.
#[deprecated(
since = "0.13.0",
note = "please use the `Plane3d` primitive in `bevy_math` instead"
)]
#[derive(Debug, Copy, Clone)]
pub struct Plane {
/// The total side length of the square.
pub size: f32,
/// The number of subdivisions in the mesh.
///
/// 0 - is the original plane geometry, the 4 points in the XZ plane.
///
/// 1 - is split by 1 line in the middle of the plane on both the X axis and the Z axis, resulting in a plane with 4 quads / 8 triangles.
///
/// 2 - is a plane split by 2 lines on both the X and Z axes, subdividing the plane into 3 equal sections along each axis, resulting in a plane with 9 quads / 18 triangles.
///
/// and so on...
pub subdivisions: u32,
}
impl Default for Plane {
fn default() -> Self {
Plane {
size: 1.0,
subdivisions: 0,
}
}
}
impl Plane {
/// Creates a new plane centered at the origin with the supplied side length and zero subdivisions.
pub fn from_size(size: f32) -> Self {
Self {
size,
subdivisions: 0,
}
}
}
impl From<Plane> for Mesh {
fn from(plane: Plane) -> Self {
// here this is split in the z and x directions if one ever needs asymmetrical subdivision
// two Plane struct fields would need to be added instead of the single subdivisions field
let z_vertex_count = plane.subdivisions + 2;
let x_vertex_count = plane.subdivisions + 2;
let num_vertices = (z_vertex_count * x_vertex_count) as usize;
let num_indices = ((z_vertex_count - 1) * (x_vertex_count - 1) * 6) as usize;
let up = Vec3::Y.to_array();
let mut positions: Vec<[f32; 3]> = Vec::with_capacity(num_vertices);
let mut normals: Vec<[f32; 3]> = Vec::with_capacity(num_vertices);
let mut uvs: Vec<[f32; 2]> = Vec::with_capacity(num_vertices);
let mut indices: Vec<u32> = Vec::with_capacity(num_indices);
for z in 0..z_vertex_count {
for x in 0..x_vertex_count {
let tx = x as f32 / (x_vertex_count - 1) as f32;
let tz = z as f32 / (z_vertex_count - 1) as f32;
positions.push([(-0.5 + tx) * plane.size, 0.0, (-0.5 + tz) * plane.size]);
normals.push(up);
uvs.push([tx, tz]);
}
}
for y in 0..z_vertex_count - 1 {
for x in 0..x_vertex_count - 1 {
let quad = y * x_vertex_count + x;
indices.push(quad + x_vertex_count + 1);
indices.push(quad + 1);
indices.push(quad + x_vertex_count);
indices.push(quad);
indices.push(quad + x_vertex_count);
indices.push(quad + 1);
}
}
Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
)
.with_inserted_indices(Indices::U32(indices))
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
}
}
mod capsule;
mod cylinder;
mod icosphere;
mod regular_polygon;
mod torus;
mod uvsphere;
pub use capsule::Capsule;
pub use cylinder::Cylinder;
pub use icosphere::Icosphere;
pub use regular_polygon::{Circle, RegularPolygon};
pub use torus::Torus;
pub use uvsphere::UVSphere;
use wgpu::PrimitiveTopology;

View file

@ -1,85 +0,0 @@
use crate::mesh::{Mesh, Meshable};
/// A regular polygon in the `XY` plane
#[deprecated(
since = "0.13.0",
note = "please use the `RegularPolygon` primitive in `bevy_math` instead"
)]
#[derive(Debug, Copy, Clone)]
pub struct RegularPolygon {
/// Circumscribed radius in the `XY` plane.
///
/// In other words, the vertices of this polygon will all touch a circle of this radius.
pub radius: f32,
/// Number of sides.
pub sides: usize,
}
impl Default for RegularPolygon {
fn default() -> Self {
Self {
radius: 0.5,
sides: 6,
}
}
}
impl RegularPolygon {
/// Creates a regular polygon in the `XY` plane
pub fn new(radius: f32, sides: usize) -> Self {
Self { radius, sides }
}
}
impl From<RegularPolygon> for Mesh {
fn from(polygon: RegularPolygon) -> Self {
bevy_math::primitives::RegularPolygon::new(polygon.radius, polygon.sides).mesh()
}
}
/// A circle in the `XY` plane
#[deprecated(
since = "0.13.0",
note = "please use the `Circle` primitive in `bevy_math` instead"
)]
#[derive(Debug, Copy, Clone)]
pub struct Circle {
/// Inscribed radius in the `XY` plane.
pub radius: f32,
/// The number of vertices used.
pub vertices: usize,
}
impl Default for Circle {
fn default() -> Self {
Self {
radius: 0.5,
vertices: 64,
}
}
}
impl Circle {
/// Creates a circle in the `XY` plane
pub fn new(radius: f32) -> Self {
Self {
radius,
..Default::default()
}
}
}
impl From<Circle> for RegularPolygon {
fn from(circle: Circle) -> Self {
Self {
radius: circle.radius,
sides: circle.vertices,
}
}
}
impl From<Circle> for Mesh {
fn from(circle: Circle) -> Self {
Mesh::from(RegularPolygon::from(circle))
}
}

View file

@ -1,38 +0,0 @@
use crate::mesh::{Mesh, Meshable};
/// A torus (donut) shape.
#[deprecated(
since = "0.13.0",
note = "please use the `Torus` primitive in `bevy_math` instead"
)]
#[derive(Debug, Clone, Copy)]
pub struct Torus {
pub radius: f32,
pub ring_radius: f32,
pub subdivisions_segments: usize,
pub subdivisions_sides: usize,
}
impl Default for Torus {
fn default() -> Self {
Torus {
radius: 1.0,
ring_radius: 0.5,
subdivisions_segments: 32,
subdivisions_sides: 24,
}
}
}
impl From<Torus> for Mesh {
fn from(torus: Torus) -> Self {
bevy_math::primitives::Torus {
minor_radius: torus.ring_radius,
major_radius: torus.radius,
}
.mesh()
.minor_resolution(torus.subdivisions_sides)
.major_resolution(torus.subdivisions_segments)
.build()
}
}

View file

@ -1,37 +0,0 @@
use bevy_math::primitives::Sphere;
use crate::mesh::{Mesh, Meshable};
/// A sphere made of sectors and stacks.
#[deprecated(
since = "0.13.0",
note = "please use the `Sphere` primitive in `bevy_math` instead"
)]
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone, Copy)]
pub struct UVSphere {
/// The radius of the sphere.
pub radius: f32,
/// Longitudinal sectors
pub sectors: usize,
/// Latitudinal stacks
pub stacks: usize,
}
impl Default for UVSphere {
fn default() -> Self {
Self {
radius: 1.0,
sectors: 36,
stacks: 18,
}
}
}
impl From<UVSphere> for Mesh {
fn from(sphere: UVSphere) -> Self {
Sphere::new(sphere.radius)
.mesh()
.uv(sphere.sectors, sphere.stacks)
}
}