mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
format comments (#1612)
Uses the new unstable comment formatting features added to rustfmt.toml.
This commit is contained in:
parent
be1c317d4e
commit
b17f8a4bce
125 changed files with 894 additions and 599 deletions
|
@ -9,24 +9,25 @@ use bevy_utils::tracing::info_span;
|
|||
#[allow(clippy::needless_doctest_main)]
|
||||
/// Containers of app logic and data
|
||||
///
|
||||
/// App store the ECS World, Resources, Schedule, and Executor. They also store the "run" function of the App, which
|
||||
/// by default executes the App schedule once. Apps are constructed using the builder pattern.
|
||||
/// App store the ECS World, Resources, Schedule, and Executor. They also store the "run" function
|
||||
/// of the App, which by default executes the App schedule once. Apps are constructed using the
|
||||
/// builder pattern.
|
||||
///
|
||||
/// ## Example
|
||||
/// Here is a simple "Hello World" Bevy app:
|
||||
/// ```
|
||||
///# use bevy_app::prelude::*;
|
||||
///# use bevy_ecs::prelude::*;
|
||||
/// # use bevy_app::prelude::*;
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
///
|
||||
///fn main() {
|
||||
/// fn main() {
|
||||
/// App::build()
|
||||
/// .add_system(hello_world_system.system())
|
||||
/// .run();
|
||||
///}
|
||||
/// }
|
||||
///
|
||||
///fn hello_world_system() {
|
||||
/// fn hello_world_system() {
|
||||
/// println!("hello world");
|
||||
///}
|
||||
/// }
|
||||
/// ```
|
||||
pub struct App {
|
||||
pub world: World,
|
||||
|
|
|
@ -234,7 +234,8 @@ impl AppBuilder {
|
|||
.add_system_to_stage(CoreStage::First, Events::<T>::update_system.system())
|
||||
}
|
||||
|
||||
/// Inserts a resource to the current [App] and overwrites any resource previously added of the same type.
|
||||
/// Inserts a resource to the current [App] and overwrites any resource previously added of the
|
||||
/// same type.
|
||||
pub fn insert_resource<T>(&mut self, resource: T) -> &mut Self
|
||||
where
|
||||
T: Component,
|
||||
|
@ -255,9 +256,9 @@ impl AppBuilder {
|
|||
where
|
||||
R: FromWorld + Send + Sync + 'static,
|
||||
{
|
||||
// PERF: We could avoid double hashing here, since the `from_resources` call is guaranteed not to
|
||||
// modify the map. However, we would need to be borrowing resources both mutably and immutably,
|
||||
// so we would need to be extremely certain this is correct
|
||||
// PERF: We could avoid double hashing here, since the `from_resources` call is guaranteed
|
||||
// not to modify the map. However, we would need to be borrowing resources both
|
||||
// mutably and immutably, so we would need to be extremely certain this is correct
|
||||
if !self.world_mut().contains_resource::<R>() {
|
||||
let resource = R::from_world(self.world_mut());
|
||||
self.insert_resource(resource);
|
||||
|
|
|
@ -55,10 +55,12 @@ enum State {
|
|||
B,
|
||||
}
|
||||
|
||||
/// An event collection that represents the events that occurred within the last two [Events::update] calls. Events can be cheaply read using
|
||||
/// an [EventReader]. This collection is meant to be paired with a system that calls [Events::update] exactly once per update/frame. [Events::update_system]
|
||||
/// is a system that does this. [EventReader]s are expected to read events from this collection at least once per update/frame. If events are not handled
|
||||
/// within one frame/update, they will be dropped.
|
||||
/// An event collection that represents the events that occurred within the last two
|
||||
/// [Events::update] calls. Events can be cheaply read using an [EventReader]. This collection is
|
||||
/// meant to be paired with a system that calls [Events::update] exactly once per update/frame.
|
||||
/// [Events::update_system] is a system that does this. [EventReader]s are expected to read events
|
||||
/// from this collection at least once per update/frame. If events are not handled within one
|
||||
/// frame/update, they will be dropped.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
|
@ -89,14 +91,16 @@ enum State {
|
|||
///
|
||||
/// # Details
|
||||
///
|
||||
/// [Events] is implemented using a double buffer. Each call to [Events::update] swaps buffers and clears out the oldest buffer.
|
||||
/// [EventReader]s that read at least once per update will never drop events. [EventReader]s that read once within two updates might
|
||||
/// still receive some events. [EventReader]s that read after two updates are guaranteed to drop all events that occurred before those updates.
|
||||
/// [Events] is implemented using a double buffer. Each call to [Events::update] swaps buffers and
|
||||
/// clears out the oldest buffer. [EventReader]s that read at least once per update will never drop
|
||||
/// events. [EventReader]s that read once within two updates might still receive some events.
|
||||
/// [EventReader]s that read after two updates are guaranteed to drop all events that occurred
|
||||
/// before those updates.
|
||||
///
|
||||
/// The buffers in [Events] will grow indefinitely if [Events::update] is never called.
|
||||
///
|
||||
/// An alternative call pattern would be to call [Events::update] manually across frames to control when events are cleared. However
|
||||
/// this complicates consumption
|
||||
/// An alternative call pattern would be to call [Events::update] manually across frames to control
|
||||
/// when events are cleared. However this complicates consumption
|
||||
#[derive(Debug)]
|
||||
pub struct Events<T> {
|
||||
events_a: Vec<EventInstance<T>>,
|
||||
|
@ -180,7 +184,8 @@ impl<T> ManualEventReader<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Like [`iter_with_id`](EventReader::iter_with_id) except not emitting any traces for read messages.
|
||||
/// Like [`iter_with_id`](EventReader::iter_with_id) except not emitting any traces for read
|
||||
/// messages.
|
||||
fn internal_event_reader<'a, T>(
|
||||
last_event_count: &mut usize,
|
||||
events: &'a Events<T>,
|
||||
|
@ -232,7 +237,8 @@ fn internal_event_reader<'a, T>(
|
|||
|
||||
impl<'a, T: Component> EventReader<'a, T> {
|
||||
/// Iterates over the events this EventReader has not seen yet. This updates the EventReader's
|
||||
/// event counter, which means subsequent event reads will not include events that happened before now.
|
||||
/// event counter, which means subsequent event reads will not include events that happened
|
||||
/// before now.
|
||||
pub fn iter(&mut self) -> impl DoubleEndedIterator<Item = &T> {
|
||||
self.iter_with_id().map(|(event, _id)| event)
|
||||
}
|
||||
|
@ -247,7 +253,8 @@ impl<'a, T: Component> EventReader<'a, T> {
|
|||
}
|
||||
|
||||
impl<T: Component> Events<T> {
|
||||
/// "Sends" an `event` by writing it to the current event buffer. [EventReader]s can then read the event.
|
||||
/// "Sends" an `event` by writing it to the current event buffer. [EventReader]s can then read
|
||||
/// the event.
|
||||
pub fn send(&mut self, event: T) {
|
||||
let event_id = EventId {
|
||||
id: self.event_count,
|
||||
|
@ -273,7 +280,8 @@ impl<T: Component> Events<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets a new [ManualEventReader]. This will ignore all events already in the event buffers. It will read all future events.
|
||||
/// Gets a new [ManualEventReader]. This will ignore all events already in the event buffers. It
|
||||
/// will read all future events.
|
||||
pub fn get_reader_current(&self) -> ManualEventReader<T> {
|
||||
ManualEventReader {
|
||||
last_event_count: self.event_count,
|
||||
|
@ -281,7 +289,8 @@ impl<T: Component> Events<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Swaps the event buffers and clears the oldest event buffer. In general, this should be called once per frame/update.
|
||||
/// Swaps the event buffers and clears the oldest event buffer. In general, this should be
|
||||
/// called once per frame/update.
|
||||
pub fn update(&mut self) {
|
||||
match self.state {
|
||||
State::A => {
|
||||
|
@ -335,10 +344,11 @@ impl<T: Component> Events<T> {
|
|||
}
|
||||
|
||||
/// Iterates over events that happened since the last "update" call.
|
||||
/// WARNING: You probably don't want to use this call. In most cases you should use an `EventReader`. You should only use
|
||||
/// this if you know you only need to consume events between the last `update()` call and your call to `iter_current_update_events`.
|
||||
/// If events happen outside that window, they will not be handled. For example, any events that happen after this call and before
|
||||
/// the next `update()` call will be dropped.
|
||||
/// WARNING: You probably don't want to use this call. In most cases you should use an
|
||||
/// `EventReader`. You should only use this if you know you only need to consume events
|
||||
/// between the last `update()` call and your call to `iter_current_update_events`.
|
||||
/// If events happen outside that window, they will not be handled. For example, any events that
|
||||
/// happen after this call and before the next `update()` call will be dropped.
|
||||
pub fn iter_current_update_events(&self) -> impl DoubleEndedIterator<Item = &T> {
|
||||
match self.state {
|
||||
State::A => self.events_a.iter().map(map_instance_event),
|
||||
|
@ -363,7 +373,8 @@ mod tests {
|
|||
let event_1 = TestEvent { i: 1 };
|
||||
let event_2 = TestEvent { i: 2 };
|
||||
|
||||
// this reader will miss event_0 and event_1 because it wont read them over the course of two updates
|
||||
// this reader will miss event_0 and event_1 because it wont read them over the course of
|
||||
// two updates
|
||||
let mut reader_missed = events.get_reader();
|
||||
|
||||
let mut reader_a = events.get_reader();
|
||||
|
|
|
@ -33,7 +33,8 @@ pub enum CoreStage {
|
|||
First,
|
||||
/// Name of app stage responsible for performing setup before an update. Runs before UPDATE.
|
||||
PreUpdate,
|
||||
/// Name of app stage responsible for doing most app logic. Systems should be registered here by default.
|
||||
/// Name of app stage responsible for doing most app logic. Systems should be registered here
|
||||
/// by default.
|
||||
Update,
|
||||
/// Name of app stage responsible for processing the results of UPDATE. Runs after UPDATE.
|
||||
PostUpdate,
|
||||
|
|
|
@ -3,7 +3,8 @@ use std::any::Any;
|
|||
|
||||
/// A collection of Bevy App logic and configuration
|
||||
///
|
||||
/// Plugins use [AppBuilder] to configure an [App](crate::App). When an [App](crate::App) registers a plugin, the plugin's [Plugin::build] function is run.
|
||||
/// Plugins use [AppBuilder] to configure an [App](crate::App). When an [App](crate::App) registers
|
||||
/// a plugin, the plugin's [Plugin::build] function is run.
|
||||
pub trait Plugin: Any + Send + Sync {
|
||||
fn build(&self, app: &mut AppBuilder);
|
||||
fn name(&self) -> &str {
|
||||
|
|
|
@ -41,7 +41,8 @@ impl ScheduleRunnerSettings {
|
|||
}
|
||||
}
|
||||
|
||||
/// Configures an App to run its [Schedule](bevy_ecs::schedule::Schedule) according to a given [RunMode]
|
||||
/// Configures an App to run its [Schedule](bevy_ecs::schedule::Schedule) according to a given
|
||||
/// [RunMode]
|
||||
#[derive(Default)]
|
||||
pub struct ScheduleRunnerPlugin {}
|
||||
|
||||
|
|
|
@ -226,7 +226,8 @@ impl AssetServer {
|
|||
let asset_loader = self.get_path_asset_loader(asset_path.path())?;
|
||||
let asset_path_id: AssetPathId = asset_path.get_id();
|
||||
|
||||
// load metadata and update source info. this is done in a scope to ensure we release the locks before loading
|
||||
// load metadata and update source info. this is done in a scope to ensure we release the
|
||||
// locks before loading
|
||||
let version = {
|
||||
let mut asset_sources = self.server.asset_sources.write();
|
||||
let source_info = match asset_sources.entry(asset_path_id.source_path_id()) {
|
||||
|
@ -282,7 +283,8 @@ impl AssetServer {
|
|||
.await
|
||||
.map_err(AssetServerError::AssetLoaderError)?;
|
||||
|
||||
// if version has changed since we loaded and grabbed a lock, return. theres is a newer version being loaded
|
||||
// if version has changed since we loaded and grabbed a lock, return. theres is a newer
|
||||
// version being loaded
|
||||
let mut asset_sources = self.server.asset_sources.write();
|
||||
let source_info = asset_sources
|
||||
.get_mut(&asset_path_id.source_path_id())
|
||||
|
|
|
@ -2,7 +2,8 @@ use crossbeam_channel::Receiver;
|
|||
use notify::{Event, RecommendedWatcher, RecursiveMode, Result, Watcher};
|
||||
use std::path::Path;
|
||||
|
||||
/// Watches for changes to assets on the filesystem. This is used by the `AssetServer` to reload them
|
||||
/// Watches for changes to assets on the filesystem. This is used by the `AssetServer` to reload
|
||||
/// them
|
||||
pub struct FilesystemWatcher {
|
||||
pub watcher: RecommendedWatcher,
|
||||
pub receiver: Receiver<Result<Event>>,
|
||||
|
|
|
@ -56,7 +56,8 @@ impl HandleId {
|
|||
|
||||
/// A handle into a specific Asset of type `T`
|
||||
///
|
||||
/// Handles contain a unique id that corresponds to a specific asset in the [Assets](crate::Assets) collection.
|
||||
/// Handles contain a unique id that corresponds to a specific asset in the [Assets](crate::Assets)
|
||||
/// collection.
|
||||
#[derive(Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct Handle<T>
|
||||
|
@ -147,7 +148,8 @@ impl<T: Asset> Drop for Handle<T> {
|
|||
fn drop(&mut self) {
|
||||
match self.handle_type {
|
||||
HandleType::Strong(ref sender) => {
|
||||
// ignore send errors because this means the channel is shut down / the game has stopped
|
||||
// ignore send errors because this means the channel is shut down / the game has
|
||||
// stopped
|
||||
let _ = sender.send(RefChange::Decrement(self.id));
|
||||
}
|
||||
HandleType::Weak => {}
|
||||
|
@ -233,7 +235,8 @@ unsafe impl<T: Asset> Sync for Handle<T> {}
|
|||
|
||||
/// A non-generic version of [Handle]
|
||||
///
|
||||
/// This allows handles to be mingled in a cross asset context. For example, storing `Handle<A>` and `Handle<B>` in the same `HashSet<HandleUntyped>`.
|
||||
/// This allows handles to be mingled in a cross asset context. For example, storing `Handle<A>` and
|
||||
/// `Handle<B>` in the same `HashSet<HandleUntyped>`.
|
||||
#[derive(Debug)]
|
||||
pub struct HandleUntyped {
|
||||
pub id: HandleId,
|
||||
|
@ -299,7 +302,8 @@ impl Drop for HandleUntyped {
|
|||
fn drop(&mut self) {
|
||||
match self.handle_type {
|
||||
HandleType::Strong(ref sender) => {
|
||||
// ignore send errors because this means the channel is shut down / the game has stopped
|
||||
// ignore send errors because this means the channel is shut down / the game has
|
||||
// stopped
|
||||
let _ = sender.send(RefChange::Decrement(self.id));
|
||||
}
|
||||
HandleType::Weak => {}
|
||||
|
|
|
@ -39,8 +39,8 @@ pub enum AssetStage {
|
|||
AssetEvents,
|
||||
}
|
||||
|
||||
/// Adds support for Assets to an App. Assets are typed collections with change tracking, which are added as App Resources.
|
||||
/// Examples of assets: textures, sounds, 3d models, maps, scenes
|
||||
/// Adds support for Assets to an App. Assets are typed collections with change tracking, which are
|
||||
/// added as App Resources. Examples of assets: textures, sounds, 3d models, maps, scenes
|
||||
#[derive(Default)]
|
||||
pub struct AssetPlugin;
|
||||
|
||||
|
|
|
@ -101,8 +101,8 @@ unsafe impl Byteable for isize {}
|
|||
unsafe impl Byteable for f32 {}
|
||||
unsafe impl Byteable for f64 {}
|
||||
unsafe impl Byteable for Vec2 {}
|
||||
// NOTE: Vec3 actually takes up the size of 4 floats / 16 bytes due to SIMD. This is actually convenient because GLSL
|
||||
// uniform buffer objects pad Vec3s to be 16 bytes.
|
||||
// NOTE: Vec3 actually takes up the size of 4 floats / 16 bytes due to SIMD. This is actually
|
||||
// convenient because GLSL uniform buffer objects pad Vec3s to be 16 bytes.
|
||||
unsafe impl Byteable for Vec3 {}
|
||||
unsafe impl Byteable for Vec4 {}
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ use std::{
|
|||
ops::Neg,
|
||||
};
|
||||
|
||||
/// A wrapper type that enables ordering floats. This is a work around for the famous "rust float ordering" problem.
|
||||
/// By using it, you acknowledge that sorting NaN is undefined according to spec. This implementation treats NaN as the
|
||||
/// "smallest" float.
|
||||
/// A wrapper type that enables ordering floats. This is a work around for the famous "rust float
|
||||
/// ordering" problem. By using it, you acknowledge that sorting NaN is undefined according to spec.
|
||||
/// This implementation treats NaN as the "smallest" float.
|
||||
#[derive(Debug, Copy, Clone, PartialOrd)]
|
||||
pub struct FloatOrd(pub f32);
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ impl Labels {
|
|||
}
|
||||
}
|
||||
|
||||
/// Maintains a mapping from [Entity](bevy_ecs::prelude::Entity) ids to entity labels and entity labels to [Entities](bevy_ecs::prelude::Entity).
|
||||
/// Maintains a mapping from [Entity](bevy_ecs::prelude::Entity) ids to entity labels and entity
|
||||
/// labels to [Entities](bevy_ecs::prelude::Entity).
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EntityLabels {
|
||||
label_entities: HashMap<Cow<'static, str>, Vec<Entity>>,
|
||||
|
|
|
@ -31,7 +31,8 @@ pub struct CorePlugin;
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash, SystemLabel)]
|
||||
pub enum CoreSystem {
|
||||
/// Updates the elapsed time. Any system that interacts with [Time] component should run after this.
|
||||
/// Updates the elapsed time. Any system that interacts with [Time] component should run after
|
||||
/// this.
|
||||
Time,
|
||||
}
|
||||
|
||||
|
@ -54,7 +55,8 @@ impl Plugin for CorePlugin {
|
|||
.register_type::<Labels>()
|
||||
.register_type::<Range<f32>>()
|
||||
.register_type::<Timer>()
|
||||
// time system is added as an "exclusive system" to ensure it runs before other systems in CoreStage::First
|
||||
// time system is added as an "exclusive system" to ensure it runs before other systems
|
||||
// in CoreStage::First
|
||||
.add_system_to_stage(
|
||||
CoreStage::First,
|
||||
time_system.exclusive_system().label(CoreSystem::Time),
|
||||
|
|
|
@ -36,9 +36,11 @@ impl TaskPoolThreadAssignmentPolicy {
|
|||
/// this helper will do nothing.
|
||||
#[derive(Clone)]
|
||||
pub struct DefaultTaskPoolOptions {
|
||||
/// If the number of physical cores is less than min_total_threads, force using min_total_threads
|
||||
/// If the number of physical cores is less than min_total_threads, force using
|
||||
/// min_total_threads
|
||||
pub min_total_threads: usize,
|
||||
/// If the number of physical cores is grater than max_total_threads, force using max_total_threads
|
||||
/// If the number of physical cores is grater than max_total_threads, force using
|
||||
/// max_total_threads
|
||||
pub max_total_threads: usize,
|
||||
|
||||
/// Used to determine number of IO threads to allocate
|
||||
|
|
|
@ -169,8 +169,8 @@ impl System for FixedTimestep {
|
|||
}
|
||||
|
||||
unsafe fn run_unsafe(&mut self, _input: Self::In, world: &World) -> Self::Out {
|
||||
// SAFE: this system inherits the internal system's component access and archetype component access,
|
||||
// which means the caller has ensured running the internal system is safe
|
||||
// SAFE: this system inherits the internal system's component access and archetype component
|
||||
// access, which means the caller has ensured running the internal system is safe
|
||||
self.internal_system.run_unsafe((), world)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@ use bevy_utils::Duration;
|
|||
/// Tracks elapsed time. Enters the finished state once `duration` is reached.
|
||||
///
|
||||
/// Non repeating timers will stop tracking and stay in the finished state until reset.
|
||||
/// Repeating timers will only be in the finished state on each tick `duration` is reached or exceeded, and can still be reset at any given point.
|
||||
/// Repeating timers will only be in the finished state on each tick `duration` is reached or
|
||||
/// exceeded, and can still be reset at any given point.
|
||||
///
|
||||
/// Paused timers will not have elapsed time increased.
|
||||
#[derive(Clone, Debug, Default, Reflect)]
|
||||
|
|
|
@ -11,8 +11,8 @@ mod shader_defs;
|
|||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
/// Derives the FromResources trait. Each field must also implement the FromResources trait or this will fail. FromResources is
|
||||
/// automatically implemented for types that implement Default.
|
||||
/// Derives the FromResources trait. Each field must also implement the FromResources trait or this
|
||||
/// will fail. FromResources is automatically implemented for types that implement Default.
|
||||
#[proc_macro_derive(FromResources, attributes(as_crate))]
|
||||
pub fn derive_from_resources(input: TokenStream) -> TokenStream {
|
||||
resource::derive_from_resources(input)
|
||||
|
|
|
@ -264,7 +264,8 @@ impl Archetype {
|
|||
self.table_info.entity_rows.reserve(additional);
|
||||
}
|
||||
|
||||
/// Removes the entity at `index` by swapping it out. Returns the table row the entity is stored in.
|
||||
/// Removes the entity at `index` by swapping it out. Returns the table row the entity is stored
|
||||
/// in.
|
||||
pub(crate) fn swap_remove(&mut self, index: usize) -> ArchetypeSwapRemoveResult {
|
||||
let is_last = index == self.entities.len() - 1;
|
||||
self.entities.swap_remove(index);
|
||||
|
@ -374,8 +375,8 @@ impl Default for Archetypes {
|
|||
};
|
||||
archetypes.get_id_or_insert(TableId::empty(), Vec::new(), Vec::new());
|
||||
|
||||
// adds the resource archetype. it is "special" in that it is inaccessible via a "hash", which prevents entities from
|
||||
// being added to it
|
||||
// adds the resource archetype. it is "special" in that it is inaccessible via a "hash",
|
||||
// which prevents entities from being added to it
|
||||
archetypes.archetypes.push(Archetype::new(
|
||||
ArchetypeId::resource(),
|
||||
TableId::empty(),
|
||||
|
@ -470,6 +471,7 @@ impl Archetypes {
|
|||
|
||||
/// Gets the archetype id matching the given inputs or inserts a new one if it doesn't exist.
|
||||
/// `table_components` and `sparse_set_components` must be sorted
|
||||
///
|
||||
/// # Safety
|
||||
/// TableId must exist in tables
|
||||
pub(crate) fn get_id_or_insert(
|
||||
|
|
|
@ -8,14 +8,15 @@ use crate::{
|
|||
use bevy_ecs_macros::all_tuples;
|
||||
use std::{any::TypeId, collections::HashMap};
|
||||
|
||||
/// An ordered collection of components, commonly used for spawning entities, and adding and removing components in bulk.
|
||||
/// An ordered collection of components, commonly used for spawning entities, and adding and
|
||||
/// removing components in bulk.
|
||||
///
|
||||
/// You cannot query for a bundle, only individual components within it.
|
||||
///
|
||||
/// Typically, you will simply use `#[derive(Bundle)]` when creating your own `Bundle`.
|
||||
/// The `Bundle` trait is automatically implemented for tuples of components:
|
||||
/// `(ComponentA, ComponentB)` is a very convenient shorthand when working with one-off collections of components.
|
||||
/// Note that both `()` and `(ComponentA, )` are valid tuples.
|
||||
/// `(ComponentA, ComponentB)` is a very convenient shorthand when working with one-off collections
|
||||
/// of components. Note that both `()` and `(ComponentA, )` are valid tuples.
|
||||
///
|
||||
/// You can nest bundles like so:
|
||||
/// ```
|
||||
|
@ -34,23 +35,29 @@ use std::{any::TypeId, collections::HashMap};
|
|||
/// z: String,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Safety
|
||||
/// [Bundle::type_info] must return the TypeInfo for each component type in the bundle, in the _exact_
|
||||
/// order that [Bundle::get_components] is called.
|
||||
/// [Bundle::from_components] must call `func` exactly once for each [TypeInfo] returned by [Bundle::type_info]
|
||||
/// [Bundle::type_info] must return the TypeInfo for each component type in the bundle, in the
|
||||
/// _exact_ order that [Bundle::get_components] is called.
|
||||
/// [Bundle::from_components] must call `func` exactly once for each [TypeInfo] returned by
|
||||
/// [Bundle::type_info]
|
||||
pub unsafe trait Bundle: Send + Sync + 'static {
|
||||
/// Gets this [Bundle]'s components type info, in the order of this bundle's Components
|
||||
fn type_info() -> Vec<TypeInfo>;
|
||||
|
||||
/// Calls `func`, which should return data for each component in the bundle, in the order of this bundle's Components
|
||||
/// Calls `func`, which should return data for each component in the bundle, in the order of
|
||||
/// this bundle's Components
|
||||
///
|
||||
/// # Safety
|
||||
/// Caller must return data for each component in the bundle, in the order of this bundle's Components
|
||||
/// Caller must return data for each component in the bundle, in the order of this bundle's
|
||||
/// Components
|
||||
unsafe fn from_components(func: impl FnMut() -> *mut u8) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Calls `func` on each value, in the order of this bundle's Components. This will "mem::forget" the bundle
|
||||
/// fields, so callers are responsible for dropping the fields if that is desirable.
|
||||
/// Calls `func` on each value, in the order of this bundle's Components. This will
|
||||
/// "mem::forget" the bundle fields, so callers are responsible for dropping the fields if
|
||||
/// that is desirable.
|
||||
fn get_components(self, func: impl FnMut(*mut u8));
|
||||
}
|
||||
|
||||
|
@ -126,7 +133,8 @@ impl BundleInfo {
|
|||
bundle_flags: &[ComponentFlags],
|
||||
bundle: T,
|
||||
) {
|
||||
// NOTE: get_components calls this closure on each component in "bundle order". bundle_info.component_ids are also in "bundle order"
|
||||
// NOTE: get_components calls this closure on each component in "bundle order".
|
||||
// bundle_info.component_ids are also in "bundle order"
|
||||
let mut bundle_component = 0;
|
||||
bundle.get_components(|component_ptr| {
|
||||
// SAFE: component_id was initialized by get_dynamic_bundle_info
|
||||
|
|
|
@ -31,7 +31,8 @@ pub struct ComponentInfo {
|
|||
name: String,
|
||||
id: ComponentId,
|
||||
type_id: Option<TypeId>,
|
||||
// SAFETY: This must remain private. It must only be set to "true" if this component is actually Send + Sync
|
||||
// SAFETY: This must remain private. It must only be set to "true" if this component is
|
||||
// actually Send + Sync
|
||||
is_send_and_sync: bool,
|
||||
layout: Layout,
|
||||
drop: unsafe fn(*mut u8),
|
||||
|
@ -116,7 +117,8 @@ impl SparseSetIndex for ComponentId {
|
|||
pub struct ComponentDescriptor {
|
||||
name: String,
|
||||
storage_type: StorageType,
|
||||
// SAFETY: This must remain private. It must only be set to "true" if this component is actually Send + Sync
|
||||
// SAFETY: This must remain private. It must only be set to "true" if this component is
|
||||
// actually Send + Sync
|
||||
is_send_and_sync: bool,
|
||||
type_id: Option<TypeId>,
|
||||
layout: Layout,
|
||||
|
|
|
@ -56,9 +56,9 @@ impl Entity {
|
|||
self.id
|
||||
}
|
||||
|
||||
/// Returns the generation of this Entity's id. The generation is incremented each time an entity with
|
||||
/// a given id is despawned. This serves as a "count" of the number of times a given id has been reused
|
||||
/// (id, generation) pairs uniquely identify a given Entity.
|
||||
/// Returns the generation of this Entity's id. The generation is incremented each time an
|
||||
/// entity with a given id is despawned. This serves as a "count" of the number of times a
|
||||
/// given id has been reused (id, generation) pairs uniquely identify a given Entity.
|
||||
#[inline]
|
||||
pub fn generation(self) -> u32 {
|
||||
self.generation
|
||||
|
@ -121,16 +121,16 @@ pub struct Entities {
|
|||
/// The `pending` and `free_cursor` fields describe three sets of Entity IDs
|
||||
/// that have been freed or are in the process of being allocated:
|
||||
///
|
||||
/// - The `freelist` IDs, previously freed by `free()`. These IDs are available to any
|
||||
/// of `alloc()`, `reserve_entity()` or `reserve_entities()`. Allocation will
|
||||
/// always prefer these over brand new IDs.
|
||||
/// - The `freelist` IDs, previously freed by `free()`. These IDs are available to any of
|
||||
/// `alloc()`, `reserve_entity()` or `reserve_entities()`. Allocation will always prefer
|
||||
/// these over brand new IDs.
|
||||
///
|
||||
/// - The `reserved` list of IDs that were once in the freelist, but got
|
||||
/// reserved by `reserve_entities` or `reserve_entity()`. They are now waiting
|
||||
/// for `flush()` to make them fully allocated.
|
||||
/// - The `reserved` list of IDs that were once in the freelist, but got reserved by
|
||||
/// `reserve_entities` or `reserve_entity()`. They are now waiting for `flush()` to make them
|
||||
/// fully allocated.
|
||||
///
|
||||
/// - The count of new IDs that do not yet exist in `self.meta()`, but which
|
||||
/// we have handed out and reserved. `flush()` will allocate room for them in `self.meta()`.
|
||||
/// - The count of new IDs that do not yet exist in `self.meta()`, but which we have handed out
|
||||
/// and reserved. `flush()` will allocate room for them in `self.meta()`.
|
||||
///
|
||||
/// The contents of `pending` look like this:
|
||||
///
|
||||
|
@ -257,7 +257,8 @@ impl Entities {
|
|||
|
||||
/// Allocate a specific entity ID, overwriting its generation
|
||||
///
|
||||
/// Returns the location of the entity currently using the given ID, if any. Location should be written immediately.
|
||||
/// Returns the location of the entity currently using the given ID, if any. Location should be
|
||||
/// written immediately.
|
||||
pub fn alloc_at(&mut self, entity: Entity) -> Option<EntityLocation> {
|
||||
self.verify_flushed();
|
||||
|
||||
|
|
|
@ -171,7 +171,8 @@ impl<T: SparseSetIndex> FilteredAccessSet<T> {
|
|||
}
|
||||
|
||||
pub fn get_conflicts(&self, filtered_access: &FilteredAccess<T>) -> Vec<T> {
|
||||
// if combined unfiltered access is incompatible, check each filtered access for compatibility
|
||||
// if combined unfiltered access is incompatible, check each filtered access for
|
||||
// compatibility
|
||||
if !filtered_access.access.is_compatible(&self.combined_access) {
|
||||
for current_filtered_access in self.filtered_accesses.iter() {
|
||||
if !current_filtered_access.is_compatible(&filtered_access) {
|
||||
|
|
|
@ -22,44 +22,60 @@ pub trait Fetch<'w>: Sized {
|
|||
type State: FetchState;
|
||||
|
||||
/// Creates a new instance of this fetch.
|
||||
///
|
||||
/// # Safety
|
||||
/// `state` must have been initialized (via [FetchState::init]) using the same `world` passed in to this function.
|
||||
/// `state` must have been initialized (via [FetchState::init]) using the same `world` passed in
|
||||
/// to this function.
|
||||
unsafe fn init(world: &World, state: &Self::State) -> Self;
|
||||
|
||||
/// Returns true if (and only if) every table of every archetype matched by this Fetch contains all of the matched components.
|
||||
/// This is used to select a more efficient "table iterator" for "dense" queries.
|
||||
/// If this returns true, [Fetch::set_table] and [Fetch::table_fetch] will be called for iterators
|
||||
/// If this returns false, [Fetch::set_archetype] and [Fetch::archetype_fetch] will be called for iterators
|
||||
/// Returns true if (and only if) every table of every archetype matched by this Fetch contains
|
||||
/// all of the matched components. This is used to select a more efficient "table iterator"
|
||||
/// for "dense" queries. If this returns true, [Fetch::set_table] and [Fetch::table_fetch]
|
||||
/// will be called for iterators If this returns false, [Fetch::set_archetype] and
|
||||
/// [Fetch::archetype_fetch] will be called for iterators
|
||||
fn is_dense(&self) -> bool;
|
||||
|
||||
/// Adjusts internal state to account for the next [Archetype]. This will always be called on archetypes that match this [Fetch]
|
||||
/// Adjusts internal state to account for the next [Archetype]. This will always be called on
|
||||
/// archetypes that match this [Fetch]
|
||||
///
|
||||
/// # Safety
|
||||
/// `archetype` and `tables` must be from the [World] [Fetch::init] was called on. `state` must be the [Self::State] this was initialized with.
|
||||
/// `archetype` and `tables` must be from the [World] [Fetch::init] was called on. `state` must
|
||||
/// be the [Self::State] this was initialized with.
|
||||
unsafe fn set_archetype(&mut self, state: &Self::State, archetype: &Archetype, tables: &Tables);
|
||||
|
||||
/// Adjusts internal state to account for the next [Table]. This will always be called on tables that match this [Fetch]
|
||||
/// Adjusts internal state to account for the next [Table]. This will always be called on tables
|
||||
/// that match this [Fetch]
|
||||
///
|
||||
/// # Safety
|
||||
/// `table` must be from the [World] [Fetch::init] was called on. `state` must be the [Self::State] this was initialized with.
|
||||
/// `table` must be from the [World] [Fetch::init] was called on. `state` must be the
|
||||
/// [Self::State] this was initialized with.
|
||||
unsafe fn set_table(&mut self, state: &Self::State, table: &Table);
|
||||
|
||||
/// Fetch [Self::Item] for the given `archetype_index` in the current [Archetype]. This must always be called after [Fetch::set_archetype] with an `archetype_index`
|
||||
/// in the range of the current [Archetype]
|
||||
/// Fetch [Self::Item] for the given `archetype_index` in the current [Archetype]. This must
|
||||
/// always be called after [Fetch::set_archetype] with an `archetype_index` in the range of
|
||||
/// the current [Archetype]
|
||||
///
|
||||
/// # Safety
|
||||
/// Must always be called _after_ [Fetch::set_archetype]. `archetype_index` must be in the range of the current archetype
|
||||
/// Must always be called _after_ [Fetch::set_archetype]. `archetype_index` must be in the range
|
||||
/// of the current archetype
|
||||
unsafe fn archetype_fetch(&mut self, archetype_index: usize) -> Self::Item;
|
||||
|
||||
/// Fetch [Self::Item] for the given `table_row` in the current [Table]. This must always be called after [Fetch::set_table] with a `table_row`
|
||||
/// in the range of the current [Table]
|
||||
/// Fetch [Self::Item] for the given `table_row` in the current [Table]. This must always be
|
||||
/// called after [Fetch::set_table] with a `table_row` in the range of the current [Table]
|
||||
///
|
||||
/// # Safety
|
||||
/// Must always be called _after_ [Fetch::set_table]. `table_row` must be in the range of the current table
|
||||
/// Must always be called _after_ [Fetch::set_table]. `table_row` must be in the range of the
|
||||
/// current table
|
||||
unsafe fn table_fetch(&mut self, table_row: usize) -> Self::Item;
|
||||
}
|
||||
|
||||
/// State used to construct a Fetch. This will be cached inside QueryState, so it is best to move as much data /
|
||||
/// computation here as possible to reduce the cost of constructing Fetch.
|
||||
/// State used to construct a Fetch. This will be cached inside QueryState, so it is best to move as
|
||||
/// much data / computation here as possible to reduce the cost of constructing Fetch.
|
||||
/// SAFETY:
|
||||
/// Implementor must ensure that [FetchState::update_component_access] and [FetchState::update_archetype_component_access] exactly
|
||||
/// reflects the results of [FetchState::matches_archetype], [FetchState::matches_table], [Fetch::archetype_fetch], and [Fetch::table_fetch]
|
||||
/// Implementor must ensure that [FetchState::update_component_access] and
|
||||
/// [FetchState::update_archetype_component_access] exactly reflects the results of
|
||||
/// [FetchState::matches_archetype], [FetchState::matches_table], [Fetch::archetype_fetch], and
|
||||
/// [Fetch::table_fetch]
|
||||
pub unsafe trait FetchState: Send + Sync + Sized {
|
||||
fn init(world: &mut World) -> Self;
|
||||
fn update_component_access(&self, access: &mut FilteredAccess<ComponentId>);
|
||||
|
@ -167,7 +183,8 @@ pub struct ReadState<T> {
|
|||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
// SAFE: component access and archetype component access are properly updated to reflect that T is read
|
||||
// SAFE: component access and archetype component access are properly updated to reflect that T is
|
||||
// read
|
||||
unsafe impl<T: Component> FetchState for ReadState<T> {
|
||||
fn init(world: &mut World) -> Self {
|
||||
let component_info = world.components.get_or_insert_info::<T>();
|
||||
|
@ -312,7 +329,8 @@ pub struct WriteState<T> {
|
|||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
// SAFE: component access and archetype component access are properly updated to reflect that T is written
|
||||
// SAFE: component access and archetype component access are properly updated to reflect that T is
|
||||
// written
|
||||
unsafe impl<T: Component> FetchState for WriteState<T> {
|
||||
fn init(world: &mut World) -> Self {
|
||||
let component_info = world.components.get_or_insert_info::<T>();
|
||||
|
@ -457,7 +475,8 @@ pub struct OptionState<T: FetchState> {
|
|||
state: T,
|
||||
}
|
||||
|
||||
// SAFE: component access and archetype component access are properly updated according to the internal Fetch
|
||||
// SAFE: component access and archetype component access are properly updated according to the
|
||||
// internal Fetch
|
||||
unsafe impl<T: FetchState> FetchState for OptionState<T> {
|
||||
fn init(world: &mut World) -> Self {
|
||||
Self {
|
||||
|
@ -589,7 +608,8 @@ pub struct FlagsState<T> {
|
|||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
// SAFE: component access and archetype component access are properly updated to reflect that T is read
|
||||
// SAFE: component access and archetype component access are properly updated to reflect that T is
|
||||
// read
|
||||
unsafe impl<T: Component> FetchState for FlagsState<T> {
|
||||
fn init(world: &mut World) -> Self {
|
||||
let component_info = world.components.get_or_insert_info::<T>();
|
||||
|
|
|
@ -10,8 +10,8 @@ use crate::{
|
|||
use bevy_ecs_macros::all_tuples;
|
||||
use std::{marker::PhantomData, ptr};
|
||||
|
||||
// TODO: uncomment this and use as shorthand (remove where F::Fetch: FilterFetch everywhere) when this bug is fixed in Rust 1.51:
|
||||
// https://github.com/rust-lang/rust/pull/81671
|
||||
// TODO: uncomment this and use as shorthand (remove where F::Fetch: FilterFetch everywhere) when
|
||||
// this bug is fixed in Rust 1.51: https://github.com/rust-lang/rust/pull/81671
|
||||
// pub trait QueryFilter: WorldQuery
|
||||
// where
|
||||
// Self::Fetch: FilterFetch,
|
||||
|
@ -21,14 +21,17 @@ use std::{marker::PhantomData, ptr};
|
|||
// impl<T: WorldQuery> QueryFilter for T where T::Fetch: FilterFetch {
|
||||
// }
|
||||
|
||||
/// Fetch methods used by query filters. This trait exists to allow "short circuit" behaviors for relevant query filter fetches.
|
||||
/// Fetch methods used by query filters. This trait exists to allow "short circuit" behaviors for
|
||||
/// relevant query filter fetches.
|
||||
pub trait FilterFetch: for<'a> Fetch<'a> {
|
||||
/// # Safety
|
||||
/// Must always be called _after_ [Fetch::set_archetype]. `archetype_index` must be in the range of the current archetype
|
||||
/// Must always be called _after_ [Fetch::set_archetype]. `archetype_index` must be in the range
|
||||
/// of the current archetype
|
||||
unsafe fn archetype_filter_fetch(&mut self, archetype_index: usize) -> bool;
|
||||
|
||||
/// # Safety
|
||||
/// Must always be called _after_ [Fetch::set_table]. `table_row` must be in the range of the current table
|
||||
/// Must always be called _after_ [Fetch::set_table]. `table_row` must be in the range of the
|
||||
/// current table
|
||||
unsafe fn table_filter_fetch(&mut self, table_row: usize) -> bool;
|
||||
}
|
||||
|
||||
|
@ -47,7 +50,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Filter that retrieves components of type `T` that have either been mutated or added since the start of the frame.
|
||||
/// Filter that retrieves components of type `T` that have either been mutated or added since the
|
||||
/// start of the frame.
|
||||
pub struct With<T>(PhantomData<T>);
|
||||
|
||||
impl<T: Component> WorldQuery for With<T> {
|
||||
|
@ -137,7 +141,8 @@ impl<'a, T: Component> Fetch<'a> for WithFetch<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Filter that retrieves components of type `T` that have either been mutated or added since the start of the frame.
|
||||
/// Filter that retrieves components of type `T` that have either been mutated or added since the
|
||||
/// start of the frame.
|
||||
pub struct Without<T>(PhantomData<T>);
|
||||
|
||||
impl<T: Component> WorldQuery for Without<T> {
|
||||
|
@ -573,13 +578,15 @@ macro_rules! impl_flag_filter {
|
|||
}
|
||||
|
||||
impl_flag_filter!(
|
||||
/// Filter that retrieves components of type `T` that have been added since the start of the frame
|
||||
/// Filter that retrieves components of type `T` that have been added since the start of the
|
||||
/// frame
|
||||
///
|
||||
/// This filter is useful as a performance optimization as it means that the query contains fewer items
|
||||
/// for a system to iterate over.
|
||||
/// This filter is useful as a performance optimization as it means that the query contains
|
||||
/// fewer items for a system to iterate over.
|
||||
///
|
||||
/// Because the ordering of systems can change and this filter is only effective on changes before the query executes
|
||||
/// you need to use explicit dependency ordering or ordered stages for these query filters to be useful.
|
||||
/// Because the ordering of systems can change and this filter is only effective on changes
|
||||
/// before the query executes you need to use explicit dependency ordering or ordered
|
||||
/// stages for these query filters to be useful.
|
||||
///
|
||||
///
|
||||
/// Example:
|
||||
|
@ -604,14 +611,15 @@ impl_flag_filter!(
|
|||
);
|
||||
|
||||
impl_flag_filter!(
|
||||
/// Filter that retrieves components of type `T` that have been mutated since the start of the frame.
|
||||
/// Added components do not count as mutated.
|
||||
/// Filter that retrieves components of type `T` that have been mutated since the start of the
|
||||
/// frame. Added components do not count as mutated.
|
||||
///
|
||||
/// This filter is useful as a performance optimization as it means that the query contains fewer items
|
||||
/// for a system to iterate over.
|
||||
/// This filter is useful as a performance optimization as it means that the query contains
|
||||
/// fewer items for a system to iterate over.
|
||||
///
|
||||
/// Because the ordering of systems can change and this filter is only effective on changes before the query executes
|
||||
/// you need to use explicit dependency ordering or ordered stages for these query filters to be useful.
|
||||
/// Because the ordering of systems can change and this filter is only effective on changes
|
||||
/// before the query executes you need to use explicit dependency ordering or ordered
|
||||
/// stages for these query filters to be useful.
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
|
@ -635,15 +643,18 @@ impl_flag_filter!(
|
|||
);
|
||||
|
||||
impl_flag_filter!(
|
||||
/// Filter that retrieves components of type `T` that have been added or mutated since the start of the frame
|
||||
/// Filter that retrieves components of type `T` that have been added or mutated since the
|
||||
/// start of the frame
|
||||
///
|
||||
/// This filter is useful as a performance optimization as it means that the query contains fewer items
|
||||
/// for a system to iterate over.
|
||||
/// This filter is useful as a performance optimization as it means that the query contains
|
||||
/// fewer items for a system to iterate over.
|
||||
///
|
||||
/// Because the ordering of systems can change and this filter is only effective on changes before the query executes
|
||||
/// you need to use explicit dependency ordering or ordered stages for these query filters to be useful.
|
||||
/// Because the ordering of systems can change and this filter is only effective on changes
|
||||
/// before the query executes you need to use explicit dependency ordering or ordered
|
||||
/// stages for these query filters to be useful.
|
||||
///
|
||||
/// Also see the documentation for [`Mutated<T>`] and [`Added`] as this filter is a logical OR of them.
|
||||
/// Also see the documentation for [`Mutated<T>`] and [`Added`] as this filter is a logical OR
|
||||
/// of them.
|
||||
Changed,
|
||||
ChangedState,
|
||||
ChangedFetch,
|
||||
|
|
|
@ -199,8 +199,8 @@ where
|
|||
/// # Safety
|
||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
||||
/// have unique access to the components they query.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world` with
|
||||
/// a mismatched WorldId is unsafe.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
|
||||
/// with a mismatched WorldId is unsafe.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn iter_unchecked_manual<'w, 's>(
|
||||
&'s self,
|
||||
|
@ -296,8 +296,8 @@ where
|
|||
/// # Safety
|
||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
||||
/// have unique access to the components they query.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world` with
|
||||
/// a mismatched WorldId is unsafe.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
|
||||
/// with a mismatched WorldId is unsafe.
|
||||
pub(crate) unsafe fn for_each_unchecked_manual<'w, 's>(
|
||||
&'s self,
|
||||
world: &'w World,
|
||||
|
@ -341,8 +341,8 @@ where
|
|||
/// # Safety
|
||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
||||
/// have unique access to the components they query.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world` with
|
||||
/// a mismatched WorldId is unsafe.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
|
||||
/// with a mismatched WorldId is unsafe.
|
||||
pub unsafe fn par_for_each_unchecked_manual<'w, 's>(
|
||||
&'s self,
|
||||
world: &'w World,
|
||||
|
|
|
@ -43,8 +43,10 @@ impl ReflectComponent {
|
|||
}
|
||||
|
||||
/// # Safety
|
||||
/// This method does not prevent you from having two mutable pointers to the same data, violating Rust's aliasing rules. To avoid this:
|
||||
/// * Only call this method in an exclusive system to avoid sharing across threads (or use a scheduler that enforces safe memory access).
|
||||
/// This method does not prevent you from having two mutable pointers to the same data,
|
||||
/// violating Rust's aliasing rules. To avoid this:
|
||||
/// * Only call this method in an exclusive system to avoid sharing across threads (or use a
|
||||
/// scheduler that enforces safe memory access).
|
||||
/// * Don't call this method more than once in the same scope for a given component.
|
||||
pub unsafe fn reflect_component_unchecked_mut<'a>(
|
||||
&self,
|
||||
|
|
|
@ -38,8 +38,8 @@ impl ParallelSystemExecutor for SingleThreadedExecutor {
|
|||
}
|
||||
|
||||
impl SingleThreadedExecutor {
|
||||
/// Calls system.new_archetype() for each archetype added since the last call to [update_archetypes] and
|
||||
/// updates cached archetype_component_access.
|
||||
/// Calls system.new_archetype() for each archetype added since the last call to
|
||||
/// [update_archetypes] and updates cached archetype_component_access.
|
||||
fn update_archetypes(&mut self, systems: &mut [ParallelSystemContainer], world: &World) {
|
||||
let archetypes = world.archetypes();
|
||||
let old_generation = self.archetype_generation;
|
||||
|
|
|
@ -148,8 +148,8 @@ impl ParallelSystemExecutor for ParallelExecutor {
|
|||
}
|
||||
|
||||
impl ParallelExecutor {
|
||||
/// Calls system.new_archetype() for each archetype added since the last call to [update_archetypes] and
|
||||
/// updates cached archetype_component_access.
|
||||
/// Calls system.new_archetype() for each archetype added since the last call to
|
||||
/// [update_archetypes] and updates cached archetype_component_access.
|
||||
fn update_archetypes(&mut self, systems: &mut [ParallelSystemContainer], world: &World) {
|
||||
let archetypes = world.archetypes();
|
||||
let old_generation = self.archetype_generation;
|
||||
|
|
|
@ -35,13 +35,14 @@ impl_downcast!(Stage);
|
|||
/// This occurs because, in the absence of explicit constraints, systems are executed in
|
||||
/// an unstable, arbitrary order within each stage that may vary between runs and frames.
|
||||
///
|
||||
/// Some ambiguities reported by the ambiguity checker may be warranted (to allow two systems to run without blocking each other)
|
||||
/// or spurious, as the exact combination of archetypes used may prevent them from ever conflicting during actual gameplay.
|
||||
/// You can resolve the warnings produced by the ambiguity checker by adding `.before` or `.after` to one of the conflicting systems
|
||||
/// Some ambiguities reported by the ambiguity checker may be warranted (to allow two systems to run
|
||||
/// without blocking each other) or spurious, as the exact combination of archetypes used may
|
||||
/// prevent them from ever conflicting during actual gameplay. You can resolve the warnings produced
|
||||
/// by the ambiguity checker by adding `.before` or `.after` to one of the conflicting systems
|
||||
/// referencing the other system to force a specific ordering.
|
||||
///
|
||||
/// The checker may report a system more times than the amount of constraints it would actually need to have
|
||||
/// unambiguous order with regards to a group of already-constrained systems.
|
||||
/// The checker may report a system more times than the amount of constraints it would actually need
|
||||
/// to have unambiguous order with regards to a group of already-constrained systems.
|
||||
pub struct ReportExecutionOrderAmbiguities;
|
||||
|
||||
struct VirtualSystemSet {
|
||||
|
@ -523,7 +524,7 @@ fn find_ambiguities(systems: &[impl SystemContainer]) -> Vec<(usize, usize, Vec<
|
|||
for (index_a, relations) in all_relations.drain(..).enumerate() {
|
||||
// TODO: prove that `.take(index_a)` would be correct here, and uncomment it if so.
|
||||
for index_b in full_bitset.difference(&relations)
|
||||
/*.take(index_a)*/
|
||||
// .take(index_a)
|
||||
{
|
||||
if !processed.contains(index_b)
|
||||
&& all_ambiguity_sets[index_a].is_disjoint(&all_ambiguity_sets[index_b])
|
||||
|
|
|
@ -217,7 +217,8 @@ impl<T: Clone> State<T> {
|
|||
self.next.as_ref()
|
||||
}
|
||||
|
||||
/// Queue a state change. This will fail if there is already a state in the queue, or if the given `state` matches the current state
|
||||
/// Queue a state change. This will fail if there is already a state in the queue, or if the
|
||||
/// given `state` matches the current state
|
||||
pub fn set_next(&mut self, state: T) -> Result<(), StateError> {
|
||||
if std::mem::discriminant(&self.current) == std::mem::discriminant(&state) {
|
||||
return Err(StateError::AlreadyInState);
|
||||
|
@ -231,7 +232,8 @@ impl<T: Clone> State<T> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Same as [Self::set_next], but if there is already a next state, it will be overwritten instead of failing
|
||||
/// Same as [Self::set_next], but if there is already a next state, it will be overwritten
|
||||
/// instead of failing
|
||||
pub fn overwrite_next(&mut self, state: T) -> Result<(), StateError> {
|
||||
if std::mem::discriminant(&self.current) == std::mem::discriminant(&state) {
|
||||
return Err(StateError::AlreadyInState);
|
||||
|
|
|
@ -98,7 +98,9 @@ impl BlobVec {
|
|||
std::ptr::copy_nonoverlapping(value, ptr, self.item_layout.size());
|
||||
}
|
||||
|
||||
/// increases the length by one (and grows the vec if needed) with uninitialized memory and returns the index
|
||||
/// increases the length by one (and grows the vec if needed) with uninitialized memory and
|
||||
/// returns the index
|
||||
///
|
||||
/// # Safety
|
||||
/// the newly allocated space must be immediately populated with a valid value
|
||||
#[inline]
|
||||
|
@ -110,17 +112,19 @@ impl BlobVec {
|
|||
}
|
||||
|
||||
/// # Safety
|
||||
/// len must be <= capacity. if length is decreased, "out of bounds" items must be dropped. Newly added items must be
|
||||
/// immediately populated with valid values and length must be increased. For better unwind safety, call [BlobVec::set_len]
|
||||
/// _after_ populating a new value.
|
||||
/// len must be <= capacity. if length is decreased, "out of bounds" items must be dropped.
|
||||
/// Newly added items must be immediately populated with valid values and length must be
|
||||
/// increased. For better unwind safety, call [BlobVec::set_len] _after_ populating a new
|
||||
/// value.
|
||||
pub unsafe fn set_len(&mut self, len: usize) {
|
||||
debug_assert!(len <= self.capacity());
|
||||
self.len = len;
|
||||
}
|
||||
|
||||
/// Performs a "swap remove" at the given `index`, which removes the item at `index` and moves the last item
|
||||
/// in the [BlobVec] to `index` (if `index` is not the last item). It is the caller's responsibility to
|
||||
/// drop the returned pointer, if that is desirable.
|
||||
/// Performs a "swap remove" at the given `index`, which removes the item at `index` and moves
|
||||
/// the last item in the [BlobVec] to `index` (if `index` is not the last item). It is the
|
||||
/// caller's responsibility to drop the returned pointer, if that is desirable.
|
||||
///
|
||||
/// # Safety
|
||||
/// It is the caller's responsibility to ensure that `index` is < self.len()
|
||||
/// Callers should _only_ access the returned pointer immediately after calling this function.
|
||||
|
@ -161,6 +165,7 @@ impl BlobVec {
|
|||
}
|
||||
|
||||
/// Gets a pointer to the start of the vec
|
||||
///
|
||||
/// # Safety
|
||||
/// must ensure rust mutability rules are not violated
|
||||
#[inline]
|
||||
|
@ -170,13 +175,13 @@ impl BlobVec {
|
|||
|
||||
pub fn clear(&mut self) {
|
||||
let len = self.len;
|
||||
// We set len to 0 _before_ dropping elements for unwind safety. This ensures we don't accidentally
|
||||
// drop elements twice in the event of a drop impl panicking.
|
||||
// We set len to 0 _before_ dropping elements for unwind safety. This ensures we don't
|
||||
// accidentally drop elements twice in the event of a drop impl panicking.
|
||||
self.len = 0;
|
||||
for i in 0..len {
|
||||
unsafe {
|
||||
// NOTE: this doesn't use self.get_unchecked(i) because the debug_assert on index will
|
||||
// panic here due to self.len being set to 0
|
||||
// NOTE: this doesn't use self.get_unchecked(i) because the debug_assert on index
|
||||
// will panic here due to self.len being set to 0
|
||||
let ptr = self.get_ptr().as_ptr().add(i * self.item_layout.size());
|
||||
(self.drop)(ptr);
|
||||
}
|
||||
|
@ -260,7 +265,8 @@ mod tests {
|
|||
use crate::component::TypeInfo;
|
||||
use std::{alloc::Layout, cell::RefCell, rc::Rc};
|
||||
|
||||
/// # Safety:
|
||||
/// # Safety
|
||||
///
|
||||
/// `blob_vec` must have a layout that matches Layout::new::<T>()
|
||||
unsafe fn push<T>(blob_vec: &mut BlobVec, mut value: T) {
|
||||
let index = blob_vec.push_uninit();
|
||||
|
@ -268,7 +274,8 @@ mod tests {
|
|||
std::mem::forget(value);
|
||||
}
|
||||
|
||||
/// # Safety:
|
||||
/// # Safety
|
||||
///
|
||||
/// `blob_vec` must have a layout that matches Layout::new::<T>()
|
||||
unsafe fn swap_remove<T>(blob_vec: &mut BlobVec, index: usize) -> T {
|
||||
assert!(index < blob_vec.len());
|
||||
|
@ -276,9 +283,10 @@ mod tests {
|
|||
value.cast::<T>().read()
|
||||
}
|
||||
|
||||
/// # Safety:
|
||||
/// `blob_vec` must have a layout that matches Layout::new::<T>(), it most store a valid T value at
|
||||
/// the given `index`
|
||||
/// # Safety
|
||||
///
|
||||
/// `blob_vec` must have a layout that matches Layout::new::<T>(), it most store a valid T value
|
||||
/// at the given `index`
|
||||
unsafe fn get_mut<T>(blob_vec: &mut BlobVec, index: usize) -> &mut T {
|
||||
assert!(index < blob_vec.len());
|
||||
&mut *blob_vec.get_unchecked(index).cast::<T>()
|
||||
|
|
|
@ -113,10 +113,12 @@ impl ComponentSparseSet {
|
|||
}
|
||||
|
||||
/// Inserts the `entity` key and component `value` pair into this sparse set.
|
||||
/// The caller is responsible for ensuring the value is not dropped. This collection will drop the value when needed.
|
||||
/// The caller is responsible for ensuring the value is not dropped. This collection will drop
|
||||
/// the value when needed.
|
||||
///
|
||||
/// # Safety
|
||||
/// The `value` pointer must point to a valid address that matches the `Layout` inside the `ComponentInfo` given
|
||||
/// when constructing this sparse set.
|
||||
/// The `value` pointer must point to a valid address that matches the `Layout` inside the
|
||||
/// `ComponentInfo` given when constructing this sparse set.
|
||||
pub unsafe fn insert(&mut self, entity: Entity, value: *mut u8, flags: ComponentFlags) {
|
||||
let dense = &mut self.dense;
|
||||
let entities = &mut self.entities;
|
||||
|
@ -175,8 +177,9 @@ impl ComponentSparseSet {
|
|||
})
|
||||
}
|
||||
|
||||
/// Removes the `entity` from this sparse set and returns a pointer to the associated value (if it exists).
|
||||
/// It is the caller's responsibility to drop the returned ptr (if Some is returned).
|
||||
/// Removes the `entity` from this sparse set and returns a pointer to the associated value (if
|
||||
/// it exists). It is the caller's responsibility to drop the returned ptr (if Some is
|
||||
/// returned).
|
||||
pub fn remove_and_forget(&mut self, entity: Entity) -> Option<*mut u8> {
|
||||
self.sparse.remove(entity).map(|dense_index| {
|
||||
// SAFE: unique access to flags
|
||||
|
@ -268,8 +271,8 @@ impl<I: SparseSetIndex, V> SparseSet<I, V> {
|
|||
self.dense.push(value);
|
||||
}
|
||||
|
||||
// PERF: switch to this. it's faster but it has an invalid memory access on table_add_remove_many
|
||||
// let dense = &mut self.dense;
|
||||
// PERF: switch to this. it's faster but it has an invalid memory access on
|
||||
// table_add_remove_many let dense = &mut self.dense;
|
||||
// let indices = &mut self.indices;
|
||||
// let dense_index = *self.sparse.get_or_insert_with(index.clone(), move || {
|
||||
// if dense.len() == dense.capacity() {
|
||||
|
|
|
@ -49,7 +49,8 @@ impl Column {
|
|||
|
||||
/// # Safety
|
||||
/// Assumes data has already been allocated for the given row/column.
|
||||
/// Allows aliased mutable accesses to the data at the given `row`. Caller must ensure that this does not happen.
|
||||
/// Allows aliased mutable accesses to the data at the given `row`. Caller must ensure that this
|
||||
/// does not happen.
|
||||
#[inline]
|
||||
pub unsafe fn set_unchecked(&self, row: usize, data: *mut u8) {
|
||||
self.data.set_unchecked(row, data);
|
||||
|
@ -67,7 +68,8 @@ impl Column {
|
|||
|
||||
/// # Safety
|
||||
/// Assumes data has already been allocated for the given row/column.
|
||||
/// Allows aliased mutable accesses to the row's ComponentFlags. Caller must ensure that this does not happen.
|
||||
/// Allows aliased mutable accesses to the row's ComponentFlags. Caller must ensure that this
|
||||
/// does not happen.
|
||||
#[inline]
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub unsafe fn get_flags_unchecked_mut(&self, row: usize) -> &mut ComponentFlags {
|
||||
|
@ -193,7 +195,9 @@ impl Table {
|
|||
)
|
||||
}
|
||||
|
||||
/// Removes the entity at the given row and returns the entity swapped in to replace it (if an entity was swapped in)
|
||||
/// Removes the entity at the given row and returns the entity swapped in to replace it (if an
|
||||
/// entity was swapped in)
|
||||
///
|
||||
/// # Safety
|
||||
/// `row` must be in-bounds
|
||||
pub unsafe fn swap_remove_unchecked(&mut self, row: usize) -> Option<Entity> {
|
||||
|
@ -209,9 +213,11 @@ impl Table {
|
|||
}
|
||||
}
|
||||
|
||||
/// Moves the `row` column values to `new_table`, for the columns shared between both tables. Returns the index of the
|
||||
/// new row in `new_table` and the entity in this table swapped in to replace it (if an entity was swapped in).
|
||||
/// missing columns will be "forgotten". It is the caller's responsibility to drop them
|
||||
/// Moves the `row` column values to `new_table`, for the columns shared between both tables.
|
||||
/// Returns the index of the new row in `new_table` and the entity in this table swapped in
|
||||
/// to replace it (if an entity was swapped in). missing columns will be "forgotten". It is
|
||||
/// the caller's responsibility to drop them
|
||||
///
|
||||
/// # Safety
|
||||
/// Row must be in-bounds
|
||||
pub unsafe fn move_to_and_forget_missing_unchecked(
|
||||
|
@ -239,8 +245,10 @@ impl Table {
|
|||
}
|
||||
}
|
||||
|
||||
/// Moves the `row` column values to `new_table`, for the columns shared between both tables. Returns the index of the
|
||||
/// new row in `new_table` and the entity in this table swapped in to replace it (if an entity was swapped in).
|
||||
/// Moves the `row` column values to `new_table`, for the columns shared between both tables.
|
||||
/// Returns the index of the new row in `new_table` and the entity in this table swapped in
|
||||
/// to replace it (if an entity was swapped in).
|
||||
///
|
||||
/// # Safety
|
||||
/// row must be in-bounds
|
||||
pub unsafe fn move_to_and_drop_missing_unchecked(
|
||||
|
@ -270,8 +278,10 @@ impl Table {
|
|||
}
|
||||
}
|
||||
|
||||
/// Moves the `row` column values to `new_table`, for the columns shared between both tables. Returns the index of the
|
||||
/// new row in `new_table` and the entity in this table swapped in to replace it (if an entity was swapped in).
|
||||
/// Moves the `row` column values to `new_table`, for the columns shared between both tables.
|
||||
/// Returns the index of the new row in `new_table` and the entity in this table swapped in
|
||||
/// to replace it (if an entity was swapped in).
|
||||
///
|
||||
/// # Safety
|
||||
/// `row` must be in-bounds. `new_table` must contain every component this table has
|
||||
pub unsafe fn move_to_superset_unchecked(
|
||||
|
@ -326,6 +336,7 @@ impl Table {
|
|||
}
|
||||
|
||||
/// Allocates space for a new entity
|
||||
///
|
||||
/// # Safety
|
||||
/// the allocated row must be written to immediately with valid values in each column
|
||||
pub unsafe fn allocate(&mut self, entity: Entity) -> usize {
|
||||
|
|
|
@ -49,7 +49,10 @@ impl<'a> Commands<'a> {
|
|||
|
||||
/// Creates a new entity with the components contained in `bundle`.
|
||||
///
|
||||
/// Note that `bundle` is a [Bundle], which is a collection of components. [Bundle] 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 [Bundle] is implemented for).
|
||||
/// Note that `bundle` is a [Bundle], which is a collection of components. [Bundle] 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 [Bundle] is implemented for).
|
||||
///
|
||||
/// See [`Self::set_current_entity`], [`Self::insert`].
|
||||
///
|
||||
|
@ -88,7 +91,8 @@ impl<'a> Commands<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Equivalent to iterating `bundles_iter` and calling [`Self::spawn`] on each bundle, but slightly more performant.
|
||||
/// 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,
|
||||
|
@ -167,7 +171,10 @@ impl<'a> Commands<'a> {
|
|||
///
|
||||
/// # 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.
|
||||
/// 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
|
||||
///
|
||||
|
@ -207,7 +214,8 @@ impl<'a> Commands<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Adds a command directly to the command list. Prefer this to [`Self::add_command_boxed`] if the type of `command` is statically known.
|
||||
/// 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));
|
||||
self
|
||||
|
@ -344,7 +352,8 @@ where
|
|||
{
|
||||
fn write(self: Box<Self>, world: &mut World) {
|
||||
if let Some(mut entity_mut) = world.get_entity_mut(self.entity) {
|
||||
// remove intersection to gracefully handle components that were removed before running this command
|
||||
// remove intersection to gracefully handle components that were removed before running
|
||||
// this command
|
||||
entity_mut.remove_bundle_intersection::<T>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ pub struct SystemState {
|
|||
pub(crate) name: Cow<'static, str>,
|
||||
pub(crate) component_access_set: FilteredAccessSet<ComponentId>,
|
||||
pub(crate) archetype_component_access: Access<ArchetypeComponentId>,
|
||||
// NOTE: this must be kept private. making a SystemState non-send is irreversible to prevent SystemParams from overriding each other
|
||||
// NOTE: this must be kept private. making a SystemState non-send is irreversible to prevent
|
||||
// SystemParams from overriding each other
|
||||
is_send: bool,
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ where
|
|||
F::Fetch: FilterFetch,
|
||||
{
|
||||
/// # Safety
|
||||
/// This will create a Query that could violate memory safety rules. Make sure that this is only called in
|
||||
/// ways that ensure the Queries have unique mutable access.
|
||||
/// This will create a Query that could violate memory safety rules. Make sure that this is only
|
||||
/// called in ways that ensure the Queries have unique mutable access.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn new(world: &'w World, state: &'w QueryState<Q, F>) -> Self {
|
||||
Self { world, state }
|
||||
|
@ -37,41 +37,49 @@ where
|
|||
where
|
||||
Q::Fetch: ReadOnlyFetch,
|
||||
{
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime
|
||||
// borrow checks when they conflict
|
||||
unsafe { self.state.iter_unchecked_manual(self.world) }
|
||||
}
|
||||
|
||||
/// Iterates over the query results
|
||||
#[inline]
|
||||
pub fn iter_mut(&mut self) -> QueryIter<'_, '_, Q, F> {
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime
|
||||
// borrow checks when they conflict
|
||||
unsafe { self.state.iter_unchecked_manual(self.world) }
|
||||
}
|
||||
|
||||
/// Iterates over the query results
|
||||
///
|
||||
/// # Safety
|
||||
/// This allows aliased mutability. You must make sure this call does not result in multiple mutable references to the same component
|
||||
/// This allows aliased mutability. You must make sure this call does not result in multiple
|
||||
/// mutable references to the same component
|
||||
#[inline]
|
||||
pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, '_, Q, F> {
|
||||
// SEMI-SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
|
||||
// SEMI-SAFE: system runs without conflicts with other systems. same-system queries have
|
||||
// runtime borrow checks when they conflict
|
||||
self.state.iter_unchecked_manual(self.world)
|
||||
}
|
||||
|
||||
/// Runs `f` on each query result. 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
|
||||
/// Runs `f` on each query result. 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
|
||||
#[inline]
|
||||
pub fn for_each(&self, f: impl FnMut(<Q::Fetch as Fetch<'w>>::Item))
|
||||
where
|
||||
Q::Fetch: ReadOnlyFetch,
|
||||
{
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime
|
||||
// borrow checks when they conflict
|
||||
unsafe { self.state.for_each_unchecked_manual(self.world, f) };
|
||||
}
|
||||
|
||||
/// Runs `f` on each query result. This is faster than the equivalent iter() method, but cannot be chained like a normal iterator.
|
||||
/// Runs `f` on each query result. This is faster than the equivalent iter() method, but cannot
|
||||
/// be chained like a normal iterator.
|
||||
#[inline]
|
||||
pub fn for_each_mut(&self, f: impl FnMut(<Q::Fetch as Fetch<'w>>::Item)) {
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime
|
||||
// borrow checks when they conflict
|
||||
unsafe { self.state.for_each_unchecked_manual(self.world, f) };
|
||||
}
|
||||
|
||||
|
@ -85,7 +93,8 @@ where
|
|||
) where
|
||||
Q::Fetch: ReadOnlyFetch,
|
||||
{
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime
|
||||
// borrow checks when they conflict
|
||||
unsafe {
|
||||
self.state
|
||||
.par_for_each_unchecked_manual(self.world, task_pool, batch_size, f)
|
||||
|
@ -100,7 +109,8 @@ where
|
|||
batch_size: usize,
|
||||
f: impl Fn(<Q::Fetch as Fetch<'w>>::Item) + Send + Sync + Clone,
|
||||
) {
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime
|
||||
// borrow checks when they conflict
|
||||
unsafe {
|
||||
self.state
|
||||
.par_for_each_unchecked_manual(self.world, task_pool, batch_size, f)
|
||||
|
@ -113,7 +123,8 @@ where
|
|||
where
|
||||
Q::Fetch: ReadOnlyFetch,
|
||||
{
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
|
||||
// SAFE: system runs without conflicts with other systems. same-system queries have runtime
|
||||
// borrow checks when they conflict
|
||||
unsafe { self.state.get_unchecked_manual(self.world, entity) }
|
||||
}
|
||||
|
||||
|
@ -123,24 +134,29 @@ where
|
|||
&mut self,
|
||||
entity: Entity,
|
||||
) -> Result<<Q::Fetch as Fetch>::Item, QueryEntityError> {
|
||||
// // SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
|
||||
// // SAFE: system runs without conflicts with other systems. same-system queries have
|
||||
// runtime borrow checks when they conflict
|
||||
unsafe { self.state.get_unchecked_manual(self.world, entity) }
|
||||
}
|
||||
|
||||
/// Gets the query result for the given `entity`
|
||||
///
|
||||
/// # Safety
|
||||
/// This allows aliased mutability. You must make sure this call does not result in multiple mutable references to the same component
|
||||
/// This allows aliased mutability. You must make sure this call does not result in multiple
|
||||
/// mutable references to the same component
|
||||
#[inline]
|
||||
pub unsafe fn get_unchecked(
|
||||
&self,
|
||||
entity: Entity,
|
||||
) -> Result<<Q::Fetch as Fetch>::Item, QueryEntityError> {
|
||||
// SEMI-SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
|
||||
// SEMI-SAFE: system runs without conflicts with other systems. same-system queries have
|
||||
// runtime borrow checks when they conflict
|
||||
self.state.get_unchecked_manual(self.world, entity)
|
||||
}
|
||||
|
||||
/// Gets a reference to the entity's component of the given type. This will fail if the entity does not have
|
||||
/// the given component type or if the given component type does not match this query.
|
||||
/// Gets a reference to the entity's component of the given type. This will fail if the entity
|
||||
/// does not have the given component type or if the given component type does not match
|
||||
/// this query.
|
||||
#[inline]
|
||||
pub fn get_component<T: Component>(&self, entity: Entity) -> Result<&T, QueryComponentError> {
|
||||
let world = self.world;
|
||||
|
@ -168,8 +184,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the entity's component of the given type. This will fail if the entity does not have
|
||||
/// the given component type or if the given component type does not match this query.
|
||||
/// Gets a mutable reference to the entity's component of the given type. This will fail if the
|
||||
/// entity does not have the given component type or if the given component type does not
|
||||
/// match this query.
|
||||
#[inline]
|
||||
pub fn get_component_mut<T: Component>(
|
||||
&mut self,
|
||||
|
@ -179,10 +196,12 @@ where
|
|||
unsafe { self.get_component_unchecked_mut(entity) }
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the entity's component of the given type. This will fail if the entity does not have
|
||||
/// the given component type or the component does not match the query.
|
||||
/// Gets a mutable reference to the entity's component of the given type. This will fail if the
|
||||
/// entity does not have the given component type or the component does not match the query.
|
||||
///
|
||||
/// # Safety
|
||||
/// This allows aliased mutability. You must make sure this call does not result in multiple mutable references to the same component
|
||||
/// This allows aliased mutability. You must make sure this call does not result in multiple
|
||||
/// mutable references to the same component
|
||||
#[inline]
|
||||
pub unsafe fn get_component_unchecked_mut<T: Component>(
|
||||
&self,
|
||||
|
|
|
@ -27,9 +27,10 @@ pub trait System: Send + Sync + 'static {
|
|||
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId>;
|
||||
fn is_send(&self) -> bool;
|
||||
/// # Safety
|
||||
/// This might access World and Resources in an unsafe manner. This should only be called in one of the following contexts:
|
||||
/// 1. This system is the only system running on the given World across all threads
|
||||
/// 2. This system only runs in parallel with other systems that do not conflict with the `archetype_component_access()`
|
||||
/// This might access World and Resources in an unsafe manner. This should only be called in one
|
||||
/// of the following contexts: 1. This system is the only system running on the given World
|
||||
/// across all threads 2. This system only runs in parallel with other systems that do not
|
||||
/// conflict with the `archetype_component_access()`
|
||||
unsafe fn run_unsafe(&mut self, input: Self::In, world: &World) -> Self::Out;
|
||||
fn run(&mut self, input: Self::In, world: &mut World) -> Self::Out {
|
||||
// SAFE: world and resources are exclusively borrowed
|
||||
|
|
|
@ -38,8 +38,9 @@ pub trait SystemParam: Sized {
|
|||
|
||||
/// # Safety
|
||||
/// it is the implementors responsibility to ensure `system_state` is populated with the _exact_
|
||||
/// [World] access used by the SystemParamState (and associated FetchSystemParam). Additionally, it is the
|
||||
/// implementor's responsibility to ensure there is no conflicting access across all SystemParams.
|
||||
/// [World] access used by the SystemParamState (and associated FetchSystemParam). Additionally, it
|
||||
/// is the implementor's responsibility to ensure there is no conflicting access across all
|
||||
/// SystemParams.
|
||||
pub unsafe trait SystemParamState: Send + Sync + 'static {
|
||||
type Config: Default + Send + Sync;
|
||||
fn init(world: &mut World, system_state: &mut SystemState, config: Self::Config) -> Self;
|
||||
|
@ -52,8 +53,8 @@ pub unsafe trait SystemParamState: Send + Sync + 'static {
|
|||
pub trait SystemParamFetch<'a>: SystemParamState {
|
||||
type Item;
|
||||
/// # Safety
|
||||
/// This call might access any of the input parameters in an unsafe way. Make sure the data access is safe in
|
||||
/// the context of the system scheduler
|
||||
/// This call might access any of the input parameters in an unsafe way. Make sure the data
|
||||
/// access is safe in the context of the system scheduler
|
||||
unsafe fn get_param(
|
||||
state: &'a mut Self,
|
||||
system_state: &'a SystemState,
|
||||
|
@ -70,8 +71,8 @@ where
|
|||
type Fetch = QueryState<Q, F>;
|
||||
}
|
||||
|
||||
// SAFE: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemState. If this QueryState conflicts
|
||||
// with any prior access, a panic will occur.
|
||||
// SAFE: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemState. If
|
||||
// this QueryState conflicts with any prior access, a panic will occur.
|
||||
unsafe impl<Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParamState for QueryState<Q, F>
|
||||
where
|
||||
F::Fetch: FilterFetch,
|
||||
|
@ -168,7 +169,8 @@ impl<'w, T: Component> Res<'w, T> {
|
|||
self.flags.contains(ComponentFlags::MUTATED)
|
||||
}
|
||||
|
||||
/// Returns true if (and only if) this resource been either mutated or added since the start of the frame.
|
||||
/// Returns true if (and only if) this resource been either mutated or added since the start of
|
||||
/// the frame.
|
||||
pub fn changed(&self) -> bool {
|
||||
self.flags
|
||||
.intersects(ComponentFlags::ADDED | ComponentFlags::MUTATED)
|
||||
|
@ -192,8 +194,8 @@ impl<'a, T: Component> SystemParam for Res<'a, T> {
|
|||
type Fetch = ResState<T>;
|
||||
}
|
||||
|
||||
// SAFE: Res ComponentId and ArchetypeComponentId access is applied to SystemState. If this Res conflicts
|
||||
// with any prior access, a panic will occur.
|
||||
// SAFE: Res ComponentId and ArchetypeComponentId access is applied to SystemState. If this Res
|
||||
// conflicts with any prior access, a panic will occur.
|
||||
unsafe impl<T: Component> SystemParamState for ResState<T> {
|
||||
type Config = ();
|
||||
|
||||
|
@ -293,7 +295,8 @@ impl<'w, T: Component> ResMut<'w, T> {
|
|||
self.flags.contains(ComponentFlags::MUTATED)
|
||||
}
|
||||
|
||||
/// Returns true if (and only if) this resource been either mutated or added since the start of the frame.
|
||||
/// Returns true if (and only if) this resource been either mutated or added since the start of
|
||||
/// the frame.
|
||||
pub fn changed(&self) -> bool {
|
||||
self.flags
|
||||
.intersects(ComponentFlags::ADDED | ComponentFlags::MUTATED)
|
||||
|
@ -324,8 +327,8 @@ impl<'a, T: Component> SystemParam for ResMut<'a, T> {
|
|||
type Fetch = ResMutState<T>;
|
||||
}
|
||||
|
||||
// SAFE: Res ComponentId and ArchetypeComponentId access is applied to SystemState. If this Res conflicts
|
||||
// with any prior access, a panic will occur.
|
||||
// SAFE: Res ComponentId and ArchetypeComponentId access is applied to SystemState. If this Res
|
||||
// conflicts with any prior access, a panic will occur.
|
||||
unsafe impl<T: Component> SystemParamState for ResMutState<T> {
|
||||
type Config = ();
|
||||
|
||||
|
@ -505,8 +508,8 @@ impl<'a, T: Component> SystemParam for RemovedComponents<'a, T> {
|
|||
type Fetch = RemovedComponentsState<T>;
|
||||
}
|
||||
|
||||
// SAFE: no component access. removed component entity collections can be read in parallel and are never mutably borrowed
|
||||
// during system execution
|
||||
// SAFE: no component access. removed component entity collections can be read in parallel and are
|
||||
// never mutably borrowed during system execution
|
||||
unsafe impl<T: Component> SystemParamState for RemovedComponentsState<T> {
|
||||
type Config = ();
|
||||
|
||||
|
@ -557,8 +560,8 @@ impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
|
|||
type Fetch = NonSendState<T>;
|
||||
}
|
||||
|
||||
// SAFE: NonSendComponentId and ArchetypeComponentId access is applied to SystemState. If this NonSend conflicts
|
||||
// with any prior access, a panic will occur.
|
||||
// SAFE: NonSendComponentId and ArchetypeComponentId access is applied to SystemState. If this
|
||||
// NonSend conflicts with any prior access, a panic will occur.
|
||||
unsafe impl<T: 'static> SystemParamState for NonSendState<T> {
|
||||
type Config = ();
|
||||
|
||||
|
@ -643,8 +646,8 @@ impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
|
|||
type Fetch = NonSendMutState<T>;
|
||||
}
|
||||
|
||||
// SAFE: NonSendMut ComponentId and ArchetypeComponentId access is applied to SystemState. If this NonSendMut conflicts
|
||||
// with any prior access, a panic will occur.
|
||||
// SAFE: NonSendMut ComponentId and ArchetypeComponentId access is applied to SystemState. If this
|
||||
// NonSendMut conflicts with any prior access, a panic will occur.
|
||||
unsafe impl<T: 'static> SystemParamState for NonSendMutState<T> {
|
||||
type Config = ();
|
||||
|
||||
|
@ -858,6 +861,6 @@ macro_rules! impl_system_param_tuple {
|
|||
};
|
||||
}
|
||||
|
||||
// TODO: consider creating a Config trait with a default() function, then implementing that for tuples.
|
||||
// that would allow us to go past tuples of len 12
|
||||
// TODO: consider creating a Config trait with a default() function, then implementing that for
|
||||
// tuples. that would allow us to go past tuples of len 12
|
||||
all_tuples!(impl_system_param_tuple, 0, 12, P);
|
||||
|
|
|
@ -36,7 +36,8 @@ impl<'w> EntityRef<'w> {
|
|||
|
||||
#[inline]
|
||||
pub fn archetype(&self) -> &Archetype {
|
||||
// SAFE: EntityRefs always point to valid entities. Valid entities always have valid archetypes
|
||||
// SAFE: EntityRefs always point to valid entities. Valid entities always have valid
|
||||
// archetypes
|
||||
unsafe {
|
||||
self.world
|
||||
.archetypes
|
||||
|
@ -76,7 +77,8 @@ impl<'w> EntityRef<'w> {
|
|||
}
|
||||
|
||||
/// # Safety
|
||||
/// This allows aliased mutability. You must make sure this call does not result in multiple mutable references to the same component
|
||||
/// This allows aliased mutability. You must make sure this call does not result in multiple
|
||||
/// mutable references to the same component
|
||||
#[inline]
|
||||
pub unsafe fn get_unchecked_mut<T: Component>(&self) -> Option<Mut<'w, T>> {
|
||||
get_component_and_flags_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)
|
||||
|
@ -121,7 +123,8 @@ impl<'w> EntityMut<'w> {
|
|||
|
||||
#[inline]
|
||||
pub fn archetype(&self) -> &Archetype {
|
||||
// SAFE: EntityRefs always point to valid entities. Valid entities always have valid archetypes
|
||||
// SAFE: EntityRefs always point to valid entities. Valid entities always have valid
|
||||
// archetypes
|
||||
unsafe {
|
||||
self.world
|
||||
.archetypes
|
||||
|
@ -157,7 +160,8 @@ impl<'w> EntityMut<'w> {
|
|||
|
||||
#[inline]
|
||||
pub fn get_mut<T: Component>(&mut self) -> Option<Mut<'w, T>> {
|
||||
// SAFE: world access is unique, entity location is valid, and returned component is of type T
|
||||
// SAFE: world access is unique, entity location is valid, and returned component is of type
|
||||
// T
|
||||
unsafe {
|
||||
get_component_and_flags_with_type(
|
||||
self.world,
|
||||
|
@ -173,7 +177,8 @@ impl<'w> EntityMut<'w> {
|
|||
}
|
||||
|
||||
/// # Safety
|
||||
/// This allows aliased mutability. You must make sure this call does not result in multiple mutable references to the same component
|
||||
/// This allows aliased mutability. You must make sure this call does not result in multiple
|
||||
/// mutable references to the same component
|
||||
#[inline]
|
||||
pub unsafe fn get_unchecked_mut<T: Component>(&self) -> Option<Mut<'w, T>> {
|
||||
get_component_and_flags_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)
|
||||
|
@ -227,7 +232,8 @@ impl<'w> EntityMut<'w> {
|
|||
let (old_table, new_table) = storages
|
||||
.tables
|
||||
.get_2_mut(old_table_id, new_archetype.table_id());
|
||||
// PERF: store "non bundle" components in edge, then just move those to avoid redundant copies
|
||||
// PERF: store "non bundle" components in edge, then just move those to avoid
|
||||
// redundant copies
|
||||
let move_result =
|
||||
old_table.move_to_superset_unchecked(old_table_row, new_table);
|
||||
|
||||
|
@ -235,7 +241,8 @@ impl<'w> EntityMut<'w> {
|
|||
// if an entity was moved into this entity's table spot, update its table row
|
||||
if let Some(swapped_entity) = move_result.swapped_entity {
|
||||
let swapped_location = entities.get(swapped_entity).unwrap();
|
||||
// SAFE: entity is live and is therefore contained in an archetype that exists
|
||||
// SAFE: entity is live and is therefore contained in an archetype that
|
||||
// exists
|
||||
archetypes
|
||||
.get_unchecked_mut(swapped_location.archetype_id)
|
||||
.set_entity_table_row(swapped_location.index, old_table_row);
|
||||
|
@ -297,7 +304,8 @@ impl<'w> EntityMut<'w> {
|
|||
let old_archetype = unsafe { archetypes.get_unchecked_mut(old_location.archetype_id) };
|
||||
let mut bundle_components = bundle_info.component_ids.iter().cloned();
|
||||
let entity = self.entity;
|
||||
// SAFE: bundle components are iterated in order, which guarantees that the component type matches
|
||||
// SAFE: bundle components are iterated in order, which guarantees that the component type
|
||||
// matches
|
||||
let result = unsafe {
|
||||
T::from_components(|| {
|
||||
let component_id = bundle_components.next().unwrap();
|
||||
|
@ -330,7 +338,8 @@ impl<'w> EntityMut<'w> {
|
|||
.tables
|
||||
.get_2_mut(old_table_id, new_archetype.table_id());
|
||||
|
||||
// SAFE: table_row exists. All "missing" components have been extracted into the bundle above and the caller takes ownership
|
||||
// SAFE: table_row exists. All "missing" components have been extracted into the bundle
|
||||
// above and the caller takes ownership
|
||||
let move_result =
|
||||
unsafe { old_table.move_to_and_forget_missing_unchecked(old_table_row, new_table) };
|
||||
|
||||
|
@ -505,22 +514,24 @@ impl<'w> EntityMut<'w> {
|
|||
|
||||
/// # Safety
|
||||
/// Caller must not modify the world in a way that changes the current entity's location
|
||||
/// If the caller _does_ do something that could change the location, self.update_location() must be
|
||||
/// called before using any other methods in EntityMut
|
||||
/// If the caller _does_ do something that could change the location, self.update_location()
|
||||
/// must be called before using any other methods in EntityMut
|
||||
#[inline]
|
||||
pub unsafe fn world_mut(&mut self) -> &mut World {
|
||||
self.world
|
||||
}
|
||||
|
||||
/// Updates the internal entity location to match the current location in the internal [World].
|
||||
/// This is only needed if the user called [EntityMut::world], which enables the location to change.
|
||||
/// This is only needed if the user called [EntityMut::world], which enables the location to
|
||||
/// change.
|
||||
pub fn update_location(&mut self) {
|
||||
self.location = self.world.entities().get(self.entity).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// `entity_location` must be within bounds of the given archetype and `entity` must exist inside the archetype
|
||||
/// `entity_location` must be within bounds of the given archetype and `entity` must exist inside
|
||||
/// the archetype
|
||||
#[inline]
|
||||
unsafe fn get_component(
|
||||
world: &World,
|
||||
|
@ -580,7 +591,8 @@ unsafe fn get_component_and_flags(
|
|||
}
|
||||
|
||||
/// # Safety
|
||||
// `entity_location` must be within bounds of the given archetype and `entity` must exist inside the archetype
|
||||
// `entity_location` must be within bounds of the given archetype and `entity` must exist inside the
|
||||
// archetype
|
||||
/// The relevant table row must be removed separately
|
||||
/// `component_id` must be valid
|
||||
#[inline]
|
||||
|
@ -666,9 +678,10 @@ unsafe fn contains_component_with_id(
|
|||
.contains(component_id)
|
||||
}
|
||||
|
||||
/// Adds a bundle to the given archetype and returns the resulting archetype. This could be the same [ArchetypeId],
|
||||
/// in the event that adding the given bundle does not result in an Archetype change. Results are cached in the
|
||||
/// Archetype Graph to avoid redundant work.
|
||||
/// Adds a bundle to the given archetype and returns the resulting archetype. This could be the same
|
||||
/// [ArchetypeId], in the event that adding the given bundle does not result in an Archetype change.
|
||||
/// Results are cached in the Archetype Graph to avoid redundant work.
|
||||
///
|
||||
/// # Safety
|
||||
/// `archetype_id` must exist and components in `bundle_info` must exist
|
||||
pub(crate) unsafe fn add_bundle_to_archetype(
|
||||
|
@ -760,11 +773,13 @@ pub(crate) unsafe fn add_bundle_to_archetype(
|
|||
}
|
||||
}
|
||||
|
||||
/// Removes a bundle from the given archetype and returns the resulting archetype (or None if the removal was invalid).
|
||||
/// in the event that adding the given bundle does not result in an Archetype change. Results are cached in the
|
||||
/// Archetype Graph to avoid redundant work.
|
||||
/// if `intersection` is false, attempting to remove a bundle with components _not_ contained in the current archetype will fail,
|
||||
/// returning None. if `intersection` is true, components in the bundle but not in the current archetype will be ignored
|
||||
/// Removes a bundle from the given archetype and returns the resulting archetype (or None if the
|
||||
/// removal was invalid). in the event that adding the given bundle does not result in an Archetype
|
||||
/// change. Results are cached in the Archetype Graph to avoid redundant work.
|
||||
/// if `intersection` is false, attempting to remove a bundle with components _not_ contained in the
|
||||
/// current archetype will fail, returning None. if `intersection` is true, components in the bundle
|
||||
/// but not in the current archetype will be ignored
|
||||
///
|
||||
/// # Safety
|
||||
/// `archetype_id` must exist and components in `bundle_info` must exist
|
||||
unsafe fn remove_bundle_from_archetype(
|
||||
|
@ -775,7 +790,8 @@ unsafe fn remove_bundle_from_archetype(
|
|||
bundle_info: &BundleInfo,
|
||||
intersection: bool,
|
||||
) -> Option<ArchetypeId> {
|
||||
// check the archetype graph to see if the Bundle has been removed from this archetype in the past
|
||||
// check the archetype graph to see if the Bundle has been removed from this archetype in the
|
||||
// past
|
||||
let remove_bundle_result = {
|
||||
// SAFE: entity location is valid and therefore the archetype exists
|
||||
let current_archetype = archetypes.get_unchecked_mut(archetype_id);
|
||||
|
@ -808,8 +824,9 @@ unsafe fn remove_bundle_from_archetype(
|
|||
StorageType::SparseSet => removed_sparse_set_components.push(component_id),
|
||||
}
|
||||
} else if !intersection {
|
||||
// a component in the bundle was not present in the entity's archetype, so this removal is invalid
|
||||
// cache the result in the archetype graph
|
||||
// a component in the bundle was not present in the entity's archetype, so this
|
||||
// removal is invalid cache the result in the archetype
|
||||
// graph
|
||||
current_archetype
|
||||
.edges_mut()
|
||||
.set_remove_bundle(bundle_info.id, None);
|
||||
|
@ -817,7 +834,8 @@ unsafe fn remove_bundle_from_archetype(
|
|||
}
|
||||
}
|
||||
|
||||
// sort removed components so we can do an efficient "sorted remove". archetype components are already sorted
|
||||
// sort removed components so we can do an efficient "sorted remove". archetype
|
||||
// components are already sorted
|
||||
removed_table_components.sort();
|
||||
removed_sparse_set_components.sort();
|
||||
next_table_components = current_archetype.table_components().to_vec();
|
||||
|
|
|
@ -30,9 +30,10 @@ impl Default for WorldId {
|
|||
}
|
||||
}
|
||||
|
||||
/// [World] stores and exposes operations on [entities](Entity), [components](Component), and their associated metadata.
|
||||
/// Each [Entity] has a set of components. Each component can have up to one instance of each component type.
|
||||
/// Entity components can be created, updated, removed, and queried using a given [World].
|
||||
/// [World] stores and exposes operations on [entities](Entity), [components](Component), and their
|
||||
/// associated metadata. Each [Entity] has a set of components. Each component can have up to one
|
||||
/// instance of each component type. Entity components can be created, updated, removed, and queried
|
||||
/// using a given [World].
|
||||
#[derive(Default)]
|
||||
pub struct World {
|
||||
id: WorldId,
|
||||
|
@ -96,16 +97,17 @@ impl World {
|
|||
&self.bundles
|
||||
}
|
||||
|
||||
/// Retrieves a [WorldCell], which safely enables multiple mutable World accesses at the same time,
|
||||
/// provided those accesses do not conflict with each other.
|
||||
/// Retrieves a [WorldCell], which safely enables multiple mutable World accesses at the same
|
||||
/// time, provided those accesses do not conflict with each other.
|
||||
#[inline]
|
||||
pub fn cell(&mut self) -> WorldCell<'_> {
|
||||
WorldCell::new(self)
|
||||
}
|
||||
|
||||
/// Registers a new component using the given [ComponentDescriptor]. Components do not need to be manually
|
||||
/// registered. This just provides a way to override default configuration. Attempting to register a component
|
||||
/// with a type that has already been used by [World] will result in an error.
|
||||
/// Registers a new component using the given [ComponentDescriptor]. Components do not need to
|
||||
/// be manually registered. This just provides a way to override default configuration.
|
||||
/// Attempting to register a component with a type that has already been used by [World]
|
||||
/// will result in an error.
|
||||
///
|
||||
/// The default component storage type can be overridden like this:
|
||||
///
|
||||
|
@ -269,7 +271,8 @@ impl World {
|
|||
// PERF: consider avoiding allocating entities in the empty archetype unless needed
|
||||
// SAFE: archetype tables always exist
|
||||
let table = self.storages.tables.get_unchecked_mut(archetype.table_id());
|
||||
// SAFE: no components are allocated by archetype.allocate() because the archetype is empty
|
||||
// SAFE: no components are allocated by archetype.allocate() because the archetype is
|
||||
// empty
|
||||
let location = archetype.allocate(entity, table.allocate(entity));
|
||||
// SAFE: entity index was just allocated
|
||||
self.entities
|
||||
|
@ -347,9 +350,9 @@ impl World {
|
|||
self.get_entity_mut(entity)?.get_mut()
|
||||
}
|
||||
|
||||
/// Despawns the given `entity`, if it exists. This will also remove all of the entity's [Component]s.
|
||||
/// Returns `true` if the `entity` is successfully despawned and `false` if the `entity` does not exist.
|
||||
/// ```
|
||||
/// Despawns the given `entity`, if it exists. This will also remove all of the entity's
|
||||
/// [Component]s. Returns `true` if the `entity` is successfully despawned and `false` if
|
||||
/// the `entity` does not exist. ```
|
||||
/// use bevy_ecs::world::World;
|
||||
///
|
||||
/// struct Position {
|
||||
|
@ -391,7 +394,6 @@ impl World {
|
|||
/// Returns [QueryState] for the given [WorldQuery], which is used to efficiently
|
||||
/// run queries on the [World].
|
||||
/// ```
|
||||
///
|
||||
/// use bevy_ecs::{entity::Entity, world::World};
|
||||
///
|
||||
/// #[derive(Debug, PartialEq)]
|
||||
|
@ -450,7 +452,8 @@ impl World {
|
|||
QueryState::new(self)
|
||||
}
|
||||
|
||||
/// Returns an iterator of entities that had components of type `T` removed since the last call to [World::clear_trackers].
|
||||
/// Returns an iterator of entities that had components of type `T` removed since the last call
|
||||
/// to [World::clear_trackers].
|
||||
pub fn removed<T: Component>(&self) -> std::iter::Cloned<std::slice::Iter<'_, Entity>> {
|
||||
if let Some(component_id) = self.components.get_id(TypeId::of::<T>()) {
|
||||
self.removed_with_id(component_id)
|
||||
|
@ -459,7 +462,8 @@ impl World {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator of entities that had components with the given `component_id` removed since the last call to [World::clear_trackers].
|
||||
/// Returns an iterator of entities that had components with the given `component_id` removed
|
||||
/// since the last call to [World::clear_trackers].
|
||||
pub fn removed_with_id(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
|
@ -501,8 +505,8 @@ impl World {
|
|||
if column.is_empty() {
|
||||
return None;
|
||||
}
|
||||
// SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of the ptr value / drop is called when
|
||||
// T is dropped
|
||||
// SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of the
|
||||
// ptr value / drop is called when T is dropped
|
||||
let (ptr, _) = unsafe { column.swap_remove_and_forget_unchecked(0) };
|
||||
// SAFE: column is of type T
|
||||
Some(unsafe { ptr.cast::<T>().read() })
|
||||
|
@ -528,8 +532,8 @@ impl World {
|
|||
unsafe { self.get_resource_with_id(component_id) }
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the resource of the given type, if it exists. Otherwise returns [None]
|
||||
/// Resources are "unique" data of a given type.
|
||||
/// Gets a mutable reference to the resource of the given type, if it exists. Otherwise returns
|
||||
/// [None] Resources are "unique" data of a given type.
|
||||
#[inline]
|
||||
pub fn get_resource_mut<T: Component>(&mut self) -> Option<Mut<'_, T>> {
|
||||
// SAFE: unique world access
|
||||
|
@ -537,7 +541,8 @@ impl World {
|
|||
}
|
||||
|
||||
// PERF: optimize this to avoid redundant lookups
|
||||
/// Gets a resource of type `T` if it exists, otherwise inserts the resource using the result of calling `func`.
|
||||
/// Gets a resource of type `T` if it exists, otherwise inserts the resource using the result of
|
||||
/// calling `func`.
|
||||
#[inline]
|
||||
pub fn get_resource_or_insert_with<T: Component>(
|
||||
&mut self,
|
||||
|
@ -549,19 +554,20 @@ impl World {
|
|||
self.get_resource_mut().unwrap()
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the resource of the given type, if it exists. Otherwise returns [None]
|
||||
/// Resources are "unique" data of a given type.
|
||||
/// Gets a mutable reference to the resource of the given type, if it exists. Otherwise returns
|
||||
/// [None] Resources are "unique" data of a given type.
|
||||
///
|
||||
/// # Safety
|
||||
/// This will allow aliased mutable access to the given resource type. The caller must ensure that only
|
||||
/// one mutable access exists at a time.
|
||||
/// This will allow aliased mutable access to the given resource type. The caller must ensure
|
||||
/// that only one mutable access exists at a time.
|
||||
#[inline]
|
||||
pub unsafe fn get_resource_unchecked_mut<T: Component>(&self) -> Option<Mut<'_, T>> {
|
||||
let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
|
||||
self.get_resource_unchecked_mut_with_id(component_id)
|
||||
}
|
||||
|
||||
/// Gets a reference to the non-send resource of the given type, if it exists. Otherwise returns [None]
|
||||
/// Resources are "unique" data of a given type.
|
||||
/// Gets a reference to the non-send resource of the given type, if it exists. Otherwise returns
|
||||
/// [None] Resources are "unique" data of a given type.
|
||||
#[inline]
|
||||
pub fn get_non_send_resource<T: 'static>(&self) -> Option<&T> {
|
||||
let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
|
||||
|
@ -569,28 +575,29 @@ impl World {
|
|||
unsafe { self.get_non_send_with_id(component_id) }
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the non-send resource of the given type, if it exists. Otherwise returns [None]
|
||||
/// Resources are "unique" data of a given type.
|
||||
/// Gets a mutable reference to the non-send resource of the given type, if it exists. Otherwise
|
||||
/// returns [None] Resources are "unique" data of a given type.
|
||||
#[inline]
|
||||
pub fn get_non_send_resource_mut<T: 'static>(&mut self) -> Option<Mut<'_, T>> {
|
||||
// SAFE: unique world access
|
||||
unsafe { self.get_non_send_resource_unchecked_mut() }
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the non-send resource of the given type, if it exists. Otherwise returns [None]
|
||||
/// Resources are "unique" data of a given type.
|
||||
/// Gets a mutable reference to the non-send resource of the given type, if it exists. Otherwise
|
||||
/// returns [None] Resources are "unique" data of a given type.
|
||||
///
|
||||
/// # Safety
|
||||
/// This will allow aliased mutable access to the given non-send resource type. The caller must ensure that only
|
||||
/// one mutable access exists at a time.
|
||||
/// This will allow aliased mutable access to the given non-send resource type. The caller must
|
||||
/// ensure that only one mutable access exists at a time.
|
||||
#[inline]
|
||||
pub unsafe fn get_non_send_resource_unchecked_mut<T: 'static>(&self) -> Option<Mut<'_, T>> {
|
||||
let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
|
||||
self.get_non_send_unchecked_mut_with_id(component_id)
|
||||
}
|
||||
|
||||
/// Temporarily removes the requested resource from this [World], then re-adds it before returning.
|
||||
/// This enables safe mutable access to a resource while still providing mutable world access
|
||||
/// ```
|
||||
/// Temporarily removes the requested resource from this [World], then re-adds it before
|
||||
/// returning. This enables safe mutable access to a resource while still providing mutable
|
||||
/// world access ```
|
||||
/// use bevy_ecs::world::{World, Mut};
|
||||
/// struct A(u32);
|
||||
/// struct B(u32);
|
||||
|
@ -621,8 +628,8 @@ impl World {
|
|||
if column.is_empty() {
|
||||
panic!("resource does not exist");
|
||||
}
|
||||
// SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of the ptr value / drop is called when
|
||||
// T is dropped
|
||||
// SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of
|
||||
// the ptr value / drop is called when T is dropped
|
||||
unsafe { column.swap_remove_and_forget_unchecked(0) }
|
||||
};
|
||||
// SAFE: pointer is of type T
|
||||
|
@ -801,7 +808,8 @@ impl World {
|
|||
.get_unchecked_mut(empty_archetype.table_id());
|
||||
// PERF: consider pre-allocating space for flushed entities
|
||||
self.entities.flush(|entity, location| {
|
||||
// SAFE: no components are allocated by archetype.allocate() because the archetype is empty
|
||||
// SAFE: no components are allocated by archetype.allocate() because the archetype
|
||||
// is empty
|
||||
*location = empty_archetype.allocate(entity, table.allocate(entity));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -41,7 +41,8 @@ impl<'w, T> Mut<'w, T> {
|
|||
self.flags.contains(ComponentFlags::MUTATED)
|
||||
}
|
||||
|
||||
/// Returns true if (and only if) this component been either mutated or added since the start of the frame.
|
||||
/// Returns true if (and only if) this component been either mutated or added since the start of
|
||||
/// the frame.
|
||||
pub fn changed(&self) -> bool {
|
||||
self.flags
|
||||
.intersects(ComponentFlags::ADDED | ComponentFlags::MUTATED)
|
||||
|
|
|
@ -88,7 +88,8 @@ where
|
|||
fn next(&mut self) -> Option<Entity> {
|
||||
let bundle = self.inner.next()?;
|
||||
let entity = self.entities.alloc();
|
||||
// SAFE: component values are immediately written to relevant storages (which have been allocated)
|
||||
// SAFE: component values are immediately written to relevant storages (which have been
|
||||
// allocated)
|
||||
unsafe {
|
||||
let table_row = self.table.allocate(entity);
|
||||
let location = self.archetype.allocate(entity, table_row);
|
||||
|
|
|
@ -11,8 +11,8 @@ use std::{
|
|||
rc::Rc,
|
||||
};
|
||||
|
||||
/// Exposes safe mutable access to multiple resources at a time in a World. Attempting to access World in a way that violates
|
||||
/// Rust's mutability rules will panic thanks to runtime checks.
|
||||
/// Exposes safe mutable access to multiple resources at a time in a World. Attempting to access
|
||||
/// World in a way that violates Rust's mutability rules will panic thanks to runtime checks.
|
||||
pub struct WorldCell<'w> {
|
||||
pub(crate) world: &'w mut World,
|
||||
pub(crate) access: Rc<RefCell<ArchetypeComponentAccess>>,
|
||||
|
|
|
@ -33,7 +33,8 @@ pub enum MouseScrollUnit {
|
|||
Pixel,
|
||||
}
|
||||
|
||||
/// A mouse scroll wheel event, where x represents horizontal scroll and y represents vertical scroll.
|
||||
/// A mouse scroll wheel event, where x represents horizontal scroll and y represents vertical
|
||||
/// scroll.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MouseWheel {
|
||||
pub unit: MouseScrollUnit,
|
||||
|
|
|
@ -79,7 +79,8 @@ pub fn lights_node_system(
|
|||
mut state: Local<LightsNodeSystemState>,
|
||||
render_resource_context: Res<Box<dyn RenderResourceContext>>,
|
||||
ambient_light_resource: Res<AmbientLight>,
|
||||
// TODO: this write on RenderResourceBindings will prevent this system from running in parallel with other systems that do the same
|
||||
// TODO: this write on RenderResourceBindings will prevent this system from running in parallel
|
||||
// with other systems that do the same
|
||||
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
||||
query: Query<(&Light, &GlobalTransform)>,
|
||||
) {
|
||||
|
|
|
@ -4,8 +4,8 @@ use bevy_utils::HashMap;
|
|||
|
||||
use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
|
||||
|
||||
/// An ordered ReflectValue->ReflectValue mapping. ReflectValue Keys are assumed to return a non-None hash.
|
||||
/// Ideally the ordering is stable across runs, but this is not required.
|
||||
/// An ordered ReflectValue->ReflectValue mapping. ReflectValue Keys are assumed to return a
|
||||
/// non-None hash. Ideally the ordering is stable across runs, but this is not required.
|
||||
/// This corresponds to types like [std::collections::HashMap].
|
||||
pub trait Map: Reflect {
|
||||
fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect>;
|
||||
|
|
|
@ -31,11 +31,14 @@ pub trait Reflect: Any + Send + Sync {
|
|||
fn reflect_ref(&self) -> ReflectRef;
|
||||
fn reflect_mut(&mut self) -> ReflectMut;
|
||||
fn clone_value(&self) -> Box<dyn Reflect>;
|
||||
/// Returns a hash of the value (which includes the type) if hashing is supported. Otherwise `None` will be returned.
|
||||
/// Returns a hash of the value (which includes the type) if hashing is supported. Otherwise
|
||||
/// `None` will be returned.
|
||||
fn reflect_hash(&self) -> Option<u64>;
|
||||
/// Returns a "partial equal" comparison result if comparison is supported. Otherwise `None` will be returned.
|
||||
/// Returns a "partial equal" comparison result if comparison is supported. Otherwise `None`
|
||||
/// will be returned.
|
||||
fn reflect_partial_eq(&self, _value: &dyn Reflect) -> Option<bool>;
|
||||
/// Returns a serializable value, if serialization is supported. Otherwise `None` will be returned.
|
||||
/// Returns a serializable value, if serialization is supported. Otherwise `None` will be
|
||||
/// returned.
|
||||
fn serializable(&self) -> Option<Serializable>;
|
||||
}
|
||||
|
||||
|
@ -47,7 +50,8 @@ impl Debug for dyn Reflect {
|
|||
|
||||
impl dyn Reflect {
|
||||
pub fn downcast<T: Reflect>(self: Box<dyn Reflect>) -> Result<Box<T>, Box<dyn Reflect>> {
|
||||
// SAFE?: Same approach used by std::any::Box::downcast. ReflectValue is always Any and type has been checked.
|
||||
// SAFE?: Same approach used by std::any::Box::downcast. ReflectValue is always Any and type
|
||||
// has been checked.
|
||||
if self.is::<T>() {
|
||||
unsafe {
|
||||
let raw: *mut dyn Reflect = Box::into_raw(self);
|
||||
|
|
|
@ -13,7 +13,8 @@ pub struct TypeRegistry {
|
|||
ambiguous_names: HashSet<String>,
|
||||
}
|
||||
|
||||
// TODO: remove this wrapper once we migrate to Atelier Assets and the Scene AssetLoader doesn't need a TypeRegistry ref
|
||||
// TODO: remove this wrapper once we migrate to Atelier Assets and the Scene AssetLoader doesn't
|
||||
// need a TypeRegistry ref
|
||||
#[derive(Clone, Default)]
|
||||
pub struct TypeRegistryArc {
|
||||
pub internal: Arc<RwLock<TypeRegistry>>,
|
||||
|
|
|
@ -73,7 +73,8 @@ pub fn camera_system<T: CameraProjection + Component>(
|
|||
)>,
|
||||
) {
|
||||
let mut changed_window_ids = Vec::new();
|
||||
// handle resize events. latest events are handled first because we only want to resize each window once
|
||||
// handle resize events. latest events are handled first because we only want to resize each
|
||||
// window once
|
||||
for event in window_resized_events.iter().rev() {
|
||||
if changed_window_ids.contains(&event.id) {
|
||||
continue;
|
||||
|
@ -82,7 +83,8 @@ pub fn camera_system<T: CameraProjection + Component>(
|
|||
changed_window_ids.push(event.id);
|
||||
}
|
||||
|
||||
// handle resize events. latest events are handled first because we only want to resize each window once
|
||||
// handle resize events. latest events are handled first because we only want to resize each
|
||||
// window once
|
||||
for event in window_created_events.iter().rev() {
|
||||
if changed_window_ids.contains(&event.id) {
|
||||
continue;
|
||||
|
|
|
@ -34,8 +34,8 @@ pub type Layer = u8;
|
|||
/// Cameras with this component will only render entities with intersecting
|
||||
/// layers.
|
||||
///
|
||||
/// There are 32 layers numbered `0` - [`TOTAL_LAYERS`](RenderLayers::TOTAL_LAYERS). Entities may belong to one or more
|
||||
/// layers, or no layer at all.
|
||||
/// There are 32 layers numbered `0` - [`TOTAL_LAYERS`](RenderLayers::TOTAL_LAYERS). Entities may
|
||||
/// belong to one or more layers, or no layer at all.
|
||||
///
|
||||
/// The [`Default`] instance of `RenderLayers` contains layer `0`, the first layer.
|
||||
///
|
||||
|
@ -228,7 +228,8 @@ pub fn visible_entities_system(
|
|||
|
||||
let order = if let Ok(global_transform) = visible_transform_query.get(entity) {
|
||||
let position = global_transform.translation;
|
||||
// smaller distances are sorted to lower indices by using the distance from the camera
|
||||
// smaller distances are sorted to lower indices by using the distance from the
|
||||
// camera
|
||||
FloatOrd(match camera.depth_calculation {
|
||||
DepthCalculation::ZDifference => camera_position.z - position.z,
|
||||
DepthCalculation::Distance => (camera_position - position).length_squared(),
|
||||
|
@ -253,6 +254,7 @@ pub fn visible_entities_system(
|
|||
transparent_entities.sort_by_key(|e| -e.order);
|
||||
visible_entities.value.extend(transparent_entities);
|
||||
|
||||
// TODO: check for big changes in visible entities len() vs capacity() (ex: 2x) and resize to prevent holding unneeded memory
|
||||
// TODO: check for big changes in visible entities len() vs capacity() (ex: 2x) and resize
|
||||
// to prevent holding unneeded memory
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ use std::ops::{Add, AddAssign, Mul, MulAssign};
|
|||
|
||||
// TODO: Separate types for non-linear sRGB and linear sRGB, with conversions between
|
||||
// see comment on bevy issue #688 https://github.com/bevyengine/bevy/pull/688#issuecomment-711414011
|
||||
/// RGBA color in the Linear sRGB colorspace (often colloquially referred to as "linear", "RGB", or "linear RGB").
|
||||
/// RGBA color in the Linear sRGB colorspace (often colloquially referred to as "linear", "RGB", or
|
||||
/// "linear RGB").
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)]
|
||||
#[reflect(PartialEq, Serialize, Deserialize)]
|
||||
|
|
|
@ -3,7 +3,7 @@ pub trait SrgbColorSpace {
|
|||
fn nonlinear_to_linear_srgb(self) -> Self;
|
||||
}
|
||||
|
||||
//source: https://entropymine.com/imageworsener/srgbformula/
|
||||
// source: https://entropymine.com/imageworsener/srgbformula/
|
||||
impl SrgbColorSpace for f32 {
|
||||
fn linear_to_nonlinear_srgb(self) -> f32 {
|
||||
if self <= 0.0 {
|
||||
|
@ -13,7 +13,7 @@ impl SrgbColorSpace for f32 {
|
|||
if self <= 0.0031308 {
|
||||
self * 12.92 // linear falloff in dark values
|
||||
} else {
|
||||
(1.055 * self.powf(1.0 / 2.4)) - 0.055 //gamma curve in other area
|
||||
(1.055 * self.powf(1.0 / 2.4)) - 0.055 // gamma curve in other area
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ impl SrgbColorSpace for f32 {
|
|||
if self <= 0.04045 {
|
||||
self / 12.92 // linear falloff in dark values
|
||||
} else {
|
||||
((self + 0.055) / 1.055).powf(2.4) //gamma curve in other area
|
||||
((self + 0.055) / 1.055).powf(2.4) // gamma curve in other area
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,7 +277,8 @@ impl<'a> DrawContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// if none of the given RenderResourceBindings have the current bind group, try their assets
|
||||
// if none of the given RenderResourceBindings have the current bind group, try their
|
||||
// assets
|
||||
let asset_render_resource_bindings =
|
||||
if let Some(value) = asset_render_resource_bindings.as_mut() {
|
||||
value
|
||||
|
|
|
@ -68,7 +68,8 @@ pub enum RenderSystem {
|
|||
pub enum RenderStage {
|
||||
/// Stage where render resources are set up
|
||||
RenderResource,
|
||||
/// Stage where Render Graph systems are run. In general you shouldn't add systems to this stage manually.
|
||||
/// Stage where Render Graph systems are run. In general you shouldn't add systems to this
|
||||
/// stage manually.
|
||||
RenderGraphSystems,
|
||||
// Stage where draw systems are executed. This is generally where Draw components are setup
|
||||
Draw,
|
||||
|
@ -78,7 +79,8 @@ pub enum RenderStage {
|
|||
|
||||
/// Adds core render types and systems to an App
|
||||
pub struct RenderPlugin {
|
||||
/// configures the "base render graph". If this is not `None`, the "base render graph" will be added
|
||||
/// configures the "base render graph". If this is not `None`, the "base render graph" will be
|
||||
/// added
|
||||
pub base_render_graph_config: Option<BaseRenderGraphConfig>,
|
||||
}
|
||||
|
||||
|
|
|
@ -208,7 +208,8 @@ impl From<&Indices> for IndexFormat {
|
|||
#[uuid = "8ecbac0f-f545-4473-ad43-e1f4243af51e"]
|
||||
pub struct Mesh {
|
||||
primitive_topology: PrimitiveTopology,
|
||||
/// `bevy_utils::HashMap` with all defined vertex attributes (Positions, Normals, ...) for this mesh. Attribute name maps to attribute values.
|
||||
/// `bevy_utils::HashMap` with all defined vertex attributes (Positions, Normals, ...) for this
|
||||
/// mesh. Attribute name maps to attribute values.
|
||||
attributes: HashMap<Cow<'static, str>, VertexAttributeValues>,
|
||||
indices: Option<Indices>,
|
||||
}
|
||||
|
@ -233,7 +234,8 @@ pub struct Mesh {
|
|||
impl Mesh {
|
||||
/// Per vertex coloring. Use in conjunction with [`Mesh::set_attribute`]
|
||||
pub const ATTRIBUTE_COLOR: &'static str = "Vertex_Color";
|
||||
/// The direction the vertex normal is facing in. Use in conjunction with [`Mesh::set_attribute`]
|
||||
/// The direction the vertex normal is facing in. Use in conjunction with
|
||||
/// [`Mesh::set_attribute`]
|
||||
pub const ATTRIBUTE_NORMAL: &'static str = "Vertex_Normal";
|
||||
/// Where the vertex is located in space. Use in conjunction with [`Mesh::set_attribute`]
|
||||
pub const ATTRIBUTE_POSITION: &'static str = "Vertex_Position";
|
||||
|
@ -279,7 +281,8 @@ impl Mesh {
|
|||
}
|
||||
|
||||
/// Indices describe how triangles are constructed out of the vertex attributes.
|
||||
/// They are only useful for the [`crate::pipeline::PrimitiveTopology`] variants that use triangles
|
||||
/// They are only useful for the [`crate::pipeline::PrimitiveTopology`] variants that use
|
||||
/// triangles
|
||||
pub fn set_indices(&mut self, indices: Option<Indices>) {
|
||||
self.indices = indices;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ pub enum CapsuleUvProfile {
|
|||
Aspect,
|
||||
/// Hemispheres get UV space according to the ratio of latitudes to rings.
|
||||
Uniform,
|
||||
/// Upper third of the texture goes to the northern hemisphere, middle third to the cylinder and lower third to the southern one.
|
||||
/// Upper third of the texture goes to the northern hemisphere, middle third to the cylinder
|
||||
/// and lower third to the southern one.
|
||||
Fixed,
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ pub enum BindType {
|
|||
readonly: bool,
|
||||
},
|
||||
Sampler {
|
||||
/// The sampling result is produced based on more than a single color sample from a texture,
|
||||
/// e.g. when bilinear interpolation is enabled.
|
||||
/// The sampling result is produced based on more than a single color sample from a
|
||||
/// texture, e.g. when bilinear interpolation is enabled.
|
||||
///
|
||||
/// A filtering sampler can only be used with a filterable texture.
|
||||
filtering: bool,
|
||||
|
|
|
@ -197,7 +197,8 @@ impl PipelineCompiler {
|
|||
}
|
||||
specialized_descriptor.layout = Some(layout);
|
||||
|
||||
// create a vertex layout that provides all attributes from either the specialized vertex buffers or a zero buffer
|
||||
// create a vertex layout that provides all attributes from either the specialized vertex
|
||||
// buffers or a zero buffer
|
||||
let mut pipeline_layout = specialized_descriptor.layout.as_mut().unwrap();
|
||||
// the vertex buffer descriptor of the mesh
|
||||
let mesh_vertex_buffer_layout = &pipeline_specialization.vertex_buffer_layout;
|
||||
|
@ -235,7 +236,7 @@ impl PipelineCompiler {
|
|||
}
|
||||
}
|
||||
|
||||
//TODO: add other buffers (like instancing) here
|
||||
// TODO: add other buffers (like instancing) here
|
||||
let mut vertex_buffer_descriptors = Vec::<VertexBufferLayout>::default();
|
||||
if !pipeline_layout.vertex_buffer_descriptors.is_empty() {
|
||||
vertex_buffer_descriptors.push(compiled_vertex_buffer_descriptor);
|
||||
|
|
|
@ -58,8 +58,8 @@ impl PipelineLayout {
|
|||
.map(|(_, value)| value)
|
||||
.collect::<Vec<BindGroupDescriptor>>();
|
||||
|
||||
// NOTE: for some reason bind groups need to be sorted by index. this is likely an issue with bevy and not with wgpu
|
||||
// TODO: try removing this
|
||||
// NOTE: for some reason bind groups need to be sorted by index. this is likely an issue
|
||||
// with bevy and not with wgpu TODO: try removing this
|
||||
bind_groups_result.sort_by(|a, b| a.index.partial_cmp(&b.index).unwrap());
|
||||
|
||||
PipelineLayout {
|
||||
|
|
|
@ -17,7 +17,8 @@ use bevy_utils::HashSet;
|
|||
pub struct RenderPipeline {
|
||||
pub pipeline: Handle<PipelineDescriptor>,
|
||||
pub specialization: PipelineSpecialization,
|
||||
/// used to track if PipelineSpecialization::dynamic_bindings is in sync with RenderResourceBindings
|
||||
/// used to track if PipelineSpecialization::dynamic_bindings is in sync with
|
||||
/// RenderResourceBindings
|
||||
pub dynamic_bindings_generation: usize,
|
||||
}
|
||||
|
||||
|
|
|
@ -92,9 +92,9 @@ impl Default for BaseRenderGraphConfig {
|
|||
}
|
||||
}
|
||||
|
||||
/// The "base render graph" provides a core set of render graph nodes which can be used to build any graph.
|
||||
/// By itself this graph doesn't do much, but it allows Render plugins to interop with each other by having a common
|
||||
/// set of nodes. It can be customized using `BaseRenderGraphConfig`.
|
||||
/// The "base render graph" provides a core set of render graph nodes which can be used to build any
|
||||
/// graph. By itself this graph doesn't do much, but it allows Render plugins to interop with each
|
||||
/// other by having a common set of nodes. It can be customized using `BaseRenderGraphConfig`.
|
||||
pub(crate) fn add_base_graph(config: &BaseRenderGraphConfig, world: &mut World) {
|
||||
let world = world.cell();
|
||||
let mut graph = world.get_resource_mut::<RenderGraph>().unwrap();
|
||||
|
@ -124,7 +124,8 @@ pub(crate) fn add_base_graph(config: &BaseRenderGraphConfig, world: &mut World)
|
|||
mip_level_count: 1,
|
||||
sample_count: msaa.samples,
|
||||
dimension: TextureDimension::D2,
|
||||
format: TextureFormat::Depth32Float, // PERF: vulkan docs recommend using 24 bit depth for better performance
|
||||
format: TextureFormat::Depth32Float, /* PERF: vulkan docs recommend using 24
|
||||
* bit depth for better performance */
|
||||
usage: TextureUsage::OUTPUT_ATTACHMENT,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -47,7 +47,8 @@ pub enum Command {
|
|||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct CommandQueue {
|
||||
// TODO: this shouldn't really need a mutex. it just needs to be shared on whatever thread it's scheduled on
|
||||
// TODO: this shouldn't really need a mutex. it just needs to be shared on whatever thread it's
|
||||
// scheduled on
|
||||
queue: Arc<Mutex<Vec<Command>>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -28,10 +28,12 @@ pub trait Node: Downcast + Send + Sync + 'static {
|
|||
&[]
|
||||
}
|
||||
|
||||
/// Prepare the graph node with unique world access. This runs once per graph run before [Node::update] is called.
|
||||
/// Prepare the graph node with unique world access. This runs once per graph run before
|
||||
/// [Node::update] is called.
|
||||
fn prepare(&mut self, _world: &mut World) {}
|
||||
|
||||
/// Run the graph node logic. This runs once per graph run after [Node::prepare] has been called on all nodes.
|
||||
/// Run the graph node logic. This runs once per graph run after [Node::prepare] has been called
|
||||
/// on all nodes.
|
||||
fn update(
|
||||
&mut self,
|
||||
world: &World,
|
||||
|
|
|
@ -70,8 +70,8 @@ pub fn camera_node_system(
|
|||
mut state: Local<CameraNodeState>,
|
||||
active_cameras: Res<ActiveCameras>,
|
||||
render_resource_context: Res<Box<dyn RenderResourceContext>>,
|
||||
// PERF: this write on RenderResourceAssignments will prevent this system from running in parallel
|
||||
// with other systems that do the same
|
||||
// PERF: this write on RenderResourceAssignments will prevent this system from running in
|
||||
// parallel with other systems that do the same
|
||||
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
||||
query: Query<(&Camera, &GlobalTransform)>,
|
||||
) {
|
||||
|
|
|
@ -182,7 +182,8 @@ where
|
|||
self.current_staging_buffer_offset = 0;
|
||||
}
|
||||
|
||||
/// Find a spot for the given RenderResources in each uniform's BufferArray and prepare space in the staging buffer
|
||||
/// Find a spot for the given RenderResources in each uniform's BufferArray and prepare space in
|
||||
/// the staging buffer
|
||||
fn prepare_uniform_buffers(&mut self, id: I, render_resources: &T) {
|
||||
for (i, render_resource) in render_resources.iter().enumerate() {
|
||||
if let Some(RenderResourceType::Buffer) = render_resource.resource_type() {
|
||||
|
@ -497,7 +498,8 @@ fn render_resources_node_system<T: RenderResources>(
|
|||
staging_buffer,
|
||||
0..state.uniform_buffer_arrays.staging_buffer_size as u64,
|
||||
&mut |mut staging_buffer, _render_resource_context| {
|
||||
// if the buffer array was resized, write all entities to the new buffer, otherwise only write changes
|
||||
// if the buffer array was resized, write all entities to the new buffer, otherwise
|
||||
// only write changes
|
||||
if resized {
|
||||
for (entity, uniforms, visible, mut render_pipelines) in
|
||||
queries.q1_mut().iter_mut()
|
||||
|
|
|
@ -67,7 +67,8 @@ impl Stages {
|
|||
}
|
||||
|
||||
pub fn borrow<'a>(&self, render_graph: &'a mut RenderGraph) -> Vec<StageBorrow<'a>> {
|
||||
// unfortunately borrowing render graph nodes in a specific order takes a little bit of gymnastics
|
||||
// unfortunately borrowing render graph nodes in a specific order takes a little bit of
|
||||
// gymnastics
|
||||
let mut stage_borrows = Vec::with_capacity(self.stages.len());
|
||||
|
||||
let mut node_borrows = Vec::new();
|
||||
|
@ -101,13 +102,15 @@ impl Stages {
|
|||
}
|
||||
}
|
||||
|
||||
/// Produces a collection of `Stages`, which are sets of OrderedJobs that must be run before moving on to the next stage
|
||||
/// Produces a collection of `Stages`, which are sets of OrderedJobs that must be run before moving
|
||||
/// on to the next stage
|
||||
pub trait RenderGraphStager {
|
||||
fn get_stages(&mut self, render_graph: &RenderGraph) -> Result<Stages, RenderGraphError>;
|
||||
}
|
||||
|
||||
// TODO: remove this
|
||||
/// This scheduler ignores dependencies and puts everything in one stage. It shouldn't be used for anything :)
|
||||
/// This scheduler ignores dependencies and puts everything in one stage. It shouldn't be used for
|
||||
/// anything :)
|
||||
#[derive(Debug, Default)]
|
||||
pub struct LinearStager;
|
||||
|
||||
|
@ -229,8 +232,9 @@ fn stage_node(
|
|||
})
|
||||
.count();
|
||||
|
||||
// if the current node has more than one parent on the highest stage (aka requires synchronization), then move it to the next
|
||||
// stage and start a new job on that stage
|
||||
// if the current node has more than one parent on the highest stage (aka requires
|
||||
// synchronization), then move it to the next stage and start a new job on that
|
||||
// stage
|
||||
if max_stage_parent_count > 1 {
|
||||
stage_index = max_parent_stage + 1;
|
||||
} else {
|
||||
|
@ -492,7 +496,8 @@ mod tests {
|
|||
|
||||
assert_eq!(job.nodes.len(), 7, "expect exactly 7 nodes in the job");
|
||||
|
||||
// its hard to test the exact order of this job's nodes because of hashing, so instead we'll test the constraints that must hold true
|
||||
// its hard to test the exact order of this job's nodes because of hashing, so instead we'll
|
||||
// test the constraints that must hold true
|
||||
let index =
|
||||
|node_id: NodeId| -> usize { job.nodes.iter().position(|id| *id == node_id).unwrap() };
|
||||
|
||||
|
|
|
@ -61,13 +61,15 @@ pub enum BindGroupStatus {
|
|||
NoMatch,
|
||||
}
|
||||
|
||||
// PERF: if the bindings are scoped to a specific pipeline layout, then names could be replaced with indices here for a perf boost
|
||||
// PERF: if the bindings are scoped to a specific pipeline layout, then names could be replaced with
|
||||
// indices here for a perf boost
|
||||
#[derive(Eq, PartialEq, Debug, Default, Clone)]
|
||||
pub struct RenderResourceBindings {
|
||||
pub bindings: HashMap<String, RenderResourceBinding>,
|
||||
/// A Buffer that contains all attributes a mesh has defined
|
||||
pub vertex_attribute_buffer: Option<BufferId>,
|
||||
/// A Buffer that is filled with zeros that will be used for attributes required by the shader, but undefined by the mesh.
|
||||
/// A Buffer that is filled with zeros that will be used for attributes required by the shader,
|
||||
/// but undefined by the mesh.
|
||||
pub vertex_fallback_buffer: Option<BufferId>,
|
||||
pub index_buffer: Option<(BufferId, IndexFormat)>,
|
||||
assets: HashSet<(HandleUntyped, TypeId)>,
|
||||
|
@ -87,7 +89,8 @@ impl RenderResourceBindings {
|
|||
self.bindings.insert(name.to_string(), binding);
|
||||
}
|
||||
|
||||
/// The current "generation" of dynamic bindings. This number increments every time a dynamic binding changes
|
||||
/// The current "generation" of dynamic bindings. This number increments every time a dynamic
|
||||
/// binding changes
|
||||
pub fn dynamic_bindings_generation(&self) -> usize {
|
||||
self.dynamic_bindings_generation
|
||||
}
|
||||
|
@ -182,8 +185,9 @@ impl RenderResourceBindings {
|
|||
Some(bind_group)
|
||||
}
|
||||
BindGroupStatus::Unchanged(id) => {
|
||||
// PERF: this is only required because RenderResourceContext::remove_stale_bind_groups doesn't inform RenderResourceBindings
|
||||
// when a stale bind group has been removed
|
||||
// PERF: this is only required because
|
||||
// RenderResourceContext::remove_stale_bind_groups doesn't inform
|
||||
// RenderResourceBindings when a stale bind group has been removed
|
||||
let bind_group = self
|
||||
.get_bind_group(id)
|
||||
.expect("`RenderResourceSet` was just changed, so it should exist.");
|
||||
|
|
|
@ -77,13 +77,16 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
|
|||
fn remove_stale_bind_groups(&self);
|
||||
/// Reflects the pipeline layout from its shaders.
|
||||
///
|
||||
/// If `bevy_conventions` is true, it will be assumed that the shader follows "bevy shader conventions". These allow
|
||||
/// richer reflection, such as inferred Vertex Buffer names and inferred instancing.
|
||||
/// If `bevy_conventions` is true, it will be assumed that the shader follows "bevy shader
|
||||
/// conventions". These allow richer reflection, such as inferred Vertex Buffer names and
|
||||
/// inferred instancing.
|
||||
///
|
||||
/// If `dynamic_bindings` has values, shader uniforms will be set to "dynamic" if there is a matching binding in the list
|
||||
/// If `dynamic_bindings` has values, shader uniforms will be set to "dynamic" if there is a
|
||||
/// matching binding in the list
|
||||
///
|
||||
/// If `vertex_buffer_descriptors` is set, the pipeline's vertex buffers
|
||||
/// will inherit their layouts from global descriptors, otherwise the layout will be assumed to be complete / local.
|
||||
/// will inherit their layouts from global descriptors, otherwise the layout will be assumed to
|
||||
/// be complete / local.
|
||||
fn reflect_pipeline_layout(
|
||||
&self,
|
||||
shaders: &Assets<Shader>,
|
||||
|
|
|
@ -4,7 +4,8 @@ use crate::{pipeline::RenderPipelines, Texture};
|
|||
pub use bevy_derive::ShaderDefs;
|
||||
use bevy_ecs::system::{Query, Res};
|
||||
|
||||
/// Something that can either be "defined" or "not defined". This is used to determine if a "shader def" should be considered "defined"
|
||||
/// Something that can either be "defined" or "not defined". This is used to determine if a "shader
|
||||
/// def" should be considered "defined"
|
||||
pub trait ShaderDef {
|
||||
fn is_defined(&self) -> bool;
|
||||
}
|
||||
|
|
|
@ -101,7 +101,8 @@ impl Texture {
|
|||
.resize(size.volume() * self.format.pixel_size(), 0);
|
||||
}
|
||||
|
||||
/// Changes the `size`, asserting that the total number of data elements (pixels) remains the same.
|
||||
/// Changes the `size`, asserting that the total number of data elements (pixels) remains the
|
||||
/// same.
|
||||
pub fn reinterpret_size(&mut self, new_size: Extent3d) {
|
||||
assert!(
|
||||
new_size.volume() == self.size.volume(),
|
||||
|
@ -113,9 +114,9 @@ impl Texture {
|
|||
self.size = new_size;
|
||||
}
|
||||
|
||||
/// Takes a 2D texture containing vertically stacked images of the same size, and reinterprets it as a 2D array texture,
|
||||
/// where each of the stacked images becomes one layer of the array. This is primarily for use with the `texture2DArray`
|
||||
/// shader uniform type.
|
||||
/// Takes a 2D texture containing vertically stacked images of the same size, and reinterprets
|
||||
/// it as a 2D array texture, where each of the stacked images becomes one layer of the
|
||||
/// array. This is primarily for use with the `texture2DArray` shader uniform type.
|
||||
pub fn reinterpret_stacked_2d_as_array(&mut self, layers: u32) {
|
||||
// Must be a stacked image, and the height must be divisible by layers.
|
||||
assert!(self.dimension == TextureDimension::D2);
|
||||
|
@ -171,8 +172,9 @@ impl Texture {
|
|||
}
|
||||
AssetEvent::Removed { handle } => {
|
||||
Self::remove_current_texture_resources(render_resource_context, handle);
|
||||
// if texture was modified and removed in the same update, ignore the modification
|
||||
// events are ordered so future modification events are ok
|
||||
// if texture was modified and removed in the same update, ignore the
|
||||
// modification events are ordered so future modification
|
||||
// events are ok
|
||||
changed_textures.remove(handle);
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +219,8 @@ impl Texture {
|
|||
}
|
||||
}
|
||||
|
||||
/// Load a bytes buffer in a [`Texture`], according to type `image_type`, using the `image` crate`
|
||||
/// Load a bytes buffer in a [`Texture`], according to type `image_type`, using the `image`
|
||||
/// crate`
|
||||
pub fn from_buffer(buffer: &[u8], image_type: ImageType) -> Result<Texture, TextureError> {
|
||||
let format = match image_type {
|
||||
ImageType::MimeType(mime_type) => match mime_type {
|
||||
|
|
|
@ -95,7 +95,8 @@ pub struct PixelInfo {
|
|||
/// Underlying texture data format.
|
||||
///
|
||||
/// If there is a conversion in the format (such as srgb -> linear), The conversion listed is for
|
||||
/// loading from texture in a shader. When writing to the texture, the opposite conversion takes place.
|
||||
/// loading from texture in a shader. When writing to the texture, the opposite conversion takes
|
||||
/// place.
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum TextureFormat {
|
||||
// Normal 8 bit formats
|
||||
|
|
|
@ -81,7 +81,8 @@ impl SceneSpawner {
|
|||
for instance_id in instance_ids {
|
||||
if let Some(instance) = self.spawned_instances.get(&instance_id) {
|
||||
for entity in instance.entity_map.values() {
|
||||
let _ = world.despawn(entity); // Ignore the result, despawn only cares if it exists.
|
||||
let _ = world.despawn(entity); // Ignore the result, despawn only cares if
|
||||
// it exists.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,8 +51,8 @@ impl DynamicTextureAtlasBuilder {
|
|||
// let change_list = self.atlas_allocator.resize_and_rearrange(new_size2);
|
||||
|
||||
// for change in change_list.changes {
|
||||
// if let Some(changed_texture_handle) = self.allocation_textures.remove(&change.old.id) {
|
||||
// let changed_texture = textures.get(&changed_texture_handle).unwrap();
|
||||
// if let Some(changed_texture_handle) = self.allocation_textures.remove(&change.old.id)
|
||||
// { let changed_texture = textures.get(&changed_texture_handle).unwrap();
|
||||
// self.place_texture(change.new, changed_texture_handle, changed_texture);
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -68,7 +68,8 @@ impl Plugin for SpritePlugin {
|
|||
color_materials.set_untracked(Handle::<ColorMaterial>::default(), ColorMaterial::default());
|
||||
meshes.set_untracked(
|
||||
QUAD_HANDLE,
|
||||
// Use a flipped quad because the camera is facing "forward" but quads should face backward
|
||||
// Use a flipped quad because the camera is facing "forward" but quads should face
|
||||
// backward
|
||||
Mesh::from(shape::Quad::new(Vec2::new(1.0, 1.0))),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use bevy_core::Byteable;
|
||||
use bevy_math::Vec2;
|
||||
|
||||
/// A rectangle defined by two points. There is no defined origin, so 0,0 could be anywhere (top-left, bottom-left, etc)
|
||||
/// A rectangle defined by two points. There is no defined origin, so 0,0 could be anywhere
|
||||
/// (top-left, bottom-left, etc)
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
pub struct Rect {
|
||||
|
|
|
@ -86,7 +86,8 @@ pub fn sprite_system(
|
|||
if let Some(ref texture_handle) = material.texture {
|
||||
if let Some(texture) = textures.get(texture_handle) {
|
||||
let texture_size = texture.size.as_vec3().truncate();
|
||||
// only set sprite size if it has changed (this check prevents change detection from triggering)
|
||||
// only set sprite size if it has changed (this check prevents change
|
||||
// detection from triggering)
|
||||
if sprite.size != texture_size {
|
||||
sprite.size = texture_size;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,8 @@ pub fn event_resets_if_listeners_are_cleared() {
|
|||
event.notify(std::usize::MAX);
|
||||
futures_lite::future::block_on(listener1);
|
||||
|
||||
// If all listeners are notified, the structure should now be cleared. We're free to listen again
|
||||
// If all listeners are notified, the structure should now be cleared. We're free to listen
|
||||
// again
|
||||
let listener2 = event.listen();
|
||||
let listener3 = event.listen();
|
||||
|
||||
|
|
|
@ -381,7 +381,8 @@ where
|
|||
.max_by_key(f)
|
||||
}
|
||||
|
||||
/// Returns the item that gives the maximum value with respect to the specified comparison function.
|
||||
/// Returns the item that gives the maximum value with respect to the specified comparison
|
||||
/// function.
|
||||
///
|
||||
/// See [`Iterator::max_by()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by)
|
||||
fn max_by<F>(mut self, pool: &TaskPool, f: F) -> Option<Self::Item>
|
||||
|
@ -420,7 +421,8 @@ where
|
|||
.min_by_key(f)
|
||||
}
|
||||
|
||||
/// Returns the item that gives the minimum value with respect to the specified comparison function.
|
||||
/// Returns the item that gives the minimum value with respect to the specified comparison
|
||||
/// function.
|
||||
///
|
||||
/// See [`Iterator::min_by()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min_by)
|
||||
fn min_by<F>(mut self, pool: &TaskPool, f: F) -> Option<Self::Item>
|
||||
|
|
|
@ -22,7 +22,8 @@ impl<T> Task<T> {
|
|||
Self(task)
|
||||
}
|
||||
|
||||
/// Detaches the task to let it keep running in the background. See `async_executor::Task::detach`
|
||||
/// Detaches the task to let it keep running in the background. See
|
||||
/// `async_executor::Task::detach`
|
||||
pub fn detach(self) {
|
||||
self.0.detach();
|
||||
}
|
||||
|
|
|
@ -86,8 +86,8 @@ pub struct TaskPool {
|
|||
/// The executor for the pool
|
||||
///
|
||||
/// This has to be separate from TaskPoolInner because we have to create an Arc<Executor> to
|
||||
/// pass into the worker threads, and we must create the worker threads before we can create the
|
||||
/// Vec<Task<T>> contained within TaskPoolInner
|
||||
/// pass into the worker threads, and we must create the worker threads before we can create
|
||||
/// the Vec<Task<T>> contained within TaskPoolInner
|
||||
executor: Arc<async_executor::Executor<'static>>,
|
||||
|
||||
/// Inner state of the pool
|
||||
|
@ -200,17 +200,18 @@ impl TaskPool {
|
|||
// Pin the futures on the stack.
|
||||
pin!(fut);
|
||||
|
||||
// SAFETY: This function blocks until all futures complete, so we do not read/write the
|
||||
// data from futures outside of the 'scope lifetime. However, rust has no way of knowing
|
||||
// this so we must convert to 'static here to appease the compiler as it is unable to
|
||||
// validate safety.
|
||||
// SAFETY: This function blocks until all futures complete, so we do not read/write
|
||||
// the data from futures outside of the 'scope lifetime. However,
|
||||
// rust has no way of knowing this so we must convert to 'static
|
||||
// here to appease the compiler as it is unable to validate safety.
|
||||
let fut: Pin<&mut (dyn Future<Output = Vec<T>>)> = fut;
|
||||
let fut: Pin<&'static mut (dyn Future<Output = Vec<T>> + 'static)> =
|
||||
unsafe { mem::transmute(fut) };
|
||||
|
||||
// The thread that calls scope() will participate in driving tasks in the pool forward
|
||||
// until the tasks that are spawned by this scope() call complete. (If the caller of scope()
|
||||
// happens to be a thread in this thread pool, and we only have one thread in the pool, then
|
||||
// The thread that calls scope() will participate in driving tasks in the pool
|
||||
// forward until the tasks that are spawned by this scope() call
|
||||
// complete. (If the caller of scope() happens to be a thread in
|
||||
// this thread pool, and we only have one thread in the pool, then
|
||||
// simply calling future::block_on(spawned) would deadlock.)
|
||||
let mut spawned = local_executor.spawn(fut);
|
||||
loop {
|
||||
|
@ -376,7 +377,8 @@ mod tests {
|
|||
scope.spawn_local(async move {
|
||||
inner_count_clone.fetch_add(1, Ordering::Release);
|
||||
if std::thread::current().id() != spawner {
|
||||
// NOTE: This check is using an atomic rather than simply panicing the thread to avoid deadlocking the barrier on failure
|
||||
// NOTE: This check is using an atomic rather than simply panicing the
|
||||
// thread to avoid deadlocking the barrier on failure
|
||||
inner_thread_check_failed.store(true, Ordering::Release);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -171,7 +171,8 @@ pub fn text2d_system(
|
|||
&mut *textures,
|
||||
) {
|
||||
Err(TextError::NoSuchFont) => {
|
||||
// There was an error processing the text layout, let's add this entity to the queue for further processing
|
||||
// There was an error processing the text layout, let's add this entity to the
|
||||
// queue for further processing
|
||||
new_queue.push(entity);
|
||||
}
|
||||
Err(e @ TextError::FailedToAddGlyph(_)) => {
|
||||
|
|
|
@ -63,7 +63,8 @@ impl GlobalTransform {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns transform with the same translation and scale, but rotation so that transform.forward() points at target
|
||||
/// Returns transform with the same translation and scale, but rotation so that
|
||||
/// transform.forward() points at target
|
||||
#[inline]
|
||||
pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self {
|
||||
self.look_at(target, up);
|
||||
|
|
|
@ -12,8 +12,8 @@ pub struct Parent(pub Entity);
|
|||
|
||||
// TODO: We need to impl either FromWorld or Default so Parent can be registered as Properties.
|
||||
// This is because Properties deserialize by creating an instance and apply a patch on top.
|
||||
// However Parent should only ever be set with a real user-defined entity. Its worth looking into better
|
||||
// ways to handle cases like this.
|
||||
// However Parent should only ever be set with a real user-defined entity. Its worth looking into
|
||||
// better ways to handle cases like this.
|
||||
impl FromWorld for Parent {
|
||||
fn from_world(_world: &mut World) -> Self {
|
||||
Parent(Entity::new(u32::MAX))
|
||||
|
|
|
@ -63,7 +63,8 @@ impl Transform {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns transform with the same translation and scale, but rotation so that transform.forward() points at target
|
||||
/// Returns transform with the same translation and scale, but rotation so that
|
||||
/// transform.forward() points at target
|
||||
#[inline]
|
||||
pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self {
|
||||
self.look_at(target, up);
|
||||
|
|
|
@ -29,7 +29,8 @@ impl Command for InsertChildren {
|
|||
added = true;
|
||||
}
|
||||
|
||||
// NOTE: ideally this is just an else statement, but currently that _incorrectly_ fails borrow-checking
|
||||
// NOTE: ideally this is just an else statement, but currently that _incorrectly_ fails
|
||||
// borrow-checking
|
||||
if !added {
|
||||
world
|
||||
.entity_mut(self.parent)
|
||||
|
@ -64,7 +65,8 @@ impl Command for PushChildren {
|
|||
added = true;
|
||||
}
|
||||
|
||||
// NOTE: ideally this is just an else statement, but currently that _incorrectly_ fails borrow-checking
|
||||
// NOTE: ideally this is just an else statement, but currently that _incorrectly_ fails
|
||||
// borrow-checking
|
||||
if !added {
|
||||
world
|
||||
.entity_mut(self.parent)
|
||||
|
@ -270,8 +272,8 @@ impl<'w> BuildWorldChildren for EntityMut<'w> {
|
|||
let mut builder = WorldChildBuilder {
|
||||
current_entity: None,
|
||||
parent_entities: vec![entity],
|
||||
// SAFE: self.update_location() is called below. It is impossible to make EntityMut function calls on `self`
|
||||
// within the scope defined here
|
||||
// SAFE: self.update_location() is called below. It is impossible to make EntityMut
|
||||
// function calls on `self` within the scope defined here
|
||||
world: unsafe { self.world_mut() },
|
||||
};
|
||||
|
||||
|
|
|
@ -106,7 +106,8 @@ mod tests {
|
|||
{
|
||||
let mut commands = Commands::new(&mut queue, &world);
|
||||
commands.despawn_recursive(parent_entity);
|
||||
commands.despawn_recursive(parent_entity); // despawning the same entity twice should not panic
|
||||
commands.despawn_recursive(parent_entity); // despawning the same entity twice should
|
||||
// not panic
|
||||
}
|
||||
queue.apply(&mut world);
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ use smallvec::SmallVec;
|
|||
pub fn parent_update_system(
|
||||
mut commands: Commands,
|
||||
removed_parent_query: Query<(Entity, &PreviousParent), Without<Parent>>,
|
||||
// The next query could be run with a Changed<Parent> filter. However, this would mean that modifications later in the frame are lost.
|
||||
// See issue 891: https://github.com/bevyengine/bevy/issues/891
|
||||
// The next query could be run with a Changed<Parent> filter. However, this would mean that
|
||||
// modifications later in the frame are lost. See issue 891: https://github.com/bevyengine/bevy/issues/891
|
||||
mut parent_query: Query<(Entity, &Parent, Option<&mut PreviousParent>)>,
|
||||
mut children_query: Query<&mut Children>,
|
||||
) {
|
||||
|
|
|
@ -93,7 +93,8 @@ pub fn ui_focus_system(
|
|||
let extents = node.size / 2.0;
|
||||
let min = ui_position - extents;
|
||||
let max = ui_position + extents;
|
||||
// if the current cursor position is within the bounds of the node, consider it for clicking
|
||||
// if the current cursor position is within the bounds of the node, consider it for
|
||||
// clicking
|
||||
if (min.x..max.x).contains(&cursor_position.x)
|
||||
&& (min.y..max.y).contains(&cursor_position.y)
|
||||
{
|
||||
|
@ -120,7 +121,8 @@ pub fn ui_focus_system(
|
|||
// only consider nodes with Interaction "clickable"
|
||||
if *interaction != Interaction::Clicked {
|
||||
*interaction = Interaction::Clicked;
|
||||
// if the mouse was simultaneously released, reset this Interaction in the next frame
|
||||
// if the mouse was simultaneously released, reset this Interaction in the next
|
||||
// frame
|
||||
if mouse_released {
|
||||
state.entities_to_reset.push(entity);
|
||||
}
|
||||
|
|
|
@ -105,7 +105,8 @@ pub fn text_system(
|
|||
&mut *textures,
|
||||
) {
|
||||
Err(TextError::NoSuchFont) => {
|
||||
// There was an error processing the text layout, let's add this entity to the queue for further processing
|
||||
// There was an error processing the text layout, let's add this entity to the
|
||||
// queue for further processing
|
||||
new_queue.push(entity);
|
||||
}
|
||||
Err(e @ TextError::FailedToAddGlyph(_)) => {
|
||||
|
|
|
@ -66,8 +66,9 @@ impl WgpuRenderContext {
|
|||
}
|
||||
}
|
||||
|
||||
/// Consume this context, finalize the current CommandEncoder (if it exists), and take the current WgpuResources.
|
||||
/// This is intended to be called from a worker thread right before synchronizing with the main thread.
|
||||
/// Consume this context, finalize the current CommandEncoder (if it exists), and take the
|
||||
/// current WgpuResources. This is intended to be called from a worker thread right before
|
||||
/// synchronizing with the main thread.
|
||||
pub fn finish(&mut self) -> Option<wgpu::CommandBuffer> {
|
||||
self.command_encoder.take().map(|encoder| encoder.finish())
|
||||
}
|
||||
|
|
|
@ -17,27 +17,32 @@ pub struct WgpuBindGroupInfo {
|
|||
}
|
||||
|
||||
/// Grabs a read lock on all wgpu resources. When paired with WgpuResourceRefs, this allows
|
||||
/// you to pass in wgpu resources to wgpu::RenderPass<'a> with the appropriate lifetime. This is accomplished by
|
||||
/// grabbing a WgpuResourcesReadLock _before_ creating a wgpu::RenderPass, getting a WgpuResourcesRefs, and storing that
|
||||
/// in the pass.
|
||||
/// you to pass in wgpu resources to wgpu::RenderPass<'a> with the appropriate lifetime. This is
|
||||
/// accomplished by grabbing a WgpuResourcesReadLock _before_ creating a wgpu::RenderPass, getting a
|
||||
/// WgpuResourcesRefs, and storing that in the pass.
|
||||
///
|
||||
/// This is only a problem because RwLockReadGuard.read() erases the guard's lifetime and creates a new anonymous lifetime. If
|
||||
/// you call RwLockReadGuard.read() during a pass, the reference will have an anonymous lifetime that lives for less than the
|
||||
/// pass, which violates the lifetime constraints in place.
|
||||
/// This is only a problem because RwLockReadGuard.read() erases the guard's lifetime and creates a
|
||||
/// new anonymous lifetime. If you call RwLockReadGuard.read() during a pass, the reference will
|
||||
/// have an anonymous lifetime that lives for less than the pass, which violates the lifetime
|
||||
/// constraints in place.
|
||||
///
|
||||
/// The biggest implication of this design (other than the additional boilerplate here) is that beginning a render pass
|
||||
/// blocks writes to these resources. This means that if the pass attempts to write any resource, a deadlock will occur. WgpuResourceRefs
|
||||
/// only has immutable references, so the only way to make a deadlock happen is to access WgpuResources directly in the pass. It also means
|
||||
/// that other threads attempting to write resources will need to wait for pass encoding to finish. Almost all writes should occur before
|
||||
/// passes start, so this hopefully won't be a problem.
|
||||
/// The biggest implication of this design (other than the additional boilerplate here) is that
|
||||
/// beginning a render pass blocks writes to these resources. This means that if the pass attempts
|
||||
/// to write any resource, a deadlock will occur. WgpuResourceRefs only has immutable references, so
|
||||
/// the only way to make a deadlock happen is to access WgpuResources directly in the pass. It also
|
||||
/// means that other threads attempting to write resources will need to wait for pass encoding to
|
||||
/// finish. Almost all writes should occur before passes start, so this hopefully won't be a
|
||||
/// problem.
|
||||
///
|
||||
/// It is worth comparing the performance of this to transactional / copy-based approaches. This lock based design guarantees
|
||||
/// consistency, doesn't perform redundant allocations, and only blocks when a write is occurring. A copy based approach would
|
||||
/// never block, but would require more allocations / state-synchronization, which I expect will be more expensive. It would also be
|
||||
/// It is worth comparing the performance of this to transactional / copy-based approaches. This
|
||||
/// lock based design guarantees consistency, doesn't perform redundant allocations, and only blocks
|
||||
/// when a write is occurring. A copy based approach would never block, but would require more
|
||||
/// allocations / state-synchronization, which I expect will be more expensive. It would also be
|
||||
/// "eventually consistent" instead of "strongly consistent".
|
||||
///
|
||||
/// Single threaded implementations don't need to worry about these lifetimes constraints at all. RenderPasses can use a RenderContext's
|
||||
/// WgpuResources directly. RenderContext already has a lifetime greater than the RenderPass.
|
||||
/// Single threaded implementations don't need to worry about these lifetimes constraints at all.
|
||||
/// RenderPasses can use a RenderContext's WgpuResources directly. RenderContext already has a
|
||||
/// lifetime greater than the RenderPass.
|
||||
#[derive(Debug)]
|
||||
pub struct WgpuResourcesReadLock<'a> {
|
||||
pub buffers: RwLockReadGuard<'a, HashMap<BufferId, Arc<wgpu::Buffer>>>,
|
||||
|
@ -62,7 +67,8 @@ impl<'a> WgpuResourcesReadLock<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Stores read only references to WgpuResource collections. See WgpuResourcesReadLock docs for context on why this exists
|
||||
/// Stores read only references to WgpuResource collections. See WgpuResourcesReadLock docs for
|
||||
/// context on why this exists
|
||||
#[derive(Debug)]
|
||||
pub struct WgpuResourceRefs<'a> {
|
||||
pub buffers: &'a HashMap<BufferId, Arc<wgpu::Buffer>>,
|
||||
|
|
|
@ -30,8 +30,8 @@ pub struct WindowCreated {
|
|||
pub id: WindowId,
|
||||
}
|
||||
|
||||
/// An event that is sent whenever a close was requested for a window. For example: when the "close" button
|
||||
/// is pressed on a window.
|
||||
/// An event that is sent whenever a close was requested for a window. For example: when the "close"
|
||||
/// button is pressed on a window.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowCloseRequested {
|
||||
pub id: WindowId,
|
||||
|
|
|
@ -304,13 +304,15 @@ impl Window {
|
|||
|
||||
/// Modifies the position of the window in physical pixels.
|
||||
///
|
||||
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen. If the user uses a desktop with multiple monitors,
|
||||
/// the top-left hand corner of the desktop is the top-left hand corner of the monitor at the top-left of the desktop. This automatically un-maximizes
|
||||
/// the window if it's maximized.
|
||||
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
|
||||
/// If the user uses a desktop with multiple monitors, the top-left hand corner of the
|
||||
/// desktop is the top-left hand corner of the monitor at the top-left of the desktop. This
|
||||
/// automatically un-maximizes the window if it's maximized.
|
||||
///
|
||||
/// # Platform-specific
|
||||
///
|
||||
/// - iOS: Can only be called on the main thread. Sets the top left coordinates of the window in the screen space coordinate system.
|
||||
/// - iOS: Can only be called on the main thread. Sets the top left coordinates of the window in
|
||||
/// the screen space coordinate system.
|
||||
/// - Web: Sets the top-left coordinates relative to the viewport.
|
||||
/// - Android / Wayland: Unsupported.
|
||||
#[inline]
|
||||
|
|
|
@ -365,7 +365,8 @@ pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) {
|
|||
let winit_window = winit_windows.get_window(window_id).unwrap();
|
||||
let mut location = touch.location.to_logical(winit_window.scale_factor());
|
||||
|
||||
// On a mobile window, the start is from the top while on PC/Linux/OSX from bottom
|
||||
// On a mobile window, the start is from the top while on PC/Linux/OSX from
|
||||
// bottom
|
||||
if cfg!(target_os = "android") || cfg!(target_os = "ios") {
|
||||
let window_height = windows.get_primary().unwrap().height();
|
||||
location.y = window_height - location.y;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use bevy::{asset::LoadState, prelude::*, sprite::TextureAtlasBuilder};
|
||||
|
||||
/// In this example we generate a new texture atlas (sprite sheet) from a folder containing individual sprites
|
||||
/// In this example we generate a new texture atlas (sprite sheet) from a folder containing
|
||||
/// individual sprites
|
||||
fn main() {
|
||||
App::build()
|
||||
.init_resource::<RpgSpriteHandles>()
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
/// This example shows how to configure Multi-Sample Anti-Aliasing. Setting the sample count higher will result in smoother edges,
|
||||
/// but it will also increase the cost to render those edges. The range should generally be somewhere between 1 (no multi sampling,
|
||||
/// but cheap) to 8 (crisp but expensive)
|
||||
/// This example shows how to configure Multi-Sample Anti-Aliasing. Setting the sample count higher
|
||||
/// will result in smoother edges, but it will also increase the cost to render those edges. The
|
||||
/// range should generally be somewhere between 1 (no multi sampling, but cheap) to 8 (crisp but
|
||||
/// expensive)
|
||||
fn main() {
|
||||
App::build()
|
||||
.insert_resource(Msaa { samples: 4 })
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
/// This example illustrates how to create parent->child relationships between entities how parent transforms
|
||||
/// are propagated to their descendants
|
||||
/// This example illustrates how to create parent->child relationships between entities how parent
|
||||
/// transforms are propagated to their descendants
|
||||
fn main() {
|
||||
App::build()
|
||||
.insert_resource(Msaa { samples: 4 })
|
||||
|
|
|
@ -5,9 +5,10 @@ use bevy::{
|
|||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||
|
||||
/// This example spawns a large number of cubes, each with its own changing position and material
|
||||
/// This is intended to be a stress test of bevy's ability to render many objects with different properties
|
||||
/// For the best results, run it in release mode: ```cargo run --example spawner --release
|
||||
/// NOTE: Bevy still has a number of optimizations to do in this area. Expect the performance here to go way up in the future
|
||||
/// This is intended to be a stress test of bevy's ability to render many objects with different
|
||||
/// properties For the best results, run it in release mode: ```cargo run --example spawner
|
||||
/// --release NOTE: Bevy still has a number of optimizations to do in this area. Expect the
|
||||
/// performance here to go way up in the future
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_plugins(DefaultPlugins)
|
||||
|
|
|
@ -6,7 +6,8 @@ use bevy::{
|
|||
},
|
||||
};
|
||||
|
||||
/// This example visualizes camera z-ordering by setting the material of rotating cubes to their distance from the camera
|
||||
/// This example visualizes camera z-ordering by setting the material of rotating cubes to their
|
||||
/// distance from the camera
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_plugins(DefaultPlugins)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue