diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d2410b57d2..28a3c16a5b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -15,7 +15,7 @@ env:
# If nightly is breaking CI, modify this variable to target a specific nightly version.
NIGHTLY_TOOLCHAIN: nightly
RUSTFLAGS: "-D warnings"
- BINSTALL_VERSION: "v1.12.3"
+ BINSTALL_VERSION: "v1.12.5"
concurrency:
group: ${{github.workflow}}-${{github.ref}}
@@ -95,7 +95,7 @@ jobs:
- name: CI job
# 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
- run: cargo miri test -p bevy_ecs
+ run: cargo miri test -p bevy_ecs --features bevy_utils/debug
env:
# -Zrandomize-layout makes sure we dont rely on the layout of anything that might change
RUSTFLAGS: -Zrandomize-layout
@@ -247,7 +247,7 @@ jobs:
- name: Check wasm
run: cargo check --target wasm32-unknown-unknown -Z build-std=std,panic_abort
env:
- RUSTFLAGS: "-C target-feature=+atomics,+bulk-memory -D warnings"
+ RUSTFLAGS: "-C target-feature=+atomics,+bulk-memory"
markdownlint:
runs-on: ubuntu-latest
@@ -272,7 +272,7 @@ jobs:
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- - uses: cargo-bins/cargo-binstall@v1.12.3
+ - uses: cargo-bins/cargo-binstall@v1.12.5
- name: Install taplo
run: cargo binstall taplo-cli@0.9.3 --locked
- name: Run Taplo
diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml
index 91a98f3ea7..485861ebdf 100644
--- a/.github/workflows/post-release.yml
+++ b/.github/workflows/post-release.yml
@@ -49,7 +49,8 @@ jobs:
--exclude ci \
--exclude errors \
--exclude bevy_mobile_example \
- --exclude build-wasm-example
+ --exclude build-wasm-example \
+ --exclude no_std_library
- name: Create PR
uses: peter-evans/create-pull-request@v7
diff --git a/Cargo.toml b/Cargo.toml
index 703877983c..87904d32fd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
categories = ["game-engines", "graphics", "gui", "rendering"]
description = "A refreshingly simple data-driven game engine and app framework"
@@ -72,7 +72,6 @@ allow_attributes_without_reason = "warn"
[workspace.lints.rust]
missing_docs = "warn"
-mismatched_lifetime_syntaxes = "allow"
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(docsrs_dep)'] }
unsafe_code = "deny"
unsafe_op_in_unsafe_fn = "warn"
@@ -134,6 +133,7 @@ default = [
"bevy_audio",
"bevy_color",
"bevy_core_pipeline",
+ "bevy_core_widgets",
"bevy_anti_aliasing",
"bevy_gilrs",
"bevy_gizmos",
@@ -164,6 +164,7 @@ default = [
"vorbis",
"webgl2",
"x11",
+ "debug",
]
# Recommended defaults for no_std applications
@@ -246,6 +247,15 @@ bevy_render = ["bevy_internal/bevy_render", "bevy_color"]
# Provides scene functionality
bevy_scene = ["bevy_internal/bevy_scene", "bevy_asset"]
+# Provides raytraced lighting (experimental)
+bevy_solari = [
+ "bevy_internal/bevy_solari",
+ "bevy_asset",
+ "bevy_core_pipeline",
+ "bevy_pbr",
+ "bevy_render",
+]
+
# Provides sprite functionality
bevy_sprite = [
"bevy_internal/bevy_sprite",
@@ -292,6 +302,9 @@ bevy_log = ["bevy_internal/bevy_log"]
# Enable input focus subsystem
bevy_input_focus = ["bevy_internal/bevy_input_focus"]
+# Headless widget collection for Bevy UI.
+bevy_core_widgets = ["bevy_internal/bevy_core_widgets"]
+
# Enable passthrough loading for SPIR-V shaders (Only supported on Vulkan, shader capabilities and extensions must agree with the platform implementation)
spirv_shader_passthrough = ["bevy_internal/spirv_shader_passthrough"]
@@ -317,6 +330,9 @@ trace = ["bevy_internal/trace", "dep:tracing"]
# Basis Universal compressed texture support
basis-universal = ["bevy_internal/basis-universal"]
+# Enables compressed KTX2 UASTC texture output on the asset processor
+compressed_image_saver = ["bevy_internal/compressed_image_saver"]
+
# BMP image format support
bmp = ["bevy_internal/bmp"]
@@ -494,7 +510,10 @@ file_watcher = ["bevy_internal/file_watcher"]
embedded_watcher = ["bevy_internal/embedded_watcher"]
# 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)
meshlet = ["bevy_internal/meshlet"]
@@ -538,30 +557,33 @@ web = ["bevy_internal/web"]
# Enable hotpatching of Bevy systems
hotpatching = ["bevy_internal/hotpatching"]
+# Enable collecting debug information about systems and components to help with diagnostics
+debug = ["bevy_internal/debug"]
+
[dependencies]
-bevy_internal = { path = "crates/bevy_internal", version = "0.16.0-dev", default-features = false }
+bevy_internal = { path = "crates/bevy_internal", version = "0.17.0-dev", default-features = false }
tracing = { version = "0.1", default-features = false, optional = true }
# Wasm does not support dynamic linking.
[target.'cfg(not(target_family = "wasm"))'.dependencies]
-bevy_dylib = { path = "crates/bevy_dylib", version = "0.16.0-dev", default-features = false, optional = true }
+bevy_dylib = { path = "crates/bevy_dylib", version = "0.17.0-dev", default-features = false, optional = true }
[dev-dependencies]
rand = "0.8.0"
rand_chacha = "0.3.1"
-ron = "0.8.0"
+ron = "0.10"
flate2 = "1.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1.0.140"
bytemuck = "1.7"
-bevy_render = { path = "crates/bevy_render", version = "0.16.0-dev", default-features = false }
+bevy_render = { path = "crates/bevy_render", version = "0.17.0-dev", default-features = false }
# The following explicit dependencies are needed for proc macros to work inside of examples as they are part of the bevy crate itself.
-bevy_ecs = { path = "crates/bevy_ecs", version = "0.16.0-dev", default-features = false }
-bevy_state = { path = "crates/bevy_state", version = "0.16.0-dev", default-features = false }
-bevy_asset = { path = "crates/bevy_asset", version = "0.16.0-dev", default-features = false }
-bevy_reflect = { path = "crates/bevy_reflect", version = "0.16.0-dev", default-features = false }
-bevy_image = { path = "crates/bevy_image", version = "0.16.0-dev", default-features = false }
-bevy_gizmos = { path = "crates/bevy_gizmos", version = "0.16.0-dev", default-features = false }
+bevy_ecs = { path = "crates/bevy_ecs", version = "0.17.0-dev", default-features = false }
+bevy_state = { path = "crates/bevy_state", version = "0.17.0-dev", default-features = false }
+bevy_asset = { path = "crates/bevy_asset", version = "0.17.0-dev", default-features = false }
+bevy_reflect = { path = "crates/bevy_reflect", version = "0.17.0-dev", default-features = false }
+bevy_image = { path = "crates/bevy_image", version = "0.17.0-dev", default-features = false }
+bevy_gizmos = { path = "crates/bevy_gizmos", version = "0.17.0-dev", default-features = false }
# Needed to poll Task examples
futures-lite = "2.0.1"
async-std = "1.13"
@@ -588,7 +610,7 @@ web-sys = { version = "0.3", features = ["Window"] }
[[example]]
name = "context_menu"
-path = "examples/usages/context_menu.rs"
+path = "examples/usage/context_menu.rs"
doc-scrape-examples = true
[package.metadata.example.context_menu]
@@ -826,6 +848,17 @@ description = "Generates a texture atlas (sprite sheet) from individual sprites"
category = "2D Rendering"
wasm = false
+[[example]]
+name = "tilemap_chunk"
+path = "examples/2d/tilemap_chunk.rs"
+doc-scrape-examples = true
+
+[package.metadata.example.tilemap_chunk]
+name = "Tilemap Chunk"
+description = "Renders a tilemap chunk"
+category = "2D Rendering"
+wasm = true
+
[[example]]
name = "transparency_2d"
path = "examples/2d/transparency_2d.rs"
@@ -1257,6 +1290,18 @@ description = "Load a cubemap texture onto a cube like a skybox and cycle throug
category = "3D Rendering"
wasm = false
+[[example]]
+name = "solari"
+path = "examples/3d/solari.rs"
+doc-scrape-examples = true
+required-features = ["bevy_solari"]
+
+[package.metadata.example.solari]
+name = "Solari"
+description = "Demonstrates realtime dynamic raytraced lighting using Bevy Solari."
+category = "3D Rendering"
+wasm = false # Raytracing is not supported on the web
+
[[example]]
name = "spherical_area_lights"
path = "examples/3d/spherical_area_lights.rs"
@@ -2073,6 +2118,7 @@ wasm = false
name = "dynamic"
path = "examples/ecs/dynamic.rs"
doc-scrape-examples = true
+required-features = ["debug"]
[package.metadata.example.dynamic]
name = "Dynamic ECS"
@@ -4438,3 +4484,25 @@ name = "Hotpatching Systems"
description = "Demonstrates how to hotpatch systems"
category = "ECS (Entity Component System)"
wasm = false
+
+[[example]]
+name = "core_widgets"
+path = "examples/ui/core_widgets.rs"
+doc-scrape-examples = true
+
+[package.metadata.example.core_widgets]
+name = "Core Widgets"
+description = "Demonstrates use of core (headless) widgets in Bevy UI"
+category = "UI (User Interface)"
+wasm = true
+
+[[example]]
+name = "core_widgets_observers"
+path = "examples/ui/core_widgets_observers.rs"
+doc-scrape-examples = true
+
+[package.metadata.example.core_widgets_observers]
+name = "Core Widgets (w/Observers)"
+description = "Demonstrates use of core (headless) widgets in Bevy UI, with Observers"
+category = "UI (User Interface)"
+wasm = true
diff --git a/assets/branding/bevy_solari.svg b/assets/branding/bevy_solari.svg
new file mode 100644
index 0000000000..65b996493f
--- /dev/null
+++ b/assets/branding/bevy_solari.svg
@@ -0,0 +1,113 @@
+
+
diff --git a/assets/shaders/array_texture.wgsl b/assets/shaders/array_texture.wgsl
index d49d492a06..293f331665 100644
--- a/assets/shaders/array_texture.wgsl
+++ b/assets/shaders/array_texture.wgsl
@@ -7,8 +7,8 @@
}
#import bevy_core_pipeline::tonemapping::tone_mapping
-@group(2) @binding(0) var my_array_texture: texture_2d_array;
-@group(2) @binding(1) var my_array_texture_sampler: sampler;
+@group(3) @binding(0) var my_array_texture: texture_2d_array;
+@group(3) @binding(1) var my_array_texture_sampler: sampler;
@fragment
fn fragment(
diff --git a/assets/shaders/automatic_instancing.wgsl b/assets/shaders/automatic_instancing.wgsl
index 35276246b0..ca2195df0d 100644
--- a/assets/shaders/automatic_instancing.wgsl
+++ b/assets/shaders/automatic_instancing.wgsl
@@ -3,8 +3,8 @@
view_transformations::position_world_to_clip
}
-@group(2) @binding(0) var texture: texture_2d;
-@group(2) @binding(1) var texture_sampler: sampler;
+@group(3) @binding(0) var texture: texture_2d;
+@group(3) @binding(1) var texture_sampler: sampler;
struct Vertex {
@builtin(instance_index) instance_index: u32,
diff --git a/assets/shaders/bindless_material.wgsl b/assets/shaders/bindless_material.wgsl
index 3de313b81a..f7fa795d94 100644
--- a/assets/shaders/bindless_material.wgsl
+++ b/assets/shaders/bindless_material.wgsl
@@ -15,12 +15,12 @@ struct MaterialBindings {
}
#ifdef BINDLESS
-@group(2) @binding(0) var materials: array;
-@group(2) @binding(10) var material_color: binding_array;
+@group(3) @binding(0) var materials: array;
+@group(3) @binding(10) var material_color: binding_array;
#else // BINDLESS
-@group(2) @binding(0) var material_color: Color;
-@group(2) @binding(1) var material_color_texture: texture_2d;
-@group(2) @binding(2) var material_color_sampler: sampler;
+@group(3) @binding(0) var material_color: Color;
+@group(3) @binding(1) var material_color_texture: texture_2d;
+@group(3) @binding(2) var material_color_sampler: sampler;
#endif // BINDLESS
@fragment
diff --git a/assets/shaders/cubemap_unlit.wgsl b/assets/shaders/cubemap_unlit.wgsl
index 14e45a045b..81e153e408 100644
--- a/assets/shaders/cubemap_unlit.wgsl
+++ b/assets/shaders/cubemap_unlit.wgsl
@@ -1,12 +1,12 @@
#import bevy_pbr::forward_io::VertexOutput
#ifdef CUBEMAP_ARRAY
-@group(2) @binding(0) var base_color_texture: texture_cube_array;
+@group(3) @binding(0) var base_color_texture: texture_cube_array;
#else
-@group(2) @binding(0) var base_color_texture: texture_cube;
+@group(3) @binding(0) var base_color_texture: texture_cube;
#endif
-@group(2) @binding(1) var base_color_sampler: sampler;
+@group(3) @binding(1) var base_color_sampler: sampler;
@fragment
fn fragment(
diff --git a/assets/shaders/custom_material.frag b/assets/shaders/custom_material.frag
index a6bc9af0d2..0617a08ae7 100644
--- a/assets/shaders/custom_material.frag
+++ b/assets/shaders/custom_material.frag
@@ -3,10 +3,10 @@ layout(location = 0) in vec2 v_Uv;
layout(location = 0) out vec4 o_Target;
-layout(set = 2, binding = 0) uniform vec4 CustomMaterial_color;
+layout(set = 3, binding = 0) uniform vec4 CustomMaterial_color;
-layout(set = 2, binding = 1) uniform texture2D CustomMaterial_texture;
-layout(set = 2, binding = 2) uniform sampler CustomMaterial_sampler;
+layout(set = 3, binding = 1) uniform texture2D CustomMaterial_texture;
+layout(set = 3, binding = 2) uniform sampler CustomMaterial_sampler;
// wgsl modules can be imported and used in glsl
// FIXME - this doesn't work any more ...
diff --git a/assets/shaders/custom_material.vert b/assets/shaders/custom_material.vert
index 86ca3629e2..f9a2813a37 100644
--- a/assets/shaders/custom_material.vert
+++ b/assets/shaders/custom_material.vert
@@ -25,9 +25,9 @@ struct Mesh {
};
#ifdef PER_OBJECT_BUFFER_BATCH_SIZE
-layout(set = 1, binding = 0) uniform Mesh Meshes[#{PER_OBJECT_BUFFER_BATCH_SIZE}];
+layout(set = 2, binding = 0) uniform Mesh Meshes[#{PER_OBJECT_BUFFER_BATCH_SIZE}];
#else
-layout(set = 1, binding = 0) readonly buffer _Meshes {
+layout(set = 2, binding = 0) readonly buffer _Meshes {
Mesh Meshes[];
};
#endif // PER_OBJECT_BUFFER_BATCH_SIZE
diff --git a/assets/shaders/custom_material.wesl b/assets/shaders/custom_material.wesl
index 5113e1cbe0..ca94668784 100644
--- a/assets/shaders/custom_material.wesl
+++ b/assets/shaders/custom_material.wesl
@@ -10,7 +10,7 @@ struct CustomMaterial {
time: vec4,
}
-@group(2) @binding(0) var material: CustomMaterial;
+@group(3) @binding(0) var material: CustomMaterial;
@fragment
fn fragment(
diff --git a/assets/shaders/custom_material.wgsl b/assets/shaders/custom_material.wgsl
index 1b65627d45..7548d2223c 100644
--- a/assets/shaders/custom_material.wgsl
+++ b/assets/shaders/custom_material.wgsl
@@ -2,9 +2,9 @@
// we can import items from shader modules in the assets folder with a quoted path
#import "shaders/custom_material_import.wgsl"::COLOR_MULTIPLIER
-@group(2) @binding(0) var material_color: vec4;
-@group(2) @binding(1) var material_color_texture: texture_2d;
-@group(2) @binding(2) var material_color_sampler: sampler;
+@group(3) @binding(0) var material_color: vec4;
+@group(3) @binding(1) var material_color_texture: texture_2d;
+@group(3) @binding(2) var material_color_sampler: sampler;
@fragment
fn fragment(
diff --git a/assets/shaders/custom_material_screenspace_texture.wgsl b/assets/shaders/custom_material_screenspace_texture.wgsl
index 36da2a7f8c..abad3cc15a 100644
--- a/assets/shaders/custom_material_screenspace_texture.wgsl
+++ b/assets/shaders/custom_material_screenspace_texture.wgsl
@@ -4,8 +4,8 @@
utils::coords_to_viewport_uv,
}
-@group(2) @binding(0) var texture: texture_2d;
-@group(2) @binding(1) var texture_sampler: sampler;
+@group(3) @binding(0) var texture: texture_2d;
+@group(3) @binding(1) var texture_sampler: sampler;
@fragment
fn fragment(
diff --git a/assets/shaders/custom_vertex_attribute.wgsl b/assets/shaders/custom_vertex_attribute.wgsl
index f8062ab77b..6b7b93e4c7 100644
--- a/assets/shaders/custom_vertex_attribute.wgsl
+++ b/assets/shaders/custom_vertex_attribute.wgsl
@@ -3,7 +3,7 @@
struct CustomMaterial {
color: vec4,
};
-@group(2) @binding(0) var material: CustomMaterial;
+@group(3) @binding(0) var material: CustomMaterial;
struct Vertex {
@builtin(instance_index) instance_index: u32,
diff --git a/assets/shaders/extended_material.wgsl b/assets/shaders/extended_material.wgsl
index fc69f30bb5..7bad24a331 100644
--- a/assets/shaders/extended_material.wgsl
+++ b/assets/shaders/extended_material.wgsl
@@ -19,7 +19,7 @@ struct MyExtendedMaterial {
quantize_steps: u32,
}
-@group(2) @binding(100)
+@group(3) @binding(100)
var my_extended_material: MyExtendedMaterial;
@fragment
diff --git a/assets/shaders/extended_material_bindless.wgsl b/assets/shaders/extended_material_bindless.wgsl
index f8650b0da7..c9cb07e0c7 100644
--- a/assets/shaders/extended_material_bindless.wgsl
+++ b/assets/shaders/extended_material_bindless.wgsl
@@ -42,19 +42,19 @@ struct ExampleBindlessExtendedMaterial {
// The indices of the bindless resources in the bindless resource arrays, for
// the `ExampleBindlessExtension` fields.
-@group(2) @binding(100) var example_extended_material_indices:
+@group(3) @binding(100) var example_extended_material_indices:
array;
// An array that holds the `ExampleBindlessExtendedMaterial` plain old data,
// indexed by `ExampleBindlessExtendedMaterialIndices.material`.
-@group(2) @binding(101) var example_extended_material:
+@group(3) @binding(101) var example_extended_material:
array;
#else // BINDLESS
// In non-bindless mode, we simply use a uniform for the plain old data.
-@group(2) @binding(50) var example_extended_material: ExampleBindlessExtendedMaterial;
-@group(2) @binding(51) var modulate_texture: texture_2d;
-@group(2) @binding(52) var modulate_sampler: sampler;
+@group(3) @binding(50) var example_extended_material: ExampleBindlessExtendedMaterial;
+@group(3) @binding(51) var modulate_texture: texture_2d;
+@group(3) @binding(52) var modulate_sampler: sampler;
#endif // BINDLESS
diff --git a/assets/shaders/fallback_image_test.wgsl b/assets/shaders/fallback_image_test.wgsl
index c48f091bcc..c92cbd1577 100644
--- a/assets/shaders/fallback_image_test.wgsl
+++ b/assets/shaders/fallback_image_test.wgsl
@@ -1,22 +1,22 @@
#import bevy_pbr::forward_io::VertexOutput
-@group(2) @binding(0) var test_texture_1d: texture_1d;
-@group(2) @binding(1) var test_texture_1d_sampler: sampler;
+@group(3) @binding(0) var test_texture_1d: texture_1d;
+@group(3) @binding(1) var test_texture_1d_sampler: sampler;
-@group(2) @binding(2) var test_texture_2d: texture_2d;
-@group(2) @binding(3) var test_texture_2d_sampler: sampler;
+@group(3) @binding(2) var test_texture_2d: texture_2d;
+@group(3) @binding(3) var test_texture_2d_sampler: sampler;
-@group(2) @binding(4) var test_texture_2d_array: texture_2d_array;
-@group(2) @binding(5) var test_texture_2d_array_sampler: sampler;
+@group(3) @binding(4) var test_texture_2d_array: texture_2d_array;
+@group(3) @binding(5) var test_texture_2d_array_sampler: sampler;
-@group(2) @binding(6) var test_texture_cube: texture_cube;
-@group(2) @binding(7) var test_texture_cube_sampler: sampler;
+@group(3) @binding(6) var test_texture_cube: texture_cube;
+@group(3) @binding(7) var test_texture_cube_sampler: sampler;
-@group(2) @binding(8) var test_texture_cube_array: texture_cube_array;
-@group(2) @binding(9) var test_texture_cube_array_sampler: sampler;
+@group(3) @binding(8) var test_texture_cube_array: texture_cube_array;
+@group(3) @binding(9) var test_texture_cube_array_sampler: sampler;
-@group(2) @binding(10) var test_texture_3d: texture_3d;
-@group(2) @binding(11) var test_texture_3d_sampler: sampler;
+@group(3) @binding(10) var test_texture_3d: texture_3d;
+@group(3) @binding(11) var test_texture_3d_sampler: sampler;
@fragment
fn fragment(in: VertexOutput) {}
diff --git a/assets/shaders/irradiance_volume_voxel_visualization.wgsl b/assets/shaders/irradiance_volume_voxel_visualization.wgsl
index f34e6f8453..0e12110f3b 100644
--- a/assets/shaders/irradiance_volume_voxel_visualization.wgsl
+++ b/assets/shaders/irradiance_volume_voxel_visualization.wgsl
@@ -12,7 +12,7 @@ struct VoxelVisualizationIrradianceVolumeInfo {
intensity: f32,
}
-@group(2) @binding(100)
+@group(3) @binding(100)
var irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo;
@fragment
diff --git a/assets/shaders/line_material.wgsl b/assets/shaders/line_material.wgsl
index cc7ca047d5..639762a444 100644
--- a/assets/shaders/line_material.wgsl
+++ b/assets/shaders/line_material.wgsl
@@ -4,7 +4,7 @@ struct LineMaterial {
color: vec4,
};
-@group(2) @binding(0) var material: LineMaterial;
+@group(3) @binding(0) var material: LineMaterial;
@fragment
fn fragment(
diff --git a/assets/shaders/shader_defs.wgsl b/assets/shaders/shader_defs.wgsl
index fdddc4caa1..776fc9ffe6 100644
--- a/assets/shaders/shader_defs.wgsl
+++ b/assets/shaders/shader_defs.wgsl
@@ -4,7 +4,7 @@ struct CustomMaterial {
color: vec4,
};
-@group(2) @binding(0) var material: CustomMaterial;
+@group(3) @binding(0) var material: CustomMaterial;
@fragment
fn fragment(
diff --git a/assets/shaders/show_prepass.wgsl b/assets/shaders/show_prepass.wgsl
index c1b3a89750..b1a53677ac 100644
--- a/assets/shaders/show_prepass.wgsl
+++ b/assets/shaders/show_prepass.wgsl
@@ -11,7 +11,7 @@ struct ShowPrepassSettings {
padding_1: u32,
padding_2: u32,
}
-@group(2) @binding(0) var settings: ShowPrepassSettings;
+@group(3) @binding(0) var settings: ShowPrepassSettings;
@fragment
fn fragment(
diff --git a/assets/shaders/storage_buffer.wgsl b/assets/shaders/storage_buffer.wgsl
index c27053b9a2..f447333cc9 100644
--- a/assets/shaders/storage_buffer.wgsl
+++ b/assets/shaders/storage_buffer.wgsl
@@ -3,7 +3,7 @@
view_transformations::position_world_to_clip
}
-@group(2) @binding(0) var colors: array, 5>;
+@group(3) @binding(0) var colors: array, 5>;
struct Vertex {
@builtin(instance_index) instance_index: u32,
diff --git a/assets/shaders/texture_binding_array.wgsl b/assets/shaders/texture_binding_array.wgsl
index de7a4e1b96..17b94a74d3 100644
--- a/assets/shaders/texture_binding_array.wgsl
+++ b/assets/shaders/texture_binding_array.wgsl
@@ -1,7 +1,7 @@
#import bevy_pbr::forward_io::VertexOutput
-@group(2) @binding(0) var textures: binding_array>;
-@group(2) @binding(1) var nearest_sampler: sampler;
+@group(3) @binding(0) var textures: binding_array>;
+@group(3) @binding(1) var nearest_sampler: sampler;
// We can also have array of samplers
// var samplers: binding_array;
diff --git a/assets/shaders/water_material.wgsl b/assets/shaders/water_material.wgsl
index 31d04b5f11..a8a9e03df4 100644
--- a/assets/shaders/water_material.wgsl
+++ b/assets/shaders/water_material.wgsl
@@ -23,9 +23,9 @@ struct WaterSettings {
@group(0) @binding(1) var globals: Globals;
-@group(2) @binding(100) var water_normals_texture: texture_2d;
-@group(2) @binding(101) var water_normals_sampler: sampler;
-@group(2) @binding(102) var water_settings: WaterSettings;
+@group(3) @binding(100) var water_normals_texture: texture_2d;
+@group(3) @binding(101) var water_normals_sampler: sampler;
+@group(3) @binding(102) var water_settings: WaterSettings;
// Samples a single octave of noise and returns the resulting normal.
fn sample_noise_octave(uv: vec2, strength: f32) -> vec3 {
diff --git a/benches/benches/bevy_ecs/change_detection.rs b/benches/benches/bevy_ecs/change_detection.rs
index 92f3251abc..3cfa5bcbed 100644
--- a/benches/benches/bevy_ecs/change_detection.rs
+++ b/benches/benches/bevy_ecs/change_detection.rs
@@ -49,6 +49,7 @@ impl BenchModify for Table {
black_box(self.0)
}
}
+
impl BenchModify for Sparse {
fn bench_modify(&mut self) -> f32 {
self.0 += 1f32;
diff --git a/benches/benches/bevy_ecs/entity_cloning.rs b/benches/benches/bevy_ecs/entity_cloning.rs
index 0eaae27ce4..44ffa1d52b 100644
--- a/benches/benches/bevy_ecs/entity_cloning.rs
+++ b/benches/benches/bevy_ecs/entity_cloning.rs
@@ -1,7 +1,7 @@
use core::hint::black_box;
use benches::bench;
-use bevy_ecs::bundle::Bundle;
+use bevy_ecs::bundle::{Bundle, InsertMode};
use bevy_ecs::component::ComponentCloneBehavior;
use bevy_ecs::entity::EntityCloner;
use bevy_ecs::hierarchy::ChildOf;
@@ -17,41 +17,15 @@ criterion_group!(
hierarchy_tall,
hierarchy_wide,
hierarchy_many,
+ filter
);
#[derive(Component, Reflect, Default, Clone)]
-struct C1(Mat4);
+struct C(Mat4);
-#[derive(Component, Reflect, Default, Clone)]
-struct C2(Mat4);
+type ComplexBundle = (C<1>, C<2>, C<3>, C<4>, C<5>, C<6>, C<7>, C<8>, C<9>, C<10>);
-#[derive(Component, Reflect, Default, Clone)]
-struct C3(Mat4);
-
-#[derive(Component, Reflect, Default, Clone)]
-struct C4(Mat4);
-
-#[derive(Component, Reflect, Default, Clone)]
-struct C5(Mat4);
-
-#[derive(Component, Reflect, Default, Clone)]
-struct C6(Mat4);
-
-#[derive(Component, Reflect, Default, Clone)]
-struct C7(Mat4);
-
-#[derive(Component, Reflect, Default, Clone)]
-struct C8(Mat4);
-
-#[derive(Component, Reflect, Default, Clone)]
-struct C9(Mat4);
-
-#[derive(Component, Reflect, Default, Clone)]
-struct C10(Mat4);
-
-type ComplexBundle = (C1, C2, C3, C4, C5, C6, C7, C8, C9, C10);
-
-/// Sets the [`ComponentCloneHandler`] for all explicit and required components in a bundle `B` to
+/// Sets the [`ComponentCloneBehavior`] for all explicit and required components in a bundle `B` to
/// use the [`Reflect`] trait instead of [`Clone`].
fn reflection_cloner(
world: &mut World,
@@ -71,7 +45,7 @@ fn reflection_cloner(
// this bundle are saved.
let component_ids: Vec<_> = world.register_bundle::().contributed_components().into();
- let mut builder = EntityCloner::build(world);
+ let mut builder = EntityCloner::build_opt_out(world);
// Overwrite the clone handler for all components in the bundle to use `Reflect`, not `Clone`.
for component in component_ids {
@@ -82,16 +56,15 @@ fn reflection_cloner(
builder.finish()
}
-/// A helper function that benchmarks running the [`EntityCommands::clone_and_spawn()`] command on a
-/// bundle `B`.
+/// A helper function that benchmarks running [`EntityCloner::spawn_clone`] with a bundle `B`.
///
/// The bundle must implement [`Default`], which is used to create the first entity that gets cloned
/// in the benchmark.
///
-/// If `clone_via_reflect` is false, this will use the default [`ComponentCloneHandler`] for all
-/// components (which is usually [`ComponentCloneHandler::clone_handler()`]). If `clone_via_reflect`
+/// If `clone_via_reflect` is false, this will use the default [`ComponentCloneBehavior`] for all
+/// components (which is usually [`ComponentCloneBehavior::clone()`]). If `clone_via_reflect`
/// is true, it will overwrite the handler for all components in the bundle to be
-/// [`ComponentCloneHandler::reflect_handler()`].
+/// [`ComponentCloneBehavior::reflect()`].
fn bench_clone(
b: &mut Bencher,
clone_via_reflect: bool,
@@ -114,8 +87,7 @@ fn bench_clone(
});
}
-/// A helper function that benchmarks running the [`EntityCommands::clone_and_spawn()`] command on a
-/// bundle `B`.
+/// A helper function that benchmarks running [`EntityCloner::spawn_clone`] with a bundle `B`.
///
/// As compared to [`bench_clone()`], this benchmarks recursively cloning an entity with several
/// children. It does so by setting up an entity tree with a given `height` where each entity has a
@@ -135,7 +107,7 @@ fn bench_clone_hierarchy(
let mut cloner = if clone_via_reflect {
reflection_cloner::(&mut world, true)
} else {
- let mut builder = EntityCloner::build(&mut world);
+ let mut builder = EntityCloner::build_opt_out(&mut world);
builder.linked_cloning(true);
builder.finish()
};
@@ -169,7 +141,7 @@ fn bench_clone_hierarchy(
// Each benchmark runs twice: using either the `Clone` or `Reflect` traits to clone entities. This
// constant represents this as an easy array that can be used in a `for` loop.
-const SCENARIOS: [(&str, bool); 2] = [("clone", false), ("reflect", true)];
+const CLONE_SCENARIOS: [(&str, bool); 2] = [("clone", false), ("reflect", true)];
/// Benchmarks cloning a single entity with 10 components and no children.
fn single(c: &mut Criterion) {
@@ -178,7 +150,7 @@ fn single(c: &mut Criterion) {
// We're cloning 1 entity.
group.throughput(Throughput::Elements(1));
- for (id, clone_via_reflect) in SCENARIOS {
+ for (id, clone_via_reflect) in CLONE_SCENARIOS {
group.bench_function(id, |b| {
bench_clone::(b, clone_via_reflect);
});
@@ -194,9 +166,9 @@ fn hierarchy_tall(c: &mut Criterion) {
// We're cloning both the root entity and its 50 descendents.
group.throughput(Throughput::Elements(51));
- for (id, clone_via_reflect) in SCENARIOS {
+ for (id, clone_via_reflect) in CLONE_SCENARIOS {
group.bench_function(id, |b| {
- bench_clone_hierarchy::(b, 50, 1, clone_via_reflect);
+ bench_clone_hierarchy::>(b, 50, 1, clone_via_reflect);
});
}
@@ -210,9 +182,9 @@ fn hierarchy_wide(c: &mut Criterion) {
// We're cloning both the root entity and its 50 direct children.
group.throughput(Throughput::Elements(51));
- for (id, clone_via_reflect) in SCENARIOS {
+ for (id, clone_via_reflect) in CLONE_SCENARIOS {
group.bench_function(id, |b| {
- bench_clone_hierarchy::(b, 1, 50, clone_via_reflect);
+ bench_clone_hierarchy::>(b, 1, 50, clone_via_reflect);
});
}
@@ -228,7 +200,7 @@ fn hierarchy_many(c: &mut Criterion) {
// of entities spawned in `bench_clone_hierarchy()` with a `println!()` statement. :)
group.throughput(Throughput::Elements(364));
- for (id, clone_via_reflect) in SCENARIOS {
+ for (id, clone_via_reflect) in CLONE_SCENARIOS {
group.bench_function(id, |b| {
bench_clone_hierarchy::(b, 5, 3, clone_via_reflect);
});
@@ -236,3 +208,157 @@ fn hierarchy_many(c: &mut Criterion) {
group.finish();
}
+
+/// Filter scenario variant for bot opt-in and opt-out filters
+#[derive(Clone, Copy)]
+#[expect(
+ clippy::enum_variant_names,
+ reason = "'Opt' is not understood as an prefix but `OptOut'/'OptIn' are"
+)]
+enum FilterScenario {
+ OptOutNone,
+ OptOutNoneKeep(bool),
+ OptOutAll,
+ OptInNone,
+ OptInAll,
+ OptInAllWithoutRequired,
+ OptInAllKeep(bool),
+ OptInAllKeepWithoutRequired(bool),
+}
+
+impl From for String {
+ fn from(value: FilterScenario) -> Self {
+ match value {
+ FilterScenario::OptOutNone => "opt_out_none",
+ FilterScenario::OptOutNoneKeep(true) => "opt_out_none_keep_none",
+ FilterScenario::OptOutNoneKeep(false) => "opt_out_none_keep_all",
+ FilterScenario::OptOutAll => "opt_out_all",
+ FilterScenario::OptInNone => "opt_in_none",
+ FilterScenario::OptInAll => "opt_in_all",
+ FilterScenario::OptInAllWithoutRequired => "opt_in_all_without_required",
+ FilterScenario::OptInAllKeep(true) => "opt_in_all_keep_none",
+ FilterScenario::OptInAllKeep(false) => "opt_in_all_keep_all",
+ FilterScenario::OptInAllKeepWithoutRequired(true) => {
+ "opt_in_all_keep_none_without_required"
+ }
+ FilterScenario::OptInAllKeepWithoutRequired(false) => {
+ "opt_in_all_keep_all_without_required"
+ }
+ }
+ .into()
+ }
+}
+
+/// Common scenarios for different filter to be benchmarked.
+const FILTER_SCENARIOS: [FilterScenario; 11] = [
+ FilterScenario::OptOutNone,
+ FilterScenario::OptOutNoneKeep(true),
+ FilterScenario::OptOutNoneKeep(false),
+ FilterScenario::OptOutAll,
+ FilterScenario::OptInNone,
+ FilterScenario::OptInAll,
+ FilterScenario::OptInAllWithoutRequired,
+ FilterScenario::OptInAllKeep(true),
+ FilterScenario::OptInAllKeep(false),
+ FilterScenario::OptInAllKeepWithoutRequired(true),
+ FilterScenario::OptInAllKeepWithoutRequired(false),
+];
+
+/// A helper function that benchmarks running [`EntityCloner::clone_entity`] with a bundle `B`.
+///
+/// The bundle must implement [`Default`], which is used to create the first entity that gets its components cloned
+/// in the benchmark. It may also be used to populate the target entity depending on the scenario.
+fn bench_filter(b: &mut Bencher, scenario: FilterScenario) {
+ let mut world = World::default();
+ let mut spawn = |empty| match empty {
+ false => world.spawn(B::default()).id(),
+ true => world.spawn_empty().id(),
+ };
+ let source = spawn(false);
+ let (target, mut cloner);
+
+ match scenario {
+ FilterScenario::OptOutNone => {
+ target = spawn(true);
+ cloner = EntityCloner::default();
+ }
+ FilterScenario::OptOutNoneKeep(is_new) => {
+ target = spawn(is_new);
+ let mut builder = EntityCloner::build_opt_out(&mut world);
+ builder.insert_mode(InsertMode::Keep);
+ cloner = builder.finish();
+ }
+ FilterScenario::OptOutAll => {
+ target = spawn(true);
+ let mut builder = EntityCloner::build_opt_out(&mut world);
+ builder.deny::();
+ cloner = builder.finish();
+ }
+ FilterScenario::OptInNone => {
+ target = spawn(true);
+ let builder = EntityCloner::build_opt_in(&mut world);
+ cloner = builder.finish();
+ }
+ FilterScenario::OptInAll => {
+ target = spawn(true);
+ let mut builder = EntityCloner::build_opt_in(&mut world);
+ builder.allow::();
+ cloner = builder.finish();
+ }
+ FilterScenario::OptInAllWithoutRequired => {
+ target = spawn(true);
+ let mut builder = EntityCloner::build_opt_in(&mut world);
+ builder.without_required_components(|builder| {
+ builder.allow::();
+ });
+ cloner = builder.finish();
+ }
+ FilterScenario::OptInAllKeep(is_new) => {
+ target = spawn(is_new);
+ let mut builder = EntityCloner::build_opt_in(&mut world);
+ builder.allow_if_new::();
+ cloner = builder.finish();
+ }
+ FilterScenario::OptInAllKeepWithoutRequired(is_new) => {
+ target = spawn(is_new);
+ let mut builder = EntityCloner::build_opt_in(&mut world);
+ builder.without_required_components(|builder| {
+ builder.allow_if_new::();
+ });
+ cloner = builder.finish();
+ }
+ }
+
+ b.iter(|| {
+ // clones the given entity into the target
+ cloner.clone_entity(&mut world, black_box(source), black_box(target));
+ world.flush();
+ });
+}
+
+/// Benchmarks filtering of cloning a single entity with 5 unclonable components (each requiring 1 unclonable component) into a target.
+fn filter(c: &mut Criterion) {
+ #[derive(Component, Default)]
+ #[component(clone_behavior = Ignore)]
+ struct C;
+
+ #[derive(Component, Default)]
+ #[component(clone_behavior = Ignore)]
+ #[require(C::)]
+ struct R;
+
+ type RequiringBundle = (R<1>, R<2>, R<3>, R<4>, R<5>);
+
+ let mut group = c.benchmark_group(bench!("filter"));
+
+ // We're cloning 1 entity into a target.
+ group.throughput(Throughput::Elements(1));
+
+ for scenario in FILTER_SCENARIOS {
+ group.bench_function(scenario, |b| {
+ bench_filter::(b, scenario);
+ });
+ }
+
+ group.finish();
+}
diff --git a/benches/benches/bevy_ecs/events/iter.rs b/benches/benches/bevy_ecs/events/iter.rs
index dc20bc3395..9ad17ed8c8 100644
--- a/benches/benches/bevy_ecs/events/iter.rs
+++ b/benches/benches/bevy_ecs/events/iter.rs
@@ -1,6 +1,6 @@
use bevy_ecs::prelude::*;
-#[derive(Event)]
+#[derive(Event, BufferedEvent)]
struct BenchEvent([u8; SIZE]);
pub struct Benchmark(Events>);
diff --git a/benches/benches/bevy_ecs/events/mod.rs b/benches/benches/bevy_ecs/events/mod.rs
index b87a138e06..c2c7f3ee28 100644
--- a/benches/benches/bevy_ecs/events/mod.rs
+++ b/benches/benches/bevy_ecs/events/mod.rs
@@ -10,19 +10,19 @@ fn send(c: &mut Criterion) {
group.warm_up_time(core::time::Duration::from_millis(500));
group.measurement_time(core::time::Duration::from_secs(4));
for count in [100, 1_000, 10_000] {
- group.bench_function(format!("size_4_events_{}", count), |b| {
+ group.bench_function(format!("size_4_events_{count}"), |b| {
let mut bench = send::Benchmark::<4>::new(count);
b.iter(move || bench.run());
});
}
for count in [100, 1_000, 10_000] {
- group.bench_function(format!("size_16_events_{}", count), |b| {
+ group.bench_function(format!("size_16_events_{count}"), |b| {
let mut bench = send::Benchmark::<16>::new(count);
b.iter(move || bench.run());
});
}
for count in [100, 1_000, 10_000] {
- group.bench_function(format!("size_512_events_{}", count), |b| {
+ group.bench_function(format!("size_512_events_{count}"), |b| {
let mut bench = send::Benchmark::<512>::new(count);
b.iter(move || bench.run());
});
@@ -35,19 +35,19 @@ fn iter(c: &mut Criterion) {
group.warm_up_time(core::time::Duration::from_millis(500));
group.measurement_time(core::time::Duration::from_secs(4));
for count in [100, 1_000, 10_000] {
- group.bench_function(format!("size_4_events_{}", count), |b| {
+ group.bench_function(format!("size_4_events_{count}"), |b| {
let mut bench = iter::Benchmark::<4>::new(count);
b.iter(move || bench.run());
});
}
for count in [100, 1_000, 10_000] {
- group.bench_function(format!("size_16_events_{}", count), |b| {
+ group.bench_function(format!("size_16_events_{count}"), |b| {
let mut bench = iter::Benchmark::<4>::new(count);
b.iter(move || bench.run());
});
}
for count in [100, 1_000, 10_000] {
- group.bench_function(format!("size_512_events_{}", count), |b| {
+ group.bench_function(format!("size_512_events_{count}"), |b| {
let mut bench = iter::Benchmark::<512>::new(count);
b.iter(move || bench.run());
});
diff --git a/benches/benches/bevy_ecs/events/send.rs b/benches/benches/bevy_ecs/events/send.rs
index fa996b50aa..be8934e789 100644
--- a/benches/benches/bevy_ecs/events/send.rs
+++ b/benches/benches/bevy_ecs/events/send.rs
@@ -1,6 +1,6 @@
use bevy_ecs::prelude::*;
-#[derive(Event)]
+#[derive(Event, BufferedEvent)]
struct BenchEvent([u8; SIZE]);
impl Default for BenchEvent {
diff --git a/benches/benches/bevy_ecs/iteration/mod.rs b/benches/benches/bevy_ecs/iteration/mod.rs
index 0fa7aced28..b296c5ce0b 100644
--- a/benches/benches/bevy_ecs/iteration/mod.rs
+++ b/benches/benches/bevy_ecs/iteration/mod.rs
@@ -130,7 +130,7 @@ fn par_iter_simple(c: &mut Criterion) {
group.warm_up_time(core::time::Duration::from_millis(500));
group.measurement_time(core::time::Duration::from_secs(4));
for f in [0, 10, 100, 1000] {
- group.bench_function(format!("with_{}_fragment", f), |b| {
+ group.bench_function(format!("with_{f}_fragment"), |b| {
let mut bench = par_iter_simple::Benchmark::new(f);
b.iter(move || bench.run());
});
diff --git a/benches/benches/bevy_ecs/observers/propagation.rs b/benches/benches/bevy_ecs/observers/propagation.rs
index 65c15f7308..808c3727d5 100644
--- a/benches/benches/bevy_ecs/observers/propagation.rs
+++ b/benches/benches/bevy_ecs/observers/propagation.rs
@@ -61,14 +61,10 @@ pub fn event_propagation(criterion: &mut Criterion) {
group.finish();
}
-#[derive(Clone, Component)]
+#[derive(Event, EntityEvent, Clone, Component)]
+#[entity_event(traversal = &'static ChildOf, auto_propagate)]
struct TestEvent {}
-impl Event for TestEvent {
- type Traversal = &'static ChildOf;
- const AUTO_PROPAGATE: bool = true;
-}
-
fn send_events(world: &mut World, leaves: &[Entity]) {
let target = leaves.iter().choose(&mut rand::thread_rng()).unwrap();
@@ -117,6 +113,6 @@ fn add_listeners_to_hierarchy(
}
}
-fn empty_listener(trigger: Trigger>) {
+fn empty_listener(trigger: On>) {
black_box(trigger);
}
diff --git a/benches/benches/bevy_ecs/observers/simple.rs b/benches/benches/bevy_ecs/observers/simple.rs
index 85207624e8..9c26b074e5 100644
--- a/benches/benches/bevy_ecs/observers/simple.rs
+++ b/benches/benches/bevy_ecs/observers/simple.rs
@@ -1,8 +1,8 @@
use core::hint::black_box;
use bevy_ecs::{
- event::Event,
- observer::{Trigger, TriggerTargets},
+ event::{EntityEvent, Event},
+ observer::{On, TriggerTargets},
world::World,
};
@@ -13,7 +13,7 @@ fn deterministic_rand() -> ChaCha8Rng {
ChaCha8Rng::seed_from_u64(42)
}
-#[derive(Clone, Event)]
+#[derive(Clone, Event, EntityEvent)]
struct EventBase;
pub fn observe_simple(criterion: &mut Criterion) {
@@ -46,7 +46,7 @@ pub fn observe_simple(criterion: &mut Criterion) {
group.finish();
}
-fn empty_listener_base(trigger: Trigger) {
+fn empty_listener_base(trigger: On) {
black_box(trigger);
}
diff --git a/benches/benches/bevy_ecs/scheduling/run_condition.rs b/benches/benches/bevy_ecs/scheduling/run_condition.rs
index 7b9cf418f4..9c40cf396e 100644
--- a/benches/benches/bevy_ecs/scheduling/run_condition.rs
+++ b/benches/benches/bevy_ecs/scheduling/run_condition.rs
@@ -24,7 +24,7 @@ pub fn run_condition_yes(criterion: &mut Criterion) {
}
// run once to initialize systems
schedule.run(&mut world);
- group.bench_function(format!("{}_systems", amount), |bencher| {
+ group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
@@ -46,7 +46,7 @@ pub fn run_condition_no(criterion: &mut Criterion) {
}
// run once to initialize systems
schedule.run(&mut world);
- group.bench_function(format!("{}_systems", amount), |bencher| {
+ group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
@@ -77,7 +77,7 @@ pub fn run_condition_yes_with_query(criterion: &mut Criterion) {
}
// run once to initialize systems
schedule.run(&mut world);
- group.bench_function(format!("{}_systems", amount), |bencher| {
+ group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
@@ -105,7 +105,7 @@ pub fn run_condition_yes_with_resource(criterion: &mut Criterion) {
}
// run once to initialize systems
schedule.run(&mut world);
- group.bench_function(format!("{}_systems", amount), |bencher| {
+ group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
diff --git a/benches/benches/bevy_ecs/scheduling/running_systems.rs b/benches/benches/bevy_ecs/scheduling/running_systems.rs
index 2fc1da1710..159974117c 100644
--- a/benches/benches/bevy_ecs/scheduling/running_systems.rs
+++ b/benches/benches/bevy_ecs/scheduling/running_systems.rs
@@ -26,7 +26,7 @@ pub fn empty_systems(criterion: &mut Criterion) {
schedule.add_systems(empty);
}
schedule.run(&mut world);
- group.bench_function(format!("{}_systems", amount), |bencher| {
+ group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
@@ -38,7 +38,7 @@ pub fn empty_systems(criterion: &mut Criterion) {
schedule.add_systems((empty, empty, empty, empty, empty));
}
schedule.run(&mut world);
- group.bench_function(format!("{}_systems", amount), |bencher| {
+ group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
@@ -79,10 +79,7 @@ pub fn busy_systems(criterion: &mut Criterion) {
}
schedule.run(&mut world);
group.bench_function(
- format!(
- "{:02}x_entities_{:02}_systems",
- entity_bunches, system_amount
- ),
+ format!("{entity_bunches:02}x_entities_{system_amount:02}_systems"),
|bencher| {
bencher.iter(|| {
schedule.run(&mut world);
@@ -128,10 +125,7 @@ pub fn contrived(criterion: &mut Criterion) {
}
schedule.run(&mut world);
group.bench_function(
- format!(
- "{:02}x_entities_{:02}_systems",
- entity_bunches, system_amount
- ),
+ format!("{entity_bunches:02}x_entities_{system_amount:02}_systems"),
|bencher| {
bencher.iter(|| {
schedule.run(&mut world);
diff --git a/benches/benches/bevy_ecs/world/commands.rs b/benches/benches/bevy_ecs/world/commands.rs
index bedfb8e5af..4836a243eb 100644
--- a/benches/benches/bevy_ecs/world/commands.rs
+++ b/benches/benches/bevy_ecs/world/commands.rs
@@ -37,7 +37,7 @@ pub fn spawn_commands(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in [100, 1_000, 10_000] {
- group.bench_function(format!("{}_entities", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities"), |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
@@ -68,7 +68,7 @@ pub fn nonempty_spawn_commands(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in [100, 1_000, 10_000] {
- group.bench_function(format!("{}_entities", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities"), |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
@@ -162,7 +162,7 @@ pub fn fake_commands(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for command_count in [100, 1_000, 10_000] {
- group.bench_function(format!("{}_commands", command_count), |bencher| {
+ group.bench_function(format!("{command_count}_commands"), |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
@@ -207,7 +207,7 @@ pub fn sized_commands_impl(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for command_count in [100, 1_000, 10_000] {
- group.bench_function(format!("{}_commands", command_count), |bencher| {
+ group.bench_function(format!("{command_count}_commands"), |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
diff --git a/benches/benches/bevy_ecs/world/despawn.rs b/benches/benches/bevy_ecs/world/despawn.rs
index cd693fc15c..7b79ed95d9 100644
--- a/benches/benches/bevy_ecs/world/despawn.rs
+++ b/benches/benches/bevy_ecs/world/despawn.rs
@@ -13,7 +13,7 @@ pub fn world_despawn(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in [1, 100, 10_000] {
- group.bench_function(format!("{}_entities", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities"), |bencher| {
bencher.iter_batched_ref(
|| {
let mut world = World::default();
diff --git a/benches/benches/bevy_ecs/world/despawn_recursive.rs b/benches/benches/bevy_ecs/world/despawn_recursive.rs
index 78c644174b..f63c1a510b 100644
--- a/benches/benches/bevy_ecs/world/despawn_recursive.rs
+++ b/benches/benches/bevy_ecs/world/despawn_recursive.rs
@@ -13,7 +13,7 @@ pub fn world_despawn_recursive(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in [1, 100, 10_000] {
- group.bench_function(format!("{}_entities", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities"), |bencher| {
bencher.iter_batched_ref(
|| {
let mut world = World::default();
diff --git a/benches/benches/bevy_ecs/world/spawn.rs b/benches/benches/bevy_ecs/world/spawn.rs
index 502d10ceb3..9cceda7ae5 100644
--- a/benches/benches/bevy_ecs/world/spawn.rs
+++ b/benches/benches/bevy_ecs/world/spawn.rs
@@ -13,7 +13,7 @@ pub fn world_spawn(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in [1, 100, 10_000] {
- group.bench_function(format!("{}_entities", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities"), |bencher| {
let mut world = World::default();
bencher.iter(|| {
for _ in 0..entity_count {
diff --git a/benches/benches/bevy_ecs/world/world_get.rs b/benches/benches/bevy_ecs/world/world_get.rs
index e6e2a0bb90..81e0bf2b0f 100644
--- a/benches/benches/bevy_ecs/world/world_get.rs
+++ b/benches/benches/bevy_ecs/world/world_get.rs
@@ -49,7 +49,7 @@ pub fn world_entity(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
- group.bench_function(format!("{}_entities", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities"), |bencher| {
let world = setup::(entity_count);
bencher.iter(|| {
@@ -72,7 +72,7 @@ pub fn world_get(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
- group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_table"), |bencher| {
let world = setup::(entity_count);
bencher.iter(|| {
@@ -84,7 +84,7 @@ pub fn world_get(criterion: &mut Criterion) {
}
});
});
- group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_sparse"), |bencher| {
let world = setup::(entity_count);
bencher.iter(|| {
@@ -107,7 +107,7 @@ pub fn world_query_get(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
- group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_table"), |bencher| {
let mut world = setup::(entity_count);
let mut query = world.query::<&Table>();
@@ -120,7 +120,7 @@ pub fn world_query_get(criterion: &mut Criterion) {
}
});
});
- group.bench_function(format!("{}_entities_table_wide", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_table_wide"), |bencher| {
let mut world = setup_wide::<(
WideTable<0>,
WideTable<1>,
@@ -147,7 +147,7 @@ pub fn world_query_get(criterion: &mut Criterion) {
}
});
});
- group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_sparse"), |bencher| {
let mut world = setup::(entity_count);
let mut query = world.query::<&Sparse>();
@@ -160,37 +160,33 @@ pub fn world_query_get(criterion: &mut Criterion) {
}
});
});
- group.bench_function(
- format!("{}_entities_sparse_wide", entity_count),
- |bencher| {
- let mut world = setup_wide::<(
- WideSparse<0>,
- WideSparse<1>,
- WideSparse<2>,
- WideSparse<3>,
- WideSparse<4>,
- WideSparse<5>,
- )>(entity_count);
- let mut query = world.query::<(
- &WideSparse<0>,
- &WideSparse<1>,
- &WideSparse<2>,
- &WideSparse<3>,
- &WideSparse<4>,
- &WideSparse<5>,
- )>();
+ group.bench_function(format!("{entity_count}_entities_sparse_wide"), |bencher| {
+ let mut world = setup_wide::<(
+ WideSparse<0>,
+ WideSparse<1>,
+ WideSparse<2>,
+ WideSparse<3>,
+ WideSparse<4>,
+ WideSparse<5>,
+ )>(entity_count);
+ let mut query = world.query::<(
+ &WideSparse<0>,
+ &WideSparse<1>,
+ &WideSparse<2>,
+ &WideSparse<3>,
+ &WideSparse<4>,
+ &WideSparse<5>,
+ )>();
- bencher.iter(|| {
- for i in 0..entity_count {
- // SAFETY: Range is exclusive.
- let entity = Entity::from_raw(EntityRow::new(unsafe {
- NonMaxU32::new_unchecked(i)
- }));
- assert!(query.get(&world, entity).is_ok());
- }
- });
- },
- );
+ bencher.iter(|| {
+ for i in 0..entity_count {
+ // SAFETY: Range is exclusive.
+ let entity =
+ Entity::from_raw(EntityRow::new(unsafe { NonMaxU32::new_unchecked(i) }));
+ assert!(query.get(&world, entity).is_ok());
+ }
+ });
+ });
}
group.finish();
@@ -202,7 +198,7 @@ pub fn world_query_iter(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
- group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_table"), |bencher| {
let mut world = setup::(entity_count);
let mut query = world.query::<&Table>();
@@ -216,7 +212,7 @@ pub fn world_query_iter(criterion: &mut Criterion) {
assert_eq!(black_box(count), entity_count);
});
});
- group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_sparse"), |bencher| {
let mut world = setup::(entity_count);
let mut query = world.query::<&Sparse>();
@@ -241,7 +237,7 @@ pub fn world_query_for_each(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
- group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_table"), |bencher| {
let mut world = setup::(entity_count);
let mut query = world.query::<&Table>();
@@ -255,7 +251,7 @@ pub fn world_query_for_each(criterion: &mut Criterion) {
assert_eq!(black_box(count), entity_count);
});
});
- group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_sparse"), |bencher| {
let mut world = setup::(entity_count);
let mut query = world.query::<&Sparse>();
@@ -280,7 +276,7 @@ pub fn query_get(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
- group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_table"), |bencher| {
let mut world = World::default();
let mut entities: Vec<_> = world
.spawn_batch((0..entity_count).map(|_| Table::default()))
@@ -299,7 +295,7 @@ pub fn query_get(criterion: &mut Criterion) {
assert_eq!(black_box(count), entity_count);
});
});
- group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_entities_sparse"), |bencher| {
let mut world = World::default();
let mut entities: Vec<_> = world
.spawn_batch((0..entity_count).map(|_| Sparse::default()))
@@ -329,7 +325,7 @@ pub fn query_get_many(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(2 * N as u64));
for entity_count in RANGE.map(|i| i * 10_000) {
- group.bench_function(format!("{}_calls_table", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_calls_table"), |bencher| {
let mut world = World::default();
let mut entity_groups: Vec<_> = (0..entity_count)
.map(|_| [(); N].map(|_| world.spawn(Table::default()).id()))
@@ -352,7 +348,7 @@ pub fn query_get_many(criterion: &mut Criterion) {
assert_eq!(black_box(count), entity_count);
});
});
- group.bench_function(format!("{}_calls_sparse", entity_count), |bencher| {
+ group.bench_function(format!("{entity_count}_calls_sparse"), |bencher| {
let mut world = World::default();
let mut entity_groups: Vec<_> = (0..entity_count)
.map(|_| [(); N].map(|_| world.spawn(Sparse::default()).id()))
diff --git a/benches/benches/bevy_picking/ray_mesh_intersection.rs b/benches/benches/bevy_picking/ray_mesh_intersection.rs
index 871a6d1062..e9fd0caf9f 100644
--- a/benches/benches/bevy_picking/ray_mesh_intersection.rs
+++ b/benches/benches/bevy_picking/ray_mesh_intersection.rs
@@ -155,6 +155,7 @@ fn bench(c: &mut Criterion) {
&mesh.positions,
Some(&mesh.normals),
Some(&mesh.indices),
+ None,
backface_culling,
);
diff --git a/benches/benches/bevy_reflect/map.rs b/benches/benches/bevy_reflect/map.rs
index 1eab01a587..a70f89e12b 100644
--- a/benches/benches/bevy_reflect/map.rs
+++ b/benches/benches/bevy_reflect/map.rs
@@ -142,7 +142,7 @@ fn concrete_map_apply(criterion: &mut Criterion) {
fn u64_to_n_byte_key(k: u64, n: usize) -> String {
let mut key = String::with_capacity(n);
- write!(&mut key, "{}", k).unwrap();
+ write!(&mut key, "{k}").unwrap();
// Pad key to n bytes.
key.extend(iter::repeat_n('\0', n - key.len()));
diff --git a/benches/benches/bevy_reflect/struct.rs b/benches/benches/bevy_reflect/struct.rs
index 7750213b6d..52d539f64d 100644
--- a/benches/benches/bevy_reflect/struct.rs
+++ b/benches/benches/bevy_reflect/struct.rs
@@ -55,7 +55,7 @@ fn concrete_struct_field(criterion: &mut Criterion) {
&s,
|bencher, s| {
let field_names = (0..field_count)
- .map(|i| format!("field_{}", i))
+ .map(|i| format!("field_{i}"))
.collect::>();
bencher.iter(|| {
@@ -256,7 +256,7 @@ fn dynamic_struct_apply(criterion: &mut Criterion) {
let mut base = DynamicStruct::default();
for i in 0..field_count {
- let field_name = format!("field_{}", i);
+ let field_name = format!("field_{i}");
base.insert(&field_name, 1u32);
}
@@ -283,7 +283,7 @@ fn dynamic_struct_apply(criterion: &mut Criterion) {
let mut base = DynamicStruct::default();
let mut patch = DynamicStruct::default();
for i in 0..field_count {
- let field_name = format!("field_{}", i);
+ let field_name = format!("field_{i}");
base.insert(&field_name, 0u32);
patch.insert(&field_name, 1u32);
}
@@ -309,11 +309,11 @@ fn dynamic_struct_insert(criterion: &mut Criterion) {
|bencher, field_count| {
let mut s = DynamicStruct::default();
for i in 0..*field_count {
- let field_name = format!("field_{}", i);
+ let field_name = format!("field_{i}");
s.insert(&field_name, ());
}
- let field = format!("field_{}", field_count);
+ let field = format!("field_{field_count}");
bencher.iter_batched(
|| s.to_dynamic_struct(),
|mut s| {
@@ -339,7 +339,7 @@ fn dynamic_struct_get_field(criterion: &mut Criterion) {
|bencher, field_count| {
let mut s = DynamicStruct::default();
for i in 0..*field_count {
- let field_name = format!("field_{}", i);
+ let field_name = format!("field_{i}");
s.insert(&field_name, ());
}
diff --git a/crates/bevy_a11y/Cargo.toml b/crates/bevy_a11y/Cargo.toml
index 39628ec046..70ee16cf77 100644
--- a/crates/bevy_a11y/Cargo.toml
+++ b/crates/bevy_a11y/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy_a11y"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Provides accessibility support for Bevy Engine"
homepage = "https://bevy.org"
@@ -40,10 +40,10 @@ critical-section = [
[dependencies]
# bevy
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false }
-bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev", default-features = false }
+bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev", default-features = false }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, optional = true }
# other
accesskit = { version = "0.19", default-features = false }
diff --git a/crates/bevy_a11y/src/lib.rs b/crates/bevy_a11y/src/lib.rs
index f8c46757dd..22b2f71f07 100644
--- a/crates/bevy_a11y/src/lib.rs
+++ b/crates/bevy_a11y/src/lib.rs
@@ -26,7 +26,8 @@ use accesskit::Node;
use bevy_app::Plugin;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
- prelude::{Component, Event},
+ component::Component,
+ event::{BufferedEvent, Event},
resource::Resource,
schedule::SystemSet,
};
@@ -44,7 +45,7 @@ use serde::{Deserialize, Serialize};
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
/// Wrapper struct for [`accesskit::ActionRequest`]. Required to allow it to be used as an `Event`.
-#[derive(Event, Deref, DerefMut)]
+#[derive(Event, BufferedEvent, Deref, DerefMut)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ActionRequest(pub accesskit::ActionRequest);
diff --git a/crates/bevy_animation/Cargo.toml b/crates/bevy_animation/Cargo.toml
index 9f9cd26587..637231fd4c 100644
--- a/crates/bevy_animation/Cargo.toml
+++ b/crates/bevy_animation/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy_animation"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Provides animation functionality for Bevy Engine"
homepage = "https://bevy.org"
@@ -10,34 +10,34 @@ keywords = ["bevy"]
[dependencies]
# bevy
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
-bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
-bevy_color = { path = "../bevy_color", version = "0.16.0-dev" }
-bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
-bevy_log = { path = "../bevy_log", version = "0.16.0-dev" }
-bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
-bevy_mesh = { path = "../bevy_mesh", version = "0.16.0-dev" }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev" }
+bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" }
+bevy_color = { path = "../bevy_color", version = "0.17.0-dev" }
+bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
+bevy_log = { path = "../bevy_log", version = "0.17.0-dev" }
+bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
+bevy_mesh = { path = "../bevy_mesh", version = "0.17.0-dev" }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", features = [
"petgraph",
] }
-bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
-bevy_time = { path = "../bevy_time", version = "0.16.0-dev" }
-bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
-bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
-bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [
+bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
+bevy_time = { path = "../bevy_time", version = "0.17.0-dev" }
+bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" }
+bevy_transform = { path = "../bevy_transform", version = "0.17.0-dev" }
+bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false, features = [
"std",
"serialize",
] }
# other
petgraph = { version = "0.7", features = ["serde-1"] }
-ron = "0.8"
+ron = "0.10"
serde = "1"
blake3 = { version = "1.0" }
downcast-rs = { version = "2", default-features = false, features = ["std"] }
thiserror = { version = "2", default-features = false }
-derive_more = { version = "1", default-features = false, features = ["from"] }
+derive_more = { version = "2", default-features = false, features = ["from"] }
either = "1.13"
thread_local = "1"
uuid = { version = "1.13.1", features = ["v4"] }
diff --git a/crates/bevy_animation/src/graph.rs b/crates/bevy_animation/src/graph.rs
index aa6d252fee..a5f4041ac7 100644
--- a/crates/bevy_animation/src/graph.rs
+++ b/crates/bevy_animation/src/graph.rs
@@ -1,10 +1,11 @@
//! The animation graph, which allows animations to be blended together.
use core::{
+ fmt::Write,
iter,
ops::{Index, IndexMut, Range},
};
-use std::io::{self, Write};
+use std::io;
use bevy_asset::{
io::Reader, Asset, AssetEvent, AssetId, AssetLoader, AssetPath, Assets, Handle, LoadContext,
diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs
index dd68595961..ae7ce42ed6 100644
--- a/crates/bevy_animation/src/lib.rs
+++ b/crates/bevy_animation/src/lib.rs
@@ -324,13 +324,13 @@ impl AnimationClip {
.push(variable_curve);
}
- /// Add a untargeted [`Event`] to this [`AnimationClip`].
+ /// Add an [`EntityEvent`] with no [`AnimationTarget`] to this [`AnimationClip`].
///
/// The `event` will be cloned and triggered on the [`AnimationPlayer`] entity once the `time` (in seconds)
/// is reached in the animation.
///
/// See also [`add_event_to_target`](Self::add_event_to_target).
- pub fn add_event(&mut self, time: f32, event: impl Event + Clone) {
+ pub fn add_event(&mut self, time: f32, event: impl EntityEvent + Clone) {
self.add_event_fn(
time,
move |commands: &mut Commands, entity: Entity, _time: f32, _weight: f32| {
@@ -339,7 +339,7 @@ impl AnimationClip {
);
}
- /// Add an [`Event`] to an [`AnimationTarget`] named by an [`AnimationTargetId`].
+ /// Add an [`EntityEvent`] to an [`AnimationTarget`] named by an [`AnimationTargetId`].
///
/// The `event` will be cloned and triggered on the entity matching the target once the `time` (in seconds)
/// is reached in the animation.
@@ -349,7 +349,7 @@ impl AnimationClip {
&mut self,
target_id: AnimationTargetId,
time: f32,
- event: impl Event + Clone,
+ event: impl EntityEvent + Clone,
) {
self.add_event_fn_to_target(
target_id,
@@ -360,19 +360,19 @@ impl AnimationClip {
);
}
- /// Add a untargeted event function to this [`AnimationClip`].
+ /// Add an event function with no [`AnimationTarget`] to this [`AnimationClip`].
///
/// The `func` will trigger on the [`AnimationPlayer`] entity once the `time` (in seconds)
/// is reached in the animation.
///
- /// For a simpler [`Event`]-based alternative, see [`AnimationClip::add_event`].
+ /// For a simpler [`EntityEvent`]-based alternative, see [`AnimationClip::add_event`].
/// See also [`add_event_to_target`](Self::add_event_to_target).
///
/// ```
/// # use bevy_animation::AnimationClip;
/// # let mut clip = AnimationClip::default();
/// clip.add_event_fn(1.0, |commands, entity, time, weight| {
- /// println!("Animation Event Triggered {entity:#?} at time {time} with weight {weight}");
+ /// println!("Animation event triggered {entity:#?} at time {time} with weight {weight}");
/// })
/// ```
pub fn add_event_fn(
@@ -388,14 +388,14 @@ impl AnimationClip {
/// The `func` will trigger on the entity matching the target once the `time` (in seconds)
/// is reached in the animation.
///
- /// For a simpler [`Event`]-based alternative, see [`AnimationClip::add_event_to_target`].
+ /// For a simpler [`EntityEvent`]-based alternative, see [`AnimationClip::add_event_to_target`].
/// Use [`add_event`](Self::add_event) instead if you don't have a specific target.
///
/// ```
/// # use bevy_animation::{AnimationClip, AnimationTargetId};
/// # let mut clip = AnimationClip::default();
/// clip.add_event_fn_to_target(AnimationTargetId::from_iter(["Arm", "Hand"]), 1.0, |commands, entity, time, weight| {
- /// println!("Animation Event Triggered {entity:#?} at time {time} with weight {weight}");
+ /// println!("Animation event triggered {entity:#?} at time {time} with weight {weight}");
/// })
/// ```
pub fn add_event_fn_to_target(
@@ -1534,7 +1534,7 @@ mod tests {
use super::*;
- #[derive(Event, Reflect, Clone)]
+ #[derive(Event, EntityEvent, Reflect, Clone)]
struct A;
#[track_caller]
diff --git a/crates/bevy_anti_aliasing/Cargo.toml b/crates/bevy_anti_aliasing/Cargo.toml
index c54608a883..8c32d70fff 100644
--- a/crates/bevy_anti_aliasing/Cargo.toml
+++ b/crates/bevy_anti_aliasing/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy_anti_aliasing"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Provides various anti aliasing implementations for Bevy Engine"
homepage = "https://bevy.org"
@@ -16,17 +16,17 @@ smaa_luts = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"]
[dependencies]
# bevy
-bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
-bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
-bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
-bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
-bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
-bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
-bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.16.0-dev" }
-bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" }
+bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" }
+bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
+bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
+bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev" }
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev" }
+bevy_image = { path = "../bevy_image", version = "0.17.0-dev" }
+bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" }
+bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.17.0-dev" }
+bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.17.0-dev" }
# other
tracing = { version = "0.1", default-features = false, features = ["std"] }
diff --git a/crates/bevy_anti_aliasing/src/contrast_adaptive_sharpening/mod.rs b/crates/bevy_anti_aliasing/src/contrast_adaptive_sharpening/mod.rs
index 0b4a99fb59..d1de3f4cea 100644
--- a/crates/bevy_anti_aliasing/src/contrast_adaptive_sharpening/mod.rs
+++ b/crates/bevy_anti_aliasing/src/contrast_adaptive_sharpening/mod.rs
@@ -3,7 +3,7 @@ use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_core_pipeline::{
core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d},
- fullscreen_vertex_shader::fullscreen_shader_vertex_state,
+ FullscreenShader,
};
use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_image::BevyDefault as _;
@@ -163,7 +163,8 @@ impl Plugin for CasPlugin {
pub struct CasPipeline {
texture_bind_group: BindGroupLayout,
sampler: Sampler,
- shader: Handle,
+ fullscreen_shader: FullscreenShader,
+ fragment_shader: Handle,
}
impl FromWorld for CasPipeline {
@@ -187,7 +188,11 @@ impl FromWorld for CasPipeline {
CasPipeline {
texture_bind_group,
sampler,
- shader: load_embedded_asset!(render_world, "robust_contrast_adaptive_sharpening.wgsl"),
+ fullscreen_shader: render_world.resource::().clone(),
+ fragment_shader: load_embedded_asset!(
+ render_world,
+ "robust_contrast_adaptive_sharpening.wgsl"
+ ),
}
}
}
@@ -209,9 +214,9 @@ impl SpecializedRenderPipeline for CasPipeline {
RenderPipelineDescriptor {
label: Some("contrast_adaptive_sharpening".into()),
layout: vec![self.texture_bind_group.clone()],
- vertex: fullscreen_shader_vertex_state(),
+ vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
- shader: self.shader.clone(),
+ shader: self.fragment_shader.clone(),
shader_defs,
entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {
diff --git a/crates/bevy_anti_aliasing/src/fxaa/mod.rs b/crates/bevy_anti_aliasing/src/fxaa/mod.rs
index 6b914c4e86..adc2a3d5a2 100644
--- a/crates/bevy_anti_aliasing/src/fxaa/mod.rs
+++ b/crates/bevy_anti_aliasing/src/fxaa/mod.rs
@@ -3,7 +3,7 @@ use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_core_pipeline::{
core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d},
- fullscreen_vertex_shader::fullscreen_shader_vertex_state,
+ FullscreenShader,
};
use bevy_ecs::prelude::*;
use bevy_image::BevyDefault as _;
@@ -130,7 +130,8 @@ impl Plugin for FxaaPlugin {
pub struct FxaaPipeline {
texture_bind_group: BindGroupLayout,
sampler: Sampler,
- shader: Handle,
+ fullscreen_shader: FullscreenShader,
+ fragment_shader: Handle,
}
impl FromWorld for FxaaPipeline {
@@ -157,7 +158,8 @@ impl FromWorld for FxaaPipeline {
FxaaPipeline {
texture_bind_group,
sampler,
- shader: load_embedded_asset!(render_world, "fxaa.wgsl"),
+ fullscreen_shader: render_world.resource::().clone(),
+ fragment_shader: load_embedded_asset!(render_world, "fxaa.wgsl"),
}
}
}
@@ -181,9 +183,9 @@ impl SpecializedRenderPipeline for FxaaPipeline {
RenderPipelineDescriptor {
label: Some("fxaa".into()),
layout: vec![self.texture_bind_group.clone()],
- vertex: fullscreen_shader_vertex_state(),
+ vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
- shader: self.shader.clone(),
+ shader: self.fragment_shader.clone(),
shader_defs: vec![
format!("EDGE_THRESH_{}", key.edge_threshold.get_str()).into(),
format!("EDGE_THRESH_MIN_{}", key.edge_threshold_min.get_str()).into(),
diff --git a/crates/bevy_anti_aliasing/src/smaa/mod.rs b/crates/bevy_anti_aliasing/src/smaa/mod.rs
index 0947abc5f8..bb082c5a01 100644
--- a/crates/bevy_anti_aliasing/src/smaa/mod.rs
+++ b/crates/bevy_anti_aliasing/src/smaa/mod.rs
@@ -847,7 +847,7 @@ impl ViewNode for SmaaNode {
view_smaa_uniform_offset,
smaa_textures,
view_smaa_bind_groups,
- ): QueryItem<'w, Self::ViewQuery>,
+ ): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::();
diff --git a/crates/bevy_anti_aliasing/src/taa/mod.rs b/crates/bevy_anti_aliasing/src/taa/mod.rs
index 0f706146b1..6a00e9c0cf 100644
--- a/crates/bevy_anti_aliasing/src/taa/mod.rs
+++ b/crates/bevy_anti_aliasing/src/taa/mod.rs
@@ -2,9 +2,9 @@ use bevy_app::{App, Plugin};
use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_core_pipeline::{
core_3d::graph::{Core3d, Node3d},
- fullscreen_vertex_shader::fullscreen_shader_vertex_state,
prelude::Camera3d,
prepass::{DepthPrepass, MotionVectorPrepass, ViewPrepassTextures},
+ FullscreenShader,
};
use bevy_diagnostic::FrameCount;
use bevy_ecs::{
@@ -238,7 +238,8 @@ struct TaaPipeline {
taa_bind_group_layout: BindGroupLayout,
nearest_sampler: Sampler,
linear_sampler: Sampler,
- shader: Handle,
+ fullscreen_shader: FullscreenShader,
+ fragment_shader: Handle,
}
impl FromWorld for TaaPipeline {
@@ -283,7 +284,8 @@ impl FromWorld for TaaPipeline {
taa_bind_group_layout,
nearest_sampler,
linear_sampler,
- shader: load_embedded_asset!(world, "taa.wgsl"),
+ fullscreen_shader: world.resource::().clone(),
+ fragment_shader: load_embedded_asset!(world, "taa.wgsl"),
}
}
}
@@ -314,9 +316,9 @@ impl SpecializedRenderPipeline for TaaPipeline {
RenderPipelineDescriptor {
label: Some("taa_pipeline".into()),
layout: vec![self.taa_bind_group_layout.clone()],
- vertex: fullscreen_shader_vertex_state(),
+ vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
- shader: self.shader.clone(),
+ shader: self.fragment_shader.clone(),
shader_defs,
entry_point: "taa".into(),
targets: vec![
diff --git a/crates/bevy_app/Cargo.toml b/crates/bevy_app/Cargo.toml
index 6b6120f182..a0c5222b0b 100644
--- a/crates/bevy_app/Cargo.toml
+++ b/crates/bevy_app/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy_app"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Provides core App functionality for Bevy Engine"
homepage = "https://bevy.org"
@@ -79,12 +79,12 @@ hotpatching = [
[dependencies]
# bevy
-bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
-bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false }
-bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false }
-bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false }
+bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev", default-features = false }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, optional = true }
+bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev", default-features = false }
+bevy_tasks = { path = "../bevy_tasks", version = "0.17.0-dev", default-features = false }
+bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false }
# other
downcast-rs = { version = "2", default-features = false }
diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs
index 2adf6c2857..05f3de27b1 100644
--- a/crates/bevy_app/src/app.rs
+++ b/crates/bevy_app/src/app.rs
@@ -106,10 +106,13 @@ impl Default for App {
#[cfg(feature = "bevy_reflect")]
{
+ use bevy_ecs::observer::ObservedBy;
+
app.init_resource::();
app.register_type::();
app.register_type::();
app.register_type::();
+ app.register_type::();
}
#[cfg(feature = "reflect_functions")]
@@ -341,7 +344,7 @@ impl App {
self
}
- /// Initializes `T` event handling by inserting an event queue resource ([`Events::`])
+ /// Initializes [`BufferedEvent`] handling for `T` by inserting an event queue resource ([`Events::`])
/// and scheduling an [`event_update_system`] in [`First`].
///
/// See [`Events`] for information on how to define events.
@@ -352,7 +355,7 @@ impl App {
/// # use bevy_app::prelude::*;
/// # use bevy_ecs::prelude::*;
/// #
- /// # #[derive(Event)]
+ /// # #[derive(Event, BufferedEvent)]
/// # struct MyEvent;
/// # let mut app = App::new();
/// #
@@ -360,7 +363,7 @@ impl App {
/// ```
pub fn add_event(&mut self) -> &mut Self
where
- T: Event,
+ T: BufferedEvent,
{
self.main_mut().add_event::();
self
@@ -1306,7 +1309,7 @@ impl App {
/// Spawns an [`Observer`] entity, which will watch for and respond to the given event.
///
- /// `observer` can be any system whose first parameter is a [`Trigger`].
+ /// `observer` can be any system whose first parameter is [`On`].
///
/// # Examples
///
@@ -1322,14 +1325,14 @@ impl App {
/// # friends_allowed: bool,
/// # };
/// #
- /// # #[derive(Event)]
+ /// # #[derive(Event, EntityEvent)]
/// # struct Invite;
/// #
/// # #[derive(Component)]
/// # struct Friend;
/// #
///
- /// app.add_observer(|trigger: Trigger, friends: Query>, mut commands: Commands| {
+ /// app.add_observer(|trigger: On, friends: Query>, mut commands: Commands| {
/// if trigger.event().friends_allowed {
/// for friend in friends.iter() {
/// commands.trigger_targets(Invite, friend);
@@ -1404,7 +1407,7 @@ fn run_once(mut app: App) -> AppExit {
app.should_exit().unwrap_or(AppExit::Success)
}
-/// An event that indicates the [`App`] should exit. If one or more of these are present at the end of an update,
+/// A [`BufferedEvent`] that indicates the [`App`] should exit. If one or more of these are present at the end of an update,
/// the [runner](App::set_runner) will end and ([maybe](App::run)) return control to the caller.
///
/// This event can be used to detect when an exit is requested. Make sure that systems listening
@@ -1414,7 +1417,7 @@ fn run_once(mut app: App) -> AppExit {
/// This type is roughly meant to map to a standard definition of a process exit code (0 means success, not 0 means error). Due to portability concerns
/// (see [`ExitCode`](https://doc.rust-lang.org/std/process/struct.ExitCode.html) and [`process::exit`](https://doc.rust-lang.org/std/process/fn.exit.html#))
/// we only allow error codes between 1 and [255](u8::MAX).
-#[derive(Event, Debug, Clone, Default, PartialEq, Eq)]
+#[derive(Event, BufferedEvent, Debug, Clone, Default, PartialEq, Eq)]
pub enum AppExit {
/// [`App`] exited without any problems.
#[default]
@@ -1482,7 +1485,7 @@ mod tests {
change_detection::{DetectChanges, ResMut},
component::Component,
entity::Entity,
- event::{Event, EventWriter, Events},
+ event::{BufferedEvent, Event, EventWriter, Events},
lifecycle::RemovedComponents,
query::With,
resource::Resource,
@@ -1579,7 +1582,7 @@ mod tests {
app.add_systems(EnterMainMenu, (foo, bar));
app.world_mut().run_schedule(EnterMainMenu);
- assert_eq!(app.world().entities().len(), 2);
+ assert_eq!(app.world().entity_count(), 2);
}
#[test]
@@ -1848,7 +1851,7 @@ mod tests {
}
#[test]
fn events_should_be_updated_once_per_update() {
- #[derive(Event, Clone)]
+ #[derive(Event, BufferedEvent, Clone)]
struct TestEvent;
let mut app = App::new();
diff --git a/crates/bevy_app/src/propagate.rs b/crates/bevy_app/src/propagate.rs
index 754ba3140e..c6ac5139b9 100644
--- a/crates/bevy_app/src/propagate.rs
+++ b/crates/bevy_app/src/propagate.rs
@@ -88,6 +88,7 @@ impl core::fmt::Debug for PropagateSet {
}
impl Eq for PropagateSet {}
+
impl core::hash::Hash for PropagateSet {
fn hash(&self, state: &mut H) {
self._p.hash(state);
diff --git a/crates/bevy_app/src/sub_app.rs b/crates/bevy_app/src/sub_app.rs
index c340b80654..56d6b43d38 100644
--- a/crates/bevy_app/src/sub_app.rs
+++ b/crates/bevy_app/src/sub_app.rs
@@ -338,7 +338,7 @@ impl SubApp {
/// See [`App::add_event`].
pub fn add_event(&mut self) -> &mut Self
where
- T: Event,
+ T: BufferedEvent,
{
if !self.world.contains_resource::>() {
EventRegistry::register_event::(self.world_mut());
diff --git a/crates/bevy_app/src/task_pool_plugin.rs b/crates/bevy_app/src/task_pool_plugin.rs
index 5ed4e3fa5d..8014790f07 100644
--- a/crates/bevy_app/src/task_pool_plugin.rs
+++ b/crates/bevy_app/src/task_pool_plugin.rs
@@ -160,7 +160,7 @@ impl TaskPoolOptions {
pub fn create_default_pools(&self) {
let total_threads = bevy_tasks::available_parallelism()
.clamp(self.min_total_threads, self.max_total_threads);
- trace!("Assigning {} cores to default task pools", total_threads);
+ trace!("Assigning {total_threads} cores to default task pools");
let mut remaining_threads = total_threads;
@@ -170,7 +170,7 @@ impl TaskPoolOptions {
.io
.get_number_of_threads(remaining_threads, total_threads);
- trace!("IO Threads: {}", io_threads);
+ trace!("IO Threads: {io_threads}");
remaining_threads = remaining_threads.saturating_sub(io_threads);
IoTaskPool::get_or_init(|| {
@@ -200,7 +200,7 @@ impl TaskPoolOptions {
.async_compute
.get_number_of_threads(remaining_threads, total_threads);
- trace!("Async Compute Threads: {}", async_compute_threads);
+ trace!("Async Compute Threads: {async_compute_threads}");
remaining_threads = remaining_threads.saturating_sub(async_compute_threads);
AsyncComputeTaskPool::get_or_init(|| {
@@ -231,7 +231,7 @@ impl TaskPoolOptions {
.compute
.get_number_of_threads(remaining_threads, total_threads);
- trace!("Compute Threads: {}", compute_threads);
+ trace!("Compute Threads: {compute_threads}");
ComputeTaskPool::get_or_init(|| {
let builder = TaskPoolBuilder::default()
diff --git a/crates/bevy_asset/Cargo.toml b/crates/bevy_asset/Cargo.toml
index cbb138b0f5..edf8986130 100644
--- a/crates/bevy_asset/Cargo.toml
+++ b/crates/bevy_asset/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy_asset"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Provides asset functionality for Bevy Engine"
homepage = "https://bevy.org"
@@ -19,19 +19,19 @@ watch = []
trace = []
[dependencies]
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, features = [
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev", default-features = false, features = [
"bevy_reflect",
] }
-bevy_asset_macros = { path = "macros", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, features = [
+bevy_asset_macros = { path = "macros", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev", default-features = false }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, features = [
"uuid",
] }
-bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, features = [
+bevy_tasks = { path = "../bevy_tasks", version = "0.17.0-dev", default-features = false, features = [
"async_executor",
] }
-bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false }
-bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [
+bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev", default-features = false }
+bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false, features = [
"std",
] }
@@ -54,10 +54,10 @@ parking_lot = { version = "0.12", default-features = false, features = [
"arc_lock",
"send_guard",
] }
-ron = { version = "0.8", default-features = false }
+ron = { version = "0.10", default-features = false }
serde = { version = "1", default-features = false, features = ["derive"] }
thiserror = { version = "2", default-features = false }
-derive_more = { version = "1", default-features = false, features = ["from"] }
+derive_more = { version = "2", default-features = false, features = ["from"] }
uuid = { version = "1.13.1", default-features = false, features = [
"v4",
"serde",
@@ -65,7 +65,7 @@ uuid = { version = "1.13.1", default-features = false, features = [
tracing = { version = "0.1", default-features = false }
[target.'cfg(target_os = "android")'.dependencies]
-bevy_window = { path = "../bevy_window", version = "0.16.0-dev" }
+bevy_window = { path = "../bevy_window", version = "0.17.0-dev" }
[target.'cfg(target_arch = "wasm32")'.dependencies]
# TODO: Assuming all wasm builds are for the browser. Require `no_std` support to break assumption.
@@ -78,13 +78,13 @@ web-sys = { version = "0.3", features = [
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
uuid = { version = "1.13.1", default-features = false, features = ["js"] }
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, features = [
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev", default-features = false, features = [
"web",
] }
-bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, features = [
+bevy_tasks = { path = "../bevy_tasks", version = "0.17.0-dev", default-features = false, features = [
"web",
] }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, features = [
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, features = [
"web",
] }
diff --git a/crates/bevy_asset/macros/Cargo.toml b/crates/bevy_asset/macros/Cargo.toml
index 4d99d228d3..0b525b3c1d 100644
--- a/crates/bevy_asset/macros/Cargo.toml
+++ b/crates/bevy_asset/macros/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy_asset_macros"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Derive implementations for bevy_asset"
homepage = "https://bevy.org"
@@ -12,7 +12,7 @@ keywords = ["bevy"]
proc-macro = true
[dependencies]
-bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.16.0-dev" }
+bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.17.0-dev" }
syn = "2.0"
proc-macro2 = "1.0"
diff --git a/crates/bevy_asset/macros/src/lib.rs b/crates/bevy_asset/macros/src/lib.rs
index 443bd09ab9..a7ea87b752 100644
--- a/crates/bevy_asset/macros/src/lib.rs
+++ b/crates/bevy_asset/macros/src/lib.rs
@@ -1,6 +1,7 @@
-#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+//! Macros for deriving asset traits.
+
use bevy_macro_utils::BevyManifest;
use proc_macro::{Span, TokenStream};
use quote::{format_ident, quote};
@@ -12,6 +13,7 @@ pub(crate) fn bevy_asset_path() -> Path {
const DEPENDENCY_ATTRIBUTE: &str = "dependency";
+/// Implement the `Asset` trait.
#[proc_macro_derive(Asset, attributes(dependency))]
pub fn derive_asset(input: TokenStream) -> TokenStream {
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))]
pub fn derive_asset_dependency_visitor(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
diff --git a/crates/bevy_asset/src/asset_changed.rs b/crates/bevy_asset/src/asset_changed.rs
index d314fa3fd6..b43a8625e7 100644
--- a/crates/bevy_asset/src/asset_changed.rs
+++ b/crates/bevy_asset/src/asset_changed.rs
@@ -158,9 +158,9 @@ unsafe impl WorldQuery for AssetChanged {
fetch
}
- unsafe fn init_fetch<'w>(
+ unsafe fn init_fetch<'w, 's>(
world: UnsafeWorldCell<'w>,
- state: &Self::State,
+ state: &'s Self::State,
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w> {
@@ -201,9 +201,9 @@ unsafe impl WorldQuery for AssetChanged {
const IS_DENSE: bool = <&A>::IS_DENSE;
- unsafe fn set_archetype<'w>(
+ unsafe fn set_archetype<'w, 's>(
fetch: &mut Self::Fetch<'w>,
- state: &Self::State,
+ state: &'s Self::State,
archetype: &'w Archetype,
table: &'w Table,
) {
@@ -215,7 +215,11 @@ unsafe impl WorldQuery for AssetChanged {
}
}
- 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 {
// SAFETY: We delegate to the inner `set_table` for `A`
unsafe {
@@ -265,6 +269,7 @@ unsafe impl QueryFilter for AssetChanged {
#[inline]
unsafe fn filter_fetch(
+ state: &Self::State,
fetch: &mut Self::Fetch<'_>,
entity: Entity,
table_row: TableRow,
@@ -272,7 +277,7 @@ unsafe impl QueryFilter for AssetChanged {
fetch.inner.as_mut().is_some_and(|inner| {
// SAFETY: We delegate to the inner `fetch` for `A`
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)
}
})
diff --git a/crates/bevy_asset/src/direct_access_ext.rs b/crates/bevy_asset/src/direct_access_ext.rs
index 792d523a30..e7e5b993de 100644
--- a/crates/bevy_asset/src/direct_access_ext.rs
+++ b/crates/bevy_asset/src/direct_access_ext.rs
@@ -20,6 +20,7 @@ pub trait DirectAssetAccessExt {
settings: impl Fn(&mut S) + Send + Sync + 'static,
) -> Handle;
}
+
impl DirectAssetAccessExt for World {
/// Insert an asset similarly to [`Assets::add`].
///
diff --git a/crates/bevy_asset/src/event.rs b/crates/bevy_asset/src/event.rs
index 087cb44b5a..42de19fe44 100644
--- a/crates/bevy_asset/src/event.rs
+++ b/crates/bevy_asset/src/event.rs
@@ -1,12 +1,12 @@
use crate::{Asset, AssetId, AssetLoadError, AssetPath, UntypedAssetId};
-use bevy_ecs::event::Event;
+use bevy_ecs::event::{BufferedEvent, Event};
use bevy_reflect::Reflect;
use core::fmt::Debug;
-/// An event emitted when a specific [`Asset`] fails to load.
+/// A [`BufferedEvent`] emitted when a specific [`Asset`] fails to load.
///
/// For an untyped equivalent, see [`UntypedAssetLoadFailedEvent`].
-#[derive(Event, Clone, Debug)]
+#[derive(Event, BufferedEvent, Clone, Debug)]
pub struct AssetLoadFailedEvent {
/// The stable identifier of the asset that failed to load.
pub id: AssetId,
@@ -24,7 +24,7 @@ impl AssetLoadFailedEvent {
}
/// An untyped version of [`AssetLoadFailedEvent`].
-#[derive(Event, Clone, Debug)]
+#[derive(Event, BufferedEvent, Clone, Debug)]
pub struct UntypedAssetLoadFailedEvent {
/// The stable identifier of the asset that failed to load.
pub id: UntypedAssetId,
@@ -44,9 +44,9 @@ impl From<&AssetLoadFailedEvent> for UntypedAssetLoadFailedEvent {
}
}
-/// Events that occur for a specific loaded [`Asset`], such as "value changed" events and "dependency" events.
+/// [`BufferedEvent`]s that occur for a specific loaded [`Asset`], such as "value changed" events and "dependency" events.
#[expect(missing_docs, reason = "Documenting the id fields is unhelpful.")]
-#[derive(Event, Reflect)]
+#[derive(Event, BufferedEvent, Reflect)]
pub enum AssetEvent {
/// Emitted whenever an [`Asset`] is added.
Added { id: AssetId },
diff --git a/crates/bevy_asset/src/io/embedded/embedded_watcher.rs b/crates/bevy_asset/src/io/embedded/embedded_watcher.rs
index f7fb56be74..06a0791a50 100644
--- a/crates/bevy_asset/src/io/embedded/embedded_watcher.rs
+++ b/crates/bevy_asset/src/io/embedded/embedded_watcher.rs
@@ -56,6 +56,7 @@ pub(crate) struct EmbeddedEventHandler {
dir: Dir,
last_event: Option,
}
+
impl FilesystemEventHandler for EmbeddedEventHandler {
fn begin(&mut self) {
self.last_event = None;
diff --git a/crates/bevy_asset/src/io/embedded/mod.rs b/crates/bevy_asset/src/io/embedded/mod.rs
index f6c44397fc..c49d55ca4a 100644
--- a/crates/bevy_asset/src/io/embedded/mod.rs
+++ b/crates/bevy_asset/src/io/embedded/mod.rs
@@ -141,16 +141,19 @@ impl EmbeddedAssetRegistry {
pub trait GetAssetServer {
fn get_asset_server(&self) -> &AssetServer;
}
+
impl GetAssetServer for App {
fn get_asset_server(&self) -> &AssetServer {
self.world().get_asset_server()
}
}
+
impl GetAssetServer for World {
fn get_asset_server(&self) -> &AssetServer {
self.resource()
}
}
+
impl GetAssetServer for AssetServer {
fn get_asset_server(&self) -> &AssetServer {
self
diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs
index de83f9aef6..35bb28d38c 100644
--- a/crates/bevy_asset/src/lib.rs
+++ b/crates/bevy_asset/src/lib.rs
@@ -264,7 +264,7 @@ pub struct AssetPlugin {
/// [`AssetSource`](io::AssetSource). Subfolders within these folders are also valid.
///
/// It is strongly discouraged to use [`Allow`](UnapprovedPathMode::Allow) if your
-/// app will include scripts or modding support, as it could allow allow arbitrary file
+/// app will include scripts or modding support, as it could allow arbitrary file
/// access for malicious code.
///
/// See [`AssetPath::is_unapproved`](crate::AssetPath::is_unapproved)
@@ -272,10 +272,10 @@ pub struct AssetPlugin {
pub enum UnapprovedPathMode {
/// Unapproved asset loading is allowed. This is strongly discouraged.
Allow,
- /// Fails to load any asset that is is unapproved, unless an override method is used, like
+ /// Fails to load any asset that is unapproved, unless an override method is used, like
/// [`AssetServer::load_override`].
Deny,
- /// Fails to load any asset that is is unapproved.
+ /// Fails to load any asset that is unapproved.
#[default]
Forbid,
}
diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs
index 50bbfb5dfc..24405f0657 100644
--- a/crates/bevy_asset/src/loader.rs
+++ b/crates/bevy_asset/src/loader.rs
@@ -344,7 +344,7 @@ impl<'a> LoadContext<'a> {
/// Begins a new labeled asset load. Use the returned [`LoadContext`] to load
/// dependencies for the new asset and call [`LoadContext::finish`] to finalize the asset load.
- /// When finished, make sure you call [`LoadContext::add_labeled_asset`] to add the results back to the parent
+ /// When finished, make sure you call [`LoadContext::add_loaded_labeled_asset`] to add the results back to the parent
/// context.
/// Prefer [`LoadContext::labeled_asset_scope`] when possible, which will automatically add
/// the labeled [`LoadContext`] back to the parent context.
@@ -360,7 +360,7 @@ impl<'a> LoadContext<'a> {
/// # let load_context: LoadContext = panic!();
/// let mut handles = Vec::new();
/// for i in 0..2 {
- /// let mut labeled = load_context.begin_labeled_asset();
+ /// let labeled = load_context.begin_labeled_asset();
/// handles.push(std::thread::spawn(move || {
/// (i.to_string(), labeled.finish(Image::default()))
/// }));
@@ -385,7 +385,7 @@ impl<'a> LoadContext<'a> {
/// [`LoadedAsset`], which is registered under the `label` label.
///
/// This exists to remove the need to manually call [`LoadContext::begin_labeled_asset`] and then manually register the
- /// result with [`LoadContext::add_labeled_asset`].
+ /// result with [`LoadContext::add_loaded_labeled_asset`].
///
/// See [`AssetPath`] for more on labeled assets.
pub fn labeled_asset_scope(
diff --git a/crates/bevy_asset/src/reflect.rs b/crates/bevy_asset/src/reflect.rs
index 5c436c1061..a3148cecb7 100644
--- a/crates/bevy_asset/src/reflect.rs
+++ b/crates/bevy_asset/src/reflect.rs
@@ -18,16 +18,16 @@ pub struct ReflectAsset {
handle_type_id: TypeId,
assets_resource_type_id: TypeId,
- get: fn(&World, UntypedHandle) -> Option<&dyn Reflect>,
+ get: fn(&World, UntypedAssetId) -> Option<&dyn Reflect>,
// SAFETY:
// - may only be called with an [`UnsafeWorldCell`] which can be used to access the corresponding `Assets` resource mutably
// - may only be used to access **at most one** access at once
- get_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>, UntypedHandle) -> Option<&mut dyn Reflect>,
+ get_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>, UntypedAssetId) -> Option<&mut dyn Reflect>,
add: fn(&mut World, &dyn PartialReflect) -> UntypedHandle,
- insert: fn(&mut World, UntypedHandle, &dyn PartialReflect),
+ insert: fn(&mut World, UntypedAssetId, &dyn PartialReflect),
len: fn(&World) -> usize,
ids: for<'w> fn(&'w World) -> Box + 'w>,
- remove: fn(&mut World, UntypedHandle) -> Option>,
+ remove: fn(&mut World, UntypedAssetId) -> Option>,
}
impl ReflectAsset {
@@ -42,15 +42,19 @@ impl ReflectAsset {
}
/// Equivalent of [`Assets::get`]
- pub fn get<'w>(&self, world: &'w World, handle: UntypedHandle) -> Option<&'w dyn Reflect> {
- (self.get)(world, handle)
+ pub fn get<'w>(
+ &self,
+ world: &'w World,
+ asset_id: impl Into,
+ ) -> Option<&'w dyn Reflect> {
+ (self.get)(world, asset_id.into())
}
/// Equivalent of [`Assets::get_mut`]
pub fn get_mut<'w>(
&self,
world: &'w mut World,
- handle: UntypedHandle,
+ asset_id: impl Into,
) -> Option<&'w mut dyn Reflect> {
// SAFETY: unique world access
#[expect(
@@ -58,7 +62,7 @@ impl ReflectAsset {
reason = "Use of unsafe `Self::get_unchecked_mut()` function."
)]
unsafe {
- (self.get_unchecked_mut)(world.as_unsafe_world_cell(), handle)
+ (self.get_unchecked_mut)(world.as_unsafe_world_cell(), asset_id.into())
}
}
@@ -76,8 +80,8 @@ impl ReflectAsset {
/// # let handle_1: UntypedHandle = unimplemented!();
/// # let handle_2: UntypedHandle = unimplemented!();
/// let unsafe_world_cell = world.as_unsafe_world_cell();
- /// let a = unsafe { reflect_asset.get_unchecked_mut(unsafe_world_cell, handle_1).unwrap() };
- /// let b = unsafe { reflect_asset.get_unchecked_mut(unsafe_world_cell, handle_2).unwrap() };
+ /// let a = unsafe { reflect_asset.get_unchecked_mut(unsafe_world_cell, &handle_1).unwrap() };
+ /// let b = unsafe { reflect_asset.get_unchecked_mut(unsafe_world_cell, &handle_2).unwrap() };
/// // ^ not allowed, two mutable references through the same asset resource, even though the
/// // handles are distinct
///
@@ -96,10 +100,10 @@ impl ReflectAsset {
pub unsafe fn get_unchecked_mut<'w>(
&self,
world: UnsafeWorldCell<'w>,
- handle: UntypedHandle,
+ asset_id: impl Into,
) -> Option<&'w mut dyn Reflect> {
// SAFETY: requirements are deferred to the caller
- unsafe { (self.get_unchecked_mut)(world, handle) }
+ unsafe { (self.get_unchecked_mut)(world, asset_id.into()) }
}
/// Equivalent of [`Assets::add`]
@@ -107,13 +111,22 @@ impl ReflectAsset {
(self.add)(world, value)
}
/// Equivalent of [`Assets::insert`]
- pub fn insert(&self, world: &mut World, handle: UntypedHandle, value: &dyn PartialReflect) {
- (self.insert)(world, handle, value);
+ pub fn insert(
+ &self,
+ world: &mut World,
+ asset_id: impl Into,
+ value: &dyn PartialReflect,
+ ) {
+ (self.insert)(world, asset_id.into(), value);
}
/// Equivalent of [`Assets::remove`]
- pub fn remove(&self, world: &mut World, handle: UntypedHandle) -> Option> {
- (self.remove)(world, handle)
+ pub fn remove(
+ &self,
+ world: &mut World,
+ asset_id: impl Into,
+ ) -> Option> {
+ (self.remove)(world, asset_id.into())
}
/// Equivalent of [`Assets::len`]
@@ -137,17 +150,17 @@ impl FromType for ReflectAsset {
ReflectAsset {
handle_type_id: TypeId::of::>(),
assets_resource_type_id: TypeId::of::>(),
- get: |world, handle| {
+ get: |world, asset_id| {
let assets = world.resource::>();
- let asset = assets.get(&handle.typed_debug_checked());
+ let asset = assets.get(asset_id.typed_debug_checked());
asset.map(|asset| asset as &dyn Reflect)
},
- get_unchecked_mut: |world, handle| {
+ get_unchecked_mut: |world, asset_id| {
// SAFETY: `get_unchecked_mut` must be called with `UnsafeWorldCell` having access to `Assets`,
// and must ensure to only have at most one reference to it live at all times.
#[expect(unsafe_code, reason = "Uses `UnsafeWorldCell::get_resource_mut()`.")]
let assets = unsafe { world.get_resource_mut::>().unwrap().into_inner() };
- let asset = assets.get_mut(&handle.typed_debug_checked());
+ let asset = assets.get_mut(asset_id.typed_debug_checked());
asset.map(|asset| asset as &mut dyn Reflect)
},
add: |world, value| {
@@ -156,11 +169,11 @@ impl FromType for ReflectAsset {
.expect("could not call `FromReflect::from_reflect` in `ReflectAsset::add`");
assets.add(value).untyped()
},
- insert: |world, handle, value| {
+ insert: |world, asset_id, value| {
let mut assets = world.resource_mut::>();
let value: A = FromReflect::from_reflect(value)
.expect("could not call `FromReflect::from_reflect` in `ReflectAsset::set`");
- assets.insert(&handle.typed_debug_checked(), value);
+ assets.insert(asset_id.typed_debug_checked(), value);
},
len: |world| {
let assets = world.resource::>();
@@ -170,9 +183,9 @@ impl FromType for ReflectAsset {
let assets = world.resource::>();
Box::new(assets.ids().map(AssetId::untyped))
},
- remove: |world, handle| {
+ remove: |world, asset_id| {
let mut assets = world.resource_mut::>();
- let value = assets.remove(&handle.typed_debug_checked());
+ let value = assets.remove(asset_id.typed_debug_checked());
value.map(|value| Box::new(value) as Box)
},
}
@@ -200,7 +213,7 @@ impl FromType for ReflectAsset {
/// let reflect_asset = type_registry.get_type_data::(reflect_handle.asset_type_id()).unwrap();
///
/// let handle = reflect_handle.downcast_handle_untyped(handle.as_any()).unwrap();
-/// let value = reflect_asset.get(world, handle).unwrap();
+/// let value = reflect_asset.get(world, &handle).unwrap();
/// println!("{value:?}");
/// }
/// ```
@@ -210,6 +223,7 @@ pub struct ReflectHandle {
downcast_handle_untyped: fn(&dyn Any) -> Option,
typed: fn(UntypedHandle) -> Box,
}
+
impl ReflectHandle {
/// The [`TypeId`] of the asset
pub fn asset_type_id(&self) -> TypeId {
@@ -247,7 +261,7 @@ mod tests {
use alloc::{string::String, vec::Vec};
use core::any::TypeId;
- use crate::{Asset, AssetApp, AssetPlugin, ReflectAsset, UntypedHandle};
+ use crate::{Asset, AssetApp, AssetPlugin, ReflectAsset};
use bevy_app::App;
use bevy_ecs::reflect::AppTypeRegistry;
use bevy_reflect::Reflect;
@@ -281,7 +295,7 @@ mod tests {
let handle = reflect_asset.add(app.world_mut(), &value);
// struct is a reserved keyword, so we can't use it here
let strukt = reflect_asset
- .get_mut(app.world_mut(), handle)
+ .get_mut(app.world_mut(), &handle)
.unwrap()
.reflect_mut()
.as_struct()
@@ -294,16 +308,12 @@ mod tests {
assert_eq!(reflect_asset.len(app.world()), 1);
let ids: Vec<_> = reflect_asset.ids(app.world()).collect();
assert_eq!(ids.len(), 1);
+ let id = ids[0];
- let fetched_handle = UntypedHandle::Weak(ids[0]);
- let asset = reflect_asset
- .get(app.world(), fetched_handle.clone_weak())
- .unwrap();
+ let asset = reflect_asset.get(app.world(), id).unwrap();
assert_eq!(asset.downcast_ref::().unwrap().field, "edited");
- reflect_asset
- .remove(app.world_mut(), fetched_handle)
- .unwrap();
+ reflect_asset.remove(app.world_mut(), id).unwrap();
assert_eq!(reflect_asset.len(app.world()), 0);
}
}
diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs
index 2b3898cd54..e5020dba75 100644
--- a/crates/bevy_asset/src/server/mod.rs
+++ b/crates/bevy_asset/src/server/mod.rs
@@ -1931,7 +1931,7 @@ pub enum AssetLoadError {
base_path,
label,
all_labels.len(),
- all_labels.iter().map(|l| format!("'{}'", l)).collect::>().join(", "))]
+ all_labels.iter().map(|l| format!("'{l}'")).collect::>().join(", "))]
MissingLabel {
base_path: AssetPath<'static>,
label: String,
@@ -1953,6 +1953,14 @@ impl AssetLoaderError {
pub fn path(&self) -> &AssetPath<'static> {
&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`.
diff --git a/crates/bevy_audio/Cargo.toml b/crates/bevy_audio/Cargo.toml
index aff7f83b37..2ffa62db9d 100644
--- a/crates/bevy_audio/Cargo.toml
+++ b/crates/bevy_audio/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy_audio"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Provides audio functionality for Bevy Engine"
homepage = "https://bevy.org"
@@ -10,30 +10,36 @@ keywords = ["bevy"]
[dependencies]
# bevy
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
-bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
-bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
-bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
-bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev" }
+bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" }
+bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" }
+bevy_transform = { path = "../bevy_transform", version = "0.17.0-dev" }
+bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
# other
+# TODO: Remove `coreaudio-sys` dep below when updating `cpal`.
rodio = { version = "0.20", default-features = false }
tracing = { version = "0.1", default-features = false, features = ["std"] }
[target.'cfg(target_os = "android")'.dependencies]
cpal = { version = "0.15", optional = true }
+[target.'cfg(target_vendor = "apple")'.dependencies]
+# NOTE: Explicitly depend on this patch version to fix:
+# https://github.com/bevyengine/bevy/issues/18893
+coreaudio-sys = { version = "0.2.17", default-features = false }
+
[target.'cfg(target_arch = "wasm32")'.dependencies]
# TODO: Assuming all wasm builds are for the browser. Require `no_std` support to break assumption.
rodio = { version = "0.20", default-features = false, features = [
"wasm-bindgen",
] }
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, features = [
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev", default-features = false, features = [
"web",
] }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, features = [
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, features = [
"web",
] }
diff --git a/crates/bevy_audio/src/audio_output.rs b/crates/bevy_audio/src/audio_output.rs
index 9fc757af44..d02d326501 100644
--- a/crates/bevy_audio/src/audio_output.rs
+++ b/crates/bevy_audio/src/audio_output.rs
@@ -57,6 +57,7 @@ pub struct PlaybackRemoveMarker;
pub(crate) struct EarPositions<'w, 's> {
pub(crate) query: Query<'w, 's, (Entity, &'static GlobalTransform, &'static SpatialListener)>,
}
+
impl<'w, 's> EarPositions<'w, 's> {
/// Gets a set of transformed ear positions.
///
diff --git a/crates/bevy_audio/src/volume.rs b/crates/bevy_audio/src/volume.rs
index 1f1f417594..b8c0c776a5 100644
--- a/crates/bevy_audio/src/volume.rs
+++ b/crates/bevy_audio/src/volume.rs
@@ -344,17 +344,11 @@ mod tests {
assert!(
db_delta.abs() < 1e-2,
- "Expected ~{}dB, got {}dB (delta {})",
- db,
- db_test,
- db_delta
+ "Expected ~{db}dB, got {db_test}dB (delta {db_delta})",
);
assert!(
linear_relative_delta.abs() < 1e-3,
- "Expected ~{}, got {} (relative delta {})",
- linear,
- linear_test,
- linear_relative_delta
+ "Expected ~{linear}, got {linear_test} (relative delta {linear_relative_delta})",
);
}
}
@@ -474,15 +468,11 @@ mod tests {
match (a, b) {
(Decibels(a), Decibels(b)) | (Linear(a), Linear(b)) => assert!(
(a - b).abs() < EPSILON,
- "Expected {:?} to be approximately equal to {:?}",
- a,
- b
+ "Expected {a:?} to be approximately equal to {b:?}",
),
(a, b) => assert!(
(a.to_decibels() - b.to_decibels()).abs() < EPSILON,
- "Expected {:?} to be approximately equal to {:?}",
- a,
- b
+ "Expected {a:?} to be approximately equal to {b:?}",
),
}
}
diff --git a/crates/bevy_color/Cargo.toml b/crates/bevy_color/Cargo.toml
index ca7a7a74f5..22ade12709 100644
--- a/crates/bevy_color/Cargo.toml
+++ b/crates/bevy_color/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy_color"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Types for representing and manipulating color values"
homepage = "https://bevy.org"
@@ -10,17 +10,17 @@ keywords = ["bevy", "color"]
rust-version = "1.85.0"
[dependencies]
-bevy_math = { path = "../bevy_math", version = "0.16.0-dev", default-features = false, features = [
+bevy_math = { path = "../bevy_math", version = "0.17.0-dev", default-features = false, features = [
"curve",
] }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, optional = true }
bytemuck = { version = "1", features = ["derive"] }
serde = { version = "1.0", features = [
"derive",
], default-features = false, optional = true }
thiserror = { version = "2", default-features = false }
-derive_more = { version = "1", default-features = false, features = ["from"] }
-wgpu-types = { version = "24", default-features = false, optional = true }
+derive_more = { version = "2", default-features = false, features = ["from"] }
+wgpu-types = { version = "25", default-features = false, optional = true }
encase = { version = "0.10", default-features = false, optional = true }
[features]
diff --git a/crates/bevy_color/src/hsla.rs b/crates/bevy_color/src/hsla.rs
index b29fce72ac..1579519274 100644
--- a/crates/bevy_color/src/hsla.rs
+++ b/crates/bevy_color/src/hsla.rs
@@ -92,7 +92,7 @@ impl Hsla {
/// // Palette with 5 distinct hues
/// let palette = (0..5).map(Hsla::sequential_dispersed).collect::>();
/// ```
- pub fn sequential_dispersed(index: u32) -> Self {
+ pub const fn sequential_dispersed(index: u32) -> Self {
const FRAC_U32MAX_GOLDEN_RATIO: u32 = 2654435769; // (u32::MAX / Φ) rounded up
const RATIO_360: f32 = 360.0 / u32::MAX as f32;
diff --git a/crates/bevy_color/src/lcha.rs b/crates/bevy_color/src/lcha.rs
index e5f5ecab32..2a3b115bb3 100644
--- a/crates/bevy_color/src/lcha.rs
+++ b/crates/bevy_color/src/lcha.rs
@@ -96,7 +96,7 @@ impl Lcha {
/// // Palette with 5 distinct hues
/// let palette = (0..5).map(Lcha::sequential_dispersed).collect::>();
/// ```
- pub fn sequential_dispersed(index: u32) -> Self {
+ pub const fn sequential_dispersed(index: u32) -> Self {
const FRAC_U32MAX_GOLDEN_RATIO: u32 = 2654435769; // (u32::MAX / Φ) rounded up
const RATIO_360: f32 = 360.0 / u32::MAX as f32;
diff --git a/crates/bevy_color/src/oklcha.rs b/crates/bevy_color/src/oklcha.rs
index 91ffe422c7..ba52a519ae 100644
--- a/crates/bevy_color/src/oklcha.rs
+++ b/crates/bevy_color/src/oklcha.rs
@@ -92,7 +92,7 @@ impl Oklcha {
/// // Palette with 5 distinct hues
/// let palette = (0..5).map(Oklcha::sequential_dispersed).collect::>();
/// ```
- pub fn sequential_dispersed(index: u32) -> Self {
+ pub const fn sequential_dispersed(index: u32) -> Self {
const FRAC_U32MAX_GOLDEN_RATIO: u32 = 2654435769; // (u32::MAX / Φ) rounded up
const RATIO_360: f32 = 360.0 / u32::MAX as f32;
diff --git a/crates/bevy_core_pipeline/Cargo.toml b/crates/bevy_core_pipeline/Cargo.toml
index 2d903d2cc4..9b3f158af2 100644
--- a/crates/bevy_core_pipeline/Cargo.toml
+++ b/crates/bevy_core_pipeline/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bevy_core_pipeline"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
authors = [
"Bevy Contributors ",
@@ -20,20 +20,20 @@ tonemapping_luts = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"]
[dependencies]
# bevy
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
-bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
-bevy_color = { path = "../bevy_color", version = "0.16.0-dev" }
-bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
-bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
-bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
-bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
-bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
-bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
-bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
-bevy_window = { path = "../bevy_window", version = "0.16.0-dev" }
-bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev" }
+bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" }
+bevy_color = { path = "../bevy_color", version = "0.17.0-dev" }
+bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
+bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" }
+bevy_image = { path = "../bevy_image", version = "0.17.0-dev" }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" }
+bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
+bevy_transform = { path = "../bevy_transform", version = "0.17.0-dev" }
+bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
+bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev" }
+bevy_window = { path = "../bevy_window", version = "0.17.0-dev" }
+bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false, features = [
"std",
"serialize",
] }
diff --git a/crates/bevy_core_pipeline/src/auto_exposure/compensation_curve.rs b/crates/bevy_core_pipeline/src/auto_exposure/compensation_curve.rs
index e2ffe1a6c4..8b6d2593c9 100644
--- a/crates/bevy_core_pipeline/src/auto_exposure/compensation_curve.rs
+++ b/crates/bevy_core_pipeline/src/auto_exposure/compensation_curve.rs
@@ -196,6 +196,7 @@ impl RenderAsset for GpuAutoExposureCompensationCurve {
source: Self::SourceAsset,
_: AssetId,
(render_device, render_queue): &mut SystemParamItem,
+ _: Option<&Self>,
) -> Result> {
let texture = render_device.create_texture_with_data(
render_queue,
diff --git a/crates/bevy_core_pipeline/src/blit/mod.rs b/crates/bevy_core_pipeline/src/blit/mod.rs
index 111b6e443b..8dc655e91f 100644
--- a/crates/bevy_core_pipeline/src/blit/mod.rs
+++ b/crates/bevy_core_pipeline/src/blit/mod.rs
@@ -10,7 +10,7 @@ use bevy_render::{
RenderApp,
};
-use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
+use crate::FullscreenShader;
/// Adds support for specialized "blit pipelines", which can be used to write one texture to another.
pub struct BlitPlugin;
@@ -38,7 +38,8 @@ impl Plugin for BlitPlugin {
pub struct BlitPipeline {
pub texture_bind_group: BindGroupLayout,
pub sampler: Sampler,
- pub shader: Handle,
+ pub fullscreen_shader: FullscreenShader,
+ pub fragment_shader: Handle,
}
impl FromWorld for BlitPipeline {
@@ -61,7 +62,8 @@ impl FromWorld for BlitPipeline {
BlitPipeline {
texture_bind_group,
sampler,
- shader: load_embedded_asset!(render_world, "blit.wgsl"),
+ fullscreen_shader: render_world.resource::().clone(),
+ fragment_shader: load_embedded_asset!(render_world, "blit.wgsl"),
}
}
}
@@ -80,9 +82,9 @@ impl SpecializedRenderPipeline for BlitPipeline {
RenderPipelineDescriptor {
label: Some("blit pipeline".into()),
layout: vec![self.texture_bind_group.clone()],
- vertex: fullscreen_shader_vertex_state(),
+ vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
- shader: self.shader.clone(),
+ shader: self.fragment_shader.clone(),
shader_defs: vec![],
entry_point: "fs_main".into(),
targets: vec![Some(ColorTargetState {
diff --git a/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs b/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs
index 88da2db0cc..201d5a6cbd 100644
--- a/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs
+++ b/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs
@@ -1,5 +1,6 @@
+use crate::FullscreenShader;
+
use super::{Bloom, BLOOM_TEXTURE_FORMAT};
-use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use bevy_asset::{load_embedded_asset, Handle};
use bevy_ecs::{
prelude::{Component, Entity},
@@ -27,8 +28,10 @@ pub struct BloomDownsamplingPipeline {
/// Layout with a texture, a sampler, and uniforms
pub bind_group_layout: BindGroupLayout,
pub sampler: Sampler,
- /// The shader asset handle.
- pub shader: Handle,
+ /// The asset handle for the fullscreen vertex shader.
+ pub fullscreen_shader: FullscreenShader,
+ /// The fragment shader asset handle.
+ pub fragment_shader: Handle,
}
#[derive(PartialEq, Eq, Hash, Clone)]
@@ -81,7 +84,8 @@ impl FromWorld for BloomDownsamplingPipeline {
BloomDownsamplingPipeline {
bind_group_layout,
sampler,
- shader: load_embedded_asset!(world, "bloom.wgsl"),
+ fullscreen_shader: world.resource::().clone(),
+ fragment_shader: load_embedded_asset!(world, "bloom.wgsl"),
}
}
}
@@ -122,9 +126,9 @@ impl SpecializedRenderPipeline for BloomDownsamplingPipeline {
.into(),
),
layout,
- vertex: fullscreen_shader_vertex_state(),
+ vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
- shader: self.shader.clone(),
+ shader: self.fragment_shader.clone(),
shader_defs,
entry_point,
targets: vec![Some(ColorTargetState {
diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs
index 10ffdf9c63..65e51c8472 100644
--- a/crates/bevy_core_pipeline/src/bloom/mod.rs
+++ b/crates/bevy_core_pipeline/src/bloom/mod.rs
@@ -121,7 +121,7 @@ impl ViewNode for BloomNode {
bloom_settings,
upsampling_pipeline_ids,
downsampling_pipeline_ids,
- ): QueryItem<'w, Self::ViewQuery>,
+ ): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
if bloom_settings.intensity == 0.0 {
diff --git a/crates/bevy_core_pipeline/src/bloom/settings.rs b/crates/bevy_core_pipeline/src/bloom/settings.rs
index 195c2eb4c0..435ed037b5 100644
--- a/crates/bevy_core_pipeline/src/bloom/settings.rs
+++ b/crates/bevy_core_pipeline/src/bloom/settings.rs
@@ -227,7 +227,7 @@ impl ExtractComponent for Bloom {
type QueryFilter = With;
type Out = (Self, BloomUniforms);
- fn extract_component((bloom, camera): QueryItem<'_, Self::QueryData>) -> Option {
+ fn extract_component((bloom, camera): QueryItem<'_, '_, Self::QueryData>) -> Option {
match (
camera.physical_viewport_rect(),
camera.physical_viewport_size(),
diff --git a/crates/bevy_core_pipeline/src/bloom/upsampling_pipeline.rs b/crates/bevy_core_pipeline/src/bloom/upsampling_pipeline.rs
index f381e664a9..c49a9d5b16 100644
--- a/crates/bevy_core_pipeline/src/bloom/upsampling_pipeline.rs
+++ b/crates/bevy_core_pipeline/src/bloom/upsampling_pipeline.rs
@@ -1,7 +1,8 @@
+use crate::FullscreenShader;
+
use super::{
downsampling_pipeline::BloomUniforms, Bloom, BloomCompositeMode, BLOOM_TEXTURE_FORMAT,
};
-use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use bevy_asset::{load_embedded_asset, Handle};
use bevy_ecs::{
prelude::{Component, Entity},
@@ -27,8 +28,10 @@ pub struct UpsamplingPipelineIds {
#[derive(Resource)]
pub struct BloomUpsamplingPipeline {
pub bind_group_layout: BindGroupLayout,
- /// The shader asset handle.
- pub shader: Handle,
+ /// The asset handle for the fullscreen vertex shader.
+ pub fullscreen_shader: FullscreenShader,
+ /// The fragment shader asset handle.
+ pub fragment_shader: Handle,
}
#[derive(PartialEq, Eq, Hash, Clone)]
@@ -58,7 +61,8 @@ impl FromWorld for BloomUpsamplingPipeline {
BloomUpsamplingPipeline {
bind_group_layout,
- shader: load_embedded_asset!(world, "bloom.wgsl"),
+ fullscreen_shader: world.resource::().clone(),
+ fragment_shader: load_embedded_asset!(world, "bloom.wgsl"),
}
}
}
@@ -108,9 +112,9 @@ impl SpecializedRenderPipeline for BloomUpsamplingPipeline {
RenderPipelineDescriptor {
label: Some("bloom_upsampling_pipeline".into()),
layout: vec![self.bind_group_layout.clone()],
- vertex: fullscreen_shader_vertex_state(),
+ vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
- shader: self.shader.clone(),
+ shader: self.fragment_shader.clone(),
shader_defs: vec![],
entry_point: "upsample".into(),
targets: vec![Some(ColorTargetState {
diff --git a/crates/bevy_core_pipeline/src/core_2d/main_opaque_pass_2d_node.rs b/crates/bevy_core_pipeline/src/core_2d/main_opaque_pass_2d_node.rs
index 60f355c115..e8cd0c65c6 100644
--- a/crates/bevy_core_pipeline/src/core_2d/main_opaque_pass_2d_node.rs
+++ b/crates/bevy_core_pipeline/src/core_2d/main_opaque_pass_2d_node.rs
@@ -31,7 +31,7 @@ impl ViewNode for MainOpaquePass2dNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
- (camera, view, target, depth): QueryItem<'w, Self::ViewQuery>,
+ (camera, view, target, depth): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let (Some(opaque_phases), Some(alpha_mask_phases)) = (
diff --git a/crates/bevy_core_pipeline/src/core_2d/main_transparent_pass_2d_node.rs b/crates/bevy_core_pipeline/src/core_2d/main_transparent_pass_2d_node.rs
index 494d4d0f89..4054283a57 100644
--- a/crates/bevy_core_pipeline/src/core_2d/main_transparent_pass_2d_node.rs
+++ b/crates/bevy_core_pipeline/src/core_2d/main_transparent_pass_2d_node.rs
@@ -28,7 +28,7 @@ impl ViewNode for MainTransparentPass2dNode {
&self,
graph: &mut RenderGraphContext,
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,
) -> Result<(), NodeRunError> {
let Some(transparent_phases) =
diff --git a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs
index 9bcb2b4f80..f5314c736d 100644
--- a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs
+++ b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs
@@ -80,6 +80,7 @@ impl From for Camera3dDepthTextureUsage {
Self(value.bits())
}
}
+
impl From for TextureUsages {
fn from(value: Camera3dDepthTextureUsage) -> Self {
Self::from_bits_truncate(value.0)
diff --git a/crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rs b/crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rs
index 3b1bc96c90..b19268ac1f 100644
--- a/crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rs
+++ b/crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rs
@@ -45,7 +45,7 @@ impl ViewNode for MainOpaquePass3dNode {
skybox_pipeline,
skybox_bind_group,
view_uniform_offset,
- ): QueryItem<'w, Self::ViewQuery>,
+ ): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let (Some(opaque_phases), Some(alpha_mask_phases)) = (
diff --git a/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs b/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs
index 0e9465aafa..2cf44a4015 100644
--- a/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs
+++ b/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs
@@ -1,6 +1,6 @@
use crate::{
- fullscreen_vertex_shader::fullscreen_shader_vertex_state,
prepass::{DeferredPrepass, ViewPrepassTextures},
+ FullscreenShader,
};
use bevy_app::prelude::*;
use bevy_asset::{embedded_asset, load_embedded_asset};
@@ -130,6 +130,7 @@ impl FromWorld for CopyDeferredLightingIdPipeline {
),
);
+ let vertex_state = world.resource::().to_vertex_state();
let shader = load_embedded_asset!(world, "copy_deferred_lighting_id.wgsl");
let pipeline_id =
@@ -138,7 +139,7 @@ impl FromWorld for CopyDeferredLightingIdPipeline {
.queue_render_pipeline(RenderPipelineDescriptor {
label: Some("copy_deferred_lighting_id_pipeline".into()),
layout: vec![layout.clone()],
- vertex: fullscreen_shader_vertex_state(),
+ vertex: vertex_state,
fragment: Some(FragmentState {
shader,
shader_defs: vec![],
diff --git a/crates/bevy_core_pipeline/src/deferred/node.rs b/crates/bevy_core_pipeline/src/deferred/node.rs
index ffac1eec6d..e786d2a222 100644
--- a/crates/bevy_core_pipeline/src/deferred/node.rs
+++ b/crates/bevy_core_pipeline/src/deferred/node.rs
@@ -36,7 +36,7 @@ impl ViewNode for EarlyDeferredGBufferPrepassNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
- view_query: QueryItem<'w, Self::ViewQuery>,
+ view_query: QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
run_deferred_prepass(
@@ -74,7 +74,7 @@ impl ViewNode for LateDeferredGBufferPrepassNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
- view_query: QueryItem<'w, Self::ViewQuery>,
+ view_query: QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let (_, _, _, _, occlusion_culling, no_indirect_drawing) = view_query;
@@ -107,6 +107,7 @@ fn run_deferred_prepass<'w>(
render_context: &mut RenderContext<'w>,
(camera, extracted_view, view_depth_texture, view_prepass_textures, _, _): QueryItem<
'w,
+ '_,
::ViewQuery,
>,
is_late: bool,
diff --git a/crates/bevy_core_pipeline/src/dof/mod.rs b/crates/bevy_core_pipeline/src/dof/mod.rs
index 38f5e1e796..7e2f52e3fc 100644
--- a/crates/bevy_core_pipeline/src/dof/mod.rs
+++ b/crates/bevy_core_pipeline/src/dof/mod.rs
@@ -66,7 +66,7 @@ use crate::{
graph::{Core3d, Node3d},
Camera3d, DEPTH_TEXTURE_SAMPLING_SUPPORTED,
},
- fullscreen_vertex_shader::fullscreen_shader_vertex_state,
+ FullscreenShader,
};
/// A plugin that adds support for the depth of field effect to Bevy.
@@ -325,8 +325,10 @@ pub struct DepthOfFieldPipeline {
/// The bind group layout shared among all invocations of the depth of field
/// shader.
global_bind_group_layout: BindGroupLayout,
- /// The shader asset handle.
- shader: Handle,
+ /// The asset handle for the fullscreen vertex shader.
+ fullscreen_shader: FullscreenShader,
+ /// The fragment shader asset handle.
+ fragment_shader: Handle,
}
impl ViewNode for DepthOfFieldNode {
@@ -352,7 +354,7 @@ impl ViewNode for DepthOfFieldNode {
view_bind_group_layouts,
depth_of_field_uniform_index,
auxiliary_dof_texture,
- ): QueryItem<'w, Self::ViewQuery>,
+ ): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::();
@@ -678,13 +680,15 @@ pub fn prepare_depth_of_field_pipelines(
&ViewDepthOfFieldBindGroupLayouts,
&Msaa,
)>,
+ fullscreen_shader: Res,
asset_server: Res,
) {
for (entity, view, depth_of_field, view_bind_group_layouts, msaa) in view_targets.iter() {
let dof_pipeline = DepthOfFieldPipeline {
view_bind_group_layouts: view_bind_group_layouts.clone(),
global_bind_group_layout: global_bind_group_layout.layout.clone(),
- shader: load_embedded_asset!(asset_server.as_ref(), "dof.wgsl"),
+ fullscreen_shader: fullscreen_shader.clone(),
+ fragment_shader: load_embedded_asset!(asset_server.as_ref(), "dof.wgsl"),
};
// We'll need these two flags to create the `DepthOfFieldPipelineKey`s.
@@ -797,12 +801,12 @@ impl SpecializedRenderPipeline for DepthOfFieldPipeline {
label: Some("depth of field pipeline".into()),
layout,
push_constant_ranges: vec![],
- vertex: fullscreen_shader_vertex_state(),
+ vertex: self.fullscreen_shader.to_vertex_state(),
primitive: default(),
depth_stencil: None,
multisample: default(),
fragment: Some(FragmentState {
- shader: self.shader.clone(),
+ shader: self.fragment_shader.clone(),
shader_defs,
entry_point: match key.pass {
DofPass::GaussianHorizontal => "gaussian_horizontal".into(),
diff --git a/crates/bevy_core_pipeline/src/fullscreen_vertex_shader/mod.rs b/crates/bevy_core_pipeline/src/fullscreen_vertex_shader/mod.rs
index fee17d1ec6..de8aa856c9 100644
--- a/crates/bevy_core_pipeline/src/fullscreen_vertex_shader/mod.rs
+++ b/crates/bevy_core_pipeline/src/fullscreen_vertex_shader/mod.rs
@@ -1,25 +1,40 @@
-use bevy_asset::{weak_handle, Handle};
+use bevy_asset::{load_embedded_asset, Handle};
+use bevy_ecs::{resource::Resource, world::FromWorld};
use bevy_render::{prelude::Shader, render_resource::VertexState};
-pub const FULLSCREEN_SHADER_HANDLE: Handle =
- weak_handle!("481fb759-d0b1-4175-8319-c439acde30a2");
+/// A shader that renders to the whole screen. Useful for post-processing.
+#[derive(Resource, Clone)]
+pub struct FullscreenShader(Handle