Merge branch 'main' into Remove-entity-reserving/pending/flushing-system
This commit is contained in:
commit
6a596cb1e5
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -95,7 +95,7 @@ jobs:
|
|||||||
- name: CI job
|
- name: CI job
|
||||||
# To run the tests one item at a time for troubleshooting, use
|
# To run the tests one item at a time for troubleshooting, use
|
||||||
# cargo --quiet test --lib -- --list | sed 's/: test$//' | MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation" xargs -n1 cargo miri test -p bevy_ecs --lib -- --exact
|
# cargo --quiet test --lib -- --list | sed 's/: test$//' | MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation" xargs -n1 cargo miri test -p bevy_ecs --lib -- --exact
|
||||||
run: cargo miri test -p bevy_ecs
|
run: cargo miri test -p bevy_ecs --features bevy_utils/debug
|
||||||
env:
|
env:
|
||||||
# -Zrandomize-layout makes sure we dont rely on the layout of anything that might change
|
# -Zrandomize-layout makes sure we dont rely on the layout of anything that might change
|
||||||
RUSTFLAGS: -Zrandomize-layout
|
RUSTFLAGS: -Zrandomize-layout
|
||||||
|
|||||||
10
Cargo.toml
10
Cargo.toml
@ -165,6 +165,7 @@ default = [
|
|||||||
"vorbis",
|
"vorbis",
|
||||||
"webgl2",
|
"webgl2",
|
||||||
"x11",
|
"x11",
|
||||||
|
"debug",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Recommended defaults for no_std applications
|
# Recommended defaults for no_std applications
|
||||||
@ -507,7 +508,10 @@ file_watcher = ["bevy_internal/file_watcher"]
|
|||||||
embedded_watcher = ["bevy_internal/embedded_watcher"]
|
embedded_watcher = ["bevy_internal/embedded_watcher"]
|
||||||
|
|
||||||
# Enable stepping-based debugging of Bevy systems
|
# Enable stepping-based debugging of Bevy systems
|
||||||
bevy_debug_stepping = ["bevy_internal/bevy_debug_stepping"]
|
bevy_debug_stepping = [
|
||||||
|
"bevy_internal/bevy_debug_stepping",
|
||||||
|
"bevy_internal/debug",
|
||||||
|
]
|
||||||
|
|
||||||
# Enables the meshlet renderer for dense high-poly scenes (experimental)
|
# Enables the meshlet renderer for dense high-poly scenes (experimental)
|
||||||
meshlet = ["bevy_internal/meshlet"]
|
meshlet = ["bevy_internal/meshlet"]
|
||||||
@ -551,6 +555,9 @@ web = ["bevy_internal/web"]
|
|||||||
# Enable hotpatching of Bevy systems
|
# Enable hotpatching of Bevy systems
|
||||||
hotpatching = ["bevy_internal/hotpatching"]
|
hotpatching = ["bevy_internal/hotpatching"]
|
||||||
|
|
||||||
|
# Enable collecting debug information about systems and components to help with diagnostics
|
||||||
|
debug = ["bevy_internal/debug"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_internal = { path = "crates/bevy_internal", version = "0.16.0-dev", default-features = false }
|
bevy_internal = { path = "crates/bevy_internal", version = "0.16.0-dev", default-features = false }
|
||||||
tracing = { version = "0.1", default-features = false, optional = true }
|
tracing = { version = "0.1", default-features = false, optional = true }
|
||||||
@ -2098,6 +2105,7 @@ wasm = false
|
|||||||
name = "dynamic"
|
name = "dynamic"
|
||||||
path = "examples/ecs/dynamic.rs"
|
path = "examples/ecs/dynamic.rs"
|
||||||
doc-scrape-examples = true
|
doc-scrape-examples = true
|
||||||
|
required-features = ["debug"]
|
||||||
|
|
||||||
[package.metadata.example.dynamic]
|
[package.metadata.example.dynamic]
|
||||||
name = "Dynamic ECS"
|
name = "Dynamic ECS"
|
||||||
|
|||||||
@ -847,7 +847,7 @@ impl ViewNode for SmaaNode {
|
|||||||
view_smaa_uniform_offset,
|
view_smaa_uniform_offset,
|
||||||
smaa_textures,
|
smaa_textures,
|
||||||
view_smaa_bind_groups,
|
view_smaa_bind_groups,
|
||||||
): QueryItem<'w, Self::ViewQuery>,
|
): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let pipeline_cache = world.resource::<PipelineCache>();
|
let pipeline_cache = world.resource::<PipelineCache>();
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]
|
|
||||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
|
//! Macros for deriving asset traits.
|
||||||
|
|
||||||
use bevy_macro_utils::BevyManifest;
|
use bevy_macro_utils::BevyManifest;
|
||||||
use proc_macro::{Span, TokenStream};
|
use proc_macro::{Span, TokenStream};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
@ -12,6 +13,7 @@ pub(crate) fn bevy_asset_path() -> Path {
|
|||||||
|
|
||||||
const DEPENDENCY_ATTRIBUTE: &str = "dependency";
|
const DEPENDENCY_ATTRIBUTE: &str = "dependency";
|
||||||
|
|
||||||
|
/// Implement the `Asset` trait.
|
||||||
#[proc_macro_derive(Asset, attributes(dependency))]
|
#[proc_macro_derive(Asset, attributes(dependency))]
|
||||||
pub fn derive_asset(input: TokenStream) -> TokenStream {
|
pub fn derive_asset(input: TokenStream) -> TokenStream {
|
||||||
let ast = parse_macro_input!(input as DeriveInput);
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
@ -30,6 +32,7 @@ pub fn derive_asset(input: TokenStream) -> TokenStream {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implement the `VisitAssetDependencies` trait.
|
||||||
#[proc_macro_derive(VisitAssetDependencies, attributes(dependency))]
|
#[proc_macro_derive(VisitAssetDependencies, attributes(dependency))]
|
||||||
pub fn derive_asset_dependency_visitor(input: TokenStream) -> TokenStream {
|
pub fn derive_asset_dependency_visitor(input: TokenStream) -> TokenStream {
|
||||||
let ast = parse_macro_input!(input as DeriveInput);
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
|
|||||||
@ -158,9 +158,9 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
|
|||||||
fetch
|
fetch
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w, 's>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
state: &Self::State,
|
state: &'s Self::State,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> Self::Fetch<'w> {
|
) -> Self::Fetch<'w> {
|
||||||
@ -201,9 +201,9 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
|
|||||||
|
|
||||||
const IS_DENSE: bool = <&A>::IS_DENSE;
|
const IS_DENSE: bool = <&A>::IS_DENSE;
|
||||||
|
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w, 's>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
state: &Self::State,
|
state: &'s Self::State,
|
||||||
archetype: &'w Archetype,
|
archetype: &'w Archetype,
|
||||||
table: &'w Table,
|
table: &'w Table,
|
||||||
) {
|
) {
|
||||||
@ -215,7 +215,11 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
|
unsafe fn set_table<'w, 's>(
|
||||||
|
fetch: &mut Self::Fetch<'w>,
|
||||||
|
state: &Self::State,
|
||||||
|
table: &'w Table,
|
||||||
|
) {
|
||||||
if let Some(inner) = &mut fetch.inner {
|
if let Some(inner) = &mut fetch.inner {
|
||||||
// SAFETY: We delegate to the inner `set_table` for `A`
|
// SAFETY: We delegate to the inner `set_table` for `A`
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -265,6 +269,7 @@ unsafe impl<A: AsAssetId> QueryFilter for AssetChanged<A> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn filter_fetch(
|
unsafe fn filter_fetch(
|
||||||
|
state: &Self::State,
|
||||||
fetch: &mut Self::Fetch<'_>,
|
fetch: &mut Self::Fetch<'_>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
table_row: TableRow,
|
table_row: TableRow,
|
||||||
@ -272,7 +277,7 @@ unsafe impl<A: AsAssetId> QueryFilter for AssetChanged<A> {
|
|||||||
fetch.inner.as_mut().is_some_and(|inner| {
|
fetch.inner.as_mut().is_some_and(|inner| {
|
||||||
// SAFETY: We delegate to the inner `fetch` for `A`
|
// SAFETY: We delegate to the inner `fetch` for `A`
|
||||||
unsafe {
|
unsafe {
|
||||||
let handle = <&A>::fetch(inner, entity, table_row);
|
let handle = <&A>::fetch(&state.asset_id, inner, entity, table_row);
|
||||||
fetch.check.has_changed(handle)
|
fetch.check.has_changed(handle)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1953,6 +1953,14 @@ impl AssetLoaderError {
|
|||||||
pub fn path(&self) -> &AssetPath<'static> {
|
pub fn path(&self) -> &AssetPath<'static> {
|
||||||
&self.path
|
&self.path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The error the loader reported when attempting to load the asset.
|
||||||
|
///
|
||||||
|
/// If you know the type of the error the asset loader returned, you can use
|
||||||
|
/// [`BevyError::downcast_ref()`] to get it.
|
||||||
|
pub fn error(&self) -> &BevyError {
|
||||||
|
&self.error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error that occurs while resolving an asset added by `add_async`.
|
/// An error that occurs while resolving an asset added by `add_async`.
|
||||||
|
|||||||
@ -121,7 +121,7 @@ impl ViewNode for BloomNode {
|
|||||||
bloom_settings,
|
bloom_settings,
|
||||||
upsampling_pipeline_ids,
|
upsampling_pipeline_ids,
|
||||||
downsampling_pipeline_ids,
|
downsampling_pipeline_ids,
|
||||||
): QueryItem<'w, Self::ViewQuery>,
|
): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
if bloom_settings.intensity == 0.0 {
|
if bloom_settings.intensity == 0.0 {
|
||||||
|
|||||||
@ -227,7 +227,7 @@ impl ExtractComponent for Bloom {
|
|||||||
type QueryFilter = With<Hdr>;
|
type QueryFilter = With<Hdr>;
|
||||||
type Out = (Self, BloomUniforms);
|
type Out = (Self, BloomUniforms);
|
||||||
|
|
||||||
fn extract_component((bloom, camera): QueryItem<'_, Self::QueryData>) -> Option<Self::Out> {
|
fn extract_component((bloom, camera): QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out> {
|
||||||
match (
|
match (
|
||||||
camera.physical_viewport_rect(),
|
camera.physical_viewport_rect(),
|
||||||
camera.physical_viewport_size(),
|
camera.physical_viewport_size(),
|
||||||
|
|||||||
@ -31,7 +31,7 @@ impl ViewNode for MainOpaquePass2dNode {
|
|||||||
&self,
|
&self,
|
||||||
graph: &mut RenderGraphContext,
|
graph: &mut RenderGraphContext,
|
||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
(camera, view, target, depth): QueryItem<'w, Self::ViewQuery>,
|
(camera, view, target, depth): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let (Some(opaque_phases), Some(alpha_mask_phases)) = (
|
let (Some(opaque_phases), Some(alpha_mask_phases)) = (
|
||||||
|
|||||||
@ -28,7 +28,7 @@ impl ViewNode for MainTransparentPass2dNode {
|
|||||||
&self,
|
&self,
|
||||||
graph: &mut RenderGraphContext,
|
graph: &mut RenderGraphContext,
|
||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
(camera, view, target, depth): bevy_ecs::query::QueryItem<'w, Self::ViewQuery>,
|
(camera, view, target, depth): bevy_ecs::query::QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let Some(transparent_phases) =
|
let Some(transparent_phases) =
|
||||||
|
|||||||
@ -45,7 +45,7 @@ impl ViewNode for MainOpaquePass3dNode {
|
|||||||
skybox_pipeline,
|
skybox_pipeline,
|
||||||
skybox_bind_group,
|
skybox_bind_group,
|
||||||
view_uniform_offset,
|
view_uniform_offset,
|
||||||
): QueryItem<'w, Self::ViewQuery>,
|
): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let (Some(opaque_phases), Some(alpha_mask_phases)) = (
|
let (Some(opaque_phases), Some(alpha_mask_phases)) = (
|
||||||
|
|||||||
@ -36,7 +36,7 @@ impl ViewNode for EarlyDeferredGBufferPrepassNode {
|
|||||||
&self,
|
&self,
|
||||||
graph: &mut RenderGraphContext,
|
graph: &mut RenderGraphContext,
|
||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
view_query: QueryItem<'w, Self::ViewQuery>,
|
view_query: QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
run_deferred_prepass(
|
run_deferred_prepass(
|
||||||
@ -74,7 +74,7 @@ impl ViewNode for LateDeferredGBufferPrepassNode {
|
|||||||
&self,
|
&self,
|
||||||
graph: &mut RenderGraphContext,
|
graph: &mut RenderGraphContext,
|
||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
view_query: QueryItem<'w, Self::ViewQuery>,
|
view_query: QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let (_, _, _, _, occlusion_culling, no_indirect_drawing) = view_query;
|
let (_, _, _, _, occlusion_culling, no_indirect_drawing) = view_query;
|
||||||
@ -107,6 +107,7 @@ fn run_deferred_prepass<'w>(
|
|||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
(camera, extracted_view, view_depth_texture, view_prepass_textures, _, _): QueryItem<
|
(camera, extracted_view, view_depth_texture, view_prepass_textures, _, _): QueryItem<
|
||||||
'w,
|
'w,
|
||||||
|
'_,
|
||||||
<LateDeferredGBufferPrepassNode as ViewNode>::ViewQuery,
|
<LateDeferredGBufferPrepassNode as ViewNode>::ViewQuery,
|
||||||
>,
|
>,
|
||||||
is_late: bool,
|
is_late: bool,
|
||||||
|
|||||||
@ -352,7 +352,7 @@ impl ViewNode for DepthOfFieldNode {
|
|||||||
view_bind_group_layouts,
|
view_bind_group_layouts,
|
||||||
depth_of_field_uniform_index,
|
depth_of_field_uniform_index,
|
||||||
auxiliary_dof_texture,
|
auxiliary_dof_texture,
|
||||||
): QueryItem<'w, Self::ViewQuery>,
|
): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let pipeline_cache = world.resource::<PipelineCache>();
|
let pipeline_cache = world.resource::<PipelineCache>();
|
||||||
|
|||||||
@ -61,7 +61,7 @@ impl ViewNode for MsaaWritebackNode {
|
|||||||
&self,
|
&self,
|
||||||
_graph: &mut RenderGraphContext,
|
_graph: &mut RenderGraphContext,
|
||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
(target, blit_pipeline_id, msaa): QueryItem<'w, Self::ViewQuery>,
|
(target, blit_pipeline_id, msaa): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
if *msaa == Msaa::Off {
|
if *msaa == Msaa::Off {
|
||||||
|
|||||||
@ -352,7 +352,7 @@ impl ViewNode for PostProcessingNode {
|
|||||||
&self,
|
&self,
|
||||||
_: &mut RenderGraphContext,
|
_: &mut RenderGraphContext,
|
||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
(view_target, pipeline_id, chromatic_aberration, post_processing_uniform_buffer_offsets): QueryItem<'w, Self::ViewQuery>,
|
(view_target, pipeline_id, chromatic_aberration, post_processing_uniform_buffer_offsets): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let pipeline_cache = world.resource::<PipelineCache>();
|
let pipeline_cache = world.resource::<PipelineCache>();
|
||||||
@ -485,7 +485,7 @@ impl ExtractComponent for ChromaticAberration {
|
|||||||
type Out = ChromaticAberration;
|
type Out = ChromaticAberration;
|
||||||
|
|
||||||
fn extract_component(
|
fn extract_component(
|
||||||
chromatic_aberration: QueryItem<'_, Self::QueryData>,
|
chromatic_aberration: QueryItem<'_, '_, Self::QueryData>,
|
||||||
) -> Option<Self::Out> {
|
) -> Option<Self::Out> {
|
||||||
// Skip the postprocessing phase entirely if the intensity is zero.
|
// Skip the postprocessing phase entirely if the intensity is zero.
|
||||||
if chromatic_aberration.intensity > 0.0 {
|
if chromatic_aberration.intensity > 0.0 {
|
||||||
|
|||||||
@ -36,7 +36,7 @@ impl ViewNode for EarlyPrepassNode {
|
|||||||
&self,
|
&self,
|
||||||
graph: &mut RenderGraphContext,
|
graph: &mut RenderGraphContext,
|
||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
view_query: QueryItem<'w, Self::ViewQuery>,
|
view_query: QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
run_prepass(graph, render_context, view_query, world, "early prepass")
|
run_prepass(graph, render_context, view_query, world, "early prepass")
|
||||||
@ -73,7 +73,7 @@ impl ViewNode for LatePrepassNode {
|
|||||||
&self,
|
&self,
|
||||||
graph: &mut RenderGraphContext,
|
graph: &mut RenderGraphContext,
|
||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
query: QueryItem<'w, Self::ViewQuery>,
|
query: QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
// We only need a late prepass if we have occlusion culling and indirect
|
// We only need a late prepass if we have occlusion culling and indirect
|
||||||
@ -112,7 +112,7 @@ fn run_prepass<'w>(
|
|||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
has_deferred,
|
has_deferred,
|
||||||
): QueryItem<'w, <LatePrepassNode as ViewNode>::ViewQuery>,
|
): QueryItem<'w, '_, <LatePrepassNode as ViewNode>::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
label: &'static str,
|
label: &'static str,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
|
|||||||
@ -113,7 +113,9 @@ impl ExtractComponent for Skybox {
|
|||||||
type QueryFilter = ();
|
type QueryFilter = ();
|
||||||
type Out = (Self, SkyboxUniforms);
|
type Out = (Self, SkyboxUniforms);
|
||||||
|
|
||||||
fn extract_component((skybox, exposure): QueryItem<'_, Self::QueryData>) -> Option<Self::Out> {
|
fn extract_component(
|
||||||
|
(skybox, exposure): QueryItem<'_, '_, Self::QueryData>,
|
||||||
|
) -> Option<Self::Out> {
|
||||||
let exposure = exposure
|
let exposure = exposure
|
||||||
.map(Exposure::exposure)
|
.map(Exposure::exposure)
|
||||||
.unwrap_or_else(|| Exposure::default().exposure());
|
.unwrap_or_else(|| Exposure::default().exposure());
|
||||||
@ -123,7 +125,7 @@ impl ExtractComponent for Skybox {
|
|||||||
SkyboxUniforms {
|
SkyboxUniforms {
|
||||||
brightness: skybox.brightness * exposure,
|
brightness: skybox.brightness * exposure,
|
||||||
transform: Transform::from_rotation(skybox.rotation)
|
transform: Transform::from_rotation(skybox.rotation)
|
||||||
.compute_matrix()
|
.to_matrix()
|
||||||
.inverse(),
|
.inverse(),
|
||||||
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
|
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
|
||||||
_wasm_padding_8b: 0,
|
_wasm_padding_8b: 0,
|
||||||
|
|||||||
@ -211,6 +211,7 @@ pub(crate) fn slider_on_pointer_down(
|
|||||||
focus: Option<ResMut<InputFocus>>,
|
focus: Option<ResMut<InputFocus>>,
|
||||||
focus_visible: Option<ResMut<InputFocusVisible>>,
|
focus_visible: Option<ResMut<InputFocusVisible>>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
|
ui_scale: Res<UiScale>,
|
||||||
) {
|
) {
|
||||||
if q_thumb.contains(trigger.target()) {
|
if q_thumb.contains(trigger.target()) {
|
||||||
// Thumb click, stop propagation to prevent track click.
|
// Thumb click, stop propagation to prevent track click.
|
||||||
@ -255,7 +256,7 @@ pub(crate) fn slider_on_pointer_down(
|
|||||||
|
|
||||||
// Detect track click.
|
// Detect track click.
|
||||||
let local_pos = transform.try_inverse().unwrap().transform_point2(
|
let local_pos = transform.try_inverse().unwrap().transform_point2(
|
||||||
trigger.event().pointer_location.position * node_target.scale_factor(),
|
trigger.event().pointer_location.position * node_target.scale_factor() / ui_scale.0,
|
||||||
);
|
);
|
||||||
let track_width = node.size().x - thumb_size;
|
let track_width = node.size().x - thumb_size;
|
||||||
// Avoid division by zero
|
// Avoid division by zero
|
||||||
@ -394,6 +395,10 @@ fn slider_on_key_input(
|
|||||||
trigger.propagate(false);
|
trigger.propagate(false);
|
||||||
if let Some(on_change) = slider.on_change {
|
if let Some(on_change) = slider.on_change {
|
||||||
commands.run_system_with(on_change, new_value);
|
commands.run_system_with(on_change, new_value);
|
||||||
|
} else {
|
||||||
|
commands
|
||||||
|
.entity(trigger.target())
|
||||||
|
.insert(SliderValue(new_value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -456,7 +461,7 @@ pub(crate) fn slider_on_insert_step(trigger: On<Insert, SliderStep>, mut world:
|
|||||||
/// commands.trigger_targets(SetSliderValue::Relative(-0.25), slider);
|
/// commands.trigger_targets(SetSliderValue::Relative(-0.25), slider);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Event, EntityEvent)]
|
#[derive(Event, EntityEvent, Clone)]
|
||||||
pub enum SetSliderValue {
|
pub enum SetSliderValue {
|
||||||
/// Set the slider value to a specific value.
|
/// Set the slider value to a specific value.
|
||||||
Absolute(f32),
|
Absolute(f32),
|
||||||
|
|||||||
@ -35,7 +35,7 @@ backtrace = ["std"]
|
|||||||
|
|
||||||
## Enables `tracing` integration, allowing spans and other metrics to be reported
|
## Enables `tracing` integration, allowing spans and other metrics to be reported
|
||||||
## through that framework.
|
## through that framework.
|
||||||
trace = ["std", "dep:tracing"]
|
trace = ["std", "dep:tracing", "bevy_utils/debug"]
|
||||||
|
|
||||||
## Enables a more detailed set of traces which may be noisy if left on by default.
|
## Enables a more detailed set of traces which may be noisy if left on by default.
|
||||||
detailed_trace = ["trace"]
|
detailed_trace = ["trace"]
|
||||||
@ -63,9 +63,9 @@ std = [
|
|||||||
"bevy_reflect?/std",
|
"bevy_reflect?/std",
|
||||||
"bevy_tasks/std",
|
"bevy_tasks/std",
|
||||||
"bevy_utils/parallel",
|
"bevy_utils/parallel",
|
||||||
|
"bevy_utils/std",
|
||||||
"bitflags/std",
|
"bitflags/std",
|
||||||
"concurrent-queue/std",
|
"concurrent-queue/std",
|
||||||
"disqualified/alloc",
|
|
||||||
"fixedbitset/std",
|
"fixedbitset/std",
|
||||||
"indexmap/std",
|
"indexmap/std",
|
||||||
"serde?/std",
|
"serde?/std",
|
||||||
@ -98,7 +98,6 @@ bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-fea
|
|||||||
] }
|
] }
|
||||||
|
|
||||||
bitflags = { version = "2.3", default-features = false }
|
bitflags = { version = "2.3", default-features = false }
|
||||||
disqualified = { version = "1.0", default-features = false }
|
|
||||||
fixedbitset = { version = "0.5", default-features = false }
|
fixedbitset = { version = "0.5", default-features = false }
|
||||||
serde = { version = "1", default-features = false, features = [
|
serde = { version = "1", default-features = false, features = [
|
||||||
"alloc",
|
"alloc",
|
||||||
|
|||||||
@ -74,12 +74,23 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
|
|||||||
let user_generics = ast.generics.clone();
|
let user_generics = ast.generics.clone();
|
||||||
let (user_impl_generics, user_ty_generics, user_where_clauses) = user_generics.split_for_impl();
|
let (user_impl_generics, user_ty_generics, user_where_clauses) = user_generics.split_for_impl();
|
||||||
let user_generics_with_world = {
|
let user_generics_with_world = {
|
||||||
let mut generics = ast.generics;
|
let mut generics = ast.generics.clone();
|
||||||
generics.params.insert(0, parse_quote!('__w));
|
generics.params.insert(0, parse_quote!('__w));
|
||||||
generics
|
generics
|
||||||
};
|
};
|
||||||
let (user_impl_generics_with_world, user_ty_generics_with_world, user_where_clauses_with_world) =
|
let (user_impl_generics_with_world, user_ty_generics_with_world, user_where_clauses_with_world) =
|
||||||
user_generics_with_world.split_for_impl();
|
user_generics_with_world.split_for_impl();
|
||||||
|
let user_generics_with_world_and_state = {
|
||||||
|
let mut generics = ast.generics;
|
||||||
|
generics.params.insert(0, parse_quote!('__w));
|
||||||
|
generics.params.insert(0, parse_quote!('__s));
|
||||||
|
generics
|
||||||
|
};
|
||||||
|
let (
|
||||||
|
user_impl_generics_with_world_and_state,
|
||||||
|
user_ty_generics_with_world_and_state,
|
||||||
|
user_where_clauses_with_world_and_state,
|
||||||
|
) = user_generics_with_world_and_state.split_for_impl();
|
||||||
|
|
||||||
let struct_name = ast.ident;
|
let struct_name = ast.ident;
|
||||||
let read_only_struct_name = if attributes.is_mutable {
|
let read_only_struct_name = if attributes.is_mutable {
|
||||||
@ -164,13 +175,13 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
|
|||||||
&visibility,
|
&visibility,
|
||||||
&item_struct_name,
|
&item_struct_name,
|
||||||
&field_types,
|
&field_types,
|
||||||
&user_impl_generics_with_world,
|
&user_impl_generics_with_world_and_state,
|
||||||
&field_attrs,
|
&field_attrs,
|
||||||
&field_visibilities,
|
&field_visibilities,
|
||||||
&field_idents,
|
&field_idents,
|
||||||
&user_ty_generics,
|
&user_ty_generics,
|
||||||
&user_ty_generics_with_world,
|
&user_ty_generics_with_world_and_state,
|
||||||
user_where_clauses_with_world,
|
user_where_clauses_with_world_and_state,
|
||||||
);
|
);
|
||||||
let mutable_world_query_impl = world_query_impl(
|
let mutable_world_query_impl = world_query_impl(
|
||||||
&path,
|
&path,
|
||||||
@ -199,13 +210,13 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
|
|||||||
&visibility,
|
&visibility,
|
||||||
&read_only_item_struct_name,
|
&read_only_item_struct_name,
|
||||||
&read_only_field_types,
|
&read_only_field_types,
|
||||||
&user_impl_generics_with_world,
|
&user_impl_generics_with_world_and_state,
|
||||||
&field_attrs,
|
&field_attrs,
|
||||||
&field_visibilities,
|
&field_visibilities,
|
||||||
&field_idents,
|
&field_idents,
|
||||||
&user_ty_generics,
|
&user_ty_generics,
|
||||||
&user_ty_generics_with_world,
|
&user_ty_generics_with_world_and_state,
|
||||||
user_where_clauses_with_world,
|
user_where_clauses_with_world_and_state,
|
||||||
);
|
);
|
||||||
let readonly_world_query_impl = world_query_impl(
|
let readonly_world_query_impl = world_query_impl(
|
||||||
&path,
|
&path,
|
||||||
@ -256,11 +267,11 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
|
|||||||
for #read_only_struct_name #user_ty_generics #user_where_clauses {
|
for #read_only_struct_name #user_ty_generics #user_where_clauses {
|
||||||
const IS_READ_ONLY: bool = true;
|
const IS_READ_ONLY: bool = true;
|
||||||
type ReadOnly = #read_only_struct_name #user_ty_generics;
|
type ReadOnly = #read_only_struct_name #user_ty_generics;
|
||||||
type Item<'__w> = #read_only_item_struct_name #user_ty_generics_with_world;
|
type Item<'__w, '__s> = #read_only_item_struct_name #user_ty_generics_with_world_and_state;
|
||||||
|
|
||||||
fn shrink<'__wlong: '__wshort, '__wshort>(
|
fn shrink<'__wlong: '__wshort, '__wshort, '__s>(
|
||||||
item: Self::Item<'__wlong>
|
item: Self::Item<'__wlong, '__s>
|
||||||
) -> Self::Item<'__wshort> {
|
) -> Self::Item<'__wshort, '__s> {
|
||||||
#read_only_item_struct_name {
|
#read_only_item_struct_name {
|
||||||
#(
|
#(
|
||||||
#field_idents: <#read_only_field_types>::shrink(item.#field_idents),
|
#field_idents: <#read_only_field_types>::shrink(item.#field_idents),
|
||||||
@ -278,13 +289,26 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
|
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn fetch<'__w>(
|
unsafe fn fetch<'__w, '__s>(
|
||||||
|
_state: &'__s Self::State,
|
||||||
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
||||||
_entity: #path::entity::Entity,
|
_entity: #path::entity::Entity,
|
||||||
_table_row: #path::storage::TableRow,
|
_table_row: #path::storage::TableRow,
|
||||||
) -> Self::Item<'__w> {
|
) -> Self::Item<'__w, '__s> {
|
||||||
Self::Item {
|
Self::Item {
|
||||||
#(#field_idents: <#read_only_field_types>::fetch(&mut _fetch.#named_field_idents, _entity, _table_row),)*
|
#(#field_idents: <#read_only_field_types>::fetch(&_state.#named_field_idents, &mut _fetch.#named_field_idents, _entity, _table_row),)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #user_impl_generics #path::query::ReleaseStateQueryData
|
||||||
|
for #read_only_struct_name #user_ty_generics #user_where_clauses
|
||||||
|
// Make these HRTBs with an unused lifetime parameter to allow trivial constraints
|
||||||
|
// See https://github.com/rust-lang/rust/issues/48214
|
||||||
|
where #(for<'__a> #field_types: #path::query::QueryData<ReadOnly: #path::query::ReleaseStateQueryData>,)* {
|
||||||
|
fn release_state<'__w>(_item: Self::Item<'__w, '_>) -> Self::Item<'__w, 'static> {
|
||||||
|
Self::Item {
|
||||||
|
#(#field_idents: <#read_only_field_types>::release_state(_item.#field_idents),)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,11 +325,11 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
|
|||||||
for #struct_name #user_ty_generics #user_where_clauses {
|
for #struct_name #user_ty_generics #user_where_clauses {
|
||||||
const IS_READ_ONLY: bool = #is_read_only;
|
const IS_READ_ONLY: bool = #is_read_only;
|
||||||
type ReadOnly = #read_only_struct_name #user_ty_generics;
|
type ReadOnly = #read_only_struct_name #user_ty_generics;
|
||||||
type Item<'__w> = #item_struct_name #user_ty_generics_with_world;
|
type Item<'__w, '__s> = #item_struct_name #user_ty_generics_with_world_and_state;
|
||||||
|
|
||||||
fn shrink<'__wlong: '__wshort, '__wshort>(
|
fn shrink<'__wlong: '__wshort, '__wshort, '__s>(
|
||||||
item: Self::Item<'__wlong>
|
item: Self::Item<'__wlong, '__s>
|
||||||
) -> Self::Item<'__wshort> {
|
) -> Self::Item<'__wshort, '__s> {
|
||||||
#item_struct_name {
|
#item_struct_name {
|
||||||
#(
|
#(
|
||||||
#field_idents: <#field_types>::shrink(item.#field_idents),
|
#field_idents: <#field_types>::shrink(item.#field_idents),
|
||||||
@ -323,13 +347,26 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
|
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn fetch<'__w>(
|
unsafe fn fetch<'__w, '__s>(
|
||||||
|
_state: &'__s Self::State,
|
||||||
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
||||||
_entity: #path::entity::Entity,
|
_entity: #path::entity::Entity,
|
||||||
_table_row: #path::storage::TableRow,
|
_table_row: #path::storage::TableRow,
|
||||||
) -> Self::Item<'__w> {
|
) -> Self::Item<'__w, '__s> {
|
||||||
Self::Item {
|
Self::Item {
|
||||||
#(#field_idents: <#field_types>::fetch(&mut _fetch.#named_field_idents, _entity, _table_row),)*
|
#(#field_idents: <#field_types>::fetch(&_state.#named_field_idents, &mut _fetch.#named_field_idents, _entity, _table_row),)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #user_impl_generics #path::query::ReleaseStateQueryData
|
||||||
|
for #struct_name #user_ty_generics #user_where_clauses
|
||||||
|
// Make these HRTBs with an unused lifetime parameter to allow trivial constraints
|
||||||
|
// See https://github.com/rust-lang/rust/issues/48214
|
||||||
|
where #(for<'__a> #field_types: #path::query::ReleaseStateQueryData,)* {
|
||||||
|
fn release_state<'__w>(_item: Self::Item<'__w, '_>) -> Self::Item<'__w, 'static> {
|
||||||
|
Self::Item {
|
||||||
|
#(#field_idents: <#field_types>::release_state(_item.#field_idents),)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -102,11 +102,12 @@ pub fn derive_query_filter_impl(input: TokenStream) -> TokenStream {
|
|||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn filter_fetch<'__w>(
|
unsafe fn filter_fetch<'__w>(
|
||||||
|
_state: &Self::State,
|
||||||
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
||||||
_entity: #path::entity::Entity,
|
_entity: #path::entity::Entity,
|
||||||
_table_row: #path::storage::TableRow,
|
_table_row: #path::storage::TableRow,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
true #(&& <#field_types>::filter_fetch(&mut _fetch.#named_field_idents, _entity, _table_row))*
|
true #(&& <#field_types>::filter_fetch(&_state.#named_field_idents, &mut _fetch.#named_field_idents, _entity, _table_row))*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,13 +10,13 @@ pub(crate) fn item_struct(
|
|||||||
visibility: &Visibility,
|
visibility: &Visibility,
|
||||||
item_struct_name: &Ident,
|
item_struct_name: &Ident,
|
||||||
field_types: &Vec<proc_macro2::TokenStream>,
|
field_types: &Vec<proc_macro2::TokenStream>,
|
||||||
user_impl_generics_with_world: &ImplGenerics,
|
user_impl_generics_with_world_and_state: &ImplGenerics,
|
||||||
field_attrs: &Vec<Vec<Attribute>>,
|
field_attrs: &Vec<Vec<Attribute>>,
|
||||||
field_visibilities: &Vec<Visibility>,
|
field_visibilities: &Vec<Visibility>,
|
||||||
field_idents: &Vec<proc_macro2::TokenStream>,
|
field_idents: &Vec<proc_macro2::TokenStream>,
|
||||||
user_ty_generics: &TypeGenerics,
|
user_ty_generics: &TypeGenerics,
|
||||||
user_ty_generics_with_world: &TypeGenerics,
|
user_ty_generics_with_world_and_state: &TypeGenerics,
|
||||||
user_where_clauses_with_world: Option<&WhereClause>,
|
user_where_clauses_with_world_and_state: Option<&WhereClause>,
|
||||||
) -> proc_macro2::TokenStream {
|
) -> proc_macro2::TokenStream {
|
||||||
let item_attrs = quote! {
|
let item_attrs = quote! {
|
||||||
#[doc = concat!(
|
#[doc = concat!(
|
||||||
@ -33,20 +33,20 @@ pub(crate) fn item_struct(
|
|||||||
Fields::Named(_) => quote! {
|
Fields::Named(_) => quote! {
|
||||||
#derive_macro_call
|
#derive_macro_call
|
||||||
#item_attrs
|
#item_attrs
|
||||||
#visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
#visibility struct #item_struct_name #user_impl_generics_with_world_and_state #user_where_clauses_with_world_and_state {
|
||||||
#(#(#field_attrs)* #field_visibilities #field_idents: <#field_types as #path::query::QueryData>::Item<'__w>,)*
|
#(#(#field_attrs)* #field_visibilities #field_idents: <#field_types as #path::query::QueryData>::Item<'__w, '__s>,)*
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Fields::Unnamed(_) => quote! {
|
Fields::Unnamed(_) => quote! {
|
||||||
#derive_macro_call
|
#derive_macro_call
|
||||||
#item_attrs
|
#item_attrs
|
||||||
#visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world(
|
#visibility struct #item_struct_name #user_impl_generics_with_world_and_state #user_where_clauses_with_world_and_state(
|
||||||
#( #field_visibilities <#field_types as #path::query::QueryData>::Item<'__w>, )*
|
#( #field_visibilities <#field_types as #path::query::QueryData>::Item<'__w, '__s>, )*
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
Fields::Unit => quote! {
|
Fields::Unit => quote! {
|
||||||
#item_attrs
|
#item_attrs
|
||||||
#visibility type #item_struct_name #user_ty_generics_with_world = #struct_name #user_ty_generics;
|
#visibility type #item_struct_name #user_ty_generics_with_world_and_state = #struct_name #user_ty_generics;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ pub(crate) fn world_query_impl(
|
|||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
#visibility struct #fetch_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
#visibility struct #fetch_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
||||||
#(#named_field_idents: <#field_types as #path::query::WorldQuery>::Fetch<'__w>,)*
|
#(#named_field_idents: <#field_types as #path::query::WorldQuery>::Fetch<'__w>,)*
|
||||||
#marker_name: &'__w (),
|
#marker_name: &'__w(),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #user_impl_generics_with_world Clone for #fetch_struct_name #user_ty_generics_with_world
|
impl #user_impl_generics_with_world Clone for #fetch_struct_name #user_ty_generics_with_world
|
||||||
@ -110,9 +110,9 @@ pub(crate) fn world_query_impl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn init_fetch<'__w>(
|
unsafe fn init_fetch<'__w, '__s>(
|
||||||
_world: #path::world::unsafe_world_cell::UnsafeWorldCell<'__w>,
|
_world: #path::world::unsafe_world_cell::UnsafeWorldCell<'__w>,
|
||||||
state: &Self::State,
|
state: &'__s Self::State,
|
||||||
_last_run: #path::component::Tick,
|
_last_run: #path::component::Tick,
|
||||||
_this_run: #path::component::Tick,
|
_this_run: #path::component::Tick,
|
||||||
) -> <Self as #path::query::WorldQuery>::Fetch<'__w> {
|
) -> <Self as #path::query::WorldQuery>::Fetch<'__w> {
|
||||||
@ -133,9 +133,9 @@ pub(crate) fn world_query_impl(
|
|||||||
|
|
||||||
/// SAFETY: we call `set_archetype` for each member that implements `Fetch`
|
/// SAFETY: we call `set_archetype` for each member that implements `Fetch`
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype<'__w>(
|
unsafe fn set_archetype<'__w, '__s>(
|
||||||
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
||||||
_state: &Self::State,
|
_state: &'__s Self::State,
|
||||||
_archetype: &'__w #path::archetype::Archetype,
|
_archetype: &'__w #path::archetype::Archetype,
|
||||||
_table: &'__w #path::storage::Table
|
_table: &'__w #path::storage::Table
|
||||||
) {
|
) {
|
||||||
@ -144,9 +144,9 @@ pub(crate) fn world_query_impl(
|
|||||||
|
|
||||||
/// SAFETY: we call `set_table` for each member that implements `Fetch`
|
/// SAFETY: we call `set_table` for each member that implements `Fetch`
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table<'__w>(
|
unsafe fn set_table<'__w, '__s>(
|
||||||
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
||||||
_state: &Self::State,
|
_state: &'__s Self::State,
|
||||||
_table: &'__w #path::storage::Table
|
_table: &'__w #path::storage::Table
|
||||||
) {
|
) {
|
||||||
#(<#field_types>::set_table(&mut _fetch.#named_field_idents, &_state.#named_field_idents, _table);)*
|
#(<#field_types>::set_table(&mut _fetch.#named_field_idents, &_state.#named_field_idents, _table);)*
|
||||||
|
|||||||
@ -550,10 +550,9 @@ impl BundleInfo {
|
|||||||
// SAFETY: the caller ensures component_id is valid.
|
// SAFETY: the caller ensures component_id is valid.
|
||||||
unsafe { components.get_info_unchecked(id).name() }
|
unsafe { components.get_info_unchecked(id).name() }
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>();
|
||||||
.join(", ");
|
|
||||||
|
|
||||||
panic!("Bundle {bundle_type_name} has duplicate components: {names}");
|
panic!("Bundle {bundle_type_name} has duplicate components: {names:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle explicit components
|
// handle explicit components
|
||||||
|
|||||||
@ -24,7 +24,7 @@ use bevy_platform::{
|
|||||||
use bevy_ptr::{OwningPtr, UnsafeCellDeref};
|
use bevy_ptr::{OwningPtr, UnsafeCellDeref};
|
||||||
#[cfg(feature = "bevy_reflect")]
|
#[cfg(feature = "bevy_reflect")]
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use bevy_utils::TypeIdMap;
|
use bevy_utils::{prelude::DebugName, TypeIdMap};
|
||||||
use core::{
|
use core::{
|
||||||
alloc::Layout,
|
alloc::Layout,
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
@ -34,7 +34,6 @@ use core::{
|
|||||||
mem::needs_drop,
|
mem::needs_drop,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
use disqualified::ShortName;
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@ -678,8 +677,8 @@ impl ComponentInfo {
|
|||||||
|
|
||||||
/// Returns the name of the current component.
|
/// Returns the name of the current component.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> DebugName {
|
||||||
&self.descriptor.name
|
self.descriptor.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the current component is mutable.
|
/// Returns `true` if the current component is mutable.
|
||||||
@ -836,7 +835,7 @@ impl SparseSetIndex for ComponentId {
|
|||||||
/// A value describing a component or resource, which may or may not correspond to a Rust type.
|
/// A value describing a component or resource, which may or may not correspond to a Rust type.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ComponentDescriptor {
|
pub struct ComponentDescriptor {
|
||||||
name: Cow<'static, str>,
|
name: DebugName,
|
||||||
// SAFETY: This must remain private. It must match the statically known StorageType of the
|
// SAFETY: This must remain private. It must match the statically known StorageType of the
|
||||||
// associated rust component type if one exists.
|
// associated rust component type if one exists.
|
||||||
storage_type: StorageType,
|
storage_type: StorageType,
|
||||||
@ -882,7 +881,7 @@ impl ComponentDescriptor {
|
|||||||
/// Create a new `ComponentDescriptor` for the type `T`.
|
/// Create a new `ComponentDescriptor` for the type `T`.
|
||||||
pub fn new<T: Component>() -> Self {
|
pub fn new<T: Component>() -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: Cow::Borrowed(core::any::type_name::<T>()),
|
name: DebugName::type_name::<T>(),
|
||||||
storage_type: T::STORAGE_TYPE,
|
storage_type: T::STORAGE_TYPE,
|
||||||
is_send_and_sync: true,
|
is_send_and_sync: true,
|
||||||
type_id: Some(TypeId::of::<T>()),
|
type_id: Some(TypeId::of::<T>()),
|
||||||
@ -907,7 +906,7 @@ impl ComponentDescriptor {
|
|||||||
clone_behavior: ComponentCloneBehavior,
|
clone_behavior: ComponentCloneBehavior,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name: name.into().into(),
|
||||||
storage_type,
|
storage_type,
|
||||||
is_send_and_sync: true,
|
is_send_and_sync: true,
|
||||||
type_id: None,
|
type_id: None,
|
||||||
@ -923,7 +922,7 @@ impl ComponentDescriptor {
|
|||||||
/// The [`StorageType`] for resources is always [`StorageType::Table`].
|
/// The [`StorageType`] for resources is always [`StorageType::Table`].
|
||||||
pub fn new_resource<T: Resource>() -> Self {
|
pub fn new_resource<T: Resource>() -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: Cow::Borrowed(core::any::type_name::<T>()),
|
name: DebugName::type_name::<T>(),
|
||||||
// PERF: `SparseStorage` may actually be a more
|
// PERF: `SparseStorage` may actually be a more
|
||||||
// reasonable choice as `storage_type` for resources.
|
// reasonable choice as `storage_type` for resources.
|
||||||
storage_type: StorageType::Table,
|
storage_type: StorageType::Table,
|
||||||
@ -938,7 +937,7 @@ impl ComponentDescriptor {
|
|||||||
|
|
||||||
fn new_non_send<T: Any>(storage_type: StorageType) -> Self {
|
fn new_non_send<T: Any>(storage_type: StorageType) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: Cow::Borrowed(core::any::type_name::<T>()),
|
name: DebugName::type_name::<T>(),
|
||||||
storage_type,
|
storage_type,
|
||||||
is_send_and_sync: false,
|
is_send_and_sync: false,
|
||||||
type_id: Some(TypeId::of::<T>()),
|
type_id: Some(TypeId::of::<T>()),
|
||||||
@ -964,8 +963,8 @@ impl ComponentDescriptor {
|
|||||||
|
|
||||||
/// Returns the name of the current component.
|
/// Returns the name of the current component.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> DebugName {
|
||||||
self.name.as_ref()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this component is mutable.
|
/// Returns whether this component is mutable.
|
||||||
@ -1854,13 +1853,10 @@ impl Components {
|
|||||||
///
|
///
|
||||||
/// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value.
|
/// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_name<'a>(&'a self, id: ComponentId) -> Option<Cow<'a, str>> {
|
pub fn get_name<'a>(&'a self, id: ComponentId) -> Option<DebugName> {
|
||||||
self.components
|
self.components
|
||||||
.get(id.0)
|
.get(id.0)
|
||||||
.and_then(|info| {
|
.and_then(|info| info.as_ref().map(|info| info.descriptor.name()))
|
||||||
info.as_ref()
|
|
||||||
.map(|info| Cow::Borrowed(info.descriptor.name()))
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);
|
let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);
|
||||||
// first check components, then resources, then dynamic
|
// first check components, then resources, then dynamic
|
||||||
@ -2813,13 +2809,13 @@ pub fn enforce_no_required_components_recursion(
|
|||||||
"Recursive required components detected: {}\nhelp: {}",
|
"Recursive required components detected: {}\nhelp: {}",
|
||||||
recursion_check_stack
|
recursion_check_stack
|
||||||
.iter()
|
.iter()
|
||||||
.map(|id| format!("{}", ShortName(&components.get_name(*id).unwrap())))
|
.map(|id| format!("{}", components.get_name(*id).unwrap().shortname()))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(" → "),
|
.join(" → "),
|
||||||
if direct_recursion {
|
if direct_recursion {
|
||||||
format!(
|
format!(
|
||||||
"Remove require({}).",
|
"Remove require({}).",
|
||||||
ShortName(&components.get_name(requiree).unwrap())
|
components.get_name(requiree).unwrap().shortname()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
"If this is intentional, consider merging the components.".into()
|
"If this is intentional, consider merging the components.".into()
|
||||||
|
|||||||
@ -10,6 +10,7 @@ use crate::{
|
|||||||
use alloc::{borrow::ToOwned, boxed::Box, collections::VecDeque, vec::Vec};
|
use alloc::{borrow::ToOwned, boxed::Box, collections::VecDeque, vec::Vec};
|
||||||
use bevy_platform::collections::{HashMap, HashSet};
|
use bevy_platform::collections::{HashMap, HashSet};
|
||||||
use bevy_ptr::{Ptr, PtrMut};
|
use bevy_ptr::{Ptr, PtrMut};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use core::any::TypeId;
|
use core::any::TypeId;
|
||||||
|
|
||||||
@ -172,7 +173,8 @@ impl<'a, 'b> ComponentCloneCtx<'a, 'b> {
|
|||||||
/// - `ComponentId` of component being written does not match expected `ComponentId`.
|
/// - `ComponentId` of component being written does not match expected `ComponentId`.
|
||||||
pub fn write_target_component<C: Component>(&mut self, mut component: C) {
|
pub fn write_target_component<C: Component>(&mut self, mut component: C) {
|
||||||
C::map_entities(&mut component, &mut self.mapper);
|
C::map_entities(&mut component, &mut self.mapper);
|
||||||
let short_name = disqualified::ShortName::of::<C>();
|
let debug_name = DebugName::type_name::<C>();
|
||||||
|
let short_name = debug_name.shortname();
|
||||||
if self.target_component_written {
|
if self.target_component_written {
|
||||||
panic!("Trying to write component '{short_name}' multiple times")
|
panic!("Trying to write component '{short_name}' multiple times")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use core::{any::type_name, fmt};
|
use core::fmt;
|
||||||
|
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
@ -31,7 +33,7 @@ where
|
|||||||
Err(err) => (error_handler)(
|
Err(err) => (error_handler)(
|
||||||
err.into(),
|
err.into(),
|
||||||
ErrorContext::Command {
|
ErrorContext::Command {
|
||||||
name: type_name::<C>().into(),
|
name: DebugName::type_name::<C>(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@ -43,7 +45,7 @@ where
|
|||||||
Err(err) => world.default_error_handler()(
|
Err(err) => world.default_error_handler()(
|
||||||
err.into(),
|
err.into(),
|
||||||
ErrorContext::Command {
|
ErrorContext::Command {
|
||||||
name: type_name::<C>().into(),
|
name: DebugName::type_name::<C>(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use core::fmt::Display;
|
use core::fmt::Display;
|
||||||
|
|
||||||
use crate::{component::Tick, error::BevyError, prelude::Resource};
|
use crate::{component::Tick, error::BevyError, prelude::Resource};
|
||||||
use alloc::borrow::Cow;
|
use bevy_utils::prelude::DebugName;
|
||||||
use derive_more::derive::{Deref, DerefMut};
|
use derive_more::derive::{Deref, DerefMut};
|
||||||
|
|
||||||
/// Context for a [`BevyError`] to aid in debugging.
|
/// Context for a [`BevyError`] to aid in debugging.
|
||||||
@ -10,26 +10,26 @@ pub enum ErrorContext {
|
|||||||
/// The error occurred in a system.
|
/// The error occurred in a system.
|
||||||
System {
|
System {
|
||||||
/// The name of the system that failed.
|
/// The name of the system that failed.
|
||||||
name: Cow<'static, str>,
|
name: DebugName,
|
||||||
/// The last tick that the system was run.
|
/// The last tick that the system was run.
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
},
|
},
|
||||||
/// The error occurred in a run condition.
|
/// The error occurred in a run condition.
|
||||||
RunCondition {
|
RunCondition {
|
||||||
/// The name of the run condition that failed.
|
/// The name of the run condition that failed.
|
||||||
name: Cow<'static, str>,
|
name: DebugName,
|
||||||
/// The last tick that the run condition was evaluated.
|
/// The last tick that the run condition was evaluated.
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
},
|
},
|
||||||
/// The error occurred in a command.
|
/// The error occurred in a command.
|
||||||
Command {
|
Command {
|
||||||
/// The name of the command that failed.
|
/// The name of the command that failed.
|
||||||
name: Cow<'static, str>,
|
name: DebugName,
|
||||||
},
|
},
|
||||||
/// The error occurred in an observer.
|
/// The error occurred in an observer.
|
||||||
Observer {
|
Observer {
|
||||||
/// The name of the observer that failed.
|
/// The name of the observer that failed.
|
||||||
name: Cow<'static, str>,
|
name: DebugName,
|
||||||
/// The last tick that the observer was run.
|
/// The last tick that the observer was run.
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
},
|
},
|
||||||
@ -54,12 +54,12 @@ impl Display for ErrorContext {
|
|||||||
|
|
||||||
impl ErrorContext {
|
impl ErrorContext {
|
||||||
/// The name of the ECS construct that failed.
|
/// The name of the ECS construct that failed.
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> DebugName {
|
||||||
match self {
|
match self {
|
||||||
Self::System { name, .. }
|
Self::System { name, .. }
|
||||||
| Self::Command { name, .. }
|
| Self::Command { name, .. }
|
||||||
| Self::Observer { name, .. }
|
| Self::Observer { name, .. }
|
||||||
| Self::RunCondition { name, .. } => name,
|
| Self::RunCondition { name, .. } => name.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,9 +22,9 @@ use alloc::{format, string::String, vec::Vec};
|
|||||||
use bevy_reflect::std_traits::ReflectDefault;
|
use bevy_reflect::std_traits::ReflectDefault;
|
||||||
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
|
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
|
||||||
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use disqualified::ShortName;
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
||||||
/// Stores the parent entity of this child entity with this component.
|
/// Stores the parent entity of this child entity with this component.
|
||||||
@ -461,11 +461,12 @@ pub fn validate_parent_has_component<C: Component>(
|
|||||||
{
|
{
|
||||||
// TODO: print name here once Name lives in bevy_ecs
|
// TODO: print name here once Name lives in bevy_ecs
|
||||||
let name: Option<String> = None;
|
let name: Option<String> = None;
|
||||||
|
let debug_name = DebugName::type_name::<C>();
|
||||||
warn!(
|
warn!(
|
||||||
"warning[B0004]: {}{name} with the {ty_name} component has a parent without {ty_name}.\n\
|
"warning[B0004]: {}{name} with the {ty_name} component has a parent without {ty_name}.\n\
|
||||||
This will cause inconsistent behaviors! See: https://bevy.org/learn/errors/b0004",
|
This will cause inconsistent behaviors! See: https://bevy.org/learn/errors/b0004",
|
||||||
caller.map(|c| format!("{c}: ")).unwrap_or_default(),
|
caller.map(|c| format!("{c}: ")).unwrap_or_default(),
|
||||||
ty_name = ShortName::of::<C>(),
|
ty_name = debug_name.shortname(),
|
||||||
name = name.map_or_else(
|
name = name.map_or_else(
|
||||||
|| format!("Entity {entity}"),
|
|| format!("Entity {entity}"),
|
||||||
|s| format!("The {s} entity")
|
|s| format!("The {s} entity")
|
||||||
|
|||||||
@ -328,7 +328,7 @@ pub const DESPAWN: ComponentId = ComponentId::new(4);
|
|||||||
/// Trigger emitted when a component is inserted onto an entity that does not already have that
|
/// Trigger emitted when a component is inserted onto an entity that does not already have that
|
||||||
/// component. Runs before `Insert`.
|
/// component. Runs before `Insert`.
|
||||||
/// See [`crate::lifecycle::ComponentHooks::on_add`] for more information.
|
/// See [`crate::lifecycle::ComponentHooks::on_add`] for more information.
|
||||||
#[derive(Event, EntityEvent, Debug)]
|
#[derive(Event, EntityEvent, Debug, Clone)]
|
||||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
||||||
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
|
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
|
||||||
#[doc(alias = "OnAdd")]
|
#[doc(alias = "OnAdd")]
|
||||||
@ -337,7 +337,7 @@ pub struct Add;
|
|||||||
/// Trigger emitted when a component is inserted, regardless of whether or not the entity already
|
/// Trigger emitted when a component is inserted, regardless of whether or not the entity already
|
||||||
/// had that component. Runs after `Add`, if it ran.
|
/// had that component. Runs after `Add`, if it ran.
|
||||||
/// See [`crate::lifecycle::ComponentHooks::on_insert`] for more information.
|
/// See [`crate::lifecycle::ComponentHooks::on_insert`] for more information.
|
||||||
#[derive(Event, EntityEvent, Debug)]
|
#[derive(Event, EntityEvent, Debug, Clone)]
|
||||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
||||||
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
|
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
|
||||||
#[doc(alias = "OnInsert")]
|
#[doc(alias = "OnInsert")]
|
||||||
@ -348,7 +348,7 @@ pub struct Insert;
|
|||||||
///
|
///
|
||||||
/// Runs before the value is replaced, so you can still access the original component data.
|
/// Runs before the value is replaced, so you can still access the original component data.
|
||||||
/// See [`crate::lifecycle::ComponentHooks::on_replace`] for more information.
|
/// See [`crate::lifecycle::ComponentHooks::on_replace`] for more information.
|
||||||
#[derive(Event, EntityEvent, Debug)]
|
#[derive(Event, EntityEvent, Debug, Clone)]
|
||||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
||||||
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
|
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
|
||||||
#[doc(alias = "OnReplace")]
|
#[doc(alias = "OnReplace")]
|
||||||
@ -357,7 +357,7 @@ pub struct Replace;
|
|||||||
/// Trigger emitted when a component is removed from an entity, and runs before the component is
|
/// Trigger emitted when a component is removed from an entity, and runs before the component is
|
||||||
/// removed, so you can still access the component data.
|
/// removed, so you can still access the component data.
|
||||||
/// See [`crate::lifecycle::ComponentHooks::on_remove`] for more information.
|
/// See [`crate::lifecycle::ComponentHooks::on_remove`] for more information.
|
||||||
#[derive(Event, EntityEvent, Debug)]
|
#[derive(Event, EntityEvent, Debug, Clone)]
|
||||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
||||||
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
|
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
|
||||||
#[doc(alias = "OnRemove")]
|
#[doc(alias = "OnRemove")]
|
||||||
@ -365,7 +365,7 @@ pub struct Remove;
|
|||||||
|
|
||||||
/// Trigger emitted for each component on an entity when it is despawned.
|
/// Trigger emitted for each component on an entity when it is despawned.
|
||||||
/// See [`crate::lifecycle::ComponentHooks::on_despawn`] for more information.
|
/// See [`crate::lifecycle::ComponentHooks::on_despawn`] for more information.
|
||||||
#[derive(Event, EntityEvent, Debug)]
|
#[derive(Event, EntityEvent, Debug, Clone)]
|
||||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
||||||
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
|
#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
|
||||||
#[doc(alias = "OnDespawn")]
|
#[doc(alias = "OnDespawn")]
|
||||||
|
|||||||
@ -141,7 +141,7 @@ pub struct NameOrEntity {
|
|||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> core::fmt::Display for NameOrEntityItem<'a> {
|
impl<'w, 's> core::fmt::Display for NameOrEntityItem<'w, 's> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
match self.name {
|
match self.name {
|
||||||
@ -274,9 +274,9 @@ mod tests {
|
|||||||
let e2 = world.spawn(name.clone()).id();
|
let e2 = world.spawn(name.clone()).id();
|
||||||
let mut query = world.query::<NameOrEntity>();
|
let mut query = world.query::<NameOrEntity>();
|
||||||
let d1 = query.get(&world, e1).unwrap();
|
let d1 = query.get(&world, e1).unwrap();
|
||||||
let d2 = query.get(&world, e2).unwrap();
|
|
||||||
// NameOrEntity Display for entities without a Name should be {index}v{generation}
|
// NameOrEntity Display for entities without a Name should be {index}v{generation}
|
||||||
assert_eq!(d1.to_string(), "0v0");
|
assert_eq!(d1.to_string(), "0v0");
|
||||||
|
let d2 = query.get(&world, e2).unwrap();
|
||||||
// NameOrEntity Display for entities with a Name should be the Name
|
// NameOrEntity Display for entities with a Name should be the Name
|
||||||
assert_eq!(d2.to_string(), "MyName");
|
assert_eq!(d2.to_string(), "MyName");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -97,7 +97,7 @@ fn component_clone_observed_by(_source: &SourceComponent, ctx: &mut ComponentClo
|
|||||||
let event_types = observer_state.descriptor.events.clone();
|
let event_types = observer_state.descriptor.events.clone();
|
||||||
let components = observer_state.descriptor.components.clone();
|
let components = observer_state.descriptor.components.clone();
|
||||||
for event_type in event_types {
|
for event_type in event_types {
|
||||||
let observers = world.observers.get_observers(event_type);
|
let observers = world.observers.get_observers_mut(event_type);
|
||||||
if components.is_empty() {
|
if components.is_empty() {
|
||||||
if let Some(map) = observers.entity_observers.get(&source).cloned() {
|
if let Some(map) = observers.entity_observers.get(&source).cloned() {
|
||||||
observers.entity_observers.insert(target, map);
|
observers.entity_observers.insert(target, map);
|
||||||
@ -108,8 +108,10 @@ fn component_clone_observed_by(_source: &SourceComponent, ctx: &mut ComponentClo
|
|||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if let Some(map) = observers.entity_map.get(&source).cloned() {
|
if let Some(map) =
|
||||||
observers.entity_map.insert(target, map);
|
observers.entity_component_observers.get(&source).cloned()
|
||||||
|
{
|
||||||
|
observers.entity_component_observers.insert(target, map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -515,40 +515,72 @@ impl ObserverTrigger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map between an observer entity and its runner
|
/// Map between an observer entity and its [`ObserverRunner`]
|
||||||
type ObserverMap = EntityHashMap<ObserverRunner>;
|
pub type ObserverMap = EntityHashMap<ObserverRunner>;
|
||||||
|
|
||||||
/// Collection of [`ObserverRunner`] for [`Observer`] registered to a particular trigger targeted at a specific component.
|
/// Collection of [`ObserverRunner`] for [`Observer`] registered to a particular event targeted at a specific component.
|
||||||
///
|
///
|
||||||
/// This is stored inside of [`CachedObservers`].
|
/// This is stored inside of [`CachedObservers`].
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct CachedComponentObservers {
|
pub struct CachedComponentObservers {
|
||||||
// Observers listening to triggers targeting this component
|
// Observers listening to events targeting this component, but not a specific entity
|
||||||
map: ObserverMap,
|
global_observers: ObserverMap,
|
||||||
// Observers listening to triggers targeting this component on a specific entity
|
// Observers listening to events targeting this component on a specific entity
|
||||||
entity_map: EntityHashMap<ObserverMap>,
|
entity_component_observers: EntityHashMap<ObserverMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collection of [`ObserverRunner`] for [`Observer`] registered to a particular trigger.
|
impl CachedComponentObservers {
|
||||||
|
/// Returns the observers listening for this trigger, regardless of target.
|
||||||
|
/// These observers will also respond to events targeting specific entities.
|
||||||
|
pub fn global_observers(&self) -> &ObserverMap {
|
||||||
|
&self.global_observers
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the observers listening for this trigger targeting this component on a specific entity.
|
||||||
|
pub fn entity_component_observers(&self) -> &EntityHashMap<ObserverMap> {
|
||||||
|
&self.entity_component_observers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collection of [`ObserverRunner`] for [`Observer`] registered to a particular event.
|
||||||
///
|
///
|
||||||
/// This is stored inside of [`Observers`], specialized for each kind of observer.
|
/// This is stored inside of [`Observers`], specialized for each kind of observer.
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct CachedObservers {
|
pub struct CachedObservers {
|
||||||
// Observers listening for any time this trigger is fired
|
// Observers listening for any time this event is fired, regardless of target
|
||||||
map: ObserverMap,
|
// This will also respond to events targeting specific components or entities
|
||||||
|
global_observers: ObserverMap,
|
||||||
// Observers listening for this trigger fired at a specific component
|
// Observers listening for this trigger fired at a specific component
|
||||||
component_observers: HashMap<ComponentId, CachedComponentObservers>,
|
component_observers: HashMap<ComponentId, CachedComponentObservers>,
|
||||||
// Observers listening for this trigger fired at a specific entity
|
// Observers listening for this trigger fired at a specific entity
|
||||||
entity_observers: EntityHashMap<ObserverMap>,
|
entity_observers: EntityHashMap<ObserverMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CachedObservers {
|
||||||
|
/// Returns the observers listening for this trigger, regardless of target.
|
||||||
|
/// These observers will also respond to events targeting specific components or entities.
|
||||||
|
pub fn global_observers(&self) -> &ObserverMap {
|
||||||
|
&self.global_observers
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the observers listening for this trigger targeting components.
|
||||||
|
pub fn get_component_observers(&self) -> &HashMap<ComponentId, CachedComponentObservers> {
|
||||||
|
&self.component_observers
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the observers listening for this trigger targeting entities.
|
||||||
|
pub fn entity_observers(&self) -> &HashMap<ComponentId, CachedComponentObservers> {
|
||||||
|
&self.component_observers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An internal lookup table tracking all of the observers in the world.
|
/// An internal lookup table tracking all of the observers in the world.
|
||||||
///
|
///
|
||||||
/// Stores a cache mapping trigger ids to the registered observers.
|
/// Stores a cache mapping trigger ids to the registered observers.
|
||||||
/// Some observer kinds (like [lifecycle](crate::lifecycle) observers) have a dedicated field,
|
/// Some observer kinds (like [lifecycle](crate::lifecycle) observers) have a dedicated field,
|
||||||
/// saving lookups for the most common triggers.
|
/// saving lookups for the most common triggers.
|
||||||
///
|
///
|
||||||
/// This is stored as a field of the [`World`].
|
/// This can be accessed via [`World::observers`].
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct Observers {
|
pub struct Observers {
|
||||||
// Cached ECS observers to save a lookup most common triggers.
|
// Cached ECS observers to save a lookup most common triggers.
|
||||||
@ -562,7 +594,7 @@ pub struct Observers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Observers {
|
impl Observers {
|
||||||
pub(crate) fn get_observers(&mut self, event_type: ComponentId) -> &mut CachedObservers {
|
pub(crate) fn get_observers_mut(&mut self, event_type: ComponentId) -> &mut CachedObservers {
|
||||||
use crate::lifecycle::*;
|
use crate::lifecycle::*;
|
||||||
|
|
||||||
match event_type {
|
match event_type {
|
||||||
@ -575,7 +607,11 @@ impl Observers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn try_get_observers(&self, event_type: ComponentId) -> Option<&CachedObservers> {
|
/// Attempts to get the observers for the given `event_type`.
|
||||||
|
///
|
||||||
|
/// When accessing the observers for lifecycle events, such as [`Add`], [`Insert`], [`Replace`], [`Remove`], and [`Despawn`],
|
||||||
|
/// use the [`ComponentId`] constants from the [`lifecycle`](crate::lifecycle) module.
|
||||||
|
pub fn try_get_observers(&self, event_type: ComponentId) -> Option<&CachedObservers> {
|
||||||
use crate::lifecycle::*;
|
use crate::lifecycle::*;
|
||||||
|
|
||||||
match event_type {
|
match event_type {
|
||||||
@ -630,7 +666,10 @@ impl Observers {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
// Trigger observers listening for any kind of this trigger
|
// Trigger observers listening for any kind of this trigger
|
||||||
observers.map.iter().for_each(&mut trigger_observer);
|
observers
|
||||||
|
.global_observers
|
||||||
|
.iter()
|
||||||
|
.for_each(&mut trigger_observer);
|
||||||
|
|
||||||
// Trigger entity observers listening for this kind of trigger
|
// Trigger entity observers listening for this kind of trigger
|
||||||
if let Some(target_entity) = current_target {
|
if let Some(target_entity) = current_target {
|
||||||
@ -643,12 +682,15 @@ impl Observers {
|
|||||||
trigger_for_components.for_each(|id| {
|
trigger_for_components.for_each(|id| {
|
||||||
if let Some(component_observers) = observers.component_observers.get(&id) {
|
if let Some(component_observers) = observers.component_observers.get(&id) {
|
||||||
component_observers
|
component_observers
|
||||||
.map
|
.global_observers
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(&mut trigger_observer);
|
.for_each(&mut trigger_observer);
|
||||||
|
|
||||||
if let Some(target_entity) = current_target {
|
if let Some(target_entity) = current_target {
|
||||||
if let Some(map) = component_observers.entity_map.get(&target_entity) {
|
if let Some(map) = component_observers
|
||||||
|
.entity_component_observers
|
||||||
|
.get(&target_entity)
|
||||||
|
{
|
||||||
map.iter().for_each(&mut trigger_observer);
|
map.iter().for_each(&mut trigger_observer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -926,10 +968,12 @@ impl World {
|
|||||||
let descriptor = &observer_state.descriptor;
|
let descriptor = &observer_state.descriptor;
|
||||||
|
|
||||||
for &event_type in &descriptor.events {
|
for &event_type in &descriptor.events {
|
||||||
let cache = observers.get_observers(event_type);
|
let cache = observers.get_observers_mut(event_type);
|
||||||
|
|
||||||
if descriptor.components.is_empty() && descriptor.entities.is_empty() {
|
if descriptor.components.is_empty() && descriptor.entities.is_empty() {
|
||||||
cache.map.insert(observer_entity, observer_state.runner);
|
cache
|
||||||
|
.global_observers
|
||||||
|
.insert(observer_entity, observer_state.runner);
|
||||||
} else if descriptor.components.is_empty() {
|
} else if descriptor.components.is_empty() {
|
||||||
// Observer is not targeting any components so register it as an entity observer
|
// Observer is not targeting any components so register it as an entity observer
|
||||||
for &watched_entity in &observer_state.descriptor.entities {
|
for &watched_entity in &observer_state.descriptor.entities {
|
||||||
@ -951,11 +995,16 @@ impl World {
|
|||||||
});
|
});
|
||||||
if descriptor.entities.is_empty() {
|
if descriptor.entities.is_empty() {
|
||||||
// Register for all triggers targeting the component
|
// Register for all triggers targeting the component
|
||||||
observers.map.insert(observer_entity, observer_state.runner);
|
observers
|
||||||
|
.global_observers
|
||||||
|
.insert(observer_entity, observer_state.runner);
|
||||||
} else {
|
} else {
|
||||||
// Register for each watched entity
|
// Register for each watched entity
|
||||||
for &watched_entity in &descriptor.entities {
|
for &watched_entity in &descriptor.entities {
|
||||||
let map = observers.entity_map.entry(watched_entity).or_default();
|
let map = observers
|
||||||
|
.entity_component_observers
|
||||||
|
.entry(watched_entity)
|
||||||
|
.or_default();
|
||||||
map.insert(observer_entity, observer_state.runner);
|
map.insert(observer_entity, observer_state.runner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -970,9 +1019,9 @@ impl World {
|
|||||||
let observers = &mut self.observers;
|
let observers = &mut self.observers;
|
||||||
|
|
||||||
for &event_type in &descriptor.events {
|
for &event_type in &descriptor.events {
|
||||||
let cache = observers.get_observers(event_type);
|
let cache = observers.get_observers_mut(event_type);
|
||||||
if descriptor.components.is_empty() && descriptor.entities.is_empty() {
|
if descriptor.components.is_empty() && descriptor.entities.is_empty() {
|
||||||
cache.map.remove(&entity);
|
cache.global_observers.remove(&entity);
|
||||||
} else if descriptor.components.is_empty() {
|
} else if descriptor.components.is_empty() {
|
||||||
for watched_entity in &descriptor.entities {
|
for watched_entity in &descriptor.entities {
|
||||||
// This check should be unnecessary since this observer hasn't been unregistered yet
|
// This check should be unnecessary since this observer hasn't been unregistered yet
|
||||||
@ -990,20 +1039,24 @@ impl World {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if descriptor.entities.is_empty() {
|
if descriptor.entities.is_empty() {
|
||||||
observers.map.remove(&entity);
|
observers.global_observers.remove(&entity);
|
||||||
} else {
|
} else {
|
||||||
for watched_entity in &descriptor.entities {
|
for watched_entity in &descriptor.entities {
|
||||||
let Some(map) = observers.entity_map.get_mut(watched_entity) else {
|
let Some(map) =
|
||||||
|
observers.entity_component_observers.get_mut(watched_entity)
|
||||||
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
map.remove(&entity);
|
map.remove(&entity);
|
||||||
if map.is_empty() {
|
if map.is_empty() {
|
||||||
observers.entity_map.remove(watched_entity);
|
observers.entity_component_observers.remove(watched_entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if observers.map.is_empty() && observers.entity_map.is_empty() {
|
if observers.global_observers.is_empty()
|
||||||
|
&& observers.entity_component_observers.is_empty()
|
||||||
|
{
|
||||||
cache.component_observers.remove(component);
|
cache.component_observers.remove(component);
|
||||||
if let Some(flag) = Observers::is_archetype_cached(event_type) {
|
if let Some(flag) = Observers::is_archetype_cached(event_type) {
|
||||||
if let Some(by_component) = archetypes.by_component.get(component) {
|
if let Some(by_component) = archetypes.by_component.get(component) {
|
||||||
@ -1078,7 +1131,7 @@ mod tests {
|
|||||||
struct ChildOf(Entity);
|
struct ChildOf(Entity);
|
||||||
|
|
||||||
impl<D> Traversal<D> for &'_ ChildOf {
|
impl<D> Traversal<D> for &'_ ChildOf {
|
||||||
fn traverse(item: Self::Item<'_>, _: &D) -> Option<Entity> {
|
fn traverse(item: Self::Item<'_, '_>, _: &D) -> Option<Entity> {
|
||||||
Some(item.0)
|
Some(item.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use alloc::{boxed::Box, vec};
|
use alloc::{boxed::Box, vec};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -194,7 +195,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
|
|||||||
pub struct Observer {
|
pub struct Observer {
|
||||||
hook_on_add: ComponentHook,
|
hook_on_add: ComponentHook,
|
||||||
error_handler: Option<ErrorHandler>,
|
error_handler: Option<ErrorHandler>,
|
||||||
system: Box<dyn Any + Send + Sync + 'static>,
|
system: Box<dyn AnyNamedSystem>,
|
||||||
pub(crate) descriptor: ObserverDescriptor,
|
pub(crate) descriptor: ObserverDescriptor,
|
||||||
pub(crate) last_trigger_id: u32,
|
pub(crate) last_trigger_id: u32,
|
||||||
pub(crate) despawned_watched_entities: u32,
|
pub(crate) despawned_watched_entities: u32,
|
||||||
@ -232,7 +233,7 @@ impl Observer {
|
|||||||
/// Creates a new [`Observer`] with custom runner, this is mostly used for dynamic event observer
|
/// Creates a new [`Observer`] with custom runner, this is mostly used for dynamic event observer
|
||||||
pub fn with_dynamic_runner(runner: ObserverRunner) -> Self {
|
pub fn with_dynamic_runner(runner: ObserverRunner) -> Self {
|
||||||
Self {
|
Self {
|
||||||
system: Box::new(|| {}),
|
system: Box::new(IntoSystem::into_system(|| {})),
|
||||||
descriptor: Default::default(),
|
descriptor: Default::default(),
|
||||||
hook_on_add: |mut world, hook_context| {
|
hook_on_add: |mut world, hook_context| {
|
||||||
let default_error_handler = world.default_error_handler();
|
let default_error_handler = world.default_error_handler();
|
||||||
@ -299,6 +300,11 @@ impl Observer {
|
|||||||
pub fn descriptor(&self) -> &ObserverDescriptor {
|
pub fn descriptor(&self) -> &ObserverDescriptor {
|
||||||
&self.descriptor
|
&self.descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the name of the [`Observer`]'s system .
|
||||||
|
pub fn system_name(&self) -> DebugName {
|
||||||
|
self.system.system_name()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Observer {
|
impl Component for Observer {
|
||||||
@ -364,7 +370,8 @@ fn observer_system_runner<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
|
|||||||
// - observer was triggered so must have an `Observer` component.
|
// - observer was triggered so must have an `Observer` component.
|
||||||
// - observer cannot be dropped or mutated until after the system pointer is already dropped.
|
// - observer cannot be dropped or mutated until after the system pointer is already dropped.
|
||||||
let system: *mut dyn ObserverSystem<E, B> = unsafe {
|
let system: *mut dyn ObserverSystem<E, B> = unsafe {
|
||||||
let system = state.system.downcast_mut::<S>().debug_checked_unwrap();
|
let system: &mut dyn Any = state.system.as_mut();
|
||||||
|
let system = system.downcast_mut::<S>().debug_checked_unwrap();
|
||||||
&mut *system
|
&mut *system
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -413,6 +420,16 @@ fn observer_system_runner<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait AnyNamedSystem: Any + Send + Sync + 'static {
|
||||||
|
fn system_name(&self) -> DebugName;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Any + System> AnyNamedSystem for T {
|
||||||
|
fn system_name(&self) -> DebugName {
|
||||||
|
self.name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A [`ComponentHook`] used by [`Observer`] to handle its [`on-add`](`crate::lifecycle::ComponentHooks::on_add`).
|
/// A [`ComponentHook`] used by [`Observer`] to handle its [`on-add`](`crate::lifecycle::ComponentHooks::on_add`).
|
||||||
///
|
///
|
||||||
/// This function exists separate from [`Observer`] to allow [`Observer`] to have its type parameters
|
/// This function exists separate from [`Observer`] to allow [`Observer`] to have its type parameters
|
||||||
@ -431,11 +448,12 @@ fn hook_on_add<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
|
|||||||
B::component_ids(&mut world.components_registrator(), &mut |id| {
|
B::component_ids(&mut world.components_registrator(), &mut |id| {
|
||||||
components.push(id);
|
components.push(id);
|
||||||
});
|
});
|
||||||
if let Some(mut observe) = world.get_mut::<Observer>(entity) {
|
if let Some(mut observer) = world.get_mut::<Observer>(entity) {
|
||||||
observe.descriptor.events.push(event_id);
|
observer.descriptor.events.push(event_id);
|
||||||
observe.descriptor.components.extend(components);
|
observer.descriptor.components.extend(components);
|
||||||
|
|
||||||
let system: *mut dyn ObserverSystem<E, B> = observe.system.downcast_mut::<S>().unwrap();
|
let system: &mut dyn Any = observer.system.as_mut();
|
||||||
|
let system: *mut dyn ObserverSystem<E, B> = system.downcast_mut::<S>().unwrap();
|
||||||
// SAFETY: World reference is exclusive and initialize does not touch system, so references do not alias
|
// SAFETY: World reference is exclusive and initialize does not touch system, so references do not alias
|
||||||
unsafe {
|
unsafe {
|
||||||
(*system).initialize(world);
|
(*system).initialize(world);
|
||||||
|
|||||||
@ -4,7 +4,6 @@ use crate::world::World;
|
|||||||
use alloc::{format, string::String, vec, vec::Vec};
|
use alloc::{format, string::String, vec, vec::Vec};
|
||||||
use core::{fmt, fmt::Debug, marker::PhantomData};
|
use core::{fmt, fmt::Debug, marker::PhantomData};
|
||||||
use derive_more::From;
|
use derive_more::From;
|
||||||
use disqualified::ShortName;
|
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@ -999,12 +998,11 @@ impl AccessConflicts {
|
|||||||
.map(|index| {
|
.map(|index| {
|
||||||
format!(
|
format!(
|
||||||
"{}",
|
"{}",
|
||||||
ShortName(
|
world
|
||||||
&world
|
|
||||||
.components
|
.components
|
||||||
.get_name(ComponentId::get_sparse_set_index(index))
|
.get_name(ComponentId::get_sparse_set_index(index))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
)
|
.shortname()
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
archetype::ArchetypeId,
|
archetype::ArchetypeId,
|
||||||
entity::{ConstructedEntityDoesNotExistError, Entity},
|
entity::{ConstructedEntityDoesNotExistError, Entity},
|
||||||
@ -28,10 +31,10 @@ pub enum QueryEntityError {
|
|||||||
pub enum QuerySingleError {
|
pub enum QuerySingleError {
|
||||||
/// No entity fits the query.
|
/// No entity fits the query.
|
||||||
#[error("No entities fit the query {0}")]
|
#[error("No entities fit the query {0}")]
|
||||||
NoEntities(&'static str),
|
NoEntities(DebugName),
|
||||||
/// Multiple entities fit the query.
|
/// Multiple entities fit the query.
|
||||||
#[error("Multiple entities fit the query {0}")]
|
#[error("Multiple entities fit the query {0}")]
|
||||||
MultipleEntities(&'static str),
|
MultipleEntities(DebugName),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,7 @@ use crate::{
|
|||||||
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
||||||
};
|
};
|
||||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::{cell::UnsafeCell, marker::PhantomData};
|
use core::{cell::UnsafeCell, marker::PhantomData};
|
||||||
use variadics_please::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
@ -103,6 +104,7 @@ pub unsafe trait QueryFilter: WorldQuery {
|
|||||||
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
|
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
|
||||||
/// `table_row` must be in the range of the current table and archetype.
|
/// `table_row` must be in the range of the current table and archetype.
|
||||||
unsafe fn filter_fetch(
|
unsafe fn filter_fetch(
|
||||||
|
state: &Self::State,
|
||||||
fetch: &mut Self::Fetch<'_>,
|
fetch: &mut Self::Fetch<'_>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
table_row: TableRow,
|
table_row: TableRow,
|
||||||
@ -204,6 +206,7 @@ unsafe impl<T: Component> QueryFilter for With<T> {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn filter_fetch(
|
unsafe fn filter_fetch(
|
||||||
|
_state: &Self::State,
|
||||||
_fetch: &mut Self::Fetch<'_>,
|
_fetch: &mut Self::Fetch<'_>,
|
||||||
_entity: Entity,
|
_entity: Entity,
|
||||||
_table_row: TableRow,
|
_table_row: TableRow,
|
||||||
@ -304,6 +307,7 @@ unsafe impl<T: Component> QueryFilter for Without<T> {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn filter_fetch(
|
unsafe fn filter_fetch(
|
||||||
|
_state: &Self::State,
|
||||||
_fetch: &mut Self::Fetch<'_>,
|
_fetch: &mut Self::Fetch<'_>,
|
||||||
_entity: Entity,
|
_entity: Entity,
|
||||||
_table_row: TableRow,
|
_table_row: TableRow,
|
||||||
@ -400,7 +404,7 @@ macro_rules! impl_or_query_filter {
|
|||||||
const IS_DENSE: bool = true $(&& $filter::IS_DENSE)*;
|
const IS_DENSE: bool = true $(&& $filter::IS_DENSE)*;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
unsafe fn init_fetch<'w, 's>(world: UnsafeWorldCell<'w>, state: &'s Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
||||||
let ($($filter,)*) = state;
|
let ($($filter,)*) = state;
|
||||||
($(OrFetch {
|
($(OrFetch {
|
||||||
// SAFETY: The invariants are upheld by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
@ -410,7 +414,7 @@ macro_rules! impl_or_query_filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
|
unsafe fn set_table<'w, 's>(fetch: &mut Self::Fetch<'w>, state: &'s Self::State, table: &'w Table) {
|
||||||
let ($($filter,)*) = fetch;
|
let ($($filter,)*) = fetch;
|
||||||
let ($($state,)*) = state;
|
let ($($state,)*) = state;
|
||||||
$(
|
$(
|
||||||
@ -423,9 +427,9 @@ macro_rules! impl_or_query_filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w, 's>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
state: & Self::State,
|
state: &'s Self::State,
|
||||||
archetype: &'w Archetype,
|
archetype: &'w Archetype,
|
||||||
table: &'w Table
|
table: &'w Table
|
||||||
) {
|
) {
|
||||||
@ -495,20 +499,22 @@ macro_rules! impl_or_query_filter {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn filter_fetch(
|
unsafe fn filter_fetch(
|
||||||
|
state: &Self::State,
|
||||||
fetch: &mut Self::Fetch<'_>,
|
fetch: &mut Self::Fetch<'_>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
table_row: TableRow
|
table_row: TableRow
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
let ($($state,)*) = state;
|
||||||
let ($($filter,)*) = fetch;
|
let ($($filter,)*) = fetch;
|
||||||
// SAFETY: The invariants are upheld by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
false $(|| ($filter.matches && unsafe { $filter::filter_fetch(&mut $filter.fetch, entity, table_row) }))*
|
false $(|| ($filter.matches && unsafe { $filter::filter_fetch($state, &mut $filter.fetch, entity, table_row) }))*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_tuple_query_filter {
|
macro_rules! impl_tuple_query_filter {
|
||||||
($(#[$meta:meta])* $($name: ident),*) => {
|
($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => {
|
||||||
#[expect(
|
#[expect(
|
||||||
clippy::allow_attributes,
|
clippy::allow_attributes,
|
||||||
reason = "This is a tuple-related macro; as such the lints below may not always apply."
|
reason = "This is a tuple-related macro; as such the lints below may not always apply."
|
||||||
@ -528,13 +534,15 @@ macro_rules! impl_tuple_query_filter {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn filter_fetch(
|
unsafe fn filter_fetch(
|
||||||
|
state: &Self::State,
|
||||||
fetch: &mut Self::Fetch<'_>,
|
fetch: &mut Self::Fetch<'_>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
table_row: TableRow
|
table_row: TableRow
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
let ($($state,)*) = state;
|
||||||
let ($($name,)*) = fetch;
|
let ($($name,)*) = fetch;
|
||||||
// SAFETY: The invariants are upheld by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
true $(&& unsafe { $name::filter_fetch($name, entity, table_row) })*
|
true $(&& unsafe { $name::filter_fetch($state, $name, entity, table_row) })*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,7 +554,8 @@ all_tuples!(
|
|||||||
impl_tuple_query_filter,
|
impl_tuple_query_filter,
|
||||||
0,
|
0,
|
||||||
15,
|
15,
|
||||||
F
|
F,
|
||||||
|
S
|
||||||
);
|
);
|
||||||
all_tuples!(
|
all_tuples!(
|
||||||
#[doc(fake_variadic)]
|
#[doc(fake_variadic)]
|
||||||
@ -609,7 +618,12 @@ unsafe impl<T: Component> QueryFilter for Allows<T> {
|
|||||||
const IS_ARCHETYPAL: bool = true;
|
const IS_ARCHETYPAL: bool = true;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn filter_fetch(_: &mut Self::Fetch<'_>, _: Entity, _: TableRow) -> bool {
|
unsafe fn filter_fetch(
|
||||||
|
_: &Self::State,
|
||||||
|
_: &mut Self::Fetch<'_>,
|
||||||
|
_: Entity,
|
||||||
|
_: TableRow,
|
||||||
|
) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -718,9 +732,9 @@ unsafe impl<T: Component> WorldQuery for Added<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w, 's>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
&id: &ComponentId,
|
&id: &'s ComponentId,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> Self::Fetch<'w> {
|
) -> Self::Fetch<'w> {
|
||||||
@ -748,9 +762,9 @@ unsafe impl<T: Component> WorldQuery for Added<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w, 's>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
component_id: &ComponentId,
|
component_id: &'s ComponentId,
|
||||||
_archetype: &'w Archetype,
|
_archetype: &'w Archetype,
|
||||||
table: &'w Table,
|
table: &'w Table,
|
||||||
) {
|
) {
|
||||||
@ -763,9 +777,9 @@ unsafe impl<T: Component> WorldQuery for Added<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table<'w>(
|
unsafe fn set_table<'w, 's>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
&component_id: &ComponentId,
|
&component_id: &'s ComponentId,
|
||||||
table: &'w Table,
|
table: &'w Table,
|
||||||
) {
|
) {
|
||||||
let table_ticks = Some(
|
let table_ticks = Some(
|
||||||
@ -781,7 +795,7 @@ unsafe impl<T: Component> WorldQuery for Added<T> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||||
if access.access().has_component_write(id) {
|
if access.access().has_component_write(id) {
|
||||||
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",core::any::type_name::<T>());
|
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", DebugName::type_name::<T>());
|
||||||
}
|
}
|
||||||
access.add_component_read(id);
|
access.add_component_read(id);
|
||||||
}
|
}
|
||||||
@ -807,6 +821,7 @@ unsafe impl<T: Component> QueryFilter for Added<T> {
|
|||||||
const IS_ARCHETYPAL: bool = false;
|
const IS_ARCHETYPAL: bool = false;
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn filter_fetch(
|
unsafe fn filter_fetch(
|
||||||
|
_state: &Self::State,
|
||||||
fetch: &mut Self::Fetch<'_>,
|
fetch: &mut Self::Fetch<'_>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
table_row: TableRow,
|
table_row: TableRow,
|
||||||
@ -944,9 +959,9 @@ unsafe impl<T: Component> WorldQuery for Changed<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w, 's>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
&id: &ComponentId,
|
&id: &'s ComponentId,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> Self::Fetch<'w> {
|
) -> Self::Fetch<'w> {
|
||||||
@ -974,9 +989,9 @@ unsafe impl<T: Component> WorldQuery for Changed<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w, 's>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
component_id: &ComponentId,
|
component_id: &'s ComponentId,
|
||||||
_archetype: &'w Archetype,
|
_archetype: &'w Archetype,
|
||||||
table: &'w Table,
|
table: &'w Table,
|
||||||
) {
|
) {
|
||||||
@ -989,9 +1004,9 @@ unsafe impl<T: Component> WorldQuery for Changed<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table<'w>(
|
unsafe fn set_table<'w, 's>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
&component_id: &ComponentId,
|
&component_id: &'s ComponentId,
|
||||||
table: &'w Table,
|
table: &'w Table,
|
||||||
) {
|
) {
|
||||||
let table_ticks = Some(
|
let table_ticks = Some(
|
||||||
@ -1007,7 +1022,7 @@ unsafe impl<T: Component> WorldQuery for Changed<T> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||||
if access.access().has_component_write(id) {
|
if access.access().has_component_write(id) {
|
||||||
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",core::any::type_name::<T>());
|
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", DebugName::type_name::<T>());
|
||||||
}
|
}
|
||||||
access.add_component_read(id);
|
access.add_component_read(id);
|
||||||
}
|
}
|
||||||
@ -1034,6 +1049,7 @@ unsafe impl<T: Component> QueryFilter for Changed<T> {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn filter_fetch(
|
unsafe fn filter_fetch(
|
||||||
|
_state: &Self::State,
|
||||||
fetch: &mut Self::Fetch<'_>,
|
fetch: &mut Self::Fetch<'_>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
table_row: TableRow,
|
table_row: TableRow,
|
||||||
@ -1141,9 +1157,9 @@ unsafe impl WorldQuery for Spawned {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w, 's>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
_state: &(),
|
_state: &'s (),
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> Self::Fetch<'w> {
|
) -> Self::Fetch<'w> {
|
||||||
@ -1157,16 +1173,16 @@ unsafe impl WorldQuery for Spawned {
|
|||||||
const IS_DENSE: bool = true;
|
const IS_DENSE: bool = true;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w, 's>(
|
||||||
_fetch: &mut Self::Fetch<'w>,
|
_fetch: &mut Self::Fetch<'w>,
|
||||||
_state: &(),
|
_state: &'s (),
|
||||||
_archetype: &'w Archetype,
|
_archetype: &'w Archetype,
|
||||||
_table: &'w Table,
|
_table: &'w Table,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &(), _table: &'w Table) {}
|
unsafe fn set_table<'w, 's>(_fetch: &mut Self::Fetch<'w>, _state: &'s (), _table: &'w Table) {}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn update_component_access(_state: &(), _access: &mut FilteredAccess<ComponentId>) {}
|
fn update_component_access(_state: &(), _access: &mut FilteredAccess<ComponentId>) {}
|
||||||
@ -1188,6 +1204,7 @@ unsafe impl QueryFilter for Spawned {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn filter_fetch(
|
unsafe fn filter_fetch(
|
||||||
|
_state: &Self::State,
|
||||||
fetch: &mut Self::Fetch<'_>,
|
fetch: &mut Self::Fetch<'_>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
_table_row: TableRow,
|
_table_row: TableRow,
|
||||||
|
|||||||
@ -140,7 +140,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
range: Option<Range<u32>>,
|
range: Option<Range<u32>>,
|
||||||
) -> B
|
) -> B
|
||||||
where
|
where
|
||||||
Func: FnMut(B, D::Item<'w>) -> B,
|
Func: FnMut(B, D::Item<'w, 's>) -> B,
|
||||||
{
|
{
|
||||||
if self.cursor.is_dense {
|
if self.cursor.is_dense {
|
||||||
// SAFETY: `self.cursor.is_dense` is true, so storage ids are guaranteed to be table ids.
|
// SAFETY: `self.cursor.is_dense` is true, so storage ids are guaranteed to be table ids.
|
||||||
@ -203,7 +203,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
rows: Range<u32>,
|
rows: Range<u32>,
|
||||||
) -> B
|
) -> B
|
||||||
where
|
where
|
||||||
Func: FnMut(B, D::Item<'w>) -> B,
|
Func: FnMut(B, D::Item<'w, 's>) -> B,
|
||||||
{
|
{
|
||||||
if table.is_empty() {
|
if table.is_empty() {
|
||||||
return accum;
|
return accum;
|
||||||
@ -225,14 +225,26 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
|
|
||||||
// SAFETY: set_table was called prior.
|
// SAFETY: set_table was called prior.
|
||||||
// Caller assures `row` in range of the current archetype.
|
// Caller assures `row` in range of the current archetype.
|
||||||
let fetched = unsafe { !F::filter_fetch(&mut self.cursor.filter, *entity, row) };
|
let fetched = unsafe {
|
||||||
|
!F::filter_fetch(
|
||||||
|
&self.query_state.filter_state,
|
||||||
|
&mut self.cursor.filter,
|
||||||
|
*entity,
|
||||||
|
row,
|
||||||
|
)
|
||||||
|
};
|
||||||
if fetched {
|
if fetched {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: set_table was called prior.
|
// SAFETY: set_table was called prior.
|
||||||
// Caller assures `row` in range of the current archetype.
|
// Caller assures `row` in range of the current archetype.
|
||||||
let item = D::fetch(&mut self.cursor.fetch, *entity, row);
|
let item = D::fetch(
|
||||||
|
&self.query_state.fetch_state,
|
||||||
|
&mut self.cursor.fetch,
|
||||||
|
*entity,
|
||||||
|
row,
|
||||||
|
);
|
||||||
|
|
||||||
accum = func(accum, item);
|
accum = func(accum, item);
|
||||||
}
|
}
|
||||||
@ -255,7 +267,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
indices: Range<u32>,
|
indices: Range<u32>,
|
||||||
) -> B
|
) -> B
|
||||||
where
|
where
|
||||||
Func: FnMut(B, D::Item<'w>) -> B,
|
Func: FnMut(B, D::Item<'w, 's>) -> B,
|
||||||
{
|
{
|
||||||
if archetype.is_empty() {
|
if archetype.is_empty() {
|
||||||
return accum;
|
return accum;
|
||||||
@ -283,6 +295,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
// Caller assures `index` in range of the current archetype.
|
// Caller assures `index` in range of the current archetype.
|
||||||
let fetched = unsafe {
|
let fetched = unsafe {
|
||||||
!F::filter_fetch(
|
!F::filter_fetch(
|
||||||
|
&self.query_state.filter_state,
|
||||||
&mut self.cursor.filter,
|
&mut self.cursor.filter,
|
||||||
archetype_entity.id(),
|
archetype_entity.id(),
|
||||||
archetype_entity.table_row(),
|
archetype_entity.table_row(),
|
||||||
@ -296,6 +309,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
// Caller assures `index` in range of the current archetype.
|
// Caller assures `index` in range of the current archetype.
|
||||||
let item = unsafe {
|
let item = unsafe {
|
||||||
D::fetch(
|
D::fetch(
|
||||||
|
&self.query_state.fetch_state,
|
||||||
&mut self.cursor.fetch,
|
&mut self.cursor.fetch,
|
||||||
archetype_entity.id(),
|
archetype_entity.id(),
|
||||||
archetype_entity.table_row(),
|
archetype_entity.table_row(),
|
||||||
@ -324,7 +338,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
rows: Range<u32>,
|
rows: Range<u32>,
|
||||||
) -> B
|
) -> B
|
||||||
where
|
where
|
||||||
Func: FnMut(B, D::Item<'w>) -> B,
|
Func: FnMut(B, D::Item<'w, 's>) -> B,
|
||||||
{
|
{
|
||||||
if archetype.is_empty() {
|
if archetype.is_empty() {
|
||||||
return accum;
|
return accum;
|
||||||
@ -356,14 +370,26 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
|
|
||||||
// SAFETY: set_table was called prior.
|
// SAFETY: set_table was called prior.
|
||||||
// Caller assures `row` in range of the current archetype.
|
// Caller assures `row` in range of the current archetype.
|
||||||
let filter_matched = unsafe { F::filter_fetch(&mut self.cursor.filter, entity, row) };
|
let filter_matched = unsafe {
|
||||||
|
F::filter_fetch(
|
||||||
|
&self.query_state.filter_state,
|
||||||
|
&mut self.cursor.filter,
|
||||||
|
entity,
|
||||||
|
row,
|
||||||
|
)
|
||||||
|
};
|
||||||
if !filter_matched {
|
if !filter_matched {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: set_table was called prior.
|
// SAFETY: set_table was called prior.
|
||||||
// Caller assures `row` in range of the current archetype.
|
// Caller assures `row` in range of the current archetype.
|
||||||
let item = D::fetch(&mut self.cursor.fetch, entity, row);
|
let item = D::fetch(
|
||||||
|
&self.query_state.fetch_state,
|
||||||
|
&mut self.cursor.fetch,
|
||||||
|
entity,
|
||||||
|
row,
|
||||||
|
);
|
||||||
|
|
||||||
accum = func(accum, item);
|
accum = func(accum, item);
|
||||||
}
|
}
|
||||||
@ -492,7 +518,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
impl ExactSizeIterator<Item = Entity> + DoubleEndedIterator + FusedIterator + 'w,
|
impl ExactSizeIterator<Item = Entity> + DoubleEndedIterator + FusedIterator + 'w,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
for<'lw> L::Item<'lw>: Ord,
|
for<'lw, 'ls> L::Item<'lw, 'ls>: Ord,
|
||||||
{
|
{
|
||||||
self.sort_impl::<L>(|keyed_query| keyed_query.sort())
|
self.sort_impl::<L>(|keyed_query| keyed_query.sort())
|
||||||
}
|
}
|
||||||
@ -549,7 +575,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
impl ExactSizeIterator<Item = Entity> + DoubleEndedIterator + FusedIterator + 'w,
|
impl ExactSizeIterator<Item = Entity> + DoubleEndedIterator + FusedIterator + 'w,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
for<'lw> L::Item<'lw>: Ord,
|
for<'lw, 'ls> L::Item<'lw, 'ls>: Ord,
|
||||||
{
|
{
|
||||||
self.sort_impl::<L>(|keyed_query| keyed_query.sort_unstable())
|
self.sort_impl::<L>(|keyed_query| keyed_query.sort_unstable())
|
||||||
}
|
}
|
||||||
@ -605,7 +631,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn sort_by<L: ReadOnlyQueryData + 'w>(
|
pub fn sort_by<L: ReadOnlyQueryData + 'w>(
|
||||||
self,
|
self,
|
||||||
mut compare: impl FnMut(&L::Item<'_>, &L::Item<'_>) -> Ordering,
|
mut compare: impl FnMut(&L::Item<'_, '_>, &L::Item<'_, '_>) -> Ordering,
|
||||||
) -> QuerySortedIter<
|
) -> QuerySortedIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -637,7 +663,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
/// This will panic if `next` has been called on `QueryIter` before, unless the underlying `Query` is empty.
|
/// This will panic if `next` has been called on `QueryIter` before, unless the underlying `Query` is empty.
|
||||||
pub fn sort_unstable_by<L: ReadOnlyQueryData + 'w>(
|
pub fn sort_unstable_by<L: ReadOnlyQueryData + 'w>(
|
||||||
self,
|
self,
|
||||||
mut compare: impl FnMut(&L::Item<'_>, &L::Item<'_>) -> Ordering,
|
mut compare: impl FnMut(&L::Item<'_, '_>, &L::Item<'_, '_>) -> Ordering,
|
||||||
) -> QuerySortedIter<
|
) -> QuerySortedIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -729,7 +755,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn sort_by_key<L: ReadOnlyQueryData + 'w, K>(
|
pub fn sort_by_key<L: ReadOnlyQueryData + 'w, K>(
|
||||||
self,
|
self,
|
||||||
mut f: impl FnMut(&L::Item<'_>) -> K,
|
mut f: impl FnMut(&L::Item<'_, '_>) -> K,
|
||||||
) -> QuerySortedIter<
|
) -> QuerySortedIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -762,7 +788,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
/// This will panic if `next` has been called on `QueryIter` before, unless the underlying `Query` is empty.
|
/// This will panic if `next` has been called on `QueryIter` before, unless the underlying `Query` is empty.
|
||||||
pub fn sort_unstable_by_key<L: ReadOnlyQueryData + 'w, K>(
|
pub fn sort_unstable_by_key<L: ReadOnlyQueryData + 'w, K>(
|
||||||
self,
|
self,
|
||||||
mut f: impl FnMut(&L::Item<'_>) -> K,
|
mut f: impl FnMut(&L::Item<'_, '_>) -> K,
|
||||||
) -> QuerySortedIter<
|
) -> QuerySortedIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -797,7 +823,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
/// This will panic if `next` has been called on `QueryIter` before, unless the underlying `Query` is empty.
|
/// This will panic if `next` has been called on `QueryIter` before, unless the underlying `Query` is empty.
|
||||||
pub fn sort_by_cached_key<L: ReadOnlyQueryData + 'w, K>(
|
pub fn sort_by_cached_key<L: ReadOnlyQueryData + 'w, K>(
|
||||||
self,
|
self,
|
||||||
mut f: impl FnMut(&L::Item<'_>) -> K,
|
mut f: impl FnMut(&L::Item<'_, '_>) -> K,
|
||||||
) -> QuerySortedIter<
|
) -> QuerySortedIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -827,7 +853,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
/// This will panic if `next` has been called on `QueryIter` before, unless the underlying `Query` is empty.
|
/// This will panic if `next` has been called on `QueryIter` before, unless the underlying `Query` is empty.
|
||||||
fn sort_impl<L: ReadOnlyQueryData + 'w>(
|
fn sort_impl<L: ReadOnlyQueryData + 'w>(
|
||||||
self,
|
self,
|
||||||
f: impl FnOnce(&mut Vec<(L::Item<'_>, NeutralOrd<Entity>)>),
|
f: impl FnOnce(&mut Vec<(L::Item<'_, '_>, NeutralOrd<Entity>)>),
|
||||||
) -> QuerySortedIter<
|
) -> QuerySortedIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -856,7 +882,11 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
.map(|(key, entity)| (key, NeutralOrd(entity)))
|
.map(|(key, entity)| (key, NeutralOrd(entity)))
|
||||||
.collect();
|
.collect();
|
||||||
f(&mut keyed_query);
|
f(&mut keyed_query);
|
||||||
let entity_iter = keyed_query.into_iter().map(|(.., entity)| entity.0);
|
let entity_iter = keyed_query
|
||||||
|
.into_iter()
|
||||||
|
.map(|(.., entity)| entity.0)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter();
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// `self.world` has permission to access the required components.
|
// `self.world` has permission to access the required components.
|
||||||
// Each lens query item is dropped before the respective actual query item is accessed.
|
// Each lens query item is dropped before the respective actual query item is accessed.
|
||||||
@ -873,7 +903,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, D: QueryData, F: QueryFilter> Iterator for QueryIter<'w, 's, D, F> {
|
impl<'w, 's, D: QueryData, F: QueryFilter> Iterator for QueryIter<'w, 's, D, F> {
|
||||||
type Item = D::Item<'w>;
|
type Item = D::Item<'w, 's>;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@ -1010,7 +1040,7 @@ where
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
/// `entity` must stem from `self.entity_iter`, and not have been passed before.
|
/// `entity` must stem from `self.entity_iter`, and not have been passed before.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn fetch_next(&mut self, entity: Entity) -> D::Item<'w> {
|
unsafe fn fetch_next(&mut self, entity: Entity) -> D::Item<'w, 's> {
|
||||||
let (location, archetype, table);
|
let (location, archetype, table);
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// `tables` and `archetypes` belong to the same world that the [`QueryIter`]
|
// `tables` and `archetypes` belong to the same world that the [`QueryIter`]
|
||||||
@ -1039,7 +1069,14 @@ where
|
|||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - set_archetype was called prior, `location.archetype_row` is an archetype index in range of the current archetype
|
// - set_archetype was called prior, `location.archetype_row` is an archetype index in range of the current archetype
|
||||||
// - fetch is only called once for each entity.
|
// - fetch is only called once for each entity.
|
||||||
unsafe { D::fetch(&mut self.fetch, entity, location.table_row) }
|
unsafe {
|
||||||
|
D::fetch(
|
||||||
|
&self.query_state.fetch_state,
|
||||||
|
&mut self.fetch,
|
||||||
|
entity,
|
||||||
|
location.table_row,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,7 +1085,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator> Iterator
|
|||||||
where
|
where
|
||||||
I: Iterator<Item = Entity>,
|
I: Iterator<Item = Entity>,
|
||||||
{
|
{
|
||||||
type Item = D::Item<'w>;
|
type Item = D::Item<'w, 's>;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@ -1170,7 +1207,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
fetch: &mut D::Fetch<'w>,
|
fetch: &mut D::Fetch<'w>,
|
||||||
filter: &mut F::Fetch<'w>,
|
filter: &mut F::Fetch<'w>,
|
||||||
query_state: &'s QueryState<D, F>,
|
query_state: &'s QueryState<D, F>,
|
||||||
) -> Option<D::Item<'w>> {
|
) -> Option<D::Item<'w, 's>> {
|
||||||
for entity_borrow in entity_iter {
|
for entity_borrow in entity_iter {
|
||||||
let entity = entity_borrow.entity();
|
let entity = entity_borrow.entity();
|
||||||
let Ok(location) = entities.get_constructed(entity) else {
|
let Ok(location) = entities.get_constructed(entity) else {
|
||||||
@ -1200,11 +1237,20 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
|
|
||||||
// SAFETY: set_archetype was called prior.
|
// SAFETY: set_archetype was called prior.
|
||||||
// `location.archetype_row` is an archetype index row in range of the current archetype, because if it was not, the match above would have `continue`d
|
// `location.archetype_row` is an archetype index row in range of the current archetype, because if it was not, the match above would have `continue`d
|
||||||
if unsafe { F::filter_fetch(filter, entity, location.table_row) } {
|
if unsafe {
|
||||||
|
F::filter_fetch(
|
||||||
|
&query_state.filter_state,
|
||||||
|
filter,
|
||||||
|
entity,
|
||||||
|
location.table_row,
|
||||||
|
)
|
||||||
|
} {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - set_archetype was called prior, `location.archetype_row` is an archetype index in range of the current archetype
|
// - set_archetype was called prior, `location.archetype_row` is an archetype index in range of the current archetype
|
||||||
// - fetch is only called once for each entity.
|
// - fetch is only called once for each entity.
|
||||||
return Some(unsafe { D::fetch(fetch, entity, location.table_row) });
|
return Some(unsafe {
|
||||||
|
D::fetch(&query_state.fetch_state, fetch, entity, location.table_row)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@ -1212,7 +1258,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
|
|
||||||
/// Get next result from the query
|
/// Get next result from the query
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn fetch_next(&mut self) -> Option<D::Item<'_>> {
|
pub fn fetch_next(&mut self) -> Option<D::Item<'_, 's>> {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// All arguments stem from self.
|
// All arguments stem from self.
|
||||||
// We are limiting the returned reference to self,
|
// We are limiting the returned reference to self,
|
||||||
@ -1336,7 +1382,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
impl ExactSizeIterator<Item = Entity> + DoubleEndedIterator + FusedIterator + 'w,
|
impl ExactSizeIterator<Item = Entity> + DoubleEndedIterator + FusedIterator + 'w,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
for<'lw> L::Item<'lw>: Ord,
|
for<'lw, 'ls> L::Item<'lw, 'ls>: Ord,
|
||||||
{
|
{
|
||||||
self.sort_impl::<L>(|keyed_query| keyed_query.sort())
|
self.sort_impl::<L>(|keyed_query| keyed_query.sort())
|
||||||
}
|
}
|
||||||
@ -1394,7 +1440,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
impl ExactSizeIterator<Item = Entity> + DoubleEndedIterator + FusedIterator + 'w,
|
impl ExactSizeIterator<Item = Entity> + DoubleEndedIterator + FusedIterator + 'w,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
for<'lw> L::Item<'lw>: Ord,
|
for<'lw, 'ls> L::Item<'lw, 'ls>: Ord,
|
||||||
{
|
{
|
||||||
self.sort_impl::<L>(|keyed_query| keyed_query.sort_unstable())
|
self.sort_impl::<L>(|keyed_query| keyed_query.sort_unstable())
|
||||||
}
|
}
|
||||||
@ -1451,7 +1497,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn sort_by<L: ReadOnlyQueryData + 'w>(
|
pub fn sort_by<L: ReadOnlyQueryData + 'w>(
|
||||||
self,
|
self,
|
||||||
mut compare: impl FnMut(&L::Item<'_>, &L::Item<'_>) -> Ordering,
|
mut compare: impl FnMut(&L::Item<'_, '_>, &L::Item<'_, '_>) -> Ordering,
|
||||||
) -> QuerySortedManyIter<
|
) -> QuerySortedManyIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -1482,7 +1528,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
/// called on [`QueryManyIter`] before.
|
/// called on [`QueryManyIter`] before.
|
||||||
pub fn sort_unstable_by<L: ReadOnlyQueryData + 'w>(
|
pub fn sort_unstable_by<L: ReadOnlyQueryData + 'w>(
|
||||||
self,
|
self,
|
||||||
mut compare: impl FnMut(&L::Item<'_>, &L::Item<'_>) -> Ordering,
|
mut compare: impl FnMut(&L::Item<'_, '_>, &L::Item<'_, '_>) -> Ordering,
|
||||||
) -> QuerySortedManyIter<
|
) -> QuerySortedManyIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -1576,7 +1622,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn sort_by_key<L: ReadOnlyQueryData + 'w, K>(
|
pub fn sort_by_key<L: ReadOnlyQueryData + 'w, K>(
|
||||||
self,
|
self,
|
||||||
mut f: impl FnMut(&L::Item<'_>) -> K,
|
mut f: impl FnMut(&L::Item<'_, '_>) -> K,
|
||||||
) -> QuerySortedManyIter<
|
) -> QuerySortedManyIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -1608,7 +1654,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
/// called on [`QueryManyIter`] before.
|
/// called on [`QueryManyIter`] before.
|
||||||
pub fn sort_unstable_by_key<L: ReadOnlyQueryData + 'w, K>(
|
pub fn sort_unstable_by_key<L: ReadOnlyQueryData + 'w, K>(
|
||||||
self,
|
self,
|
||||||
mut f: impl FnMut(&L::Item<'_>) -> K,
|
mut f: impl FnMut(&L::Item<'_, '_>) -> K,
|
||||||
) -> QuerySortedManyIter<
|
) -> QuerySortedManyIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -1642,7 +1688,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
/// called on [`QueryManyIter`] before.
|
/// called on [`QueryManyIter`] before.
|
||||||
pub fn sort_by_cached_key<L: ReadOnlyQueryData + 'w, K>(
|
pub fn sort_by_cached_key<L: ReadOnlyQueryData + 'w, K>(
|
||||||
self,
|
self,
|
||||||
mut f: impl FnMut(&L::Item<'_>) -> K,
|
mut f: impl FnMut(&L::Item<'_, '_>) -> K,
|
||||||
) -> QuerySortedManyIter<
|
) -> QuerySortedManyIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -1671,7 +1717,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
|||||||
/// called on [`QueryManyIter`] before.
|
/// called on [`QueryManyIter`] before.
|
||||||
fn sort_impl<L: ReadOnlyQueryData + 'w>(
|
fn sort_impl<L: ReadOnlyQueryData + 'w>(
|
||||||
self,
|
self,
|
||||||
f: impl FnOnce(&mut Vec<(L::Item<'_>, NeutralOrd<Entity>)>),
|
f: impl FnOnce(&mut Vec<(L::Item<'_, '_>, NeutralOrd<Entity>)>),
|
||||||
) -> QuerySortedManyIter<
|
) -> QuerySortedManyIter<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
@ -1721,7 +1767,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: DoubleEndedIterator<Item: EntityEq
|
|||||||
{
|
{
|
||||||
/// Get next result from the back of the query
|
/// Get next result from the back of the query
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn fetch_next_back(&mut self) -> Option<D::Item<'_>> {
|
pub fn fetch_next_back(&mut self) -> Option<D::Item<'_, 's>> {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// All arguments stem from self.
|
// All arguments stem from self.
|
||||||
// We are limiting the returned reference to self,
|
// We are limiting the returned reference to self,
|
||||||
@ -1745,7 +1791,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: DoubleEndedIterator<Item: EntityEq
|
|||||||
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>> Iterator
|
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>> Iterator
|
||||||
for QueryManyIter<'w, 's, D, F, I>
|
for QueryManyIter<'w, 's, D, F, I>
|
||||||
{
|
{
|
||||||
type Item = D::Item<'w>;
|
type Item = D::Item<'w, 's>;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@ -1861,7 +1907,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: EntitySetIterator>
|
|||||||
impl<'w, 's, D: QueryData, F: QueryFilter, I: EntitySetIterator> Iterator
|
impl<'w, 's, D: QueryData, F: QueryFilter, I: EntitySetIterator> Iterator
|
||||||
for QueryManyUniqueIter<'w, 's, D, F, I>
|
for QueryManyUniqueIter<'w, 's, D, F, I>
|
||||||
{
|
{
|
||||||
type Item = D::Item<'w>;
|
type Item = D::Item<'w, 's>;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@ -1954,7 +2000,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item = Entity>>
|
|||||||
/// It is always safe for shared access.
|
/// It is always safe for shared access.
|
||||||
/// `entity` must stem from `self.entity_iter`, and not have been passed before.
|
/// `entity` must stem from `self.entity_iter`, and not have been passed before.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn fetch_next_aliased_unchecked(&mut self, entity: Entity) -> D::Item<'w> {
|
unsafe fn fetch_next_aliased_unchecked(&mut self, entity: Entity) -> D::Item<'w, 's> {
|
||||||
let (location, archetype, table);
|
let (location, archetype, table);
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// `tables` and `archetypes` belong to the same world that the [`QueryIter`]
|
// `tables` and `archetypes` belong to the same world that the [`QueryIter`]
|
||||||
@ -1983,12 +2029,19 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item = Entity>>
|
|||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - set_archetype was called prior, `location.archetype_row` is an archetype index in range of the current archetype
|
// - set_archetype was called prior, `location.archetype_row` is an archetype index in range of the current archetype
|
||||||
// - fetch is only called once for each entity.
|
// - fetch is only called once for each entity.
|
||||||
unsafe { D::fetch(&mut self.fetch, entity, location.table_row) }
|
unsafe {
|
||||||
|
D::fetch(
|
||||||
|
&self.query_state.fetch_state,
|
||||||
|
&mut self.fetch,
|
||||||
|
entity,
|
||||||
|
location.table_row,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get next result from the query
|
/// Get next result from the query
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn fetch_next(&mut self) -> Option<D::Item<'_>> {
|
pub fn fetch_next(&mut self) -> Option<D::Item<'_, 's>> {
|
||||||
let entity = self.entity_iter.next()?;
|
let entity = self.entity_iter.next()?;
|
||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
@ -2007,7 +2060,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: DoubleEndedIterator<Item = Entity>
|
|||||||
{
|
{
|
||||||
/// Get next result from the query
|
/// Get next result from the query
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn fetch_next_back(&mut self) -> Option<D::Item<'_>> {
|
pub fn fetch_next_back(&mut self) -> Option<D::Item<'_, 's>> {
|
||||||
let entity = self.entity_iter.next_back()?;
|
let entity = self.entity_iter.next_back()?;
|
||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
@ -2024,7 +2077,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: DoubleEndedIterator<Item = Entity>
|
|||||||
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, I: Iterator<Item = Entity>> Iterator
|
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, I: Iterator<Item = Entity>> Iterator
|
||||||
for QuerySortedManyIter<'w, 's, D, F, I>
|
for QuerySortedManyIter<'w, 's, D, F, I>
|
||||||
{
|
{
|
||||||
type Item = D::Item<'w>;
|
type Item = D::Item<'w, 's>;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@ -2185,7 +2238,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, const K: usize> QueryCombinationIter<
|
|||||||
/// .
|
/// .
|
||||||
/// It is always safe for shared access.
|
/// It is always safe for shared access.
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn fetch_next_aliased_unchecked(&mut self) -> Option<[D::Item<'w>; K]> {
|
unsafe fn fetch_next_aliased_unchecked(&mut self) -> Option<[D::Item<'w, 's>; K]> {
|
||||||
// PERF: can speed up the following code using `cursor.remaining()` instead of `next_item.is_none()`
|
// PERF: can speed up the following code using `cursor.remaining()` instead of `next_item.is_none()`
|
||||||
// when D::IS_ARCHETYPAL && F::IS_ARCHETYPAL
|
// when D::IS_ARCHETYPAL && F::IS_ARCHETYPAL
|
||||||
//
|
//
|
||||||
@ -2211,11 +2264,12 @@ impl<'w, 's, D: QueryData, F: QueryFilter, const K: usize> QueryCombinationIter<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut values = MaybeUninit::<[D::Item<'w>; K]>::uninit();
|
let mut values = MaybeUninit::<[D::Item<'w, 's>; K]>::uninit();
|
||||||
|
|
||||||
let ptr = values.as_mut_ptr().cast::<D::Item<'w>>();
|
let ptr = values.as_mut_ptr().cast::<D::Item<'w, 's>>();
|
||||||
for (offset, cursor) in self.cursors.iter_mut().enumerate() {
|
for (offset, cursor) in self.cursors.iter_mut().enumerate() {
|
||||||
ptr.add(offset).write(cursor.peek_last().unwrap());
|
ptr.add(offset)
|
||||||
|
.write(cursor.peek_last(self.query_state).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(values.assume_init())
|
Some(values.assume_init())
|
||||||
@ -2223,7 +2277,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, const K: usize> QueryCombinationIter<
|
|||||||
|
|
||||||
/// Get next combination of queried components
|
/// Get next combination of queried components
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fetch_next(&mut self) -> Option<[D::Item<'_>; K]> {
|
pub fn fetch_next(&mut self) -> Option<[D::Item<'_, 's>; K]> {
|
||||||
// SAFETY: we are limiting the returned reference to self,
|
// SAFETY: we are limiting the returned reference to self,
|
||||||
// making sure this method cannot be called multiple times without getting rid
|
// making sure this method cannot be called multiple times without getting rid
|
||||||
// of any previously returned unique references first, thus preventing aliasing.
|
// of any previously returned unique references first, thus preventing aliasing.
|
||||||
@ -2240,7 +2294,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, const K: usize> QueryCombinationIter<
|
|||||||
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, const K: usize> Iterator
|
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, const K: usize> Iterator
|
||||||
for QueryCombinationIter<'w, 's, D, F, K>
|
for QueryCombinationIter<'w, 's, D, F, K>
|
||||||
{
|
{
|
||||||
type Item = [D::Item<'w>; K];
|
type Item = [D::Item<'w, 's>; K];
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@ -2390,7 +2444,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
|||||||
/// The result of `next` and any previous calls to `peek_last` with this row must have been
|
/// The result of `next` and any previous calls to `peek_last` with this row must have been
|
||||||
/// dropped to prevent aliasing mutable references.
|
/// dropped to prevent aliasing mutable references.
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn peek_last(&mut self) -> Option<D::Item<'w>> {
|
unsafe fn peek_last(&mut self, query_state: &'s QueryState<D, F>) -> Option<D::Item<'w, 's>> {
|
||||||
if self.current_row > 0 {
|
if self.current_row > 0 {
|
||||||
let index = self.current_row - 1;
|
let index = self.current_row - 1;
|
||||||
if self.is_dense {
|
if self.is_dense {
|
||||||
@ -2401,6 +2455,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
|||||||
// - `*entity` and `index` are in the current table.
|
// - `*entity` and `index` are in the current table.
|
||||||
unsafe {
|
unsafe {
|
||||||
Some(D::fetch(
|
Some(D::fetch(
|
||||||
|
&query_state.fetch_state,
|
||||||
&mut self.fetch,
|
&mut self.fetch,
|
||||||
*entity,
|
*entity,
|
||||||
// SAFETY: This is from an exclusive range, so it can't be max.
|
// SAFETY: This is from an exclusive range, so it can't be max.
|
||||||
@ -2416,6 +2471,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
|||||||
// - `archetype_entity.id()` and `archetype_entity.table_row()` are in the current archetype.
|
// - `archetype_entity.id()` and `archetype_entity.table_row()` are in the current archetype.
|
||||||
unsafe {
|
unsafe {
|
||||||
Some(D::fetch(
|
Some(D::fetch(
|
||||||
|
&query_state.fetch_state,
|
||||||
&mut self.fetch,
|
&mut self.fetch,
|
||||||
archetype_entity.id(),
|
archetype_entity.id(),
|
||||||
archetype_entity.table_row(),
|
archetype_entity.table_row(),
|
||||||
@ -2457,7 +2513,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
|||||||
tables: &'w Tables,
|
tables: &'w Tables,
|
||||||
archetypes: &'w Archetypes,
|
archetypes: &'w Archetypes,
|
||||||
query_state: &'s QueryState<D, F>,
|
query_state: &'s QueryState<D, F>,
|
||||||
) -> Option<D::Item<'w>> {
|
) -> Option<D::Item<'w, 's>> {
|
||||||
if self.is_dense {
|
if self.is_dense {
|
||||||
loop {
|
loop {
|
||||||
// we are on the beginning of the query, or finished processing a table, so skip to the next
|
// we are on the beginning of the query, or finished processing a table, so skip to the next
|
||||||
@ -2484,7 +2540,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
|||||||
unsafe { self.table_entities.get_unchecked(self.current_row as usize) };
|
unsafe { self.table_entities.get_unchecked(self.current_row as usize) };
|
||||||
// SAFETY: The row is less than the u32 len, so it must not be max.
|
// SAFETY: The row is less than the u32 len, so it must not be max.
|
||||||
let row = unsafe { TableRow::new(NonMaxU32::new_unchecked(self.current_row)) };
|
let row = unsafe { TableRow::new(NonMaxU32::new_unchecked(self.current_row)) };
|
||||||
if !F::filter_fetch(&mut self.filter, *entity, row) {
|
if !F::filter_fetch(&query_state.filter_state, &mut self.filter, *entity, row) {
|
||||||
self.current_row += 1;
|
self.current_row += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2494,7 +2550,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
|||||||
// - `current_row` must be a table row in range of the current table,
|
// - `current_row` must be a table row in range of the current table,
|
||||||
// because if it was not, then the above would have been executed.
|
// because if it was not, then the above would have been executed.
|
||||||
// - fetch is only called once for each `entity`.
|
// - fetch is only called once for each `entity`.
|
||||||
let item = unsafe { D::fetch(&mut self.fetch, *entity, row) };
|
let item =
|
||||||
|
unsafe { D::fetch(&query_state.fetch_state, &mut self.fetch, *entity, row) };
|
||||||
|
|
||||||
self.current_row += 1;
|
self.current_row += 1;
|
||||||
return Some(item);
|
return Some(item);
|
||||||
@ -2536,6 +2593,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
|||||||
.get_unchecked(self.current_row as usize)
|
.get_unchecked(self.current_row as usize)
|
||||||
};
|
};
|
||||||
if !F::filter_fetch(
|
if !F::filter_fetch(
|
||||||
|
&query_state.filter_state,
|
||||||
&mut self.filter,
|
&mut self.filter,
|
||||||
archetype_entity.id(),
|
archetype_entity.id(),
|
||||||
archetype_entity.table_row(),
|
archetype_entity.table_row(),
|
||||||
@ -2551,6 +2609,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
|||||||
// - fetch is only called once for each `archetype_entity`.
|
// - fetch is only called once for each `archetype_entity`.
|
||||||
let item = unsafe {
|
let item = unsafe {
|
||||||
D::fetch(
|
D::fetch(
|
||||||
|
&query_state.fetch_state,
|
||||||
&mut self.fetch,
|
&mut self.fetch,
|
||||||
archetype_entity.id(),
|
archetype_entity.id(),
|
||||||
archetype_entity.table_row(),
|
archetype_entity.table_row(),
|
||||||
|
|||||||
@ -824,9 +824,9 @@ mod tests {
|
|||||||
|
|
||||||
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
|
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
|
||||||
|
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w, 's>(
|
||||||
_world: UnsafeWorldCell<'w>,
|
_world: UnsafeWorldCell<'w>,
|
||||||
_state: &Self::State,
|
_state: &'s Self::State,
|
||||||
_last_run: Tick,
|
_last_run: Tick,
|
||||||
_this_run: Tick,
|
_this_run: Tick,
|
||||||
) -> Self::Fetch<'w> {
|
) -> Self::Fetch<'w> {
|
||||||
@ -835,18 +835,18 @@ mod tests {
|
|||||||
const IS_DENSE: bool = true;
|
const IS_DENSE: bool = true;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w, 's>(
|
||||||
_fetch: &mut Self::Fetch<'w>,
|
_fetch: &mut Self::Fetch<'w>,
|
||||||
_state: &Self::State,
|
_state: &'s Self::State,
|
||||||
_archetype: &'w Archetype,
|
_archetype: &'w Archetype,
|
||||||
_table: &Table,
|
_table: &Table,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table<'w>(
|
unsafe fn set_table<'w, 's>(
|
||||||
_fetch: &mut Self::Fetch<'w>,
|
_fetch: &mut Self::Fetch<'w>,
|
||||||
_state: &Self::State,
|
_state: &'s Self::State,
|
||||||
_table: &'w Table,
|
_table: &'w Table,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@ -882,16 +882,20 @@ mod tests {
|
|||||||
unsafe impl QueryData for ReadsRData {
|
unsafe impl QueryData for ReadsRData {
|
||||||
const IS_READ_ONLY: bool = true;
|
const IS_READ_ONLY: bool = true;
|
||||||
type ReadOnly = Self;
|
type ReadOnly = Self;
|
||||||
type Item<'w> = ();
|
type Item<'w, 's> = ();
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(_item: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
fn shrink<'wlong: 'wshort, 'wshort, 's>(
|
||||||
|
_item: Self::Item<'wlong, 's>,
|
||||||
|
) -> Self::Item<'wshort, 's> {
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn fetch<'w>(
|
unsafe fn fetch<'w, 's>(
|
||||||
|
_state: &'s Self::State,
|
||||||
_fetch: &mut Self::Fetch<'w>,
|
_fetch: &mut Self::Fetch<'w>,
|
||||||
_entity: Entity,
|
_entity: Entity,
|
||||||
_table_row: TableRow,
|
_table_row: TableRow,
|
||||||
) -> Self::Item<'w> {
|
) -> Self::Item<'w, 's> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryParIter<'w, 's, D, F> {
|
|||||||
///
|
///
|
||||||
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each<FN: Fn(QueryItem<'w, D>) + Send + Sync + Clone>(self, func: FN) {
|
pub fn for_each<FN: Fn(QueryItem<'w, 's, D>) + Send + Sync + Clone>(self, func: FN) {
|
||||||
self.for_each_init(|| {}, |_, item| func(item));
|
self.for_each_init(|| {}, |_, item| func(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryParIter<'w, 's, D, F> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
|
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
|
||||||
where
|
where
|
||||||
FN: Fn(&mut T, QueryItem<'w, D>) + Send + Sync + Clone,
|
FN: Fn(&mut T, QueryItem<'w, 's, D>) + Send + Sync + Clone,
|
||||||
INIT: Fn() -> T + Sync + Send + Clone,
|
INIT: Fn() -> T + Sync + Send + Clone,
|
||||||
{
|
{
|
||||||
let func = |mut init, item| {
|
let func = |mut init, item| {
|
||||||
@ -190,7 +190,7 @@ impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, E: EntityEquivalent + Sync>
|
|||||||
///
|
///
|
||||||
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each<FN: Fn(QueryItem<'w, D>) + Send + Sync + Clone>(self, func: FN) {
|
pub fn for_each<FN: Fn(QueryItem<'w, 's, D>) + Send + Sync + Clone>(self, func: FN) {
|
||||||
self.for_each_init(|| {}, |_, item| func(item));
|
self.for_each_init(|| {}, |_, item| func(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, E: EntityEquivalent + Sync>
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
|
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
|
||||||
where
|
where
|
||||||
FN: Fn(&mut T, QueryItem<'w, D>) + Send + Sync + Clone,
|
FN: Fn(&mut T, QueryItem<'w, 's, D>) + Send + Sync + Clone,
|
||||||
INIT: Fn() -> T + Sync + Send + Clone,
|
INIT: Fn() -> T + Sync + Send + Clone,
|
||||||
{
|
{
|
||||||
let func = |mut init, item| {
|
let func = |mut init, item| {
|
||||||
@ -345,7 +345,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, E: EntityEquivalent + Sync>
|
|||||||
///
|
///
|
||||||
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each<FN: Fn(QueryItem<'w, D>) + Send + Sync + Clone>(self, func: FN) {
|
pub fn for_each<FN: Fn(QueryItem<'w, 's, D>) + Send + Sync + Clone>(self, func: FN) {
|
||||||
self.for_each_init(|| {}, |_, item| func(item));
|
self.for_each_init(|| {}, |_, item| func(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,7 +402,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, E: EntityEquivalent + Sync>
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
|
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
|
||||||
where
|
where
|
||||||
FN: Fn(&mut T, QueryItem<'w, D>) + Send + Sync + Clone,
|
FN: Fn(&mut T, QueryItem<'w, 's, D>) + Send + Sync + Clone,
|
||||||
INIT: Fn() -> T + Sync + Send + Clone,
|
INIT: Fn() -> T + Sync + Send + Clone,
|
||||||
{
|
{
|
||||||
let func = |mut init, item| {
|
let func = |mut init, item| {
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use crate::{
|
|||||||
use crate::entity::UniqueEntityEquivalentSlice;
|
use crate::entity::UniqueEntityEquivalentSlice;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::{fmt, ptr};
|
use core::{fmt, ptr};
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
@ -672,7 +673,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
assert!(
|
assert!(
|
||||||
component_access.is_subset(&self_access),
|
component_access.is_subset(&self_access),
|
||||||
"Transmuted state for {} attempts to access terms that are not allowed by original state {}.",
|
"Transmuted state for {} attempts to access terms that are not allowed by original state {}.",
|
||||||
core::any::type_name::<(NewD, NewF)>(), core::any::type_name::<(D, F)>()
|
DebugName::type_name::<(NewD, NewF)>(), DebugName::type_name::<(D, F)>()
|
||||||
);
|
);
|
||||||
|
|
||||||
QueryState {
|
QueryState {
|
||||||
@ -791,7 +792,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
assert!(
|
assert!(
|
||||||
component_access.is_subset(&joined_component_access),
|
component_access.is_subset(&joined_component_access),
|
||||||
"Joined state for {} attempts to access terms that are not allowed by state {} joined with {}.",
|
"Joined state for {} attempts to access terms that are not allowed by state {} joined with {}.",
|
||||||
core::any::type_name::<(NewD, NewF)>(), core::any::type_name::<(D, F)>(), core::any::type_name::<(OtherD, OtherF)>()
|
DebugName::type_name::<(NewD, NewF)>(), DebugName::type_name::<(D, F)>(), DebugName::type_name::<(OtherD, OtherF)>()
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.archetype_generation != other.archetype_generation {
|
if self.archetype_generation != other.archetype_generation {
|
||||||
@ -845,13 +846,17 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
///
|
///
|
||||||
/// This can only be called for read-only queries, see [`Self::get_mut`] for write-queries.
|
/// This can only be called for read-only queries, see [`Self::get_mut`] for write-queries.
|
||||||
///
|
///
|
||||||
|
/// If you need to get multiple items at once but get borrowing errors,
|
||||||
|
/// consider using [`Self::update_archetypes`] followed by multiple [`Self::get_manual`] calls,
|
||||||
|
/// or making a single call with [`Self::get_many`] or [`Self::iter_many`].
|
||||||
|
///
|
||||||
/// This is always guaranteed to run in `O(1)` time.
|
/// This is always guaranteed to run in `O(1)` time.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get<'w>(
|
pub fn get<'w>(
|
||||||
&mut self,
|
&mut self,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> Result<ROQueryItem<'w, D>, QueryEntityError> {
|
) -> Result<ROQueryItem<'w, '_, D>, QueryEntityError> {
|
||||||
self.query(world).get_inner(entity)
|
self.query(world).get_inner(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -892,7 +897,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
entities: [Entity; N],
|
entities: [Entity; N],
|
||||||
) -> Result<[ROQueryItem<'w, D>; N], QueryEntityError> {
|
) -> Result<[ROQueryItem<'w, '_, D>; N], QueryEntityError> {
|
||||||
self.query(world).get_many_inner(entities)
|
self.query(world).get_many_inner(entities)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -930,7 +935,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
entities: UniqueEntityArray<N>,
|
entities: UniqueEntityArray<N>,
|
||||||
) -> Result<[ROQueryItem<'w, D>; N], QueryEntityError> {
|
) -> Result<[ROQueryItem<'w, '_, D>; N], QueryEntityError> {
|
||||||
self.query(world).get_many_unique_inner(entities)
|
self.query(world).get_many_unique_inner(entities)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -942,7 +947,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
world: &'w mut World,
|
world: &'w mut World,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> Result<D::Item<'w>, QueryEntityError> {
|
) -> Result<D::Item<'w, '_>, QueryEntityError> {
|
||||||
self.query_mut(world).get_inner(entity)
|
self.query_mut(world).get_inner(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -989,7 +994,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
world: &'w mut World,
|
world: &'w mut World,
|
||||||
entities: [Entity; N],
|
entities: [Entity; N],
|
||||||
) -> Result<[D::Item<'w>; N], QueryEntityError> {
|
) -> Result<[D::Item<'w, '_>; N], QueryEntityError> {
|
||||||
self.query_mut(world).get_many_mut_inner(entities)
|
self.query_mut(world).get_many_mut_inner(entities)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1034,7 +1039,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
world: &'w mut World,
|
world: &'w mut World,
|
||||||
entities: UniqueEntityArray<N>,
|
entities: UniqueEntityArray<N>,
|
||||||
) -> Result<[D::Item<'w>; N], QueryEntityError> {
|
) -> Result<[D::Item<'w, '_>; N], QueryEntityError> {
|
||||||
self.query_mut(world).get_many_unique_inner(entities)
|
self.query_mut(world).get_many_unique_inner(entities)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1056,7 +1061,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
&self,
|
&self,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> Result<ROQueryItem<'w, D>, QueryEntityError> {
|
) -> Result<ROQueryItem<'w, '_, D>, QueryEntityError> {
|
||||||
self.query_manual(world).get_inner(entity)
|
self.query_manual(world).get_inner(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1073,13 +1078,16 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> Result<D::Item<'w>, QueryEntityError> {
|
) -> Result<D::Item<'w, '_>, QueryEntityError> {
|
||||||
self.query_unchecked(world).get_inner(entity)
|
self.query_unchecked(world).get_inner(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an [`Iterator`] over the query results for the given [`World`].
|
/// Returns an [`Iterator`] over the query results for the given [`World`].
|
||||||
///
|
///
|
||||||
/// This can only be called for read-only queries, see [`Self::iter_mut`] for write-queries.
|
/// This can only be called for read-only queries, see [`Self::iter_mut`] for write-queries.
|
||||||
|
///
|
||||||
|
/// If you need to iterate multiple times at once but get borrowing errors,
|
||||||
|
/// consider using [`Self::update_archetypes`] followed by multiple [`Self::iter_manual`] calls.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter<'w, 's>(&'s mut self, world: &'w World) -> QueryIter<'w, 's, D::ReadOnly, F> {
|
pub fn iter<'w, 's>(&'s mut self, world: &'w World) -> QueryIter<'w, 's, D::ReadOnly, F> {
|
||||||
self.query(world).into_iter()
|
self.query(world).into_iter()
|
||||||
@ -1168,6 +1176,9 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
/// Items are returned in the order of the list of entities.
|
/// Items are returned in the order of the list of entities.
|
||||||
/// Entities that don't match the query are skipped.
|
/// Entities that don't match the query are skipped.
|
||||||
///
|
///
|
||||||
|
/// If you need to iterate multiple times at once but get borrowing errors,
|
||||||
|
/// consider using [`Self::update_archetypes`] followed by multiple [`Self::iter_many_manual`] calls.
|
||||||
|
///
|
||||||
/// # See also
|
/// # See also
|
||||||
///
|
///
|
||||||
/// - [`iter_many_mut`](Self::iter_many_mut) to get mutable query items.
|
/// - [`iter_many_mut`](Self::iter_many_mut) to get mutable query items.
|
||||||
@ -1387,8 +1398,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
///
|
///
|
||||||
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
|
||||||
pub(crate) unsafe fn par_fold_init_unchecked_manual<'w, T, FN, INIT>(
|
pub(crate) unsafe fn par_fold_init_unchecked_manual<'w, 's, T, FN, INIT>(
|
||||||
&self,
|
&'s self,
|
||||||
init_accum: INIT,
|
init_accum: INIT,
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
batch_size: u32,
|
batch_size: u32,
|
||||||
@ -1396,7 +1407,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) where
|
) where
|
||||||
FN: Fn(T, D::Item<'w>) -> T + Send + Sync + Clone,
|
FN: Fn(T, D::Item<'w, 's>) -> T + Send + Sync + Clone,
|
||||||
INIT: Fn() -> T + Sync + Send + Clone,
|
INIT: Fn() -> T + Sync + Send + Clone,
|
||||||
{
|
{
|
||||||
// NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
|
// NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
|
||||||
@ -1501,8 +1512,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
///
|
///
|
||||||
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
|
||||||
pub(crate) unsafe fn par_many_unique_fold_init_unchecked_manual<'w, T, FN, INIT, E>(
|
pub(crate) unsafe fn par_many_unique_fold_init_unchecked_manual<'w, 's, T, FN, INIT, E>(
|
||||||
&self,
|
&'s self,
|
||||||
init_accum: INIT,
|
init_accum: INIT,
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
entity_list: &UniqueEntityEquivalentSlice<E>,
|
entity_list: &UniqueEntityEquivalentSlice<E>,
|
||||||
@ -1511,7 +1522,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) where
|
) where
|
||||||
FN: Fn(T, D::Item<'w>) -> T + Send + Sync + Clone,
|
FN: Fn(T, D::Item<'w, 's>) -> T + Send + Sync + Clone,
|
||||||
INIT: Fn() -> T + Sync + Send + Clone,
|
INIT: Fn() -> T + Sync + Send + Clone,
|
||||||
E: EntityEquivalent + Sync,
|
E: EntityEquivalent + Sync,
|
||||||
{
|
{
|
||||||
@ -1564,8 +1575,8 @@ impl<D: ReadOnlyQueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
///
|
///
|
||||||
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
|
||||||
pub(crate) unsafe fn par_many_fold_init_unchecked_manual<'w, T, FN, INIT, E>(
|
pub(crate) unsafe fn par_many_fold_init_unchecked_manual<'w, 's, T, FN, INIT, E>(
|
||||||
&self,
|
&'s self,
|
||||||
init_accum: INIT,
|
init_accum: INIT,
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
entity_list: &[E],
|
entity_list: &[E],
|
||||||
@ -1574,7 +1585,7 @@ impl<D: ReadOnlyQueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) where
|
) where
|
||||||
FN: Fn(T, D::Item<'w>) -> T + Send + Sync + Clone,
|
FN: Fn(T, D::Item<'w, 's>) -> T + Send + Sync + Clone,
|
||||||
INIT: Fn() -> T + Sync + Send + Clone,
|
INIT: Fn() -> T + Sync + Send + Clone,
|
||||||
E: EntityEquivalent + Sync,
|
E: EntityEquivalent + Sync,
|
||||||
{
|
{
|
||||||
@ -1686,7 +1697,10 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
///
|
///
|
||||||
/// Simply unwrapping the [`Result`] also works, but should generally be reserved for tests.
|
/// Simply unwrapping the [`Result`] also works, but should generally be reserved for tests.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn single<'w>(&mut self, world: &'w World) -> Result<ROQueryItem<'w, D>, QuerySingleError> {
|
pub fn single<'w>(
|
||||||
|
&mut self,
|
||||||
|
world: &'w World,
|
||||||
|
) -> Result<ROQueryItem<'w, '_, D>, QuerySingleError> {
|
||||||
self.query(world).single_inner()
|
self.query(world).single_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1703,7 +1717,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
pub fn single_mut<'w>(
|
pub fn single_mut<'w>(
|
||||||
&mut self,
|
&mut self,
|
||||||
world: &'w mut World,
|
world: &'w mut World,
|
||||||
) -> Result<D::Item<'w>, QuerySingleError> {
|
) -> Result<D::Item<'w, '_>, QuerySingleError> {
|
||||||
self.query_mut(world).single_inner()
|
self.query_mut(world).single_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1720,7 +1734,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
pub unsafe fn single_unchecked<'w>(
|
pub unsafe fn single_unchecked<'w>(
|
||||||
&mut self,
|
&mut self,
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
) -> Result<D::Item<'w>, QuerySingleError> {
|
) -> Result<D::Item<'w, '_>, QuerySingleError> {
|
||||||
self.query_unchecked(world).single_inner()
|
self.query_unchecked(world).single_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1742,7 +1756,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> Result<D::Item<'w>, QuerySingleError> {
|
) -> Result<D::Item<'w, '_>, QuerySingleError> {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - The caller ensured we have the correct access to the world.
|
// - The caller ensured we have the correct access to the world.
|
||||||
// - The caller ensured that the world matches.
|
// - The caller ensured that the world matches.
|
||||||
|
|||||||
@ -42,7 +42,7 @@ use variadics_please::all_tuples;
|
|||||||
/// [`QueryFilter`]: crate::query::QueryFilter
|
/// [`QueryFilter`]: crate::query::QueryFilter
|
||||||
pub unsafe trait WorldQuery {
|
pub unsafe trait WorldQuery {
|
||||||
/// Per archetype/table state retrieved by this [`WorldQuery`] to compute [`Self::Item`](crate::query::QueryData::Item) for each entity.
|
/// Per archetype/table state retrieved by this [`WorldQuery`] to compute [`Self::Item`](crate::query::QueryData::Item) for each entity.
|
||||||
type Fetch<'a>: Clone;
|
type Fetch<'w>: Clone;
|
||||||
|
|
||||||
/// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
|
/// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
|
||||||
/// so it is best to move as much data / computation here as possible to reduce the cost of
|
/// so it is best to move as much data / computation here as possible to reduce the cost of
|
||||||
@ -62,9 +62,9 @@ pub unsafe trait WorldQuery {
|
|||||||
/// in to this function.
|
/// in to this function.
|
||||||
/// - `world` must have the **right** to access any access registered in `update_component_access`.
|
/// - `world` must have the **right** to access any access registered in `update_component_access`.
|
||||||
/// - There must not be simultaneous resource access conflicting with readonly resource access registered in [`WorldQuery::update_component_access`].
|
/// - There must not be simultaneous resource access conflicting with readonly resource access registered in [`WorldQuery::update_component_access`].
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w, 's>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
state: &Self::State,
|
state: &'s Self::State,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> Self::Fetch<'w>;
|
) -> Self::Fetch<'w>;
|
||||||
@ -87,9 +87,9 @@ pub unsafe trait WorldQuery {
|
|||||||
/// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
|
/// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
|
||||||
/// - `table` must correspond to `archetype`.
|
/// - `table` must correspond to `archetype`.
|
||||||
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
|
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w, 's>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
state: &Self::State,
|
state: &'s Self::State,
|
||||||
archetype: &'w Archetype,
|
archetype: &'w Archetype,
|
||||||
table: &'w Table,
|
table: &'w Table,
|
||||||
);
|
);
|
||||||
@ -101,7 +101,11 @@ pub unsafe trait WorldQuery {
|
|||||||
///
|
///
|
||||||
/// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
|
/// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
|
||||||
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
|
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
|
||||||
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table);
|
unsafe fn set_table<'w, 's>(
|
||||||
|
fetch: &mut Self::Fetch<'w>,
|
||||||
|
state: &'s Self::State,
|
||||||
|
table: &'w Table,
|
||||||
|
);
|
||||||
|
|
||||||
/// Adds any component accesses used by this [`WorldQuery`] to `access`.
|
/// Adds any component accesses used by this [`WorldQuery`] to `access`.
|
||||||
///
|
///
|
||||||
@ -166,7 +170,7 @@ macro_rules! impl_tuple_world_query {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
unsafe fn init_fetch<'w, 's>(world: UnsafeWorldCell<'w>, state: &'s Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
||||||
let ($($name,)*) = state;
|
let ($($name,)*) = state;
|
||||||
// SAFETY: The invariants are upheld by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)
|
($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)
|
||||||
@ -175,9 +179,9 @@ macro_rules! impl_tuple_world_query {
|
|||||||
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
|
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w, 's>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
state: &Self::State,
|
state: &'s Self::State,
|
||||||
archetype: &'w Archetype,
|
archetype: &'w Archetype,
|
||||||
table: &'w Table
|
table: &'w Table
|
||||||
) {
|
) {
|
||||||
@ -188,7 +192,7 @@ macro_rules! impl_tuple_world_query {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
|
unsafe fn set_table<'w, 's>(fetch: &mut Self::Fetch<'w>, state: &'s Self::State, table: &'w Table) {
|
||||||
let ($($name,)*) = fetch;
|
let ($($name,)*) = fetch;
|
||||||
let ($($state,)*) = state;
|
let ($($state,)*) = state;
|
||||||
// SAFETY: The invariants are upheld by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
//!
|
//!
|
||||||
//! Same as [`super::component`], but for bundles.
|
//! Same as [`super::component`], but for bundles.
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::any::{Any, TypeId};
|
use core::any::{Any, TypeId};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -172,7 +173,7 @@ impl<B: Bundle + Reflect + TypePath + BundleFromComponents> FromType<B> for Refl
|
|||||||
_ => panic!(
|
_ => panic!(
|
||||||
"expected bundle `{}` to be named struct or tuple",
|
"expected bundle `{}` to be named struct or tuple",
|
||||||
// FIXME: once we have unique reflect, use `TypePath`.
|
// FIXME: once we have unique reflect, use `TypePath`.
|
||||||
core::any::type_name::<B>(),
|
DebugName::type_name::<B>(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,7 +216,7 @@ impl<B: Bundle + Reflect + TypePath + BundleFromComponents> FromType<B> for Refl
|
|||||||
_ => panic!(
|
_ => panic!(
|
||||||
"expected bundle `{}` to be a named struct or tuple",
|
"expected bundle `{}` to be a named struct or tuple",
|
||||||
// FIXME: once we have unique reflect, use `TypePath`.
|
// FIXME: once we have unique reflect, use `TypePath`.
|
||||||
core::any::type_name::<B>(),
|
DebugName::type_name::<B>(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,7 +70,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
|
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
|
||||||
use disqualified::ShortName;
|
use bevy_utils::prelude::DebugName;
|
||||||
|
|
||||||
/// A struct used to operate on reflected [`Component`] trait of a type.
|
/// A struct used to operate on reflected [`Component`] trait of a type.
|
||||||
///
|
///
|
||||||
@ -308,7 +308,8 @@ impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
|
|||||||
},
|
},
|
||||||
apply: |mut entity, reflected_component| {
|
apply: |mut entity, reflected_component| {
|
||||||
if !C::Mutability::MUTABLE {
|
if !C::Mutability::MUTABLE {
|
||||||
let name = ShortName::of::<C>();
|
let name = DebugName::type_name::<C>();
|
||||||
|
let name = name.shortname();
|
||||||
panic!("Cannot call `ReflectComponent::apply` on component {name}. It is immutable, and cannot modified through reflection");
|
panic!("Cannot call `ReflectComponent::apply` on component {name}. It is immutable, and cannot modified through reflection");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +358,8 @@ impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
|
|||||||
reflect: |entity| entity.get::<C>().map(|c| c as &dyn Reflect),
|
reflect: |entity| entity.get::<C>().map(|c| c as &dyn Reflect),
|
||||||
reflect_mut: |entity| {
|
reflect_mut: |entity| {
|
||||||
if !C::Mutability::MUTABLE {
|
if !C::Mutability::MUTABLE {
|
||||||
let name = ShortName::of::<C>();
|
let name = DebugName::type_name::<C>();
|
||||||
|
let name = name.shortname();
|
||||||
panic!("Cannot call `ReflectComponent::reflect_mut` on component {name}. It is immutable, and cannot modified through reflection");
|
panic!("Cannot call `ReflectComponent::reflect_mut` on component {name}. It is immutable, and cannot modified through reflection");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,7 +372,8 @@ impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
|
|||||||
},
|
},
|
||||||
reflect_unchecked_mut: |entity| {
|
reflect_unchecked_mut: |entity| {
|
||||||
if !C::Mutability::MUTABLE {
|
if !C::Mutability::MUTABLE {
|
||||||
let name = ShortName::of::<C>();
|
let name = DebugName::type_name::<C>();
|
||||||
|
let name = name.shortname();
|
||||||
panic!("Cannot call `ReflectComponent::reflect_unchecked_mut` on component {name}. It is immutable, and cannot modified through reflection");
|
panic!("Cannot call `ReflectComponent::reflect_unchecked_mut` on component {name}. It is immutable, and cannot modified through reflection");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ mod from_world;
|
|||||||
mod map_entities;
|
mod map_entities;
|
||||||
mod resource;
|
mod resource;
|
||||||
|
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
pub use bundle::{ReflectBundle, ReflectBundleFns};
|
pub use bundle::{ReflectBundle, ReflectBundleFns};
|
||||||
pub use component::{ReflectComponent, ReflectComponentFns};
|
pub use component::{ReflectComponent, ReflectComponentFns};
|
||||||
pub use entity_commands::ReflectCommandExt;
|
pub use entity_commands::ReflectCommandExt;
|
||||||
@ -136,7 +137,7 @@ pub fn from_reflect_with_fallback<T: Reflect + TypePath>(
|
|||||||
`Default` or `FromWorld` traits. Are you perhaps missing a `#[reflect(Default)]` \
|
`Default` or `FromWorld` traits. Are you perhaps missing a `#[reflect(Default)]` \
|
||||||
or `#[reflect(FromWorld)]`?",
|
or `#[reflect(FromWorld)]`?",
|
||||||
// FIXME: once we have unique reflect, use `TypePath`.
|
// FIXME: once we have unique reflect, use `TypePath`.
|
||||||
core::any::type_name::<T>(),
|
DebugName::type_name::<T>(),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ mod relationship_source_collection;
|
|||||||
|
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
|
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
pub use related_methods::*;
|
pub use related_methods::*;
|
||||||
pub use relationship_query::*;
|
pub use relationship_query::*;
|
||||||
pub use relationship_source_collection::*;
|
pub use relationship_source_collection::*;
|
||||||
@ -105,8 +106,8 @@ pub trait Relationship: Component + Sized {
|
|||||||
warn!(
|
warn!(
|
||||||
"{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.",
|
"{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.",
|
||||||
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
|
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
|
||||||
core::any::type_name::<Self>(),
|
DebugName::type_name::<Self>(),
|
||||||
core::any::type_name::<Self>()
|
DebugName::type_name::<Self>()
|
||||||
);
|
);
|
||||||
world.commands().entity(entity).remove::<Self>();
|
world.commands().entity(entity).remove::<Self>();
|
||||||
return;
|
return;
|
||||||
@ -125,8 +126,8 @@ pub trait Relationship: Component + Sized {
|
|||||||
warn!(
|
warn!(
|
||||||
"{}The {}({target_entity:?}) relationship on entity {entity:?} relates to an entity that does not exist. The invalid {} relationship has been removed.",
|
"{}The {}({target_entity:?}) relationship on entity {entity:?} relates to an entity that does not exist. The invalid {} relationship has been removed.",
|
||||||
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
|
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
|
||||||
core::any::type_name::<Self>(),
|
DebugName::type_name::<Self>(),
|
||||||
core::any::type_name::<Self>()
|
DebugName::type_name::<Self>()
|
||||||
);
|
);
|
||||||
world.commands().entity(entity).remove::<Self>();
|
world.commands().entity(entity).remove::<Self>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
/// target entity of that relationship.
|
/// target entity of that relationship.
|
||||||
pub fn related<R: Relationship>(&'w self, entity: Entity) -> Option<Entity>
|
pub fn related<R: Relationship>(&'w self, entity: Entity) -> Option<Entity>
|
||||||
where
|
where
|
||||||
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w R>,
|
<D as QueryData>::ReadOnly: QueryData<Item<'w, 's> = &'w R>,
|
||||||
{
|
{
|
||||||
self.get(entity).map(R::get).ok()
|
self.get(entity).map(R::get).ok()
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> impl Iterator<Item = Entity> + 'w
|
) -> impl Iterator<Item = Entity> + 'w
|
||||||
where
|
where
|
||||||
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w S>,
|
<D as QueryData>::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
|
||||||
{
|
{
|
||||||
self.get(entity)
|
self.get(entity)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -42,7 +42,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
|
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
|
||||||
pub fn root_ancestor<R: Relationship>(&'w self, entity: Entity) -> Entity
|
pub fn root_ancestor<R: Relationship>(&'w self, entity: Entity) -> Entity
|
||||||
where
|
where
|
||||||
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w R>,
|
<D as QueryData>::ReadOnly: QueryData<Item<'w, 's> = &'w R>,
|
||||||
{
|
{
|
||||||
// Recursively search up the tree until we're out of parents
|
// Recursively search up the tree until we're out of parents
|
||||||
match self.get(entity) {
|
match self.get(entity) {
|
||||||
@ -60,9 +60,9 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn iter_leaves<S: RelationshipTarget>(
|
pub fn iter_leaves<S: RelationshipTarget>(
|
||||||
&'w self,
|
&'w self,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> impl Iterator<Item = Entity> + 'w
|
) -> impl Iterator<Item = Entity> + use<'w, 's, S, D, F>
|
||||||
where
|
where
|
||||||
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w S>,
|
<D as QueryData>::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
|
||||||
SourceIter<'w, S>: DoubleEndedIterator,
|
SourceIter<'w, S>: DoubleEndedIterator,
|
||||||
{
|
{
|
||||||
self.iter_descendants_depth_first(entity).filter(|entity| {
|
self.iter_descendants_depth_first(entity).filter(|entity| {
|
||||||
@ -80,7 +80,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> impl Iterator<Item = Entity> + 'w
|
) -> impl Iterator<Item = Entity> + 'w
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = (Option<&'w R>, Option<&'w R::RelationshipTarget>)>,
|
D::ReadOnly: QueryData<Item<'w, 's> = (Option<&'w R>, Option<&'w R::RelationshipTarget>)>,
|
||||||
{
|
{
|
||||||
self.get(entity)
|
self.get(entity)
|
||||||
.ok()
|
.ok()
|
||||||
@ -103,7 +103,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> DescendantIter<'w, 's, D, F, S>
|
) -> DescendantIter<'w, 's, D, F, S>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w S>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
|
||||||
{
|
{
|
||||||
DescendantIter::new(self, entity)
|
DescendantIter::new(self, entity)
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> DescendantDepthFirstIter<'w, 's, D, F, S>
|
) -> DescendantDepthFirstIter<'w, 's, D, F, S>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w S>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
|
||||||
SourceIter<'w, S>: DoubleEndedIterator,
|
SourceIter<'w, S>: DoubleEndedIterator,
|
||||||
{
|
{
|
||||||
DescendantDepthFirstIter::new(self, entity)
|
DescendantDepthFirstIter::new(self, entity)
|
||||||
@ -137,7 +137,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> AncestorIter<'w, 's, D, F, R>
|
) -> AncestorIter<'w, 's, D, F, R>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w R>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w R>,
|
||||||
{
|
{
|
||||||
AncestorIter::new(self, entity)
|
AncestorIter::new(self, entity)
|
||||||
}
|
}
|
||||||
@ -148,7 +148,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
/// Traverses the hierarchy breadth-first.
|
/// Traverses the hierarchy breadth-first.
|
||||||
pub struct DescendantIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
|
pub struct DescendantIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w S>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
|
||||||
{
|
{
|
||||||
children_query: &'w Query<'w, 's, D, F>,
|
children_query: &'w Query<'w, 's, D, F>,
|
||||||
vecdeque: VecDeque<Entity>,
|
vecdeque: VecDeque<Entity>,
|
||||||
@ -156,7 +156,7 @@ where
|
|||||||
|
|
||||||
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> DescendantIter<'w, 's, D, F, S>
|
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> DescendantIter<'w, 's, D, F, S>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w S>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
|
||||||
{
|
{
|
||||||
/// Returns a new [`DescendantIter`].
|
/// Returns a new [`DescendantIter`].
|
||||||
pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
|
pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
|
||||||
@ -174,7 +174,7 @@ where
|
|||||||
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
|
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
|
||||||
for DescendantIter<'w, 's, D, F, S>
|
for DescendantIter<'w, 's, D, F, S>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w S>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
|
||||||
{
|
{
|
||||||
type Item = Entity;
|
type Item = Entity;
|
||||||
|
|
||||||
@ -194,7 +194,7 @@ where
|
|||||||
/// Traverses the hierarchy depth-first.
|
/// Traverses the hierarchy depth-first.
|
||||||
pub struct DescendantDepthFirstIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
|
pub struct DescendantDepthFirstIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w S>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
|
||||||
{
|
{
|
||||||
children_query: &'w Query<'w, 's, D, F>,
|
children_query: &'w Query<'w, 's, D, F>,
|
||||||
stack: SmallVec<[Entity; 8]>,
|
stack: SmallVec<[Entity; 8]>,
|
||||||
@ -203,7 +203,7 @@ where
|
|||||||
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
|
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
|
||||||
DescendantDepthFirstIter<'w, 's, D, F, S>
|
DescendantDepthFirstIter<'w, 's, D, F, S>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w S>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
|
||||||
SourceIter<'w, S>: DoubleEndedIterator,
|
SourceIter<'w, S>: DoubleEndedIterator,
|
||||||
{
|
{
|
||||||
/// Returns a new [`DescendantDepthFirstIter`].
|
/// Returns a new [`DescendantDepthFirstIter`].
|
||||||
@ -220,7 +220,7 @@ where
|
|||||||
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
|
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
|
||||||
for DescendantDepthFirstIter<'w, 's, D, F, S>
|
for DescendantDepthFirstIter<'w, 's, D, F, S>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w S>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
|
||||||
SourceIter<'w, S>: DoubleEndedIterator,
|
SourceIter<'w, S>: DoubleEndedIterator,
|
||||||
{
|
{
|
||||||
type Item = Entity;
|
type Item = Entity;
|
||||||
@ -239,7 +239,7 @@ where
|
|||||||
/// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`].
|
/// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`].
|
||||||
pub struct AncestorIter<'w, 's, D: QueryData, F: QueryFilter, R: Relationship>
|
pub struct AncestorIter<'w, 's, D: QueryData, F: QueryFilter, R: Relationship>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w R>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w R>,
|
||||||
{
|
{
|
||||||
parent_query: &'w Query<'w, 's, D, F>,
|
parent_query: &'w Query<'w, 's, D, F>,
|
||||||
next: Option<Entity>,
|
next: Option<Entity>,
|
||||||
@ -247,7 +247,7 @@ where
|
|||||||
|
|
||||||
impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> AncestorIter<'w, 's, D, F, R>
|
impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> AncestorIter<'w, 's, D, F, R>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w R>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w R>,
|
||||||
{
|
{
|
||||||
/// Returns a new [`AncestorIter`].
|
/// Returns a new [`AncestorIter`].
|
||||||
pub fn new(parent_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
|
pub fn new(parent_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
|
||||||
@ -261,7 +261,7 @@ where
|
|||||||
impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> Iterator
|
impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> Iterator
|
||||||
for AncestorIter<'w, 's, D, F, R>
|
for AncestorIter<'w, 's, D, F, R>
|
||||||
where
|
where
|
||||||
D::ReadOnly: QueryData<Item<'w> = &'w R>,
|
D::ReadOnly: QueryData<Item<'w, 's> = &'w R>,
|
||||||
{
|
{
|
||||||
type Item = Entity;
|
type Item = Entity;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use alloc::{borrow::Cow, boxed::Box, format};
|
use alloc::{boxed::Box, format};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::ops::Not;
|
use core::ops::Not;
|
||||||
|
|
||||||
use crate::system::{
|
use crate::system::{
|
||||||
@ -154,7 +155,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
|||||||
let a = IntoSystem::into_system(self);
|
let a = IntoSystem::into_system(self);
|
||||||
let b = IntoSystem::into_system(and);
|
let b = IntoSystem::into_system(and);
|
||||||
let name = format!("{} && {}", a.name(), b.name());
|
let name = format!("{} && {}", a.name(), b.name());
|
||||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new run condition that only returns `false`
|
/// Returns a new run condition that only returns `false`
|
||||||
@ -206,7 +207,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
|||||||
let a = IntoSystem::into_system(self);
|
let a = IntoSystem::into_system(self);
|
||||||
let b = IntoSystem::into_system(nand);
|
let b = IntoSystem::into_system(nand);
|
||||||
let name = format!("!({} && {})", a.name(), b.name());
|
let name = format!("!({} && {})", a.name(), b.name());
|
||||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new run condition that only returns `true`
|
/// Returns a new run condition that only returns `true`
|
||||||
@ -258,7 +259,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
|||||||
let a = IntoSystem::into_system(self);
|
let a = IntoSystem::into_system(self);
|
||||||
let b = IntoSystem::into_system(nor);
|
let b = IntoSystem::into_system(nor);
|
||||||
let name = format!("!({} || {})", a.name(), b.name());
|
let name = format!("!({} || {})", a.name(), b.name());
|
||||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new run condition that returns `true`
|
/// Returns a new run condition that returns `true`
|
||||||
@ -305,7 +306,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
|||||||
let a = IntoSystem::into_system(self);
|
let a = IntoSystem::into_system(self);
|
||||||
let b = IntoSystem::into_system(or);
|
let b = IntoSystem::into_system(or);
|
||||||
let name = format!("{} || {}", a.name(), b.name());
|
let name = format!("{} || {}", a.name(), b.name());
|
||||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new run condition that only returns `true`
|
/// Returns a new run condition that only returns `true`
|
||||||
@ -357,7 +358,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
|||||||
let a = IntoSystem::into_system(self);
|
let a = IntoSystem::into_system(self);
|
||||||
let b = IntoSystem::into_system(xnor);
|
let b = IntoSystem::into_system(xnor);
|
||||||
let name = format!("!({} ^ {})", a.name(), b.name());
|
let name = format!("!({} ^ {})", a.name(), b.name());
|
||||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new run condition that only returns `true`
|
/// Returns a new run condition that only returns `true`
|
||||||
@ -399,7 +400,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
|||||||
let a = IntoSystem::into_system(self);
|
let a = IntoSystem::into_system(self);
|
||||||
let b = IntoSystem::into_system(xor);
|
let b = IntoSystem::into_system(xor);
|
||||||
let name = format!("({} ^ {})", a.name(), b.name());
|
let name = format!("({} ^ {})", a.name(), b.name());
|
||||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,8 @@ mod multi_threaded;
|
|||||||
mod simple;
|
mod simple;
|
||||||
mod single_threaded;
|
mod single_threaded;
|
||||||
|
|
||||||
use alloc::{borrow::Cow, vec, vec::Vec};
|
use alloc::{vec, vec::Vec};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::any::TypeId;
|
use core::any::TypeId;
|
||||||
|
|
||||||
#[expect(deprecated, reason = "We still need to support this.")]
|
#[expect(deprecated, reason = "We still need to support this.")]
|
||||||
@ -158,8 +159,8 @@ impl System for ApplyDeferred {
|
|||||||
type In = ();
|
type In = ();
|
||||||
type Out = Result<()>;
|
type Out = Result<()>;
|
||||||
|
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> DebugName {
|
||||||
Cow::Borrowed("bevy_ecs::apply_deferred")
|
DebugName::borrowed("bevy_ecs::apply_deferred")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flags(&self) -> SystemStateFlags {
|
fn flags(&self) -> SystemStateFlags {
|
||||||
|
|||||||
@ -342,7 +342,7 @@ impl<'scope, 'env: 'scope, 'sys> Context<'scope, 'env, 'sys> {
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
|
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
|
||||||
{
|
{
|
||||||
eprintln!("Encountered a panic in system `{}`!", &*system.name());
|
eprintln!("Encountered a panic in system `{}`!", system.name());
|
||||||
}
|
}
|
||||||
// set the payload to propagate the error
|
// set the payload to propagate the error
|
||||||
{
|
{
|
||||||
@ -799,7 +799,7 @@ fn apply_deferred(
|
|||||||
{
|
{
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Encountered a panic when applying buffers for system `{}`!",
|
"Encountered a panic when applying buffers for system `{}`!",
|
||||||
&*system.name()
|
system.name()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Err(payload);
|
return Err(payload);
|
||||||
|
|||||||
@ -73,7 +73,7 @@ impl SystemExecutor for SimpleExecutor {
|
|||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let name = schedule.systems[system_index].system.name();
|
let name = schedule.systems[system_index].system.name();
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let should_run_span = info_span!("check_conditions", name = &*name).entered();
|
let should_run_span = info_span!("check_conditions", name = name.as_string()).entered();
|
||||||
|
|
||||||
let mut should_run = !self.completed_systems.contains(system_index);
|
let mut should_run = !self.completed_systems.contains(system_index);
|
||||||
for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
|
for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
|
||||||
@ -161,7 +161,7 @@ impl SystemExecutor for SimpleExecutor {
|
|||||||
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
|
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
|
||||||
{
|
{
|
||||||
if let Err(payload) = std::panic::catch_unwind(f) {
|
if let Err(payload) = std::panic::catch_unwind(f) {
|
||||||
eprintln!("Encountered a panic in system `{}`!", &*system.name());
|
eprintln!("Encountered a panic in system `{}`!", system.name());
|
||||||
std::panic::resume_unwind(payload);
|
std::panic::resume_unwind(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,7 +74,7 @@ impl SystemExecutor for SingleThreadedExecutor {
|
|||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let name = schedule.systems[system_index].system.name();
|
let name = schedule.systems[system_index].system.name();
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let should_run_span = info_span!("check_conditions", name = &*name).entered();
|
let should_run_span = info_span!("check_conditions", name = name.as_string()).entered();
|
||||||
|
|
||||||
let mut should_run = !self.completed_systems.contains(system_index);
|
let mut should_run = !self.completed_systems.contains(system_index);
|
||||||
for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
|
for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
|
||||||
@ -166,7 +166,7 @@ impl SystemExecutor for SingleThreadedExecutor {
|
|||||||
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
|
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
|
||||||
{
|
{
|
||||||
if let Err(payload) = std::panic::catch_unwind(f) {
|
if let Err(payload) = std::panic::catch_unwind(f) {
|
||||||
eprintln!("Encountered a panic in system `{}`!", &*system.name());
|
eprintln!("Encountered a panic in system `{}`!", system.name());
|
||||||
std::panic::resume_unwind(payload);
|
std::panic::resume_unwind(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
clippy::module_inception,
|
clippy::module_inception,
|
||||||
reason = "This instance of module inception is being discussed; see #17344."
|
reason = "This instance of module inception is being discussed; see #17344."
|
||||||
)]
|
)]
|
||||||
use alloc::borrow::Cow;
|
|
||||||
use alloc::{
|
use alloc::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
@ -12,12 +11,11 @@ use alloc::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use bevy_platform::collections::{HashMap, HashSet};
|
use bevy_platform::collections::{HashMap, HashSet};
|
||||||
use bevy_utils::{default, TypeIdMap};
|
use bevy_utils::{default, prelude::DebugName, TypeIdMap};
|
||||||
use core::{
|
use core::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
fmt::{Debug, Write},
|
fmt::{Debug, Write},
|
||||||
};
|
};
|
||||||
use disqualified::ShortName;
|
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use pass::ScheduleBuildPassObj;
|
use pass::ScheduleBuildPassObj;
|
||||||
@ -1694,14 +1692,14 @@ impl ScheduleGraph {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_node_name_inner(&self, id: &NodeId, report_sets: bool) -> String {
|
fn get_node_name_inner(&self, id: &NodeId, report_sets: bool) -> String {
|
||||||
let name = match id {
|
match id {
|
||||||
NodeId::System(_) => {
|
NodeId::System(_) => {
|
||||||
let name = self.systems[id.index()]
|
let name = self.systems[id.index()].get().unwrap().system.name();
|
||||||
.get()
|
let name = if self.settings.use_shortnames {
|
||||||
.unwrap()
|
name.shortname().to_string()
|
||||||
.system
|
} else {
|
||||||
.name()
|
name.to_string()
|
||||||
.to_string();
|
};
|
||||||
if report_sets {
|
if report_sets {
|
||||||
let sets = self.names_of_sets_containing_node(id);
|
let sets = self.names_of_sets_containing_node(id);
|
||||||
if sets.is_empty() {
|
if sets.is_empty() {
|
||||||
@ -1723,11 +1721,6 @@ impl ScheduleGraph {
|
|||||||
set.name()
|
set.name()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
if self.settings.use_shortnames {
|
|
||||||
ShortName(&name).to_string()
|
|
||||||
} else {
|
|
||||||
name
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2007,7 +2000,7 @@ impl ScheduleGraph {
|
|||||||
&'a self,
|
&'a self,
|
||||||
ambiguities: &'a [(NodeId, NodeId, Vec<ComponentId>)],
|
ambiguities: &'a [(NodeId, NodeId, Vec<ComponentId>)],
|
||||||
components: &'a Components,
|
components: &'a Components,
|
||||||
) -> impl Iterator<Item = (String, String, Vec<Cow<'a, str>>)> + 'a {
|
) -> impl Iterator<Item = (String, String, Vec<DebugName>)> + 'a {
|
||||||
ambiguities
|
ambiguities
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |(system_a, system_b, conflicts)| {
|
.map(move |(system_a, system_b, conflicts)| {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::{
|
use core::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
@ -196,7 +197,7 @@ impl<T: 'static> SystemTypeSet<T> {
|
|||||||
impl<T> Debug for SystemTypeSet<T> {
|
impl<T> Debug for SystemTypeSet<T> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_tuple("SystemTypeSet")
|
f.debug_tuple("SystemTypeSet")
|
||||||
.field(&format_args!("fn {}()", &core::any::type_name::<T>()))
|
.field(&format_args!("fn {}()", DebugName::type_name::<T>()))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -895,9 +895,9 @@ mod tests {
|
|||||||
($schedule:expr, $skipped_systems:expr, $($system:expr),*) => {
|
($schedule:expr, $skipped_systems:expr, $($system:expr),*) => {
|
||||||
// pull an ordered list of systems in the schedule, and save the
|
// pull an ordered list of systems in the schedule, and save the
|
||||||
// system TypeId, and name.
|
// system TypeId, and name.
|
||||||
let systems: Vec<(TypeId, alloc::borrow::Cow<'static, str>)> = $schedule.systems().unwrap()
|
let systems: Vec<(TypeId, alloc::string::String)> = $schedule.systems().unwrap()
|
||||||
.map(|(_, system)| {
|
.map(|(_, system)| {
|
||||||
(system.type_id(), system.name())
|
(system.type_id(), system.name().as_string())
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|||||||
@ -3,8 +3,8 @@ use crate::{
|
|||||||
component::{CheckChangeTicks, ComponentId, ComponentTicks, Components, Tick, TickCells},
|
component::{CheckChangeTicks, ComponentId, ComponentTicks, Components, Tick, TickCells},
|
||||||
storage::{blob_vec::BlobVec, SparseSet},
|
storage::{blob_vec::BlobVec, SparseSet},
|
||||||
};
|
};
|
||||||
use alloc::string::String;
|
|
||||||
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
|
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::{cell::UnsafeCell, mem::ManuallyDrop, panic::Location};
|
use core::{cell::UnsafeCell, mem::ManuallyDrop, panic::Location};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -23,7 +23,7 @@ pub struct ResourceData<const SEND: bool> {
|
|||||||
not(feature = "std"),
|
not(feature = "std"),
|
||||||
expect(dead_code, reason = "currently only used with the std feature")
|
expect(dead_code, reason = "currently only used with the std feature")
|
||||||
)]
|
)]
|
||||||
type_name: String,
|
type_name: DebugName,
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
origin_thread_id: Option<ThreadId>,
|
origin_thread_id: Option<ThreadId>,
|
||||||
changed_by: MaybeLocation<UnsafeCell<&'static Location<'static>>>,
|
changed_by: MaybeLocation<UnsafeCell<&'static Location<'static>>>,
|
||||||
@ -385,7 +385,7 @@ impl<const SEND: bool> Resources<SEND> {
|
|||||||
data: ManuallyDrop::new(data),
|
data: ManuallyDrop::new(data),
|
||||||
added_ticks: UnsafeCell::new(Tick::new(0)),
|
added_ticks: UnsafeCell::new(Tick::new(0)),
|
||||||
changed_ticks: UnsafeCell::new(Tick::new(0)),
|
changed_ticks: UnsafeCell::new(Tick::new(0)),
|
||||||
type_name: String::from(component_info.name()),
|
type_name: component_info.name(),
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
origin_thread_id: None,
|
origin_thread_id: None,
|
||||||
changed_by: MaybeLocation::caller().map(UnsafeCell::new),
|
changed_by: MaybeLocation::caller().map(UnsafeCell::new),
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use alloc::{borrow::Cow, vec::Vec};
|
use alloc::vec::Vec;
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
|
|
||||||
use super::{IntoSystem, ReadOnlySystem, System, SystemParamValidationError};
|
use super::{IntoSystem, ReadOnlySystem, System, SystemParamValidationError};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -101,7 +102,7 @@ where
|
|||||||
pub struct AdapterSystem<Func, S> {
|
pub struct AdapterSystem<Func, S> {
|
||||||
func: Func,
|
func: Func,
|
||||||
system: S,
|
system: S,
|
||||||
name: Cow<'static, str>,
|
name: DebugName,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Func, S> AdapterSystem<Func, S>
|
impl<Func, S> AdapterSystem<Func, S>
|
||||||
@ -110,7 +111,7 @@ where
|
|||||||
S: System,
|
S: System,
|
||||||
{
|
{
|
||||||
/// Creates a new [`System`] that uses `func` to adapt `system`, via the [`Adapt`] trait.
|
/// Creates a new [`System`] that uses `func` to adapt `system`, via the [`Adapt`] trait.
|
||||||
pub const fn new(func: Func, system: S, name: Cow<'static, str>) -> Self {
|
pub const fn new(func: Func, system: S, name: DebugName) -> Self {
|
||||||
Self { func, system, name }
|
Self { func, system, name }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +124,7 @@ where
|
|||||||
type In = Func::In;
|
type In = Func::In;
|
||||||
type Out = Func::Out;
|
type Out = Func::Out;
|
||||||
|
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> DebugName {
|
||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use alloc::{borrow::Cow, format, vec::Vec};
|
use alloc::{format, vec::Vec};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -55,7 +56,7 @@ use super::{IntoSystem, ReadOnlySystem, System};
|
|||||||
/// IntoSystem::into_system(resource_equals(A(1))),
|
/// IntoSystem::into_system(resource_equals(A(1))),
|
||||||
/// IntoSystem::into_system(resource_equals(B(1))),
|
/// IntoSystem::into_system(resource_equals(B(1))),
|
||||||
/// // The name of the combined system.
|
/// // The name of the combined system.
|
||||||
/// std::borrow::Cow::Borrowed("a ^ b"),
|
/// "a ^ b".into(),
|
||||||
/// )));
|
/// )));
|
||||||
/// # fn my_system(mut flag: ResMut<RanFlag>) { flag.0 = true; }
|
/// # fn my_system(mut flag: ResMut<RanFlag>) { flag.0 = true; }
|
||||||
/// #
|
/// #
|
||||||
@ -112,14 +113,14 @@ pub struct CombinatorSystem<Func, A, B> {
|
|||||||
_marker: PhantomData<fn() -> Func>,
|
_marker: PhantomData<fn() -> Func>,
|
||||||
a: A,
|
a: A,
|
||||||
b: B,
|
b: B,
|
||||||
name: Cow<'static, str>,
|
name: DebugName,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Func, A, B> CombinatorSystem<Func, A, B> {
|
impl<Func, A, B> CombinatorSystem<Func, A, B> {
|
||||||
/// Creates a new system that combines two inner systems.
|
/// Creates a new system that combines two inner systems.
|
||||||
///
|
///
|
||||||
/// The returned system will only be usable if `Func` implements [`Combine<A, B>`].
|
/// The returned system will only be usable if `Func` implements [`Combine<A, B>`].
|
||||||
pub fn new(a: A, b: B, name: Cow<'static, str>) -> Self {
|
pub fn new(a: A, b: B, name: DebugName) -> Self {
|
||||||
Self {
|
Self {
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
a,
|
a,
|
||||||
@ -138,7 +139,7 @@ where
|
|||||||
type In = Func::In;
|
type In = Func::In;
|
||||||
type Out = Func::Out;
|
type Out = Func::Out;
|
||||||
|
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> DebugName {
|
||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,7 +272,7 @@ where
|
|||||||
let system_a = IntoSystem::into_system(this.a);
|
let system_a = IntoSystem::into_system(this.a);
|
||||||
let system_b = IntoSystem::into_system(this.b);
|
let system_b = IntoSystem::into_system(this.b);
|
||||||
let name = format!("Pipe({}, {})", system_a.name(), system_b.name());
|
let name = format!("Pipe({}, {})", system_a.name(), system_b.name());
|
||||||
PipeSystem::new(system_a, system_b, Cow::Owned(name))
|
PipeSystem::new(system_a, system_b, DebugName::owned(name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,7 +318,7 @@ where
|
|||||||
pub struct PipeSystem<A, B> {
|
pub struct PipeSystem<A, B> {
|
||||||
a: A,
|
a: A,
|
||||||
b: B,
|
b: B,
|
||||||
name: Cow<'static, str>,
|
name: DebugName,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B> PipeSystem<A, B>
|
impl<A, B> PipeSystem<A, B>
|
||||||
@ -327,7 +328,7 @@ where
|
|||||||
for<'a> B::In: SystemInput<Inner<'a> = A::Out>,
|
for<'a> B::In: SystemInput<Inner<'a> = A::Out>,
|
||||||
{
|
{
|
||||||
/// Creates a new system that pipes two inner systems.
|
/// Creates a new system that pipes two inner systems.
|
||||||
pub fn new(a: A, b: B, name: Cow<'static, str>) -> Self {
|
pub fn new(a: A, b: B, name: DebugName) -> Self {
|
||||||
Self { a, b, name }
|
Self { a, b, name }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -341,7 +342,7 @@ where
|
|||||||
type In = A::In;
|
type In = A::In;
|
||||||
type Out = B::Out;
|
type Out = B::Out;
|
||||||
|
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> DebugName {
|
||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -144,10 +144,11 @@ where
|
|||||||
|
|
||||||
/// A [`Command`] that runs the given system,
|
/// A [`Command`] that runs the given system,
|
||||||
/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
|
/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
|
||||||
pub fn run_system_cached<M, S>(system: S) -> impl Command<Result>
|
pub fn run_system_cached<O, M, S>(system: S) -> impl Command<Result>
|
||||||
where
|
where
|
||||||
|
O: 'static,
|
||||||
M: 'static,
|
M: 'static,
|
||||||
S: IntoSystem<(), (), M> + Send + 'static,
|
S: IntoSystem<(), O, M> + Send + 'static,
|
||||||
{
|
{
|
||||||
move |world: &mut World| -> Result {
|
move |world: &mut World| -> Result {
|
||||||
world.run_system_cached(system)?;
|
world.run_system_cached(system)?;
|
||||||
@ -157,11 +158,15 @@ where
|
|||||||
|
|
||||||
/// A [`Command`] that runs the given system with the given input value,
|
/// A [`Command`] that runs the given system with the given input value,
|
||||||
/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
|
/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
|
||||||
pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command<Result>
|
pub fn run_system_cached_with<I, O, M, S>(
|
||||||
|
system: S,
|
||||||
|
input: I::Inner<'static>,
|
||||||
|
) -> impl Command<Result>
|
||||||
where
|
where
|
||||||
I: SystemInput<Inner<'static>: Send> + Send + 'static,
|
I: SystemInput<Inner<'static>: Send> + Send + 'static,
|
||||||
|
O: 'static,
|
||||||
M: 'static,
|
M: 'static,
|
||||||
S: IntoSystem<I, (), M> + Send + 'static,
|
S: IntoSystem<I, O, M> + Send + 'static,
|
||||||
{
|
{
|
||||||
move |world: &mut World| -> Result {
|
move |world: &mut World| -> Result {
|
||||||
world.run_system_cached_with(system, input)?;
|
world.run_system_cached_with(system, input)?;
|
||||||
@ -175,7 +180,7 @@ where
|
|||||||
pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command<Result>
|
pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command<Result>
|
||||||
where
|
where
|
||||||
I: SystemInput + Send + 'static,
|
I: SystemInput + Send + 'static,
|
||||||
O: Send + 'static,
|
O: 'static,
|
||||||
{
|
{
|
||||||
move |world: &mut World| -> Result {
|
move |world: &mut World| -> Result {
|
||||||
world.unregister_system(system_id)?;
|
world.unregister_system(system_id)?;
|
||||||
|
|||||||
@ -917,7 +917,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
///
|
///
|
||||||
/// It will internally return a [`RegisteredSystemError`](crate::system::system_registry::RegisteredSystemError),
|
/// It will internally return a [`RegisteredSystemError`](crate::system::system_registry::RegisteredSystemError),
|
||||||
/// which will be handled by [logging the error at the `warn` level](warn).
|
/// which will be handled by [logging the error at the `warn` level](warn).
|
||||||
pub fn run_system(&mut self, id: SystemId) {
|
pub fn run_system<O: 'static>(&mut self, id: SystemId<(), O>) {
|
||||||
self.queue(command::run_system(id).handle_error_with(warn));
|
self.queue(command::run_system(id).handle_error_with(warn));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,7 +1010,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
) -> SystemId<I, O>
|
) -> SystemId<I, O>
|
||||||
where
|
where
|
||||||
I: SystemInput + Send + 'static,
|
I: SystemInput + Send + 'static,
|
||||||
O: Send + 'static,
|
O: 'static,
|
||||||
{
|
{
|
||||||
let entity = self.spawn_empty().id();
|
let entity = self.spawn_empty().id();
|
||||||
let system = RegisteredSystem::<I, O>::new(Box::new(IntoSystem::into_system(system)));
|
let system = RegisteredSystem::<I, O>::new(Box::new(IntoSystem::into_system(system)));
|
||||||
@ -1035,7 +1035,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
pub fn unregister_system<I, O>(&mut self, system_id: SystemId<I, O>)
|
pub fn unregister_system<I, O>(&mut self, system_id: SystemId<I, O>)
|
||||||
where
|
where
|
||||||
I: SystemInput + Send + 'static,
|
I: SystemInput + Send + 'static,
|
||||||
O: Send + 'static,
|
O: 'static,
|
||||||
{
|
{
|
||||||
self.queue(command::unregister_system(system_id).handle_error_with(warn));
|
self.queue(command::unregister_system(system_id).handle_error_with(warn));
|
||||||
}
|
}
|
||||||
@ -1084,10 +1084,11 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
/// consider passing them in as inputs via [`Commands::run_system_cached_with`].
|
/// consider passing them in as inputs via [`Commands::run_system_cached_with`].
|
||||||
///
|
///
|
||||||
/// If that's not an option, consider [`Commands::register_system`] instead.
|
/// If that's not an option, consider [`Commands::register_system`] instead.
|
||||||
pub fn run_system_cached<M, S>(&mut self, system: S)
|
pub fn run_system_cached<O, M, S>(&mut self, system: S)
|
||||||
where
|
where
|
||||||
|
O: 'static,
|
||||||
M: 'static,
|
M: 'static,
|
||||||
S: IntoSystem<(), (), M> + Send + 'static,
|
S: IntoSystem<(), O, M> + Send + 'static,
|
||||||
{
|
{
|
||||||
self.queue(command::run_system_cached(system).handle_error_with(warn));
|
self.queue(command::run_system_cached(system).handle_error_with(warn));
|
||||||
}
|
}
|
||||||
@ -1114,11 +1115,12 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
/// consider passing them in as inputs.
|
/// consider passing them in as inputs.
|
||||||
///
|
///
|
||||||
/// If that's not an option, consider [`Commands::register_system`] instead.
|
/// If that's not an option, consider [`Commands::register_system`] instead.
|
||||||
pub fn run_system_cached_with<I, M, S>(&mut self, system: S, input: I::Inner<'static>)
|
pub fn run_system_cached_with<I, O, M, S>(&mut self, system: S, input: I::Inner<'static>)
|
||||||
where
|
where
|
||||||
I: SystemInput<Inner<'static>: Send> + Send + 'static,
|
I: SystemInput<Inner<'static>: Send> + Send + 'static,
|
||||||
|
O: 'static,
|
||||||
M: 'static,
|
M: 'static,
|
||||||
S: IntoSystem<I, (), M> + Send + 'static,
|
S: IntoSystem<I, O, M> + Send + 'static,
|
||||||
{
|
{
|
||||||
self.queue(command::run_system_cached_with(system, input).handle_error_with(warn));
|
self.queue(command::run_system_cached_with(system, input).handle_error_with(warn));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use alloc::{borrow::Cow, vec, vec::Vec};
|
use alloc::{borrow::Cow, vec, vec::Vec};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use variadics_please::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ where
|
|||||||
///
|
///
|
||||||
/// Useful to give closure systems more readable and unique names for debugging and tracing.
|
/// Useful to give closure systems more readable and unique names for debugging and tracing.
|
||||||
pub fn with_name(mut self, new_name: impl Into<Cow<'static, str>>) -> Self {
|
pub fn with_name(mut self, new_name: impl Into<Cow<'static, str>>) -> Self {
|
||||||
self.system_meta.set_name(new_name.into());
|
self.system_meta.set_name(new_name);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +84,7 @@ where
|
|||||||
type Out = F::Out;
|
type Out = F::Out;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> DebugName {
|
||||||
self.system_meta.name.clone()
|
self.system_meta.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +182,7 @@ where
|
|||||||
check_system_change_tick(
|
check_system_change_tick(
|
||||||
&mut self.system_meta.last_run,
|
&mut self.system_meta.last_run,
|
||||||
check,
|
check,
|
||||||
self.system_meta.name.as_ref(),
|
self.system_meta.name.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use alloc::{borrow::Cow, vec, vec::Vec};
|
use alloc::{borrow::Cow, vec, vec::Vec};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use variadics_please::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ use super::{
|
|||||||
/// The metadata of a [`System`].
|
/// The metadata of a [`System`].
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SystemMeta {
|
pub struct SystemMeta {
|
||||||
pub(crate) name: Cow<'static, str>,
|
pub(crate) name: DebugName,
|
||||||
// NOTE: this must be kept private. making a SystemMeta non-send is irreversible to prevent
|
// NOTE: this must be kept private. making a SystemMeta non-send is irreversible to prevent
|
||||||
// SystemParams from overriding each other
|
// SystemParams from overriding each other
|
||||||
flags: SystemStateFlags,
|
flags: SystemStateFlags,
|
||||||
@ -37,21 +38,21 @@ pub struct SystemMeta {
|
|||||||
|
|
||||||
impl SystemMeta {
|
impl SystemMeta {
|
||||||
pub(crate) fn new<T>() -> Self {
|
pub(crate) fn new<T>() -> Self {
|
||||||
let name = core::any::type_name::<T>();
|
let name = DebugName::type_name::<T>();
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
#[cfg(feature = "trace")]
|
||||||
|
system_span: info_span!("system", name = name.clone().as_string()),
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
commands_span: info_span!("system_commands", name = name.clone().as_string()),
|
||||||
|
name,
|
||||||
flags: SystemStateFlags::empty(),
|
flags: SystemStateFlags::empty(),
|
||||||
last_run: Tick::new(0),
|
last_run: Tick::new(0),
|
||||||
#[cfg(feature = "trace")]
|
|
||||||
system_span: info_span!("system", name = name),
|
|
||||||
#[cfg(feature = "trace")]
|
|
||||||
commands_span: info_span!("system_commands", name = name),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the system's name
|
/// Returns the system's name
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &DebugName {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ impl SystemMeta {
|
|||||||
self.system_span = info_span!("system", name = name);
|
self.system_span = info_span!("system", name = name);
|
||||||
self.commands_span = info_span!("system_commands", name = name);
|
self.commands_span = info_span!("system_commands", name = name);
|
||||||
}
|
}
|
||||||
self.name = new_name;
|
self.name = new_name.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the system is [`Send`].
|
/// Returns true if the system is [`Send`].
|
||||||
@ -600,7 +601,7 @@ where
|
|||||||
type Out = F::Out;
|
type Out = F::Out;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> DebugName {
|
||||||
self.system_meta.name.clone()
|
self.system_meta.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,7 +713,7 @@ where
|
|||||||
check_system_change_tick(
|
check_system_change_tick(
|
||||||
&mut self.system_meta.last_run,
|
&mut self.system_meta.last_run,
|
||||||
check,
|
check,
|
||||||
self.system_meta.name.as_ref(),
|
self.system_meta.name.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use alloc::{borrow::Cow, vec::Vec};
|
use alloc::vec::Vec;
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -112,7 +113,7 @@ where
|
|||||||
type Out = Result;
|
type Out = Result;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> DebugName {
|
||||||
self.observer.name()
|
self.observer.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
batching::BatchingStrategy,
|
batching::BatchingStrategy,
|
||||||
component::Tick,
|
component::Tick,
|
||||||
@ -1185,7 +1187,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
/// [`par_iter_mut`]: Self::par_iter_mut
|
/// [`par_iter_mut`]: Self::par_iter_mut
|
||||||
/// [`World`]: crate::world::World
|
/// [`World`]: crate::world::World
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn par_iter(&self) -> QueryParIter<'_, '_, D::ReadOnly, F> {
|
pub fn par_iter(&self) -> QueryParIter<'_, 's, D::ReadOnly, F> {
|
||||||
self.as_readonly().par_iter_inner()
|
self.as_readonly().par_iter_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1220,7 +1222,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
/// [`par_iter`]: Self::par_iter
|
/// [`par_iter`]: Self::par_iter
|
||||||
/// [`World`]: crate::world::World
|
/// [`World`]: crate::world::World
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn par_iter_mut(&mut self) -> QueryParIter<'_, '_, D, F> {
|
pub fn par_iter_mut(&mut self) -> QueryParIter<'_, 's, D, F> {
|
||||||
self.reborrow().par_iter_inner()
|
self.reborrow().par_iter_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1280,7 +1282,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn par_iter_many<EntityList: IntoIterator<Item: EntityEquivalent>>(
|
pub fn par_iter_many<EntityList: IntoIterator<Item: EntityEquivalent>>(
|
||||||
&self,
|
&self,
|
||||||
entities: EntityList,
|
entities: EntityList,
|
||||||
) -> QueryParManyIter<'_, '_, D::ReadOnly, F, EntityList::Item> {
|
) -> QueryParManyIter<'_, 's, D::ReadOnly, F, EntityList::Item> {
|
||||||
QueryParManyIter {
|
QueryParManyIter {
|
||||||
world: self.world,
|
world: self.world,
|
||||||
state: self.state.as_readonly(),
|
state: self.state.as_readonly(),
|
||||||
@ -1309,7 +1311,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn par_iter_many_unique<EntityList: EntitySet<Item: Sync>>(
|
pub fn par_iter_many_unique<EntityList: EntitySet<Item: Sync>>(
|
||||||
&self,
|
&self,
|
||||||
entities: EntityList,
|
entities: EntityList,
|
||||||
) -> QueryParManyUniqueIter<'_, '_, D::ReadOnly, F, EntityList::Item> {
|
) -> QueryParManyUniqueIter<'_, 's, D::ReadOnly, F, EntityList::Item> {
|
||||||
QueryParManyUniqueIter {
|
QueryParManyUniqueIter {
|
||||||
world: self.world,
|
world: self.world,
|
||||||
state: self.state.as_readonly(),
|
state: self.state.as_readonly(),
|
||||||
@ -1338,7 +1340,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn par_iter_many_unique_mut<EntityList: EntitySet<Item: Sync>>(
|
pub fn par_iter_many_unique_mut<EntityList: EntitySet<Item: Sync>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
entities: EntityList,
|
entities: EntityList,
|
||||||
) -> QueryParManyUniqueIter<'_, '_, D, F, EntityList::Item> {
|
) -> QueryParManyUniqueIter<'_, 's, D, F, EntityList::Item> {
|
||||||
QueryParManyUniqueIter {
|
QueryParManyUniqueIter {
|
||||||
world: self.world,
|
world: self.world,
|
||||||
state: self.state,
|
state: self.state,
|
||||||
@ -1383,7 +1385,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
///
|
///
|
||||||
/// - [`get_mut`](Self::get_mut) to get a mutable query item.
|
/// - [`get_mut`](Self::get_mut) to get a mutable query item.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, entity: Entity) -> Result<ROQueryItem<'_, D>, QueryEntityError> {
|
pub fn get(&self, entity: Entity) -> Result<ROQueryItem<'_, 's, D>, QueryEntityError> {
|
||||||
self.as_readonly().get_inner(entity)
|
self.as_readonly().get_inner(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1434,7 +1436,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn get_many<const N: usize>(
|
pub fn get_many<const N: usize>(
|
||||||
&self,
|
&self,
|
||||||
entities: [Entity; N],
|
entities: [Entity; N],
|
||||||
) -> Result<[ROQueryItem<'_, D>; N], QueryEntityError> {
|
) -> Result<[ROQueryItem<'_, 's, D>; N], QueryEntityError> {
|
||||||
// Note that we call a separate `*_inner` method from `get_many_mut`
|
// Note that we call a separate `*_inner` method from `get_many_mut`
|
||||||
// because we don't need to check for duplicates.
|
// because we don't need to check for duplicates.
|
||||||
self.as_readonly().get_many_inner(entities)
|
self.as_readonly().get_many_inner(entities)
|
||||||
@ -1485,7 +1487,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn get_many_unique<const N: usize>(
|
pub fn get_many_unique<const N: usize>(
|
||||||
&self,
|
&self,
|
||||||
entities: UniqueEntityArray<N>,
|
entities: UniqueEntityArray<N>,
|
||||||
) -> Result<[ROQueryItem<'_, D>; N], QueryEntityError> {
|
) -> Result<[ROQueryItem<'_, 's, D>; N], QueryEntityError> {
|
||||||
self.as_readonly().get_many_unique_inner(entities)
|
self.as_readonly().get_many_unique_inner(entities)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1519,7 +1521,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
///
|
///
|
||||||
/// - [`get`](Self::get) to get a read-only query item.
|
/// - [`get`](Self::get) to get a read-only query item.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_mut(&mut self, entity: Entity) -> Result<D::Item<'_>, QueryEntityError> {
|
pub fn get_mut(&mut self, entity: Entity) -> Result<D::Item<'_, 's>, QueryEntityError> {
|
||||||
self.reborrow().get_inner(entity)
|
self.reborrow().get_inner(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1534,7 +1536,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
///
|
///
|
||||||
/// - [`get_mut`](Self::get_mut) to get the item using a mutable borrow of the [`Query`].
|
/// - [`get_mut`](Self::get_mut) to get the item using a mutable borrow of the [`Query`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_inner(self, entity: Entity) -> Result<D::Item<'w>, QueryEntityError> {
|
pub fn get_inner(self, entity: Entity) -> Result<D::Item<'w, 's>, QueryEntityError> {
|
||||||
// SAFETY: system runs without conflicts with other systems.
|
// SAFETY: system runs without conflicts with other systems.
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
// same-system queries have runtime borrow checks when they conflict
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -1576,8 +1578,18 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
D::set_archetype(&mut fetch, &self.state.fetch_state, archetype, table);
|
D::set_archetype(&mut fetch, &self.state.fetch_state, archetype, table);
|
||||||
F::set_archetype(&mut filter, &self.state.filter_state, archetype, table);
|
F::set_archetype(&mut filter, &self.state.filter_state, archetype, table);
|
||||||
|
|
||||||
if F::filter_fetch(&mut filter, entity, location.table_row) {
|
if F::filter_fetch(
|
||||||
Ok(D::fetch(&mut fetch, entity, location.table_row))
|
&self.state.filter_state,
|
||||||
|
&mut filter,
|
||||||
|
entity,
|
||||||
|
location.table_row,
|
||||||
|
) {
|
||||||
|
Ok(D::fetch(
|
||||||
|
&self.state.fetch_state,
|
||||||
|
&mut fetch,
|
||||||
|
entity,
|
||||||
|
location.table_row,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(QueryEntityError::QueryDoesNotMatch(
|
Err(QueryEntityError::QueryDoesNotMatch(
|
||||||
entity,
|
entity,
|
||||||
@ -1658,7 +1670,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn get_many_mut<const N: usize>(
|
pub fn get_many_mut<const N: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
entities: [Entity; N],
|
entities: [Entity; N],
|
||||||
) -> Result<[D::Item<'_>; N], QueryEntityError> {
|
) -> Result<[D::Item<'_, 's>; N], QueryEntityError> {
|
||||||
self.reborrow().get_many_mut_inner(entities)
|
self.reborrow().get_many_mut_inner(entities)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1726,7 +1738,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn get_many_unique_mut<const N: usize>(
|
pub fn get_many_unique_mut<const N: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
entities: UniqueEntityArray<N>,
|
entities: UniqueEntityArray<N>,
|
||||||
) -> Result<[D::Item<'_>; N], QueryEntityError> {
|
) -> Result<[D::Item<'_, 's>; N], QueryEntityError> {
|
||||||
self.reborrow().get_many_unique_inner(entities)
|
self.reborrow().get_many_unique_inner(entities)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1745,7 +1757,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn get_many_mut_inner<const N: usize>(
|
pub fn get_many_mut_inner<const N: usize>(
|
||||||
self,
|
self,
|
||||||
entities: [Entity; N],
|
entities: [Entity; N],
|
||||||
) -> Result<[D::Item<'w>; N], QueryEntityError> {
|
) -> Result<[D::Item<'w, 's>; N], QueryEntityError> {
|
||||||
// Verify that all entities are unique
|
// Verify that all entities are unique
|
||||||
for i in 0..N {
|
for i in 0..N {
|
||||||
for j in 0..i {
|
for j in 0..i {
|
||||||
@ -1773,7 +1785,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn get_many_inner<const N: usize>(
|
pub fn get_many_inner<const N: usize>(
|
||||||
self,
|
self,
|
||||||
entities: [Entity; N],
|
entities: [Entity; N],
|
||||||
) -> Result<[D::Item<'w>; N], QueryEntityError>
|
) -> Result<[D::Item<'w, 's>; N], QueryEntityError>
|
||||||
where
|
where
|
||||||
D: ReadOnlyQueryData,
|
D: ReadOnlyQueryData,
|
||||||
{
|
{
|
||||||
@ -1795,7 +1807,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
pub fn get_many_unique_inner<const N: usize>(
|
pub fn get_many_unique_inner<const N: usize>(
|
||||||
self,
|
self,
|
||||||
entities: UniqueEntityArray<N>,
|
entities: UniqueEntityArray<N>,
|
||||||
) -> Result<[D::Item<'w>; N], QueryEntityError> {
|
) -> Result<[D::Item<'w, 's>; N], QueryEntityError> {
|
||||||
// SAFETY: All entities are unique, so the results don't alias.
|
// SAFETY: All entities are unique, so the results don't alias.
|
||||||
unsafe { self.get_many_impl(entities.into_inner()) }
|
unsafe { self.get_many_impl(entities.into_inner()) }
|
||||||
}
|
}
|
||||||
@ -1810,7 +1822,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
unsafe fn get_many_impl<const N: usize>(
|
unsafe fn get_many_impl<const N: usize>(
|
||||||
self,
|
self,
|
||||||
entities: [Entity; N],
|
entities: [Entity; N],
|
||||||
) -> Result<[D::Item<'w>; N], QueryEntityError> {
|
) -> Result<[D::Item<'w, 's>; N], QueryEntityError> {
|
||||||
let mut values = [(); N].map(|_| MaybeUninit::uninit());
|
let mut values = [(); N].map(|_| MaybeUninit::uninit());
|
||||||
|
|
||||||
for (value, entity) in core::iter::zip(&mut values, entities) {
|
for (value, entity) in core::iter::zip(&mut values, entities) {
|
||||||
@ -1838,7 +1850,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
///
|
///
|
||||||
/// - [`get_mut`](Self::get_mut) for the safe version.
|
/// - [`get_mut`](Self::get_mut) for the safe version.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_unchecked(&self, entity: Entity) -> Result<D::Item<'_>, QueryEntityError> {
|
pub unsafe fn get_unchecked(
|
||||||
|
&self,
|
||||||
|
entity: Entity,
|
||||||
|
) -> Result<D::Item<'_, 's>, QueryEntityError> {
|
||||||
// SAFETY: The caller promises that this will not result in multiple mutable references.
|
// SAFETY: The caller promises that this will not result in multiple mutable references.
|
||||||
unsafe { self.reborrow_unsafe() }.get_inner(entity)
|
unsafe { self.reborrow_unsafe() }.get_inner(entity)
|
||||||
}
|
}
|
||||||
@ -1874,7 +1889,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
///
|
///
|
||||||
/// - [`single_mut`](Self::single_mut) to get the mutable query item.
|
/// - [`single_mut`](Self::single_mut) to get the mutable query item.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn single(&self) -> Result<ROQueryItem<'_, D>, QuerySingleError> {
|
pub fn single(&self) -> Result<ROQueryItem<'_, 's, D>, QuerySingleError> {
|
||||||
self.as_readonly().single_inner()
|
self.as_readonly().single_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1903,7 +1918,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
///
|
///
|
||||||
/// - [`single`](Self::single) to get the read-only query item.
|
/// - [`single`](Self::single) to get the read-only query item.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn single_mut(&mut self) -> Result<D::Item<'_>, QuerySingleError> {
|
pub fn single_mut(&mut self) -> Result<D::Item<'_, 's>, QuerySingleError> {
|
||||||
self.reborrow().single_inner()
|
self.reborrow().single_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1935,15 +1950,15 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
/// - [`single_mut`](Self::single_mut) to get the mutable query item.
|
/// - [`single_mut`](Self::single_mut) to get the mutable query item.
|
||||||
/// - [`single_inner`](Self::single_inner) for the panicking version.
|
/// - [`single_inner`](Self::single_inner) for the panicking version.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn single_inner(self) -> Result<D::Item<'w>, QuerySingleError> {
|
pub fn single_inner(self) -> Result<D::Item<'w, 's>, QuerySingleError> {
|
||||||
let mut query = self.into_iter();
|
let mut query = self.into_iter();
|
||||||
let first = query.next();
|
let first = query.next();
|
||||||
let extra = query.next().is_some();
|
let extra = query.next().is_some();
|
||||||
|
|
||||||
match (first, extra) {
|
match (first, extra) {
|
||||||
(Some(r), false) => Ok(r),
|
(Some(r), false) => Ok(r),
|
||||||
(None, _) => Err(QuerySingleError::NoEntities(core::any::type_name::<Self>())),
|
(None, _) => Err(QuerySingleError::NoEntities(DebugName::type_name::<Self>())),
|
||||||
(Some(_), _) => Err(QuerySingleError::MultipleEntities(core::any::type_name::<
|
(Some(_), _) => Err(QuerySingleError::MultipleEntities(DebugName::type_name::<
|
||||||
Self,
|
Self,
|
||||||
>())),
|
>())),
|
||||||
}
|
}
|
||||||
@ -2447,7 +2462,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for Query<'w, 's, D, F> {
|
impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for Query<'w, 's, D, F> {
|
||||||
type Item = D::Item<'w>;
|
type Item = D::Item<'w, 's>;
|
||||||
type IntoIter = QueryIter<'w, 's, D, F>;
|
type IntoIter = QueryIter<'w, 's, D, F>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
@ -2460,7 +2475,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for Query<'w, 's, D, F>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for &'w Query<'_, 's, D, F> {
|
impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for &'w Query<'_, 's, D, F> {
|
||||||
type Item = ROQueryItem<'w, D>;
|
type Item = ROQueryItem<'w, 's, D>;
|
||||||
type IntoIter = QueryIter<'w, 's, D::ReadOnly, F>;
|
type IntoIter = QueryIter<'w, 's, D::ReadOnly, F>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
@ -2469,7 +2484,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for &'w Query<'_, 's, D,
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for &'w mut Query<'_, 's, D, F> {
|
impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for &'w mut Query<'_, 's, D, F> {
|
||||||
type Item = D::Item<'w>;
|
type Item = D::Item<'w, 's>;
|
||||||
type IntoIter = QueryIter<'w, 's, D, F>;
|
type IntoIter = QueryIter<'w, 's, D, F>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
@ -2584,28 +2599,28 @@ impl<'w, 'q, Q: QueryData, F: QueryFilter> From<&'q mut Query<'w, '_, Q, F>>
|
|||||||
/// ```
|
/// ```
|
||||||
/// Note that because [`Single`] implements [`Deref`] and [`DerefMut`], methods and fields like `health` can be accessed directly.
|
/// Note that because [`Single`] implements [`Deref`] and [`DerefMut`], methods and fields like `health` can be accessed directly.
|
||||||
/// You can also access the underlying data manually, by calling `.deref`/`.deref_mut`, or by using the `*` operator.
|
/// You can also access the underlying data manually, by calling `.deref`/`.deref_mut`, or by using the `*` operator.
|
||||||
pub struct Single<'w, D: QueryData, F: QueryFilter = ()> {
|
pub struct Single<'w, 's, D: QueryData, F: QueryFilter = ()> {
|
||||||
pub(crate) item: D::Item<'w>,
|
pub(crate) item: D::Item<'w, 's>,
|
||||||
pub(crate) _filter: PhantomData<F>,
|
pub(crate) _filter: PhantomData<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, D: QueryData, F: QueryFilter> Deref for Single<'w, D, F> {
|
impl<'w, 's, D: QueryData, F: QueryFilter> Deref for Single<'w, 's, D, F> {
|
||||||
type Target = D::Item<'w>;
|
type Target = D::Item<'w, 's>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.item
|
&self.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, D: QueryData, F: QueryFilter> DerefMut for Single<'w, D, F> {
|
impl<'w, 's, D: QueryData, F: QueryFilter> DerefMut for Single<'w, 's, D, F> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.item
|
&mut self.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, D: QueryData, F: QueryFilter> Single<'w, D, F> {
|
impl<'w, 's, D: QueryData, F: QueryFilter> Single<'w, 's, D, F> {
|
||||||
/// Returns the inner item with ownership.
|
/// Returns the inner item with ownership.
|
||||||
pub fn into_inner(self) -> D::Item<'w> {
|
pub fn into_inner(self) -> D::Item<'w, 's> {
|
||||||
self.item
|
self.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use alloc::{borrow::Cow, vec::Vec};
|
use alloc::vec::Vec;
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
component::{CheckChangeTicks, ComponentId, Tick},
|
component::{CheckChangeTicks, ComponentId, Tick},
|
||||||
@ -25,7 +26,7 @@ impl<S: System<In = ()>> System for InfallibleSystemWrapper<S> {
|
|||||||
type Out = Result;
|
type Out = Result;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> DebugName {
|
||||||
self.0.name()
|
self.0.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,10 +138,9 @@ where
|
|||||||
T: Send + Sync + 'static,
|
T: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type In = ();
|
type In = ();
|
||||||
|
|
||||||
type Out = S::Out;
|
type Out = S::Out;
|
||||||
|
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> DebugName {
|
||||||
self.system.name()
|
self.system.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,10 +231,9 @@ where
|
|||||||
T: FromWorld + Send + Sync + 'static,
|
T: FromWorld + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type In = ();
|
type In = ();
|
||||||
|
|
||||||
type Out = S::Out;
|
type Out = S::Out;
|
||||||
|
|
||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> DebugName {
|
||||||
self.system.name()
|
self.system.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
clippy::module_inception,
|
clippy::module_inception,
|
||||||
reason = "This instance of module inception is being discussed; see #17353."
|
reason = "This instance of module inception is being discussed; see #17353."
|
||||||
)]
|
)]
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
@ -15,7 +16,7 @@ use crate::{
|
|||||||
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
|
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
|
||||||
};
|
};
|
||||||
|
|
||||||
use alloc::{borrow::Cow, boxed::Box, vec::Vec};
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
use core::any::TypeId;
|
use core::any::TypeId;
|
||||||
|
|
||||||
use super::{IntoSystem, SystemParamValidationError};
|
use super::{IntoSystem, SystemParamValidationError};
|
||||||
@ -49,8 +50,9 @@ pub trait System: Send + Sync + 'static {
|
|||||||
type In: SystemInput;
|
type In: SystemInput;
|
||||||
/// The system's output.
|
/// The system's output.
|
||||||
type Out;
|
type Out;
|
||||||
|
|
||||||
/// Returns the system's name.
|
/// Returns the system's name.
|
||||||
fn name(&self) -> Cow<'static, str>;
|
fn name(&self) -> DebugName;
|
||||||
/// Returns the [`TypeId`] of the underlying system type.
|
/// Returns the [`TypeId`] of the underlying system type.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn type_id(&self) -> TypeId {
|
fn type_id(&self) -> TypeId {
|
||||||
@ -227,7 +229,7 @@ pub type BoxedSystem<In = (), Out = ()> = Box<dyn System<In = In, Out = Out>>;
|
|||||||
pub(crate) fn check_system_change_tick(
|
pub(crate) fn check_system_change_tick(
|
||||||
last_run: &mut Tick,
|
last_run: &mut Tick,
|
||||||
check: CheckChangeTicks,
|
check: CheckChangeTicks,
|
||||||
system_name: &str,
|
system_name: DebugName,
|
||||||
) {
|
) {
|
||||||
if last_run.check_tick(check) {
|
if last_run.check_tick(check) {
|
||||||
let age = check.present_tick().relative_to(*last_run).get();
|
let age = check.present_tick().relative_to(*last_run).get();
|
||||||
@ -398,7 +400,7 @@ pub enum RunSystemError {
|
|||||||
#[error("System {system} did not run due to failed parameter validation: {err}")]
|
#[error("System {system} did not run due to failed parameter validation: {err}")]
|
||||||
InvalidParams {
|
InvalidParams {
|
||||||
/// The identifier of the system that was run.
|
/// The identifier of the system that was run.
|
||||||
system: Cow<'static, str>,
|
system: DebugName,
|
||||||
/// The returned parameter validation error.
|
/// The returned parameter validation error.
|
||||||
err: SystemParamValidationError,
|
err: SystemParamValidationError,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -5,9 +5,8 @@ use crate::{
|
|||||||
system::{ExclusiveSystemParam, ReadOnlySystemParam, SystemMeta, SystemParam},
|
system::{ExclusiveSystemParam, ReadOnlySystemParam, SystemMeta, SystemParam},
|
||||||
world::unsafe_world_cell::UnsafeWorldCell,
|
world::unsafe_world_cell::UnsafeWorldCell,
|
||||||
};
|
};
|
||||||
use alloc::borrow::Cow;
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::ops::Deref;
|
use derive_more::derive::{Display, Into};
|
||||||
use derive_more::derive::{AsRef, Display, Into};
|
|
||||||
|
|
||||||
/// [`SystemParam`] that returns the name of the system which it is used in.
|
/// [`SystemParam`] that returns the name of the system which it is used in.
|
||||||
///
|
///
|
||||||
@ -35,21 +34,13 @@ use derive_more::derive::{AsRef, Display, Into};
|
|||||||
/// logger.log("Hello");
|
/// logger.log("Hello");
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Into, Display, AsRef)]
|
#[derive(Debug, Into, Display)]
|
||||||
#[as_ref(str)]
|
pub struct SystemName(DebugName);
|
||||||
pub struct SystemName(Cow<'static, str>);
|
|
||||||
|
|
||||||
impl SystemName {
|
impl SystemName {
|
||||||
/// Gets the name of the system.
|
/// Gets the name of the system.
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> DebugName {
|
||||||
&self.0
|
self.0.clone()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for SystemName {
|
|
||||||
type Target = str;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.name()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +95,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_system_name_regular_param() {
|
fn test_system_name_regular_param() {
|
||||||
fn testing(name: SystemName) -> String {
|
fn testing(name: SystemName) -> String {
|
||||||
name.name().to_owned()
|
name.name().as_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
@ -116,7 +107,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_system_name_exclusive_param() {
|
fn test_system_name_exclusive_param() {
|
||||||
fn testing(_world: &mut World, name: SystemName) -> String {
|
fn testing(_world: &mut World, name: SystemName) -> String {
|
||||||
name.name().to_owned()
|
name.name().as_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
@ -130,7 +121,7 @@ mod tests {
|
|||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
let system =
|
let system =
|
||||||
IntoSystem::into_system(|name: SystemName| name.name().to_owned()).with_name("testing");
|
IntoSystem::into_system(|name: SystemName| name.name().to_owned()).with_name("testing");
|
||||||
let name = world.run_system_once(system).unwrap();
|
let name = world.run_system_once(system).unwrap().as_string();
|
||||||
assert_eq!(name, "testing");
|
assert_eq!(name, "testing");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +131,7 @@ mod tests {
|
|||||||
let system =
|
let system =
|
||||||
IntoSystem::into_system(|_world: &mut World, name: SystemName| name.name().to_owned())
|
IntoSystem::into_system(|_world: &mut World, name: SystemName| name.name().to_owned())
|
||||||
.with_name("testing");
|
.with_name("testing");
|
||||||
let name = world.run_system_once(system).unwrap();
|
let name = world.run_system_once(system).unwrap().as_string();
|
||||||
assert_eq!(name, "testing");
|
assert_eq!(name, "testing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ use alloc::{
|
|||||||
pub use bevy_ecs_macros::SystemParam;
|
pub use bevy_ecs_macros::SystemParam;
|
||||||
use bevy_platform::cell::SyncCell;
|
use bevy_platform::cell::SyncCell;
|
||||||
use bevy_ptr::UnsafeCellDeref;
|
use bevy_ptr::UnsafeCellDeref;
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::{
|
use core::{
|
||||||
any::Any,
|
any::Any,
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
@ -32,7 +33,6 @@ use core::{
|
|||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
panic::Location,
|
panic::Location,
|
||||||
};
|
};
|
||||||
use disqualified::ShortName;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use super::Populated;
|
use super::Populated;
|
||||||
@ -343,8 +343,8 @@ unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Qu
|
|||||||
) {
|
) {
|
||||||
assert_component_access_compatibility(
|
assert_component_access_compatibility(
|
||||||
&system_meta.name,
|
&system_meta.name,
|
||||||
core::any::type_name::<D>(),
|
DebugName::type_name::<D>(),
|
||||||
core::any::type_name::<F>(),
|
DebugName::type_name::<F>(),
|
||||||
component_access_set,
|
component_access_set,
|
||||||
&state.component_access,
|
&state.component_access,
|
||||||
world,
|
world,
|
||||||
@ -368,9 +368,9 @@ unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Qu
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn assert_component_access_compatibility(
|
fn assert_component_access_compatibility(
|
||||||
system_name: &str,
|
system_name: &DebugName,
|
||||||
query_type: &'static str,
|
query_type: DebugName,
|
||||||
filter_type: &'static str,
|
filter_type: DebugName,
|
||||||
system_access: &FilteredAccessSet<ComponentId>,
|
system_access: &FilteredAccessSet<ComponentId>,
|
||||||
current: &FilteredAccess<ComponentId>,
|
current: &FilteredAccess<ComponentId>,
|
||||||
world: &World,
|
world: &World,
|
||||||
@ -384,14 +384,16 @@ fn assert_component_access_compatibility(
|
|||||||
if !accesses.is_empty() {
|
if !accesses.is_empty() {
|
||||||
accesses.push(' ');
|
accesses.push(' ');
|
||||||
}
|
}
|
||||||
panic!("error[B0001]: Query<{}, {}> in system {system_name} accesses component(s) {accesses}in a way that conflicts with a previous system parameter. Consider using `Without<T>` to create disjoint Queries or merging conflicting Queries into a `ParamSet`. See: https://bevy.org/learn/errors/b0001", ShortName(query_type), ShortName(filter_type));
|
panic!("error[B0001]: Query<{}, {}> in system {system_name} accesses component(s) {accesses}in a way that conflicts with a previous system parameter. Consider using `Without<T>` to create disjoint Queries or merging conflicting Queries into a `ParamSet`. See: https://bevy.org/learn/errors/b0001", query_type.shortname(), filter_type.shortname());
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: Relevant query ComponentId access is applied to SystemMeta. If
|
// SAFETY: Relevant query ComponentId access is applied to SystemMeta. If
|
||||||
// this Query conflicts with any prior access, a panic will occur.
|
// this Query conflicts with any prior access, a panic will occur.
|
||||||
unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Single<'a, D, F> {
|
unsafe impl<'a, 'b, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
|
||||||
|
for Single<'a, 'b, D, F>
|
||||||
|
{
|
||||||
type State = QueryState<D, F>;
|
type State = QueryState<D, F>;
|
||||||
type Item<'w, 's> = Single<'w, D, F>;
|
type Item<'w, 's> = Single<'w, 's, D, F>;
|
||||||
|
|
||||||
fn init_state(world: &mut World) -> Self::State {
|
fn init_state(world: &mut World) -> Self::State {
|
||||||
Query::init_state(world)
|
Query::init_state(world)
|
||||||
@ -451,8 +453,8 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam fo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
|
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
|
||||||
unsafe impl<'a, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
|
unsafe impl<'a, 'b, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
|
||||||
for Single<'a, D, F>
|
for Single<'a, 'b, D, F>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,9 +767,10 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
|
|||||||
assert!(
|
assert!(
|
||||||
!combined_access.has_resource_write(component_id),
|
!combined_access.has_resource_write(component_id),
|
||||||
"error[B0002]: Res<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
"error[B0002]: Res<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||||
core::any::type_name::<T>(),
|
DebugName::type_name::<T>(),
|
||||||
system_meta.name,
|
system_meta.name,
|
||||||
);
|
);
|
||||||
|
|
||||||
component_access_set.add_unfiltered_resource_read(component_id);
|
component_access_set.add_unfiltered_resource_read(component_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,8 +808,8 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
|
|||||||
panic!(
|
panic!(
|
||||||
"Resource requested by {} does not exist: {}",
|
"Resource requested by {} does not exist: {}",
|
||||||
system_meta.name,
|
system_meta.name,
|
||||||
core::any::type_name::<T>()
|
DebugName::type_name::<T>()
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
Res {
|
Res {
|
||||||
value: ptr.deref(),
|
value: ptr.deref(),
|
||||||
@ -841,11 +844,11 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
|
|||||||
if combined_access.has_resource_write(component_id) {
|
if combined_access.has_resource_write(component_id) {
|
||||||
panic!(
|
panic!(
|
||||||
"error[B0002]: ResMut<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
"error[B0002]: ResMut<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||||
core::any::type_name::<T>(), system_meta.name);
|
DebugName::type_name::<T>(), system_meta.name);
|
||||||
} else if combined_access.has_resource_read(component_id) {
|
} else if combined_access.has_resource_read(component_id) {
|
||||||
panic!(
|
panic!(
|
||||||
"error[B0002]: ResMut<{}> in system {} conflicts with a previous Res<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
"error[B0002]: ResMut<{}> in system {} conflicts with a previous Res<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||||
core::any::type_name::<T>(), system_meta.name);
|
DebugName::type_name::<T>(), system_meta.name);
|
||||||
}
|
}
|
||||||
component_access_set.add_unfiltered_resource_write(component_id);
|
component_access_set.add_unfiltered_resource_write(component_id);
|
||||||
}
|
}
|
||||||
@ -883,8 +886,8 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
|
|||||||
panic!(
|
panic!(
|
||||||
"Resource requested by {} does not exist: {}",
|
"Resource requested by {} does not exist: {}",
|
||||||
system_meta.name,
|
system_meta.name,
|
||||||
core::any::type_name::<T>()
|
DebugName::type_name::<T>()
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
ResMut {
|
ResMut {
|
||||||
value: value.value.deref_mut::<T>(),
|
value: value.value.deref_mut::<T>(),
|
||||||
@ -1433,7 +1436,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
|
|||||||
assert!(
|
assert!(
|
||||||
!combined_access.has_resource_write(component_id),
|
!combined_access.has_resource_write(component_id),
|
||||||
"error[B0002]: NonSend<{}> in system {} conflicts with a previous mutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
"error[B0002]: NonSend<{}> in system {} conflicts with a previous mutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||||
core::any::type_name::<T>(),
|
DebugName::type_name::<T>(),
|
||||||
system_meta.name,
|
system_meta.name,
|
||||||
);
|
);
|
||||||
component_access_set.add_unfiltered_resource_read(component_id);
|
component_access_set.add_unfiltered_resource_read(component_id);
|
||||||
@ -1473,7 +1476,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
|
|||||||
panic!(
|
panic!(
|
||||||
"Non-send resource requested by {} does not exist: {}",
|
"Non-send resource requested by {} does not exist: {}",
|
||||||
system_meta.name,
|
system_meta.name,
|
||||||
core::any::type_name::<T>()
|
DebugName::type_name::<T>()
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1509,11 +1512,11 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
|
|||||||
if combined_access.has_component_write(component_id) {
|
if combined_access.has_component_write(component_id) {
|
||||||
panic!(
|
panic!(
|
||||||
"error[B0002]: NonSendMut<{}> in system {} conflicts with a previous mutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
"error[B0002]: NonSendMut<{}> in system {} conflicts with a previous mutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||||
core::any::type_name::<T>(), system_meta.name);
|
DebugName::type_name::<T>(), system_meta.name);
|
||||||
} else if combined_access.has_component_read(component_id) {
|
} else if combined_access.has_component_read(component_id) {
|
||||||
panic!(
|
panic!(
|
||||||
"error[B0002]: NonSendMut<{}> in system {} conflicts with a previous immutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
"error[B0002]: NonSendMut<{}> in system {} conflicts with a previous immutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||||
core::any::type_name::<T>(), system_meta.name);
|
DebugName::type_name::<T>(), system_meta.name);
|
||||||
}
|
}
|
||||||
component_access_set.add_unfiltered_resource_write(component_id);
|
component_access_set.add_unfiltered_resource_write(component_id);
|
||||||
}
|
}
|
||||||
@ -1552,8 +1555,8 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
|
|||||||
panic!(
|
panic!(
|
||||||
"Non-send resource requested by {} does not exist: {}",
|
"Non-send resource requested by {} does not exist: {}",
|
||||||
system_meta.name,
|
system_meta.name,
|
||||||
core::any::type_name::<T>()
|
DebugName::type_name::<T>()
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
NonSendMut {
|
NonSendMut {
|
||||||
value: ptr.assert_unique().deref_mut(),
|
value: ptr.assert_unique().deref_mut(),
|
||||||
@ -2805,7 +2808,7 @@ pub struct SystemParamValidationError {
|
|||||||
|
|
||||||
/// A string identifying the invalid parameter.
|
/// A string identifying the invalid parameter.
|
||||||
/// This is usually the type name of the parameter.
|
/// This is usually the type name of the parameter.
|
||||||
pub param: Cow<'static, str>,
|
pub param: DebugName,
|
||||||
|
|
||||||
/// A string identifying the field within a parameter using `#[derive(SystemParam)]`.
|
/// A string identifying the field within a parameter using `#[derive(SystemParam)]`.
|
||||||
/// This will be an empty string for other parameters.
|
/// This will be an empty string for other parameters.
|
||||||
@ -2837,7 +2840,7 @@ impl SystemParamValidationError {
|
|||||||
Self {
|
Self {
|
||||||
skipped,
|
skipped,
|
||||||
message: message.into(),
|
message: message.into(),
|
||||||
param: Cow::Borrowed(core::any::type_name::<T>()),
|
param: DebugName::type_name::<T>(),
|
||||||
field: field.into(),
|
field: field.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2848,7 +2851,7 @@ impl Display for SystemParamValidationError {
|
|||||||
write!(
|
write!(
|
||||||
fmt,
|
fmt,
|
||||||
"Parameter `{}{}` failed validation: {}",
|
"Parameter `{}{}` failed validation: {}",
|
||||||
ShortName(&self.param),
|
self.param.shortname(),
|
||||||
self.field,
|
self.field,
|
||||||
self.message
|
self.message
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
@ -651,6 +651,19 @@ mod tests {
|
|||||||
assert_eq!(output, NonCopy(3));
|
assert_eq!(output, NonCopy(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fallible_system() {
|
||||||
|
fn sys() -> Result<()> {
|
||||||
|
Err("error")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
let fallible_system_id = world.register_system(sys);
|
||||||
|
let output = world.run_system(fallible_system_id);
|
||||||
|
assert!(matches!(output, Ok(Err(_))));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exclusive_system() {
|
fn exclusive_system() {
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
@ -751,19 +764,54 @@ mod tests {
|
|||||||
assert!(matches!(output, Ok(x) if x == four()));
|
assert!(matches!(output, Ok(x) if x == four()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cached_fallible_system() {
|
||||||
|
fn sys() -> Result<()> {
|
||||||
|
Err("error")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
let fallible_system_id = world.register_system_cached(sys);
|
||||||
|
let output = world.run_system(fallible_system_id);
|
||||||
|
assert!(matches!(output, Ok(Err(_))));
|
||||||
|
let output = world.run_system_cached(sys);
|
||||||
|
assert!(matches!(output, Ok(Err(_))));
|
||||||
|
let output = world.run_system_cached_with(sys, ());
|
||||||
|
assert!(matches!(output, Ok(Err(_))));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cached_system_commands() {
|
fn cached_system_commands() {
|
||||||
fn sys(mut counter: ResMut<Counter>) {
|
fn sys(mut counter: ResMut<Counter>) {
|
||||||
counter.0 = 1;
|
counter.0 += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
world.insert_resource(Counter(0));
|
world.insert_resource(Counter(0));
|
||||||
|
|
||||||
world.commands().run_system_cached(sys);
|
world.commands().run_system_cached(sys);
|
||||||
world.flush_commands();
|
world.flush_commands();
|
||||||
|
|
||||||
assert_eq!(world.resource::<Counter>().0, 1);
|
assert_eq!(world.resource::<Counter>().0, 1);
|
||||||
|
world.commands().run_system_cached_with(sys, ());
|
||||||
|
world.flush_commands();
|
||||||
|
assert_eq!(world.resource::<Counter>().0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cached_fallible_system_commands() {
|
||||||
|
fn sys(mut counter: ResMut<Counter>) -> Result {
|
||||||
|
counter.0 += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
world.insert_resource(Counter(0));
|
||||||
|
world.commands().run_system_cached(sys);
|
||||||
|
world.flush_commands();
|
||||||
|
assert_eq!(world.resource::<Counter>().0, 1);
|
||||||
|
world.commands().run_system_cached_with(sys, ());
|
||||||
|
world.flush_commands();
|
||||||
|
assert_eq!(world.resource::<Counter>().0, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
//! A trait for components that let you traverse the ECS.
|
//! A trait for components that let you traverse the ECS.
|
||||||
|
|
||||||
use crate::{entity::Entity, query::ReadOnlyQueryData, relationship::Relationship};
|
use crate::{
|
||||||
|
entity::Entity,
|
||||||
|
query::{ReadOnlyQueryData, ReleaseStateQueryData},
|
||||||
|
relationship::Relationship,
|
||||||
|
};
|
||||||
|
|
||||||
/// A component that can point to another entity, and which can be used to define a path through the ECS.
|
/// A component that can point to another entity, and which can be used to define a path through the ECS.
|
||||||
///
|
///
|
||||||
@ -20,13 +24,13 @@ use crate::{entity::Entity, query::ReadOnlyQueryData, relationship::Relationship
|
|||||||
/// [specify the direction]: crate::event::EntityEvent::Traversal
|
/// [specify the direction]: crate::event::EntityEvent::Traversal
|
||||||
/// [event propagation]: crate::observer::On::propagate
|
/// [event propagation]: crate::observer::On::propagate
|
||||||
/// [observers]: crate::observer::Observer
|
/// [observers]: crate::observer::Observer
|
||||||
pub trait Traversal<D: ?Sized>: ReadOnlyQueryData {
|
pub trait Traversal<D: ?Sized>: ReadOnlyQueryData + ReleaseStateQueryData {
|
||||||
/// Returns the next entity to visit.
|
/// Returns the next entity to visit.
|
||||||
fn traverse(item: Self::Item<'_>, data: &D) -> Option<Entity>;
|
fn traverse(item: Self::Item<'_, '_>, data: &D) -> Option<Entity>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> Traversal<D> for () {
|
impl<D> Traversal<D> for () {
|
||||||
fn traverse(_: Self::Item<'_>, _data: &D) -> Option<Entity> {
|
fn traverse(_: Self::Item<'_, '_>, _data: &D) -> Option<Entity> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,7 +43,7 @@ impl<D> Traversal<D> for () {
|
|||||||
///
|
///
|
||||||
/// [event propagation]: crate::observer::On::propagate
|
/// [event propagation]: crate::observer::On::propagate
|
||||||
impl<R: Relationship, D> Traversal<D> for &R {
|
impl<R: Relationship, D> Traversal<D> for &R {
|
||||||
fn traverse(item: Self::Item<'_>, _data: &D) -> Option<Entity> {
|
fn traverse(item: Self::Item<'_, '_>, _data: &D) -> Option<Entity> {
|
||||||
Some(item.get())
|
Some(item.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
archetype::Archetype,
|
archetype::Archetype,
|
||||||
change_detection::{MaybeLocation, MutUntyped},
|
change_detection::{MaybeLocation, MutUntyped},
|
||||||
@ -460,7 +462,7 @@ impl<'w> DeferredWorld<'w> {
|
|||||||
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
||||||
Resources are also implicitly added via `app.add_event`,
|
Resources are also implicitly added via `app.add_event`,
|
||||||
and can be added by plugins.",
|
and can be added by plugins.",
|
||||||
core::any::type_name::<R>()
|
DebugName::type_name::<R>()
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -489,7 +491,7 @@ impl<'w> DeferredWorld<'w> {
|
|||||||
"Requested non-send resource {} does not exist in the `World`.
|
"Requested non-send resource {} does not exist in the `World`.
|
||||||
Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?
|
Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?
|
||||||
Non-send resources can also be added by plugins.",
|
Non-send resources can also be added by plugins.",
|
||||||
core::any::type_name::<R>()
|
DebugName::type_name::<R>()
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -532,7 +534,7 @@ impl<'w> DeferredWorld<'w> {
|
|||||||
let Some(mut events_resource) = self.get_resource_mut::<Events<E>>() else {
|
let Some(mut events_resource) = self.get_resource_mut::<Events<E>>() else {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Unable to send event `{}`\n\tEvent must be added to the app with `add_event()`\n\thttps://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event ",
|
"Unable to send event `{}`\n\tEvent must be added to the app with `add_event()`\n\thttps://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event ",
|
||||||
core::any::type_name::<E>()
|
DebugName::type_name::<E>()
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,7 +16,7 @@ use crate::{
|
|||||||
event::EntityEvent,
|
event::EntityEvent,
|
||||||
lifecycle::{DESPAWN, REMOVE, REPLACE},
|
lifecycle::{DESPAWN, REMOVE, REPLACE},
|
||||||
observer::Observer,
|
observer::Observer,
|
||||||
query::{Access, DebugCheckedUnwrap, ReadOnlyQueryData},
|
query::{Access, DebugCheckedUnwrap, ReadOnlyQueryData, ReleaseStateQueryData},
|
||||||
relationship::RelationshipHookMode,
|
relationship::RelationshipHookMode,
|
||||||
resource::Resource,
|
resource::Resource,
|
||||||
system::IntoObserverSystem,
|
system::IntoObserverSystem,
|
||||||
@ -285,14 +285,16 @@ impl<'w> EntityRef<'w> {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If the entity does not have the components required by the query `Q`.
|
/// If the entity does not have the components required by the query `Q`.
|
||||||
pub fn components<Q: ReadOnlyQueryData>(&self) -> Q::Item<'w> {
|
pub fn components<Q: ReadOnlyQueryData + ReleaseStateQueryData>(&self) -> Q::Item<'w, 'static> {
|
||||||
self.get_components::<Q>()
|
self.get_components::<Q>()
|
||||||
.expect("Query does not match the current entity")
|
.expect("Query does not match the current entity")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns read-only components for the current entity that match the query `Q`,
|
/// Returns read-only components for the current entity that match the query `Q`,
|
||||||
/// or `None` if the entity does not have the components required by the query `Q`.
|
/// or `None` if the entity does not have the components required by the query `Q`.
|
||||||
pub fn get_components<Q: ReadOnlyQueryData>(&self) -> Option<Q::Item<'w>> {
|
pub fn get_components<Q: ReadOnlyQueryData + ReleaseStateQueryData>(
|
||||||
|
&self,
|
||||||
|
) -> Option<Q::Item<'w, 'static>> {
|
||||||
// SAFETY: We have read-only access to all components of this entity.
|
// SAFETY: We have read-only access to all components of this entity.
|
||||||
unsafe { self.cell.get_components::<Q>() }
|
unsafe { self.cell.get_components::<Q>() }
|
||||||
}
|
}
|
||||||
@ -558,13 +560,15 @@ impl<'w> EntityMut<'w> {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If the entity does not have the components required by the query `Q`.
|
/// If the entity does not have the components required by the query `Q`.
|
||||||
pub fn components<Q: ReadOnlyQueryData>(&self) -> Q::Item<'_> {
|
pub fn components<Q: ReadOnlyQueryData + ReleaseStateQueryData>(&self) -> Q::Item<'_, 'static> {
|
||||||
self.as_readonly().components::<Q>()
|
self.as_readonly().components::<Q>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns read-only components for the current entity that match the query `Q`,
|
/// Returns read-only components for the current entity that match the query `Q`,
|
||||||
/// or `None` if the entity does not have the components required by the query `Q`.
|
/// or `None` if the entity does not have the components required by the query `Q`.
|
||||||
pub fn get_components<Q: ReadOnlyQueryData>(&self) -> Option<Q::Item<'_>> {
|
pub fn get_components<Q: ReadOnlyQueryData + ReleaseStateQueryData>(
|
||||||
|
&self,
|
||||||
|
) -> Option<Q::Item<'_, 'static>> {
|
||||||
self.as_readonly().get_components::<Q>()
|
self.as_readonly().get_components::<Q>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1325,7 +1329,7 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
/// If the entity does not have the components required by the query `Q` or if the entity
|
/// If the entity does not have the components required by the query `Q` or if the entity
|
||||||
/// has been despawned while this `EntityWorldMut` is still alive.
|
/// has been despawned while this `EntityWorldMut` is still alive.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn components<Q: ReadOnlyQueryData>(&self) -> Q::Item<'_> {
|
pub fn components<Q: ReadOnlyQueryData + ReleaseStateQueryData>(&self) -> Q::Item<'_, 'static> {
|
||||||
self.as_readonly().components::<Q>()
|
self.as_readonly().components::<Q>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1336,7 +1340,9 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
///
|
///
|
||||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_components<Q: ReadOnlyQueryData>(&self) -> Option<Q::Item<'_>> {
|
pub fn get_components<Q: ReadOnlyQueryData + ReleaseStateQueryData>(
|
||||||
|
&self,
|
||||||
|
) -> Option<Q::Item<'_, 'static>> {
|
||||||
self.as_readonly().get_components::<Q>()
|
self.as_readonly().get_components::<Q>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
//! Contains error types returned by bevy's schedule.
|
//! Contains error types returned by bevy's schedule.
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
component::ComponentId,
|
component::ComponentId,
|
||||||
@ -24,7 +25,7 @@ pub struct TryRunScheduleError(pub InternedScheduleLabel);
|
|||||||
#[error("Could not insert bundles of type {bundle_type} into the entities with the following IDs because they do not exist: {entities:?}")]
|
#[error("Could not insert bundles of type {bundle_type} into the entities with the following IDs because they do not exist: {entities:?}")]
|
||||||
pub struct TryInsertBatchError {
|
pub struct TryInsertBatchError {
|
||||||
/// The bundles' type name.
|
/// The bundles' type name.
|
||||||
pub bundle_type: &'static str,
|
pub bundle_type: DebugName,
|
||||||
/// The IDs of the provided entities that do not exist.
|
/// The IDs of the provided entities that do not exist.
|
||||||
pub entities: Vec<Entity>,
|
pub entities: Vec<Entity>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ use crate::{
|
|||||||
prelude::{Add, Despawn, Insert, Remove, Replace},
|
prelude::{Add, Despawn, Insert, Remove, Replace},
|
||||||
};
|
};
|
||||||
pub use bevy_ecs_macros::FromWorld;
|
pub use bevy_ecs_macros::FromWorld;
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
pub use deferred_world::DeferredWorld;
|
pub use deferred_world::DeferredWorld;
|
||||||
pub use entity_fetch::{EntityFetcher, WorldEntityFetch};
|
pub use entity_fetch::{EntityFetcher, WorldEntityFetch};
|
||||||
pub use entity_ref::{
|
pub use entity_ref::{
|
||||||
@ -264,6 +265,12 @@ impl World {
|
|||||||
&self.removed_components
|
&self.removed_components
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves this world's [`Observers`] list
|
||||||
|
#[inline]
|
||||||
|
pub fn observers(&self) -> &Observers {
|
||||||
|
&self.observers
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new [`Commands`] instance that writes to the world's command queue
|
/// Creates a new [`Commands`] instance that writes to the world's command queue
|
||||||
/// Use [`World::flush`] to apply all queued commands
|
/// Use [`World::flush`] to apply all queued commands
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -2087,7 +2094,7 @@ impl World {
|
|||||||
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
||||||
Resources are also implicitly added via `app.add_event`,
|
Resources are also implicitly added via `app.add_event`,
|
||||||
and can be added by plugins.",
|
and can be added by plugins.",
|
||||||
core::any::type_name::<R>()
|
DebugName::type_name::<R>()
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2111,7 +2118,7 @@ impl World {
|
|||||||
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
||||||
Resources are also implicitly added via `app.add_event`,
|
Resources are also implicitly added via `app.add_event`,
|
||||||
and can be added by plugins.",
|
and can be added by plugins.",
|
||||||
core::any::type_name::<R>()
|
DebugName::type_name::<R>()
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2135,7 +2142,7 @@ impl World {
|
|||||||
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
||||||
Resources are also implicitly added via `app.add_event`,
|
Resources are also implicitly added via `app.add_event`,
|
||||||
and can be added by plugins.",
|
and can be added by plugins.",
|
||||||
core::any::type_name::<R>()
|
DebugName::type_name::<R>()
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2299,7 +2306,7 @@ impl World {
|
|||||||
"Requested non-send resource {} does not exist in the `World`.
|
"Requested non-send resource {} does not exist in the `World`.
|
||||||
Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?
|
Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?
|
||||||
Non-send resources can also be added by plugins.",
|
Non-send resources can also be added by plugins.",
|
||||||
core::any::type_name::<R>()
|
DebugName::type_name::<R>()
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2321,7 +2328,7 @@ impl World {
|
|||||||
"Requested non-send resource {} does not exist in the `World`.
|
"Requested non-send resource {} does not exist in the `World`.
|
||||||
Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?
|
Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?
|
||||||
Non-send resources can also be added by plugins.",
|
Non-send resources can also be added by plugins.",
|
||||||
core::any::type_name::<R>()
|
DebugName::type_name::<R>()
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2660,7 +2667,7 @@ impl World {
|
|||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(TryInsertBatchError {
|
Err(TryInsertBatchError {
|
||||||
bundle_type: core::any::type_name::<B>(),
|
bundle_type: DebugName::type_name::<B>(),
|
||||||
entities: invalid_entities,
|
entities: invalid_entities,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -2694,7 +2701,7 @@ impl World {
|
|||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn resource_scope<R: Resource, U>(&mut self, f: impl FnOnce(&mut World, Mut<R>) -> U) -> U {
|
pub fn resource_scope<R: Resource, U>(&mut self, f: impl FnOnce(&mut World, Mut<R>) -> U) -> U {
|
||||||
self.try_resource_scope(f)
|
self.try_resource_scope(f)
|
||||||
.unwrap_or_else(|| panic!("resource does not exist: {}", core::any::type_name::<R>()))
|
.unwrap_or_else(|| panic!("resource does not exist: {}", DebugName::type_name::<R>()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Temporarily removes the requested resource from this [`World`] if it exists, runs custom user code,
|
/// Temporarily removes the requested resource from this [`World`] if it exists, runs custom user code,
|
||||||
@ -2734,7 +2741,7 @@ impl World {
|
|||||||
assert!(!self.contains_resource::<R>(),
|
assert!(!self.contains_resource::<R>(),
|
||||||
"Resource `{}` was inserted during a call to World::resource_scope.\n\
|
"Resource `{}` was inserted during a call to World::resource_scope.\n\
|
||||||
This is not allowed as the original resource is reinserted to the world after the closure is invoked.",
|
This is not allowed as the original resource is reinserted to the world after the closure is invoked.",
|
||||||
core::any::type_name::<R>());
|
DebugName::type_name::<R>());
|
||||||
|
|
||||||
OwningPtr::make(value, |ptr| {
|
OwningPtr::make(value, |ptr| {
|
||||||
// SAFETY: pointer is of type R
|
// SAFETY: pointer is of type R
|
||||||
@ -2775,7 +2782,7 @@ impl World {
|
|||||||
let Some(mut events_resource) = self.get_resource_mut::<Events<E>>() else {
|
let Some(mut events_resource) = self.get_resource_mut::<Events<E>>() else {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Unable to send event `{}`\n\tEvent must be added to the app with `add_event()`\n\thttps://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event ",
|
"Unable to send event `{}`\n\tEvent must be added to the app with `add_event()`\n\thttps://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event ",
|
||||||
core::any::type_name::<E>()
|
DebugName::type_name::<E>()
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
@ -3752,6 +3759,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use bevy_ecs_macros::Component;
|
use bevy_ecs_macros::Component;
|
||||||
use bevy_platform::collections::{HashMap, HashSet};
|
use bevy_platform::collections::{HashMap, HashSet};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
use core::{
|
use core::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
panic,
|
panic,
|
||||||
@ -3935,12 +3943,12 @@ mod tests {
|
|||||||
let mut iter = world.iter_resources();
|
let mut iter = world.iter_resources();
|
||||||
|
|
||||||
let (info, ptr) = iter.next().unwrap();
|
let (info, ptr) = iter.next().unwrap();
|
||||||
assert_eq!(info.name(), core::any::type_name::<TestResource>());
|
assert_eq!(info.name(), DebugName::type_name::<TestResource>());
|
||||||
// SAFETY: We know that the resource is of type `TestResource`
|
// SAFETY: We know that the resource is of type `TestResource`
|
||||||
assert_eq!(unsafe { ptr.deref::<TestResource>().0 }, 42);
|
assert_eq!(unsafe { ptr.deref::<TestResource>().0 }, 42);
|
||||||
|
|
||||||
let (info, ptr) = iter.next().unwrap();
|
let (info, ptr) = iter.next().unwrap();
|
||||||
assert_eq!(info.name(), core::any::type_name::<TestResource2>());
|
assert_eq!(info.name(), DebugName::type_name::<TestResource2>());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
// SAFETY: We know that the resource is of type `TestResource2`
|
// SAFETY: We know that the resource is of type `TestResource2`
|
||||||
unsafe { &ptr.deref::<TestResource2>().0 },
|
unsafe { &ptr.deref::<TestResource2>().0 },
|
||||||
@ -3963,14 +3971,14 @@ mod tests {
|
|||||||
let mut iter = world.iter_resources_mut();
|
let mut iter = world.iter_resources_mut();
|
||||||
|
|
||||||
let (info, mut mut_untyped) = iter.next().unwrap();
|
let (info, mut mut_untyped) = iter.next().unwrap();
|
||||||
assert_eq!(info.name(), core::any::type_name::<TestResource>());
|
assert_eq!(info.name(), DebugName::type_name::<TestResource>());
|
||||||
// SAFETY: We know that the resource is of type `TestResource`
|
// SAFETY: We know that the resource is of type `TestResource`
|
||||||
unsafe {
|
unsafe {
|
||||||
mut_untyped.as_mut().deref_mut::<TestResource>().0 = 43;
|
mut_untyped.as_mut().deref_mut::<TestResource>().0 = 43;
|
||||||
};
|
};
|
||||||
|
|
||||||
let (info, mut mut_untyped) = iter.next().unwrap();
|
let (info, mut mut_untyped) = iter.next().unwrap();
|
||||||
assert_eq!(info.name(), core::any::type_name::<TestResource2>());
|
assert_eq!(info.name(), DebugName::type_name::<TestResource2>());
|
||||||
// SAFETY: We know that the resource is of type `TestResource2`
|
// SAFETY: We know that the resource is of type `TestResource2`
|
||||||
unsafe {
|
unsafe {
|
||||||
mut_untyped.as_mut().deref_mut::<TestResource2>().0 = "Hello, world?".to_string();
|
mut_untyped.as_mut().deref_mut::<TestResource2>().0 = "Hello, world?".to_string();
|
||||||
|
|||||||
@ -4,8 +4,8 @@ use core::any::TypeId;
|
|||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use alloc::string::{String, ToString};
|
|
||||||
use bevy_reflect::{Reflect, ReflectFromPtr};
|
use bevy_reflect::{Reflect, ReflectFromPtr};
|
||||||
|
use bevy_utils::prelude::DebugName;
|
||||||
|
|
||||||
use crate::{prelude::*, world::ComponentId};
|
use crate::{prelude::*, world::ComponentId};
|
||||||
|
|
||||||
@ -77,10 +77,7 @@ impl World {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let Some(comp_ptr) = self.get_by_id(entity, component_id) else {
|
let Some(comp_ptr) = self.get_by_id(entity, component_id) else {
|
||||||
let component_name = self
|
let component_name = self.components().get_name(component_id);
|
||||||
.components()
|
|
||||||
.get_name(component_id)
|
|
||||||
.map(|name| name.to_string());
|
|
||||||
|
|
||||||
return Err(GetComponentReflectError::EntityDoesNotHaveComponent {
|
return Err(GetComponentReflectError::EntityDoesNotHaveComponent {
|
||||||
entity,
|
entity,
|
||||||
@ -166,10 +163,7 @@ impl World {
|
|||||||
|
|
||||||
// HACK: Only required for the `None`-case/`else`-branch, but it borrows `self`, which will
|
// HACK: Only required for the `None`-case/`else`-branch, but it borrows `self`, which will
|
||||||
// already be mutably borrowed by `self.get_mut_by_id()`, and I didn't find a way around it.
|
// already be mutably borrowed by `self.get_mut_by_id()`, and I didn't find a way around it.
|
||||||
let component_name = self
|
let component_name = self.components().get_name(component_id).clone();
|
||||||
.components()
|
|
||||||
.get_name(component_id)
|
|
||||||
.map(|name| name.to_string());
|
|
||||||
|
|
||||||
let Some(comp_mut_untyped) = self.get_mut_by_id(entity, component_id) else {
|
let Some(comp_mut_untyped) = self.get_mut_by_id(entity, component_id) else {
|
||||||
return Err(GetComponentReflectError::EntityDoesNotHaveComponent {
|
return Err(GetComponentReflectError::EntityDoesNotHaveComponent {
|
||||||
@ -223,7 +217,7 @@ pub enum GetComponentReflectError {
|
|||||||
component_id: ComponentId,
|
component_id: ComponentId,
|
||||||
/// The name corresponding to the [`Component`] with the given [`TypeId`], or `None`
|
/// The name corresponding to the [`Component`] with the given [`TypeId`], or `None`
|
||||||
/// if not available.
|
/// if not available.
|
||||||
component_name: Option<String>,
|
component_name: Option<DebugName>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// The [`World`] was missing the [`AppTypeRegistry`] resource.
|
/// The [`World`] was missing the [`AppTypeRegistry`] resource.
|
||||||
|
|||||||
@ -14,7 +14,7 @@ use crate::{
|
|||||||
lifecycle::RemovedComponentEvents,
|
lifecycle::RemovedComponentEvents,
|
||||||
observer::Observers,
|
observer::Observers,
|
||||||
prelude::Component,
|
prelude::Component,
|
||||||
query::{DebugCheckedUnwrap, ReadOnlyQueryData},
|
query::{DebugCheckedUnwrap, ReadOnlyQueryData, ReleaseStateQueryData},
|
||||||
resource::Resource,
|
resource::Resource,
|
||||||
storage::{ComponentSparseSet, Storages, Table},
|
storage::{ComponentSparseSet, Storages, Table},
|
||||||
world::RawCommandQueue,
|
world::RawCommandQueue,
|
||||||
@ -1005,7 +1005,9 @@ impl<'w> UnsafeEntityCell<'w> {
|
|||||||
/// It is the caller's responsibility to ensure that
|
/// It is the caller's responsibility to ensure that
|
||||||
/// - the [`UnsafeEntityCell`] has permission to access the queried data immutably
|
/// - the [`UnsafeEntityCell`] has permission to access the queried data immutably
|
||||||
/// - no mutable references to the queried data exist at the same time
|
/// - no mutable references to the queried data exist at the same time
|
||||||
pub(crate) unsafe fn get_components<Q: ReadOnlyQueryData>(&self) -> Option<Q::Item<'w>> {
|
pub(crate) unsafe fn get_components<Q: ReadOnlyQueryData + ReleaseStateQueryData>(
|
||||||
|
&self,
|
||||||
|
) -> Option<Q::Item<'w, 'static>> {
|
||||||
// SAFETY: World is only used to access query data and initialize query state
|
// SAFETY: World is only used to access query data and initialize query state
|
||||||
let state = unsafe {
|
let state = unsafe {
|
||||||
let world = self.world().world();
|
let world = self.world().world();
|
||||||
@ -1035,7 +1037,8 @@ impl<'w> UnsafeEntityCell<'w> {
|
|||||||
// Table corresponds to archetype. State is the same state used to init fetch above.
|
// Table corresponds to archetype. State is the same state used to init fetch above.
|
||||||
unsafe { Q::set_archetype(&mut fetch, &state, archetype, table) }
|
unsafe { Q::set_archetype(&mut fetch, &state, archetype, table) }
|
||||||
// SAFETY: Called after set_archetype above. Entity and location are guaranteed to exist.
|
// SAFETY: Called after set_archetype above. Entity and location are guaranteed to exist.
|
||||||
unsafe { Some(Q::fetch(&mut fetch, self.id(), location.table_row)) }
|
let item = unsafe { Q::fetch(&state, &mut fetch, self.id(), location.table_row) };
|
||||||
|
Some(Q::release_state(item))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
@ -631,8 +631,8 @@ impl<const I: usize, P: PhaseItem> RenderCommand<P> for SetLineGizmoBindGroup<I>
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn render<'w>(
|
fn render<'w>(
|
||||||
_item: &P,
|
_item: &P,
|
||||||
_view: ROQueryItem<'w, Self::ViewQuery>,
|
_view: ROQueryItem<'w, '_, Self::ViewQuery>,
|
||||||
uniform_index: Option<ROQueryItem<'w, Self::ItemQuery>>,
|
uniform_index: Option<ROQueryItem<'w, '_, Self::ItemQuery>>,
|
||||||
bind_group: SystemParamItem<'w, '_, Self::Param>,
|
bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
@ -662,8 +662,8 @@ impl<P: PhaseItem, const STRIP: bool> RenderCommand<P> for DrawLineGizmo<STRIP>
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn render<'w>(
|
fn render<'w>(
|
||||||
_item: &P,
|
_item: &P,
|
||||||
_view: ROQueryItem<'w, Self::ViewQuery>,
|
_view: ROQueryItem<'w, '_, Self::ViewQuery>,
|
||||||
config: Option<ROQueryItem<'w, Self::ItemQuery>>,
|
config: Option<ROQueryItem<'w, '_, Self::ItemQuery>>,
|
||||||
line_gizmos: SystemParamItem<'w, '_, Self::Param>,
|
line_gizmos: SystemParamItem<'w, '_, Self::Param>,
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
@ -725,8 +725,8 @@ impl<P: PhaseItem> RenderCommand<P> for DrawLineJointGizmo {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn render<'w>(
|
fn render<'w>(
|
||||||
_item: &P,
|
_item: &P,
|
||||||
_view: ROQueryItem<'w, Self::ViewQuery>,
|
_view: ROQueryItem<'w, '_, Self::ViewQuery>,
|
||||||
config: Option<ROQueryItem<'w, Self::ItemQuery>>,
|
config: Option<ROQueryItem<'w, '_, Self::ItemQuery>>,
|
||||||
line_gizmos: SystemParamItem<'w, '_, Self::Param>,
|
line_gizmos: SystemParamItem<'w, '_, Self::Param>,
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
|
|||||||
80
crates/bevy_gltf/src/convert_coordinates.rs
Normal file
80
crates/bevy_gltf/src/convert_coordinates.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
use core::f32::consts::PI;
|
||||||
|
|
||||||
|
use bevy_math::{Mat4, Quat, Vec3};
|
||||||
|
use bevy_transform::components::Transform;
|
||||||
|
|
||||||
|
pub(crate) trait ConvertCoordinates {
|
||||||
|
/// Converts the glTF coordinates to Bevy's coordinate system.
|
||||||
|
/// - glTF:
|
||||||
|
/// - forward: Z
|
||||||
|
/// - up: Y
|
||||||
|
/// - right: -X
|
||||||
|
/// - Bevy:
|
||||||
|
/// - forward: -Z
|
||||||
|
/// - up: Y
|
||||||
|
/// - right: X
|
||||||
|
///
|
||||||
|
/// See <https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#coordinate-system-and-units>
|
||||||
|
fn convert_coordinates(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait ConvertCameraCoordinates {
|
||||||
|
/// Like `convert_coordinates`, but uses the following for the lens rotation:
|
||||||
|
/// - forward: -Z
|
||||||
|
/// - up: Y
|
||||||
|
/// - right: X
|
||||||
|
///
|
||||||
|
/// See <https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#view-matrix>
|
||||||
|
fn convert_camera_coordinates(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertCoordinates for Vec3 {
|
||||||
|
fn convert_coordinates(self) -> Self {
|
||||||
|
Vec3::new(-self.x, self.y, -self.z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertCoordinates for [f32; 3] {
|
||||||
|
fn convert_coordinates(self) -> Self {
|
||||||
|
[-self[0], self[1], -self[2]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertCoordinates for [f32; 4] {
|
||||||
|
fn convert_coordinates(self) -> Self {
|
||||||
|
// Solution of q' = r q r*
|
||||||
|
[-self[0], self[1], -self[2], self[3]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertCoordinates for Quat {
|
||||||
|
fn convert_coordinates(self) -> Self {
|
||||||
|
// Solution of q' = r q r*
|
||||||
|
Quat::from_array([-self.x, self.y, -self.z, self.w])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertCoordinates for Mat4 {
|
||||||
|
fn convert_coordinates(self) -> Self {
|
||||||
|
let m: Mat4 = Mat4::from_scale(Vec3::new(-1.0, 1.0, -1.0));
|
||||||
|
// Same as the original matrix
|
||||||
|
let m_inv = m;
|
||||||
|
m_inv * self * m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertCoordinates for Transform {
|
||||||
|
fn convert_coordinates(mut self) -> Self {
|
||||||
|
self.translation = self.translation.convert_coordinates();
|
||||||
|
self.rotation = self.rotation.convert_coordinates();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertCameraCoordinates for Transform {
|
||||||
|
fn convert_camera_coordinates(mut self) -> Self {
|
||||||
|
self.translation = self.translation.convert_coordinates();
|
||||||
|
self.rotate_y(PI);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -91,6 +91,7 @@
|
|||||||
//! You can use [`GltfAssetLabel`] to ensure you are using the correct label.
|
//! You can use [`GltfAssetLabel`] to ensure you are using the correct label.
|
||||||
|
|
||||||
mod assets;
|
mod assets;
|
||||||
|
mod convert_coordinates;
|
||||||
mod label;
|
mod label;
|
||||||
mod loader;
|
mod loader;
|
||||||
mod vertex_attributes;
|
mod vertex_attributes;
|
||||||
|
|||||||
@ -10,7 +10,10 @@ use itertools::Itertools;
|
|||||||
#[cfg(feature = "bevy_animation")]
|
#[cfg(feature = "bevy_animation")]
|
||||||
use bevy_platform::collections::{HashMap, HashSet};
|
use bevy_platform::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use crate::GltfError;
|
use crate::{
|
||||||
|
convert_coordinates::{ConvertCameraCoordinates as _, ConvertCoordinates as _},
|
||||||
|
GltfError,
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) fn node_name(node: &Node) -> Name {
|
pub(crate) fn node_name(node: &Node) -> Name {
|
||||||
let name = node
|
let name = node
|
||||||
@ -26,8 +29,8 @@ pub(crate) fn node_name(node: &Node) -> Name {
|
|||||||
/// on [`Node::transform()`](gltf::Node::transform) directly because it uses optimized glam types and
|
/// on [`Node::transform()`](gltf::Node::transform) directly because it uses optimized glam types and
|
||||||
/// if `libm` feature of `bevy_math` crate is enabled also handles cross
|
/// if `libm` feature of `bevy_math` crate is enabled also handles cross
|
||||||
/// platform determinism properly.
|
/// platform determinism properly.
|
||||||
pub(crate) fn node_transform(node: &Node) -> Transform {
|
pub(crate) fn node_transform(node: &Node, convert_coordinates: bool) -> Transform {
|
||||||
match node.transform() {
|
let transform = match node.transform() {
|
||||||
gltf::scene::Transform::Matrix { matrix } => {
|
gltf::scene::Transform::Matrix { matrix } => {
|
||||||
Transform::from_matrix(Mat4::from_cols_array_2d(&matrix))
|
Transform::from_matrix(Mat4::from_cols_array_2d(&matrix))
|
||||||
}
|
}
|
||||||
@ -40,6 +43,15 @@ pub(crate) fn node_transform(node: &Node) -> Transform {
|
|||||||
rotation: bevy_math::Quat::from_array(rotation),
|
rotation: bevy_math::Quat::from_array(rotation),
|
||||||
scale: Vec3::from(scale),
|
scale: Vec3::from(scale),
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
if convert_coordinates {
|
||||||
|
if node.camera().is_some() {
|
||||||
|
transform.convert_camera_coordinates()
|
||||||
|
} else {
|
||||||
|
transform.convert_coordinates()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
transform
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -84,6 +84,7 @@ use self::{
|
|||||||
texture::{texture_handle, texture_sampler, texture_transform_to_affine2},
|
texture::{texture_handle, texture_sampler, texture_transform_to_affine2},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use crate::convert_coordinates::ConvertCoordinates as _;
|
||||||
|
|
||||||
/// An error that occurs when loading a glTF file.
|
/// An error that occurs when loading a glTF file.
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@ -191,6 +192,16 @@ pub struct GltfLoaderSettings {
|
|||||||
pub default_sampler: Option<ImageSamplerDescriptor>,
|
pub default_sampler: Option<ImageSamplerDescriptor>,
|
||||||
/// If true, the loader will ignore sampler data from gltf and use the default sampler.
|
/// If true, the loader will ignore sampler data from gltf and use the default sampler.
|
||||||
pub override_sampler: bool,
|
pub override_sampler: bool,
|
||||||
|
/// If true, the loader will convert glTF coordinates to Bevy's coordinate system.
|
||||||
|
/// - glTF:
|
||||||
|
/// - forward: Z
|
||||||
|
/// - up: Y
|
||||||
|
/// - right: -X
|
||||||
|
/// - Bevy:
|
||||||
|
/// - forward: -Z
|
||||||
|
/// - up: Y
|
||||||
|
/// - right: X
|
||||||
|
pub convert_coordinates: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GltfLoaderSettings {
|
impl Default for GltfLoaderSettings {
|
||||||
@ -203,6 +214,7 @@ impl Default for GltfLoaderSettings {
|
|||||||
include_source: false,
|
include_source: false,
|
||||||
default_sampler: None,
|
default_sampler: None,
|
||||||
override_sampler: false,
|
override_sampler: false,
|
||||||
|
convert_coordinates: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,7 +315,16 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||||||
match outputs {
|
match outputs {
|
||||||
ReadOutputs::Translations(tr) => {
|
ReadOutputs::Translations(tr) => {
|
||||||
let translation_property = animated_field!(Transform::translation);
|
let translation_property = animated_field!(Transform::translation);
|
||||||
let translations: Vec<Vec3> = tr.map(Vec3::from).collect();
|
let translations: Vec<Vec3> = tr
|
||||||
|
.map(Vec3::from)
|
||||||
|
.map(|verts| {
|
||||||
|
if settings.convert_coordinates {
|
||||||
|
Vec3::convert_coordinates(verts)
|
||||||
|
} else {
|
||||||
|
verts
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
if keyframe_timestamps.len() == 1 {
|
if keyframe_timestamps.len() == 1 {
|
||||||
Some(VariableCurve::new(AnimatableCurve::new(
|
Some(VariableCurve::new(AnimatableCurve::new(
|
||||||
translation_property,
|
translation_property,
|
||||||
@ -350,8 +371,17 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||||||
}
|
}
|
||||||
ReadOutputs::Rotations(rots) => {
|
ReadOutputs::Rotations(rots) => {
|
||||||
let rotation_property = animated_field!(Transform::rotation);
|
let rotation_property = animated_field!(Transform::rotation);
|
||||||
let rotations: Vec<Quat> =
|
let rotations: Vec<Quat> = rots
|
||||||
rots.into_f32().map(Quat::from_array).collect();
|
.into_f32()
|
||||||
|
.map(Quat::from_array)
|
||||||
|
.map(|quat| {
|
||||||
|
if settings.convert_coordinates {
|
||||||
|
Quat::convert_coordinates(quat)
|
||||||
|
} else {
|
||||||
|
quat
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
if keyframe_timestamps.len() == 1 {
|
if keyframe_timestamps.len() == 1 {
|
||||||
Some(VariableCurve::new(AnimatableCurve::new(
|
Some(VariableCurve::new(AnimatableCurve::new(
|
||||||
rotation_property,
|
rotation_property,
|
||||||
@ -633,6 +663,7 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||||||
accessor,
|
accessor,
|
||||||
&buffer_data,
|
&buffer_data,
|
||||||
&loader.custom_vertex_attributes,
|
&loader.custom_vertex_attributes,
|
||||||
|
settings.convert_coordinates,
|
||||||
) {
|
) {
|
||||||
Ok((attribute, values)) => mesh.insert_attribute(attribute, values),
|
Ok((attribute, values)) => mesh.insert_attribute(attribute, values),
|
||||||
Err(err) => warn!("{}", err),
|
Err(err) => warn!("{}", err),
|
||||||
@ -752,7 +783,17 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||||||
let reader = gltf_skin.reader(|buffer| Some(&buffer_data[buffer.index()]));
|
let reader = gltf_skin.reader(|buffer| Some(&buffer_data[buffer.index()]));
|
||||||
let local_to_bone_bind_matrices: Vec<Mat4> = reader
|
let local_to_bone_bind_matrices: Vec<Mat4> = reader
|
||||||
.read_inverse_bind_matrices()
|
.read_inverse_bind_matrices()
|
||||||
.map(|mats| mats.map(|mat| Mat4::from_cols_array_2d(&mat)).collect())
|
.map(|mats| {
|
||||||
|
mats.map(|mat| Mat4::from_cols_array_2d(&mat))
|
||||||
|
.map(|mat| {
|
||||||
|
if settings.convert_coordinates {
|
||||||
|
mat.convert_coordinates()
|
||||||
|
} else {
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
core::iter::repeat_n(Mat4::IDENTITY, gltf_skin.joints().len()).collect()
|
core::iter::repeat_n(Mat4::IDENTITY, gltf_skin.joints().len()).collect()
|
||||||
});
|
});
|
||||||
@ -834,7 +875,7 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||||||
&node,
|
&node,
|
||||||
children,
|
children,
|
||||||
mesh,
|
mesh,
|
||||||
node_transform(&node),
|
node_transform(&node, settings.convert_coordinates),
|
||||||
skin,
|
skin,
|
||||||
node.extras().as_deref().map(GltfExtras::from),
|
node.extras().as_deref().map(GltfExtras::from),
|
||||||
);
|
);
|
||||||
@ -1306,7 +1347,7 @@ fn load_node(
|
|||||||
document: &Document,
|
document: &Document,
|
||||||
) -> Result<(), GltfError> {
|
) -> Result<(), GltfError> {
|
||||||
let mut gltf_error = None;
|
let mut gltf_error = None;
|
||||||
let transform = node_transform(gltf_node);
|
let transform = node_transform(gltf_node, settings.convert_coordinates);
|
||||||
let world_transform = *parent_transform * transform;
|
let world_transform = *parent_transform * transform;
|
||||||
// according to https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#instantiation,
|
// according to https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#instantiation,
|
||||||
// if the determinant of the transform is negative we must invert the winding order of
|
// if the determinant of the transform is negative we must invert the winding order of
|
||||||
@ -1359,7 +1400,6 @@ fn load_node(
|
|||||||
},
|
},
|
||||||
..OrthographicProjection::default_3d()
|
..OrthographicProjection::default_3d()
|
||||||
};
|
};
|
||||||
|
|
||||||
Projection::Orthographic(orthographic_projection)
|
Projection::Orthographic(orthographic_projection)
|
||||||
}
|
}
|
||||||
gltf::camera::Projection::Perspective(perspective) => {
|
gltf::camera::Projection::Perspective(perspective) => {
|
||||||
@ -1377,6 +1417,7 @@ fn load_node(
|
|||||||
Projection::Perspective(perspective_projection)
|
Projection::Perspective(perspective_projection)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
node.insert((
|
node.insert((
|
||||||
Camera3d::default(),
|
Camera3d::default(),
|
||||||
projection,
|
projection,
|
||||||
|
|||||||
@ -6,6 +6,8 @@ use gltf::{
|
|||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::convert_coordinates::ConvertCoordinates;
|
||||||
|
|
||||||
/// Represents whether integer data requires normalization
|
/// Represents whether integer data requires normalization
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct Normalization(bool);
|
struct Normalization(bool);
|
||||||
@ -132,15 +134,23 @@ impl<'a> VertexAttributeIter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Materializes values for any supported format of vertex attribute
|
/// Materializes values for any supported format of vertex attribute
|
||||||
fn into_any_values(self) -> Result<Values, AccessFailed> {
|
fn into_any_values(self, convert_coordinates: bool) -> Result<Values, AccessFailed> {
|
||||||
match self {
|
match self {
|
||||||
VertexAttributeIter::F32(it) => Ok(Values::Float32(it.collect())),
|
VertexAttributeIter::F32(it) => Ok(Values::Float32(it.collect())),
|
||||||
VertexAttributeIter::U32(it) => Ok(Values::Uint32(it.collect())),
|
VertexAttributeIter::U32(it) => Ok(Values::Uint32(it.collect())),
|
||||||
VertexAttributeIter::F32x2(it) => Ok(Values::Float32x2(it.collect())),
|
VertexAttributeIter::F32x2(it) => Ok(Values::Float32x2(it.collect())),
|
||||||
VertexAttributeIter::U32x2(it) => Ok(Values::Uint32x2(it.collect())),
|
VertexAttributeIter::U32x2(it) => Ok(Values::Uint32x2(it.collect())),
|
||||||
VertexAttributeIter::F32x3(it) => Ok(Values::Float32x3(it.collect())),
|
VertexAttributeIter::F32x3(it) => Ok(if convert_coordinates {
|
||||||
|
Values::Float32x3(it.map(ConvertCoordinates::convert_coordinates).collect())
|
||||||
|
} else {
|
||||||
|
Values::Float32x3(it.collect())
|
||||||
|
}),
|
||||||
VertexAttributeIter::U32x3(it) => Ok(Values::Uint32x3(it.collect())),
|
VertexAttributeIter::U32x3(it) => Ok(Values::Uint32x3(it.collect())),
|
||||||
VertexAttributeIter::F32x4(it) => Ok(Values::Float32x4(it.collect())),
|
VertexAttributeIter::F32x4(it) => Ok(if convert_coordinates {
|
||||||
|
Values::Float32x4(it.map(ConvertCoordinates::convert_coordinates).collect())
|
||||||
|
} else {
|
||||||
|
Values::Float32x4(it.collect())
|
||||||
|
}),
|
||||||
VertexAttributeIter::U32x4(it) => Ok(Values::Uint32x4(it.collect())),
|
VertexAttributeIter::U32x4(it) => Ok(Values::Uint32x4(it.collect())),
|
||||||
VertexAttributeIter::S16x2(it, n) => {
|
VertexAttributeIter::S16x2(it, n) => {
|
||||||
Ok(n.apply_either(it.collect(), Values::Snorm16x2, Values::Sint16x2))
|
Ok(n.apply_either(it.collect(), Values::Snorm16x2, Values::Sint16x2))
|
||||||
@ -188,7 +198,7 @@ impl<'a> VertexAttributeIter<'a> {
|
|||||||
VertexAttributeIter::U16x4(it, Normalization(true)) => Ok(Values::Float32x4(
|
VertexAttributeIter::U16x4(it, Normalization(true)) => Ok(Values::Float32x4(
|
||||||
ReadColors::RgbaU16(it).into_rgba_f32().collect(),
|
ReadColors::RgbaU16(it).into_rgba_f32().collect(),
|
||||||
)),
|
)),
|
||||||
s => s.into_any_values(),
|
s => s.into_any_values(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +208,7 @@ impl<'a> VertexAttributeIter<'a> {
|
|||||||
VertexAttributeIter::U8x4(it, Normalization(false)) => {
|
VertexAttributeIter::U8x4(it, Normalization(false)) => {
|
||||||
Ok(Values::Uint16x4(ReadJoints::U8(it).into_u16().collect()))
|
Ok(Values::Uint16x4(ReadJoints::U8(it).into_u16().collect()))
|
||||||
}
|
}
|
||||||
s => s.into_any_values(),
|
s => s.into_any_values(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +221,7 @@ impl<'a> VertexAttributeIter<'a> {
|
|||||||
VertexAttributeIter::U16x4(it, Normalization(true)) => {
|
VertexAttributeIter::U16x4(it, Normalization(true)) => {
|
||||||
Ok(Values::Float32x4(ReadWeights::U16(it).into_f32().collect()))
|
Ok(Values::Float32x4(ReadWeights::U16(it).into_f32().collect()))
|
||||||
}
|
}
|
||||||
s => s.into_any_values(),
|
s => s.into_any_values(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +234,7 @@ impl<'a> VertexAttributeIter<'a> {
|
|||||||
VertexAttributeIter::U16x2(it, Normalization(true)) => Ok(Values::Float32x2(
|
VertexAttributeIter::U16x2(it, Normalization(true)) => Ok(Values::Float32x2(
|
||||||
ReadTexCoords::U16(it).into_f32().collect(),
|
ReadTexCoords::U16(it).into_f32().collect(),
|
||||||
)),
|
)),
|
||||||
s => s.into_any_values(),
|
s => s.into_any_values(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,28 +262,49 @@ pub(crate) fn convert_attribute(
|
|||||||
accessor: gltf::Accessor,
|
accessor: gltf::Accessor,
|
||||||
buffer_data: &Vec<Vec<u8>>,
|
buffer_data: &Vec<Vec<u8>>,
|
||||||
custom_vertex_attributes: &HashMap<Box<str>, MeshVertexAttribute>,
|
custom_vertex_attributes: &HashMap<Box<str>, MeshVertexAttribute>,
|
||||||
|
convert_coordinates: bool,
|
||||||
) -> Result<(MeshVertexAttribute, Values), ConvertAttributeError> {
|
) -> Result<(MeshVertexAttribute, Values), ConvertAttributeError> {
|
||||||
if let Some((attribute, conversion)) = match &semantic {
|
if let Some((attribute, conversion, convert_coordinates)) = match &semantic {
|
||||||
gltf::Semantic::Positions => Some((Mesh::ATTRIBUTE_POSITION, ConversionMode::Any)),
|
gltf::Semantic::Positions => Some((
|
||||||
gltf::Semantic::Normals => Some((Mesh::ATTRIBUTE_NORMAL, ConversionMode::Any)),
|
Mesh::ATTRIBUTE_POSITION,
|
||||||
gltf::Semantic::Tangents => Some((Mesh::ATTRIBUTE_TANGENT, ConversionMode::Any)),
|
ConversionMode::Any,
|
||||||
gltf::Semantic::Colors(0) => Some((Mesh::ATTRIBUTE_COLOR, ConversionMode::Rgba)),
|
convert_coordinates,
|
||||||
gltf::Semantic::TexCoords(0) => Some((Mesh::ATTRIBUTE_UV_0, ConversionMode::TexCoord)),
|
)),
|
||||||
gltf::Semantic::TexCoords(1) => Some((Mesh::ATTRIBUTE_UV_1, ConversionMode::TexCoord)),
|
gltf::Semantic::Normals => Some((
|
||||||
gltf::Semantic::Joints(0) => {
|
Mesh::ATTRIBUTE_NORMAL,
|
||||||
Some((Mesh::ATTRIBUTE_JOINT_INDEX, ConversionMode::JointIndex))
|
ConversionMode::Any,
|
||||||
|
convert_coordinates,
|
||||||
|
)),
|
||||||
|
gltf::Semantic::Tangents => Some((
|
||||||
|
Mesh::ATTRIBUTE_TANGENT,
|
||||||
|
ConversionMode::Any,
|
||||||
|
convert_coordinates,
|
||||||
|
)),
|
||||||
|
gltf::Semantic::Colors(0) => Some((Mesh::ATTRIBUTE_COLOR, ConversionMode::Rgba, false)),
|
||||||
|
gltf::Semantic::TexCoords(0) => {
|
||||||
|
Some((Mesh::ATTRIBUTE_UV_0, ConversionMode::TexCoord, false))
|
||||||
}
|
}
|
||||||
gltf::Semantic::Weights(0) => {
|
gltf::Semantic::TexCoords(1) => {
|
||||||
Some((Mesh::ATTRIBUTE_JOINT_WEIGHT, ConversionMode::JointWeight))
|
Some((Mesh::ATTRIBUTE_UV_1, ConversionMode::TexCoord, false))
|
||||||
}
|
}
|
||||||
|
gltf::Semantic::Joints(0) => Some((
|
||||||
|
Mesh::ATTRIBUTE_JOINT_INDEX,
|
||||||
|
ConversionMode::JointIndex,
|
||||||
|
false,
|
||||||
|
)),
|
||||||
|
gltf::Semantic::Weights(0) => Some((
|
||||||
|
Mesh::ATTRIBUTE_JOINT_WEIGHT,
|
||||||
|
ConversionMode::JointWeight,
|
||||||
|
false,
|
||||||
|
)),
|
||||||
gltf::Semantic::Extras(name) => custom_vertex_attributes
|
gltf::Semantic::Extras(name) => custom_vertex_attributes
|
||||||
.get(name.as_str())
|
.get(name.as_str())
|
||||||
.map(|attr| (*attr, ConversionMode::Any)),
|
.map(|attr| (*attr, ConversionMode::Any, false)),
|
||||||
_ => None,
|
_ => None,
|
||||||
} {
|
} {
|
||||||
let raw_iter = VertexAttributeIter::from_accessor(accessor.clone(), buffer_data);
|
let raw_iter = VertexAttributeIter::from_accessor(accessor.clone(), buffer_data);
|
||||||
let converted_values = raw_iter.and_then(|iter| match conversion {
|
let converted_values = raw_iter.and_then(|iter| match conversion {
|
||||||
ConversionMode::Any => iter.into_any_values(),
|
ConversionMode::Any => iter.into_any_values(convert_coordinates),
|
||||||
ConversionMode::Rgba => iter.into_rgba_values(),
|
ConversionMode::Rgba => iter.into_rgba_values(),
|
||||||
ConversionMode::TexCoord => iter.into_tex_coord_values(),
|
ConversionMode::TexCoord => iter.into_tex_coord_values(),
|
||||||
ConversionMode::JointIndex => iter.into_joint_index_values(),
|
ConversionMode::JointIndex => iter.into_joint_index_values(),
|
||||||
|
|||||||
@ -122,7 +122,7 @@ use {
|
|||||||
/// [`DetectChangesMut::bypass_change_detection`]: bevy_ecs::change_detection::DetectChangesMut::bypass_change_detection
|
/// [`DetectChangesMut::bypass_change_detection`]: bevy_ecs::change_detection::DetectChangesMut::bypass_change_detection
|
||||||
#[derive(Debug, Clone, Resource)]
|
#[derive(Debug, Clone, Resource)]
|
||||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Default, Resource))]
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Default, Resource))]
|
||||||
pub struct ButtonInput<T: Copy + Eq + Hash + Send + Sync + 'static> {
|
pub struct ButtonInput<T: Clone + Eq + Hash + Send + Sync + 'static> {
|
||||||
/// A collection of every button that is currently being pressed.
|
/// A collection of every button that is currently being pressed.
|
||||||
pressed: HashSet<T>,
|
pressed: HashSet<T>,
|
||||||
/// A collection of every button that has just been pressed.
|
/// A collection of every button that has just been pressed.
|
||||||
@ -131,7 +131,7 @@ pub struct ButtonInput<T: Copy + Eq + Hash + Send + Sync + 'static> {
|
|||||||
just_released: HashSet<T>,
|
just_released: HashSet<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy + Eq + Hash + Send + Sync + 'static> Default for ButtonInput<T> {
|
impl<T: Clone + Eq + Hash + Send + Sync + 'static> Default for ButtonInput<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
pressed: Default::default(),
|
pressed: Default::default(),
|
||||||
@ -143,12 +143,12 @@ impl<T: Copy + Eq + Hash + Send + Sync + 'static> Default for ButtonInput<T> {
|
|||||||
|
|
||||||
impl<T> ButtonInput<T>
|
impl<T> ButtonInput<T>
|
||||||
where
|
where
|
||||||
T: Copy + Eq + Hash + Send + Sync + 'static,
|
T: Clone + Eq + Hash + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
/// Registers a press for the given `input`.
|
/// Registers a press for the given `input`.
|
||||||
pub fn press(&mut self, input: T) {
|
pub fn press(&mut self, input: T) {
|
||||||
// Returns `true` if the `input` wasn't pressed.
|
// Returns `true` if the `input` wasn't pressed.
|
||||||
if self.pressed.insert(input) {
|
if self.pressed.insert(input.clone()) {
|
||||||
self.just_pressed.insert(input);
|
self.just_pressed.insert(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,8 +92,9 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
|||||||
///
|
///
|
||||||
/// ## Usage
|
/// ## Usage
|
||||||
///
|
///
|
||||||
/// The event is consumed inside of the [`keyboard_input_system`]
|
/// The event is consumed inside of the [`keyboard_input_system`] to update the
|
||||||
/// to update the [`ButtonInput<KeyCode>`](ButtonInput<KeyCode>) resource.
|
/// [`ButtonInput<KeyCode>`](ButtonInput<KeyCode>) and
|
||||||
|
/// [`ButtonInput<Key>`](ButtonInput<Key>) resources.
|
||||||
#[derive(Event, BufferedEvent, Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Event, BufferedEvent, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "bevy_reflect",
|
feature = "bevy_reflect",
|
||||||
@ -107,8 +108,12 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
|||||||
)]
|
)]
|
||||||
pub struct KeyboardInput {
|
pub struct KeyboardInput {
|
||||||
/// The physical key code of the key.
|
/// The physical key code of the key.
|
||||||
|
///
|
||||||
|
/// This corresponds to the location of the key independent of the keyboard layout.
|
||||||
pub key_code: KeyCode,
|
pub key_code: KeyCode,
|
||||||
/// The logical key of the input
|
/// The logical key of the input.
|
||||||
|
///
|
||||||
|
/// This corresponds to the actual key taking keyboard layout into account.
|
||||||
pub logical_key: Key,
|
pub logical_key: Key,
|
||||||
/// The press state of the key.
|
/// The press state of the key.
|
||||||
pub state: ButtonState,
|
pub state: ButtonState,
|
||||||
@ -148,32 +153,46 @@ pub struct KeyboardInput {
|
|||||||
)]
|
)]
|
||||||
pub struct KeyboardFocusLost;
|
pub struct KeyboardFocusLost;
|
||||||
|
|
||||||
/// Updates the [`ButtonInput<KeyCode>`] resource with the latest [`KeyboardInput`] events.
|
/// Updates the [`ButtonInput<KeyCode>`] and [`ButtonInput<Key>`] resources with the latest [`KeyboardInput`] events.
|
||||||
///
|
///
|
||||||
/// ## Differences
|
/// ## Differences
|
||||||
///
|
///
|
||||||
/// The main difference between the [`KeyboardInput`] event and the [`ButtonInput<KeyCode>`] resources is that
|
/// The main difference between the [`KeyboardInput`] event and the [`ButtonInput`] resources are that
|
||||||
/// the latter has convenient functions such as [`ButtonInput::pressed`], [`ButtonInput::just_pressed`] and [`ButtonInput::just_released`] and is window id agnostic.
|
/// the latter has convenient functions such as [`ButtonInput::pressed`], [`ButtonInput::just_pressed`] and [`ButtonInput::just_released`] and is window id agnostic.
|
||||||
|
///
|
||||||
|
/// There is a [`ButtonInput`] for both [`KeyCode`] and [`Key`] as they are both useful in different situations, see their documentation for the details.
|
||||||
pub fn keyboard_input_system(
|
pub fn keyboard_input_system(
|
||||||
mut key_input: ResMut<ButtonInput<KeyCode>>,
|
mut keycode_input: ResMut<ButtonInput<KeyCode>>,
|
||||||
|
mut key_input: ResMut<ButtonInput<Key>>,
|
||||||
mut keyboard_input_events: EventReader<KeyboardInput>,
|
mut keyboard_input_events: EventReader<KeyboardInput>,
|
||||||
mut focus_events: EventReader<KeyboardFocusLost>,
|
mut focus_events: EventReader<KeyboardFocusLost>,
|
||||||
) {
|
) {
|
||||||
// Avoid clearing if it's not empty to ensure change detection is not triggered.
|
// Avoid clearing if not empty to ensure change detection is not triggered.
|
||||||
|
keycode_input.bypass_change_detection().clear();
|
||||||
key_input.bypass_change_detection().clear();
|
key_input.bypass_change_detection().clear();
|
||||||
|
|
||||||
for event in keyboard_input_events.read() {
|
for event in keyboard_input_events.read() {
|
||||||
let KeyboardInput {
|
let KeyboardInput {
|
||||||
key_code, state, ..
|
key_code,
|
||||||
|
logical_key,
|
||||||
|
state,
|
||||||
|
..
|
||||||
} = event;
|
} = event;
|
||||||
match state {
|
match state {
|
||||||
ButtonState::Pressed => key_input.press(*key_code),
|
ButtonState::Pressed => {
|
||||||
ButtonState::Released => key_input.release(*key_code),
|
keycode_input.press(*key_code);
|
||||||
|
key_input.press(logical_key.clone());
|
||||||
|
}
|
||||||
|
ButtonState::Released => {
|
||||||
|
keycode_input.release(*key_code);
|
||||||
|
key_input.release(logical_key.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release all cached input to avoid having stuck input when switching between windows in os
|
// Release all cached input to avoid having stuck input when switching between windows in os
|
||||||
if !focus_events.is_empty() {
|
if !focus_events.is_empty() {
|
||||||
key_input.release_all();
|
keycode_input.release_all();
|
||||||
focus_events.clear();
|
focus_events.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,13 +239,13 @@ pub enum NativeKeyCode {
|
|||||||
/// It is used as the generic `T` value of an [`ButtonInput`] to create a `Res<ButtonInput<KeyCode>>`.
|
/// It is used as the generic `T` value of an [`ButtonInput`] to create a `Res<ButtonInput<KeyCode>>`.
|
||||||
///
|
///
|
||||||
/// Code representing the location of a physical key
|
/// Code representing the location of a physical key
|
||||||
/// This mostly conforms to the UI Events Specification's [`KeyboardEvent.code`] with a few
|
/// This mostly conforms to the [`UI Events Specification's KeyboardEvent.code`] with a few
|
||||||
/// exceptions:
|
/// exceptions:
|
||||||
/// - The keys that the specification calls `MetaLeft` and `MetaRight` are named `SuperLeft` and
|
/// - The keys that the specification calls `MetaLeft` and `MetaRight` are named `SuperLeft` and
|
||||||
/// `SuperRight` here.
|
/// `SuperRight` here.
|
||||||
/// - The key that the specification calls "Super" is reported as `Unidentified` here.
|
/// - The key that the specification calls "Super" is reported as `Unidentified` here.
|
||||||
///
|
///
|
||||||
/// [`KeyboardEvent.code`]: https://w3c.github.io/uievents-code/#code-value-tables
|
/// [`UI Events Specification's KeyboardEvent.code`]: https://w3c.github.io/uievents-code/#code-value-tables
|
||||||
///
|
///
|
||||||
/// ## Updating
|
/// ## Updating
|
||||||
///
|
///
|
||||||
@ -756,6 +775,19 @@ pub enum NativeKey {
|
|||||||
|
|
||||||
/// The logical key code of a [`KeyboardInput`].
|
/// The logical key code of a [`KeyboardInput`].
|
||||||
///
|
///
|
||||||
|
/// This contains the actual value that is produced by pressing the key. This is
|
||||||
|
/// useful when you need the actual letters, and for symbols like `+` and `-`
|
||||||
|
/// when implementing zoom, as they can be in different locations depending on
|
||||||
|
/// the keyboard layout.
|
||||||
|
///
|
||||||
|
/// In many cases you want the key location instead, for example when
|
||||||
|
/// implementing WASD controls so the keys are located the same place on QWERTY
|
||||||
|
/// and other layouts. In that case use [`KeyCode`] instead.
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// It is used as the generic `T` value of an [`ButtonInput`] to create a `Res<ButtonInput<Key>>`.
|
||||||
|
///
|
||||||
/// ## Technical
|
/// ## Technical
|
||||||
///
|
///
|
||||||
/// Its values map 1 to 1 to winit's Key.
|
/// Its values map 1 to 1 to winit's Key.
|
||||||
|
|||||||
@ -49,7 +49,7 @@ use bevy_ecs::prelude::*;
|
|||||||
#[cfg(feature = "bevy_reflect")]
|
#[cfg(feature = "bevy_reflect")]
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use gestures::*;
|
use gestures::*;
|
||||||
use keyboard::{keyboard_input_system, KeyCode, KeyboardFocusLost, KeyboardInput};
|
use keyboard::{keyboard_input_system, Key, KeyCode, KeyboardFocusLost, KeyboardInput};
|
||||||
use mouse::{
|
use mouse::{
|
||||||
accumulate_mouse_motion_system, accumulate_mouse_scroll_system, mouse_button_input_system,
|
accumulate_mouse_motion_system, accumulate_mouse_scroll_system, mouse_button_input_system,
|
||||||
AccumulatedMouseMotion, AccumulatedMouseScroll, MouseButton, MouseButtonInput, MouseMotion,
|
AccumulatedMouseMotion, AccumulatedMouseScroll, MouseButton, MouseButtonInput, MouseMotion,
|
||||||
@ -89,6 +89,7 @@ impl Plugin for InputPlugin {
|
|||||||
.add_event::<KeyboardInput>()
|
.add_event::<KeyboardInput>()
|
||||||
.add_event::<KeyboardFocusLost>()
|
.add_event::<KeyboardFocusLost>()
|
||||||
.init_resource::<ButtonInput<KeyCode>>()
|
.init_resource::<ButtonInput<KeyCode>>()
|
||||||
|
.init_resource::<ButtonInput<Key>>()
|
||||||
.add_systems(PreUpdate, keyboard_input_system.in_set(InputSystems))
|
.add_systems(PreUpdate, keyboard_input_system.in_set(InputSystems))
|
||||||
// mouse
|
// mouse
|
||||||
.add_event::<MouseButtonInput>()
|
.add_event::<MouseButtonInput>()
|
||||||
|
|||||||
@ -155,7 +155,7 @@ pub struct WindowTraversal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: BufferedEvent + Clone> Traversal<FocusedInput<E>> for WindowTraversal {
|
impl<E: BufferedEvent + Clone> Traversal<FocusedInput<E>> for WindowTraversal {
|
||||||
fn traverse(item: Self::Item<'_>, event: &FocusedInput<E>) -> Option<Entity> {
|
fn traverse(item: Self::Item<'_, '_>, event: &FocusedInput<E>) -> Option<Entity> {
|
||||||
let WindowTraversalItem { child_of, window } = item;
|
let WindowTraversalItem { child_of, window } = item;
|
||||||
|
|
||||||
// Send event to parent, if it has one.
|
// Send event to parent, if it has one.
|
||||||
|
|||||||
@ -346,6 +346,8 @@ web = [
|
|||||||
|
|
||||||
hotpatching = ["bevy_app/hotpatching", "bevy_ecs/hotpatching"]
|
hotpatching = ["bevy_app/hotpatching", "bevy_ecs/hotpatching"]
|
||||||
|
|
||||||
|
debug = ["bevy_utils/debug"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# bevy (no_std)
|
# bevy (no_std)
|
||||||
bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, features = [
|
bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, features = [
|
||||||
|
|||||||
@ -309,7 +309,7 @@ impl ExtractComponent for Atmosphere {
|
|||||||
|
|
||||||
type Out = Atmosphere;
|
type Out = Atmosphere;
|
||||||
|
|
||||||
fn extract_component(item: QueryItem<'_, Self::QueryData>) -> Option<Self::Out> {
|
fn extract_component(item: QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out> {
|
||||||
Some(item.clone())
|
Some(item.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -405,7 +405,7 @@ impl ExtractComponent for AtmosphereSettings {
|
|||||||
|
|
||||||
type Out = AtmosphereSettings;
|
type Out = AtmosphereSettings;
|
||||||
|
|
||||||
fn extract_component(item: QueryItem<'_, Self::QueryData>) -> Option<Self::Out> {
|
fn extract_component(item: QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out> {
|
||||||
Some(item.clone())
|
Some(item.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -181,7 +181,7 @@ impl ViewNode for RenderSkyNode {
|
|||||||
view_uniforms_offset,
|
view_uniforms_offset,
|
||||||
lights_uniforms_offset,
|
lights_uniforms_offset,
|
||||||
render_sky_pipeline_id,
|
render_sky_pipeline_id,
|
||||||
): QueryItem<'w, Self::ViewQuery>,
|
): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let pipeline_cache = world.resource::<PipelineCache>();
|
let pipeline_cache = world.resource::<PipelineCache>();
|
||||||
|
|||||||
@ -560,7 +560,7 @@ pub(super) fn prepare_atmosphere_transforms(
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (entity, view) in &views {
|
for (entity, view) in &views {
|
||||||
let world_from_view = view.world_from_view.compute_matrix();
|
let world_from_view = view.world_from_view.to_matrix();
|
||||||
let camera_z = world_from_view.z_axis.truncate();
|
let camera_z = world_from_view.z_axis.truncate();
|
||||||
let camera_y = world_from_view.y_axis.truncate();
|
let camera_y = world_from_view.y_axis.truncate();
|
||||||
let atmo_z = camera_z
|
let atmo_z = camera_z
|
||||||
|
|||||||
@ -353,7 +353,7 @@ pub(crate) fn assign_objects_to_clusters(
|
|||||||
|
|
||||||
let mut requested_cluster_dimensions = config.dimensions_for_screen_size(screen_size);
|
let mut requested_cluster_dimensions = config.dimensions_for_screen_size(screen_size);
|
||||||
|
|
||||||
let world_from_view = camera_transform.compute_matrix();
|
let world_from_view = camera_transform.to_matrix();
|
||||||
let view_from_world_scale = camera_transform.compute_transform().scale.recip();
|
let view_from_world_scale = camera_transform.compute_transform().scale.recip();
|
||||||
let view_from_world_scale_max = view_from_world_scale.abs().max_element();
|
let view_from_world_scale_max = view_from_world_scale.abs().max_element();
|
||||||
let view_from_world = world_from_view.inverse();
|
let view_from_world = world_from_view.inverse();
|
||||||
|
|||||||
@ -341,7 +341,7 @@ pub fn build_directional_light_cascades(
|
|||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(entity, transform, projection, camera)| {
|
.filter_map(|(entity, transform, projection, camera)| {
|
||||||
if camera.is_active {
|
if camera.is_active {
|
||||||
Some((entity, projection, transform.compute_matrix()))
|
Some((entity, projection, transform.to_matrix()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -357,7 +357,7 @@ pub fn build_directional_light_cascades(
|
|||||||
// light_to_world has orthogonal upper-left 3x3 and zero translation.
|
// light_to_world has orthogonal upper-left 3x3 and zero translation.
|
||||||
// Even though only the direction (i.e. rotation) of the light matters, we don't constrain
|
// Even though only the direction (i.e. rotation) of the light matters, we don't constrain
|
||||||
// users to not change any other aspects of the transform - there's no guarantee
|
// users to not change any other aspects of the transform - there's no guarantee
|
||||||
// `transform.compute_matrix()` will give us a matrix with our desired properties.
|
// `transform.to_matrix()` will give us a matrix with our desired properties.
|
||||||
// Instead, we directly create a good matrix from just the rotation.
|
// Instead, we directly create a good matrix from just the rotation.
|
||||||
let world_from_light = Mat4::from_quat(transform.compute_transform().rotation);
|
let world_from_light = Mat4::from_quat(transform.compute_transform().rotation);
|
||||||
let light_to_world_inverse = world_from_light.inverse();
|
let light_to_world_inverse = world_from_light.inverse();
|
||||||
@ -628,7 +628,7 @@ pub fn update_point_light_frusta(
|
|||||||
|
|
||||||
for (view_rotation, frustum) in view_rotations.iter().zip(cubemap_frusta.iter_mut()) {
|
for (view_rotation, frustum) in view_rotations.iter().zip(cubemap_frusta.iter_mut()) {
|
||||||
let world_from_view = view_translation * *view_rotation;
|
let world_from_view = view_translation * *view_rotation;
|
||||||
let clip_from_world = clip_from_view * world_from_view.compute_matrix().inverse();
|
let clip_from_world = clip_from_view * world_from_view.to_matrix().inverse();
|
||||||
|
|
||||||
*frustum = Frustum::from_clip_from_world_custom_far(
|
*frustum = Frustum::from_clip_from_world_custom_far(
|
||||||
&clip_from_world,
|
&clip_from_world,
|
||||||
|
|||||||
@ -192,7 +192,7 @@ impl ExtractInstance for EnvironmentMapIds {
|
|||||||
|
|
||||||
type QueryFilter = ();
|
type QueryFilter = ();
|
||||||
|
|
||||||
fn extract(item: QueryItem<'_, Self::QueryData>) -> Option<Self> {
|
fn extract(item: QueryItem<'_, '_, Self::QueryData>) -> Option<Self> {
|
||||||
Some(EnvironmentMapIds {
|
Some(EnvironmentMapIds {
|
||||||
diffuse: item.diffuse_map.id(),
|
diffuse: item.diffuse_map.id(),
|
||||||
specular: item.specular_map.id(),
|
specular: item.specular_map.id(),
|
||||||
|
|||||||
@ -378,7 +378,7 @@ fn gather_environment_map_uniform(
|
|||||||
let environment_map_uniform = if let Some(environment_map_light) = environment_map_light {
|
let environment_map_uniform = if let Some(environment_map_light) = environment_map_light {
|
||||||
EnvironmentMapUniform {
|
EnvironmentMapUniform {
|
||||||
transform: Transform::from_rotation(environment_map_light.rotation)
|
transform: Transform::from_rotation(environment_map_light.rotation)
|
||||||
.compute_matrix()
|
.to_matrix()
|
||||||
.inverse(),
|
.inverse(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -595,7 +595,7 @@ where
|
|||||||
) -> Option<LightProbeInfo<C>> {
|
) -> Option<LightProbeInfo<C>> {
|
||||||
environment_map.id(image_assets).map(|id| LightProbeInfo {
|
environment_map.id(image_assets).map(|id| LightProbeInfo {
|
||||||
world_from_light: light_probe_transform.affine(),
|
world_from_light: light_probe_transform.affine(),
|
||||||
light_from_world: light_probe_transform.compute_matrix().inverse(),
|
light_from_world: light_probe_transform.to_matrix().inverse(),
|
||||||
asset_id: id,
|
asset_id: id,
|
||||||
intensity: environment_map.intensity(),
|
intensity: environment_map.intensity(),
|
||||||
affects_lightmapped_mesh_diffuse: environment_map.affects_lightmapped_mesh_diffuse(),
|
affects_lightmapped_mesh_diffuse: environment_map.affects_lightmapped_mesh_diffuse(),
|
||||||
|
|||||||
@ -216,7 +216,7 @@ pub fn update_previous_view_data(
|
|||||||
query: Query<(Entity, &Camera, &GlobalTransform), Or<(With<Camera3d>, With<ShadowView>)>>,
|
query: Query<(Entity, &Camera, &GlobalTransform), Or<(With<Camera3d>, With<ShadowView>)>>,
|
||||||
) {
|
) {
|
||||||
for (entity, camera, camera_transform) in &query {
|
for (entity, camera, camera_transform) in &query {
|
||||||
let world_from_view = camera_transform.compute_matrix();
|
let world_from_view = camera_transform.to_matrix();
|
||||||
let view_from_world = world_from_view.inverse();
|
let view_from_world = world_from_view.inverse();
|
||||||
let view_from_clip = camera.clip_from_view().inverse();
|
let view_from_clip = camera.clip_from_view().inverse();
|
||||||
|
|
||||||
@ -703,7 +703,7 @@ pub fn prepare_previous_view_uniforms(
|
|||||||
let prev_view_data = match maybe_previous_view_uniforms {
|
let prev_view_data = match maybe_previous_view_uniforms {
|
||||||
Some(previous_view) => previous_view.clone(),
|
Some(previous_view) => previous_view.clone(),
|
||||||
None => {
|
None => {
|
||||||
let world_from_view = camera.world_from_view.compute_matrix();
|
let world_from_view = camera.world_from_view.to_matrix();
|
||||||
let view_from_world = world_from_view.inverse();
|
let view_from_world = world_from_view.inverse();
|
||||||
let view_from_clip = camera.clip_from_view.inverse();
|
let view_from_clip = camera.clip_from_view.inverse();
|
||||||
|
|
||||||
|
|||||||
@ -1540,7 +1540,7 @@ fn extract_mesh_for_gpu_building(
|
|||||||
not_shadow_caster,
|
not_shadow_caster,
|
||||||
no_automatic_batching,
|
no_automatic_batching,
|
||||||
visibility_range,
|
visibility_range,
|
||||||
): <GpuMeshExtractionQuery as QueryData>::Item<'_>,
|
): <GpuMeshExtractionQuery as QueryData>::Item<'_, '_>,
|
||||||
render_visibility_ranges: &RenderVisibilityRanges,
|
render_visibility_ranges: &RenderVisibilityRanges,
|
||||||
render_mesh_instances: &RenderMeshInstancesGpu,
|
render_mesh_instances: &RenderMeshInstancesGpu,
|
||||||
queue: &mut RenderMeshInstanceGpuQueue,
|
queue: &mut RenderMeshInstanceGpuQueue,
|
||||||
@ -2874,7 +2874,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I>
|
|||||||
view_environment_map,
|
view_environment_map,
|
||||||
mesh_view_bind_group,
|
mesh_view_bind_group,
|
||||||
maybe_oit_layers_count_offset,
|
maybe_oit_layers_count_offset,
|
||||||
): ROQueryItem<'w, Self::ViewQuery>,
|
): ROQueryItem<'w, '_, Self::ViewQuery>,
|
||||||
_entity: Option<()>,
|
_entity: Option<()>,
|
||||||
_: SystemParamItem<'w, '_, Self::Param>,
|
_: SystemParamItem<'w, '_, Self::Param>,
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
|
|||||||
@ -280,7 +280,7 @@ impl ViewNode for ScreenSpaceReflectionsNode {
|
|||||||
view_environment_map_offset,
|
view_environment_map_offset,
|
||||||
view_bind_group,
|
view_bind_group,
|
||||||
ssr_pipeline_id,
|
ssr_pipeline_id,
|
||||||
): QueryItem<'w, Self::ViewQuery>,
|
): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
// Grab the render pipeline.
|
// Grab the render pipeline.
|
||||||
@ -498,7 +498,7 @@ impl ExtractComponent for ScreenSpaceReflections {
|
|||||||
|
|
||||||
type Out = ScreenSpaceReflectionsUniform;
|
type Out = ScreenSpaceReflectionsUniform;
|
||||||
|
|
||||||
fn extract_component(settings: QueryItem<'_, Self::QueryData>) -> Option<Self::Out> {
|
fn extract_component(settings: QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out> {
|
||||||
if !DEPTH_TEXTURE_SAMPLING_SUPPORTED {
|
if !DEPTH_TEXTURE_SAMPLING_SUPPORTED {
|
||||||
once!(info!(
|
once!(info!(
|
||||||
"Disabling screen-space reflections on this platform because depth textures \
|
"Disabling screen-space reflections on this platform because depth textures \
|
||||||
|
|||||||
@ -347,7 +347,7 @@ impl ViewNode for VolumetricFogNode {
|
|||||||
view_ssr_offset,
|
view_ssr_offset,
|
||||||
msaa,
|
msaa,
|
||||||
view_environment_map_offset,
|
view_environment_map_offset,
|
||||||
): QueryItem<'w, Self::ViewQuery>,
|
): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let pipeline_cache = world.resource::<PipelineCache>();
|
let pipeline_cache = world.resource::<PipelineCache>();
|
||||||
@ -700,7 +700,7 @@ pub fn prepare_volumetric_fog_uniforms(
|
|||||||
// Do this up front to avoid O(n^2) matrix inversion.
|
// Do this up front to avoid O(n^2) matrix inversion.
|
||||||
local_from_world_matrices.clear();
|
local_from_world_matrices.clear();
|
||||||
for (_, _, fog_transform) in fog_volumes.iter() {
|
for (_, _, fog_transform) in fog_volumes.iter() {
|
||||||
local_from_world_matrices.push(fog_transform.compute_matrix().inverse());
|
local_from_world_matrices.push(fog_transform.to_matrix().inverse());
|
||||||
}
|
}
|
||||||
|
|
||||||
let uniform_count = view_targets.iter().len() * local_from_world_matrices.len();
|
let uniform_count = view_targets.iter().len() * local_from_world_matrices.len();
|
||||||
@ -712,7 +712,7 @@ pub fn prepare_volumetric_fog_uniforms(
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (view_entity, extracted_view, volumetric_fog) in view_targets.iter() {
|
for (view_entity, extracted_view, volumetric_fog) in view_targets.iter() {
|
||||||
let world_from_view = extracted_view.world_from_view.compute_matrix();
|
let world_from_view = extracted_view.world_from_view.to_matrix();
|
||||||
|
|
||||||
let mut view_fog_volumes = vec![];
|
let mut view_fog_volumes = vec![];
|
||||||
|
|
||||||
|
|||||||
@ -374,7 +374,7 @@ impl ViewNode for Wireframe3dNode {
|
|||||||
&self,
|
&self,
|
||||||
graph: &mut RenderGraphContext,
|
graph: &mut RenderGraphContext,
|
||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
(camera, view, target, depth): QueryItem<'w, Self::ViewQuery>,
|
(camera, view, target, depth): QueryItem<'w, '_, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let Some(wireframe_phase) = world.get_resource::<ViewBinnedRenderPhases<Wireframe3d>>()
|
let Some(wireframe_phase) = world.get_resource::<ViewBinnedRenderPhases<Wireframe3d>>()
|
||||||
|
|||||||
@ -86,7 +86,7 @@ impl<E> Traversal<Pointer<E>> for PointerTraversal
|
|||||||
where
|
where
|
||||||
E: Debug + Clone + Reflect,
|
E: Debug + Clone + Reflect,
|
||||||
{
|
{
|
||||||
fn traverse(item: Self::Item<'_>, pointer: &Pointer<E>) -> Option<Entity> {
|
fn traverse(item: Self::Item<'_, '_>, pointer: &Pointer<E>) -> Option<Entity> {
|
||||||
let PointerTraversalItem { child_of, window } = item;
|
let PointerTraversalItem { child_of, window } = item;
|
||||||
|
|
||||||
// Send event to parent, if it has one.
|
// Send event to parent, if it has one.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user