From 97131e1909f8047b5268d9b863e62b9f7d279c89 Mon Sep 17 00:00:00 2001
From: BD103 <59022059+BD103@users.noreply.github.com>
Date: Tue, 2 Apr 2024 21:29:06 -0400
Subject: [PATCH 1/4] Move `close_on_esc` to `bevy_dev_tools` (#12855)
# Objective
- As @james7132 said [on
Discord](https://discord.com/channels/691052431525675048/692572690833473578/1224626740773523536),
the `close_on_esc` system is forcing `bevy_window` to depend on
`bevy_input`.
- `close_on_esc` is not likely to be used in production, so it arguably
does not have a place in `bevy_window`.
## Solution
- As suggested by @afonsolage, move `close_on_esc` into
`bevy_dev_tools`.
- Add an example to the documentation too.
- Remove `bevy_window`'s dependency on `bevy_input`.
- Add `bevy_reflect`'s `smol_str` feature to `bevy_window` because it
was implicitly depended upon with `bevy_input` before it was removed.
- Remove any usage of `close_on_esc` from the examples.
- `bevy_dev_tools` is not enabled by default. I personally find it
frustrating to run examples with additional features, so I opted to
remove it entirely.
- This is up for discussion if you have an alternate solution.
---
## Changelog
- Moved `bevy_window::close_on_esc` to `bevy_dev_tools::close_on_esc`.
- Removed usage of `bevy_dev_tools::close_on_esc` from all examples.
## Migration Guide
`bevy_window::close_on_esc` has been moved to
`bevy_dev_tools::close_on_esc`. You will first need to enable
`bevy_dev_tools` as a feature in your `Cargo.toml`:
```toml
[dependencies]
bevy = { version = "0.14", features = ["bevy_dev_tools"] }
```
Finally, modify any imports to use `bevy_dev_tools` instead:
```rust
// Old:
// use bevy::window::close_on_esc;
// New:
use bevy::dev_tools::close_on_esc;
App::new()
.add_systems(Update, close_on_esc)
// ...
.run();
```
---
crates/bevy_dev_tools/src/close_on_esc.rs | 32 +++++++++++++++++++++++
crates/bevy_dev_tools/src/lib.rs | 5 ++++
crates/bevy_window/Cargo.toml | 3 +--
crates/bevy_window/src/event.rs | 5 ++--
crates/bevy_window/src/system.rs | 20 --------------
crates/bevy_window/src/window.rs | 2 +-
examples/2d/rotation.rs | 1 -
examples/3d/parallax_mapping.rs | 3 +--
examples/games/alien_cake_addict.rs | 5 +---
examples/games/breakout.rs | 2 +-
examples/window/multiple_windows.rs | 1 -
tests/window/resizing.rs | 9 +------
12 files changed, 45 insertions(+), 43 deletions(-)
create mode 100644 crates/bevy_dev_tools/src/close_on_esc.rs
diff --git a/crates/bevy_dev_tools/src/close_on_esc.rs b/crates/bevy_dev_tools/src/close_on_esc.rs
new file mode 100644
index 0000000000000..a3245caed8ffa
--- /dev/null
+++ b/crates/bevy_dev_tools/src/close_on_esc.rs
@@ -0,0 +1,32 @@
+use bevy_ecs::prelude::*;
+use bevy_input::{keyboard::KeyCode, ButtonInput};
+use bevy_window::Window;
+
+/// Close the focused window whenever the escape key (Esc) is pressed
+///
+/// This is useful for examples or prototyping.
+///
+/// # Example
+///
+/// ```no_run
+/// # use bevy_app::prelude::*;
+/// # use bevy_dev_tools::close_on_esc;
+/// #
+/// App::new()
+/// .add_systems(Update, close_on_esc);
+/// ```
+pub fn close_on_esc(
+ mut commands: Commands,
+ focused_windows: Query<(Entity, &Window)>,
+ input: Res>,
+) {
+ for (window, focus) in focused_windows.iter() {
+ if !focus.focused {
+ continue;
+ }
+
+ if input.just_pressed(KeyCode::Escape) {
+ commands.entity(window).despawn();
+ }
+ }
+}
diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs
index d244873160d72..957e6ab83a909 100644
--- a/crates/bevy_dev_tools/src/lib.rs
+++ b/crates/bevy_dev_tools/src/lib.rs
@@ -12,11 +12,16 @@ use bevy_app::prelude::*;
#[cfg(feature = "bevy_ci_testing")]
pub mod ci_testing;
+
pub mod fps_overlay;
#[cfg(feature = "bevy_ui_debug")]
pub mod ui_debug_overlay;
+mod close_on_esc;
+
+pub use crate::close_on_esc::close_on_esc;
+
/// Enables developer tools in an [`App`]. This plugin is added automatically with `bevy_dev_tools`
/// feature.
///
diff --git a/crates/bevy_window/Cargo.toml b/crates/bevy_window/Cargo.toml
index 6555e8acb606f..6937c73b85933 100644
--- a/crates/bevy_window/Cargo.toml
+++ b/crates/bevy_window/Cargo.toml
@@ -20,10 +20,9 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.14.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.14.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev", features = [
"glam",
+ "smol_str",
] }
bevy_utils = { path = "../bevy_utils", version = "0.14.0-dev" }
-# Used for close_on_esc
-bevy_input = { path = "../bevy_input", version = "0.14.0-dev" }
# other
serde = { version = "1.0", features = ["derive"], optional = true }
diff --git a/crates/bevy_window/src/event.rs b/crates/bevy_window/src/event.rs
index ad9f7573af4aa..bc9fa066d0ed3 100644
--- a/crates/bevy_window/src/event.rs
+++ b/crates/bevy_window/src/event.rs
@@ -117,13 +117,12 @@ pub struct WindowDestroyed {
/// The event is sent only if the cursor is over one of the application's windows.
/// It is the translated version of [`WindowEvent::CursorMoved`] from the `winit` crate with the addition of `delta`.
///
-/// Not to be confused with the [`MouseMotion`] event from `bevy_input`.
+/// Not to be confused with the `MouseMotion` event from `bevy_input`.
///
/// Because the range of data is limited by the window area and it may have been transformed by the OS to implement certain effects like acceleration,
-/// you should not use it for non-cursor-like behaviour such as 3D camera control. Please see [`MouseMotion`] instead.
+/// you should not use it for non-cursor-like behaviour such as 3D camera control. Please see `MouseMotion` instead.
///
/// [`WindowEvent::CursorMoved`]: https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.CursorMoved
-/// [`MouseMotion`]: bevy_input::mouse::MouseMotion
#[derive(Event, Debug, Clone, PartialEq, Reflect)]
#[reflect(Debug, PartialEq)]
#[cfg_attr(
diff --git a/crates/bevy_window/src/system.rs b/crates/bevy_window/src/system.rs
index 96db42c96c252..690ff63a77e26 100644
--- a/crates/bevy_window/src/system.rs
+++ b/crates/bevy_window/src/system.rs
@@ -2,7 +2,6 @@ use crate::{PrimaryWindow, Window, WindowCloseRequested};
use bevy_app::AppExit;
use bevy_ecs::prelude::*;
-use bevy_input::{keyboard::KeyCode, ButtonInput};
/// Exit the application when there are no open windows.
///
@@ -45,22 +44,3 @@ pub fn close_when_requested(mut commands: Commands, mut closed: EventReaderEsc) is pressed
-///
-/// This is useful for examples or prototyping.
-pub fn close_on_esc(
- mut commands: Commands,
- focused_windows: Query<(Entity, &Window)>,
- input: Res>,
-) {
- for (window, focus) in focused_windows.iter() {
- if !focus.focused {
- continue;
- }
-
- if input.just_pressed(KeyCode::Escape) {
- commands.entity(window).despawn();
- }
- }
-}
diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs
index ccc861a78d23b..2600b817a0b22 100644
--- a/crates/bevy_window/src/window.rs
+++ b/crates/bevy_window/src/window.rs
@@ -227,7 +227,7 @@ pub struct Window {
///
/// If enabled, the window will receive [`Ime`](crate::Ime) events instead of
/// [`ReceivedCharacter`](crate::ReceivedCharacter) or
- /// [`KeyboardInput`](bevy_input::keyboard::KeyboardInput).
+ /// `KeyboardInput` from `bevy_input`.
///
/// IME should be enabled during text input, but not when you expect to get the exact key pressed.
///
diff --git a/examples/2d/rotation.rs b/examples/2d/rotation.rs
index 75e80548c7c75..9cd944ac0c137 100644
--- a/examples/2d/rotation.rs
+++ b/examples/2d/rotation.rs
@@ -17,7 +17,6 @@ fn main() {
rotate_to_player_system,
),
)
- .add_systems(Update, bevy::window::close_on_esc)
.run();
}
diff --git a/examples/3d/parallax_mapping.rs b/examples/3d/parallax_mapping.rs
index 0eca86240682a..612b403b3e8e1 100644
--- a/examples/3d/parallax_mapping.rs
+++ b/examples/3d/parallax_mapping.rs
@@ -3,7 +3,7 @@
use std::fmt;
-use bevy::{prelude::*, render::render_resource::TextureFormat, window::close_on_esc};
+use bevy::{prelude::*, render::render_resource::TextureFormat};
fn main() {
App::new()
@@ -19,7 +19,6 @@ fn main() {
update_parallax_depth_scale,
update_parallax_layers,
switch_method,
- close_on_esc,
),
)
.run();
diff --git a/examples/games/alien_cake_addict.rs b/examples/games/alien_cake_addict.rs
index 721cf9bbba671..700580f12de54 100644
--- a/examples/games/alien_cake_addict.rs
+++ b/examples/games/alien_cake_addict.rs
@@ -42,10 +42,7 @@ fn main() {
.add_systems(OnEnter(GameState::GameOver), display_score)
.add_systems(
Update,
- (
- gameover_keyboard.run_if(in_state(GameState::GameOver)),
- bevy::window::close_on_esc,
- ),
+ gameover_keyboard.run_if(in_state(GameState::GameOver)),
)
.add_systems(OnExit(GameState::GameOver), teardown)
.run();
diff --git a/examples/games/breakout.rs b/examples/games/breakout.rs
index 5b62d81a9252f..4e5324b5a0312 100644
--- a/examples/games/breakout.rs
+++ b/examples/games/breakout.rs
@@ -75,7 +75,7 @@ fn main() {
// `chain`ing systems together runs them in order
.chain(),
)
- .add_systems(Update, (update_scoreboard, bevy::window::close_on_esc))
+ .add_systems(Update, update_scoreboard)
.run();
}
diff --git a/examples/window/multiple_windows.rs b/examples/window/multiple_windows.rs
index 94c156833810f..9fbd443b130a3 100644
--- a/examples/window/multiple_windows.rs
+++ b/examples/window/multiple_windows.rs
@@ -7,7 +7,6 @@ fn main() {
// By default, a primary window gets spawned by `WindowPlugin`, contained in `DefaultPlugins`
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup_scene)
- .add_systems(Update, bevy::window::close_on_esc)
.run();
}
diff --git a/tests/window/resizing.rs b/tests/window/resizing.rs
index 73eab801f04ed..3cb6d4913a294 100644
--- a/tests/window/resizing.rs
+++ b/tests/window/resizing.rs
@@ -36,14 +36,7 @@ fn main() {
})
.insert_resource(ContractingY)
.add_systems(Startup, (setup_3d, setup_2d))
- .add_systems(
- Update,
- (
- change_window_size,
- sync_dimensions,
- bevy::window::close_on_esc,
- ),
- )
+ .add_systems(Update, (change_window_size, sync_dimensions))
.run();
}
From 257df3af5fbd26394f34fb80126a9deadf6a53e4 Mon Sep 17 00:00:00 2001
From: Stephen Turley
Date: Tue, 2 Apr 2024 21:46:20 -0400
Subject: [PATCH 2/4] Changed the order of arguments for the Arc gizmo docs
(#12854)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Just updating docs for the arc gizmo so that the argument documentation
matches the order of the function arguments.
Also added docs for the color argument.
# Objective
- Improve docs
## Solution
- Moved the radius argument to the end of the argument list to match the
function
---
## Changelog
> N/A
## Migration Guide
> N/A
---------
Co-authored-by: François Mockers
---
crates/bevy_gizmos/src/arcs.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/crates/bevy_gizmos/src/arcs.rs b/crates/bevy_gizmos/src/arcs.rs
index 9f9181afe71f8..0c2835c9fb0b8 100644
--- a/crates/bevy_gizmos/src/arcs.rs
+++ b/crates/bevy_gizmos/src/arcs.rs
@@ -18,10 +18,11 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
///
/// # Arguments
/// - `position` sets the center of this circle.
- /// - `radius` controls the distance from `position` to this arc, and thus its curvature.
/// - `direction_angle` sets the clockwise angle in radians between `Vec2::Y` and
/// the vector from `position` to the midpoint of the arc.
/// - `arc_angle` sets the length of this arc, in radians.
+ /// - `radius` controls the distance from `position` to this arc, and thus its curvature.
+ /// - `color` sets the color to draw the arc.
///
/// # Example
/// ```
From 1d4176d4cd5ae658f7cf2eea3da427622a59b319 Mon Sep 17 00:00:00 2001
From: Mateusz Wachowiak
Date: Wed, 3 Apr 2024 04:47:08 +0200
Subject: [PATCH 3/4] Add methods `iter_resources` and `iter_resources_mut`
(#12829)
# Objective
- Closes #12019
- Related to #4955
- Useful for dev_tools and networking
## Solution
- Create `World::iter_resources()` and `World::iter_resources_mut()`
---------
Co-authored-by: Alice Cecile
Co-authored-by: James Liu
Co-authored-by: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com>
---
crates/bevy_ecs/src/world/mod.rs | 269 +++++++++++++++++++++++++++++++
1 file changed, 269 insertions(+)
diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs
index d245df8241930..ed6781ffe3596 100644
--- a/crates/bevy_ecs/src/world/mod.rs
+++ b/crates/bevy_ecs/src/world/mod.rs
@@ -2136,6 +2136,209 @@ impl World {
}
}
+ /// Iterates over all resources in the world.
+ ///
+ /// The returned iterator provides lifetimed, but type-unsafe pointers. Actually reading the contents
+ /// of each resource will require the use of unsafe code.
+ ///
+ /// # Examples
+ ///
+ /// ## Printing the size of all resources
+ ///
+ /// ```
+ /// # use bevy_ecs::prelude::*;
+ /// # #[derive(Resource)]
+ /// # struct A(u32);
+ /// # #[derive(Resource)]
+ /// # struct B(u32);
+ /// #
+ /// # let mut world = World::new();
+ /// # world.insert_resource(A(1));
+ /// # world.insert_resource(B(2));
+ /// let mut total = 0;
+ /// for (info, _) in world.iter_resources() {
+ /// println!("Resource: {}", info.name());
+ /// println!("Size: {} bytes", info.layout().size());
+ /// total += info.layout().size();
+ /// }
+ /// println!("Total size: {} bytes", total);
+ /// # assert_eq!(total, std::mem::size_of::() + std::mem::size_of::());
+ /// ```
+ ///
+ /// ## Dynamically running closures for resources matching specific `TypeId`s
+ ///
+ /// ```
+ /// # use bevy_ecs::prelude::*;
+ /// # use std::collections::HashMap;
+ /// # use std::any::TypeId;
+ /// # use bevy_ptr::Ptr;
+ /// # #[derive(Resource)]
+ /// # struct A(u32);
+ /// # #[derive(Resource)]
+ /// # struct B(u32);
+ /// #
+ /// # let mut world = World::new();
+ /// # world.insert_resource(A(1));
+ /// # world.insert_resource(B(2));
+ /// #
+ /// // In this example, `A` and `B` are resources. We deliberately do not use the
+ /// // `bevy_reflect` crate here to showcase the low-level [`Ptr`] usage. You should
+ /// // probably use something like `ReflectFromPtr` in a real-world scenario.
+ ///
+ /// // Create the hash map that will store the closures for each resource type
+ /// let mut closures: HashMap)>> = HashMap::new();
+ ///
+ /// // Add closure for `A`
+ /// closures.insert(TypeId::of::(), Box::new(|ptr| {
+ /// // SAFETY: We assert ptr is the same type of A with TypeId of A
+ /// let a = unsafe { &ptr.deref::() };
+ /// # assert_eq!(a.0, 1);
+ /// // ... do something with `a` here
+ /// }));
+ ///
+ /// // Add closure for `B`
+ /// closures.insert(TypeId::of::(), Box::new(|ptr| {
+ /// // SAFETY: We assert ptr is the same type of B with TypeId of B
+ /// let b = unsafe { &ptr.deref::() };
+ /// # assert_eq!(b.0, 2);
+ /// // ... do something with `b` here
+ /// }));
+ ///
+ /// // Iterate all resources, in order to run the closures for each matching resource type
+ /// for (info, ptr) in world.iter_resources() {
+ /// let Some(type_id) = info.type_id() else {
+ /// // It's possible for resources to not have a `TypeId` (e.g. non-Rust resources
+ /// // dynamically inserted via a scripting language) in which case we can't match them.
+ /// continue;
+ /// };
+ ///
+ /// let Some(closure) = closures.get(&type_id) else {
+ /// // No closure for this resource type, skip it.
+ /// continue;
+ /// };
+ ///
+ /// // Run the closure for the resource
+ /// closure(&ptr);
+ /// }
+ /// ```
+ #[inline]
+ pub fn iter_resources(&self) -> impl Iterator- )> {
+ self.storages
+ .resources
+ .iter()
+ .filter_map(|(component_id, data)| {
+ // SAFETY: If a resource has been initialized, a corresponding ComponentInfo must exist with it's ID.
+ let component_info = unsafe {
+ self.components
+ .get_info(component_id)
+ .debug_checked_unwrap()
+ };
+ Some((component_info, data.get_data()?))
+ })
+ }
+
+ /// Mutably iterates over all resources in the world.
+ ///
+ /// The returned iterator provides lifetimed, but type-unsafe pointers. Actually reading from or writing
+ /// to the contents of each resource will require the use of unsafe code.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use bevy_ecs::prelude::*;
+ /// # use bevy_ecs::change_detection::MutUntyped;
+ /// # use std::collections::HashMap;
+ /// # use std::any::TypeId;
+ /// # #[derive(Resource)]
+ /// # struct A(u32);
+ /// # #[derive(Resource)]
+ /// # struct B(u32);
+ /// #
+ /// # let mut world = World::new();
+ /// # world.insert_resource(A(1));
+ /// # world.insert_resource(B(2));
+ /// #
+ /// // In this example, `A` and `B` are resources. We deliberately do not use the
+ /// // `bevy_reflect` crate here to showcase the low-level `MutUntyped` usage. You should
+ /// // probably use something like `ReflectFromPtr` in a real-world scenario.
+ ///
+ /// // Create the hash map that will store the mutator closures for each resource type
+ /// let mut mutators: HashMap)>> = HashMap::new();
+ ///
+ /// // Add mutator closure for `A`
+ /// mutators.insert(TypeId::of::(), Box::new(|mut_untyped| {
+ /// // Note: `MutUntyped::as_mut()` automatically marks the resource as changed
+ /// // for ECS change detection, and gives us a `PtrMut` we can use to mutate the resource.
+ /// // SAFETY: We assert ptr is the same type of A with TypeId of A
+ /// let a = unsafe { &mut mut_untyped.as_mut().deref_mut::() };
+ /// # a.0 += 1;
+ /// // ... mutate `a` here
+ /// }));
+ ///
+ /// // Add mutator closure for `B`
+ /// mutators.insert(TypeId::of::(), Box::new(|mut_untyped| {
+ /// // SAFETY: We assert ptr is the same type of B with TypeId of B
+ /// let b = unsafe { &mut mut_untyped.as_mut().deref_mut::() };
+ /// # b.0 += 1;
+ /// // ... mutate `b` here
+ /// }));
+ ///
+ /// // Iterate all resources, in order to run the mutator closures for each matching resource type
+ /// for (info, mut mut_untyped) in world.iter_resources_mut() {
+ /// let Some(type_id) = info.type_id() else {
+ /// // It's possible for resources to not have a `TypeId` (e.g. non-Rust resources
+ /// // dynamically inserted via a scripting language) in which case we can't match them.
+ /// continue;
+ /// };
+ ///
+ /// let Some(mutator) = mutators.get(&type_id) else {
+ /// // No mutator closure for this resource type, skip it.
+ /// continue;
+ /// };
+ ///
+ /// // Run the mutator closure for the resource
+ /// mutator(&mut mut_untyped);
+ /// }
+ /// # assert_eq!(world.resource::().0, 2);
+ /// # assert_eq!(world.resource::().0, 3);
+ /// ```
+ #[inline]
+ pub fn iter_resources_mut(&mut self) -> impl Iterator
- )> {
+ self.storages
+ .resources
+ .iter()
+ .filter_map(|(component_id, data)| {
+ // SAFETY: If a resource has been initialized, a corresponding ComponentInfo must exist with it's ID.
+ let component_info = unsafe {
+ self.components
+ .get_info(component_id)
+ .debug_checked_unwrap()
+ };
+ let (ptr, ticks) = data.get_with_ticks()?;
+
+ // SAFETY:
+ // - We have exclusive access to the world, so no other code can be aliasing the `TickCells`
+ // - We only hold one `TicksMut` at a time, and we let go of it before getting the next one
+ let ticks = unsafe {
+ TicksMut::from_tick_cells(
+ ticks,
+ self.last_change_tick(),
+ self.read_change_tick(),
+ )
+ };
+
+ let mut_untyped = MutUntyped {
+ // SAFETY:
+ // - We have exclusive access to the world, so no other code can be aliasing the `Ptr`
+ // - We iterate one resource at a time, and we let go of each `PtrMut` before getting the next one
+ value: unsafe { ptr.assert_unique() },
+ ticks,
+ };
+
+ Some((component_info, mut_untyped))
+ })
+ }
+
/// Gets a `!Send` resource to the resource with the id [`ComponentId`] if it exists.
/// The returned pointer must not be used to modify the resource, and must not be
/// dereferenced after the immutable borrow of the [`World`] ends.
@@ -2554,6 +2757,12 @@ mod tests {
#[derive(Resource)]
struct TestResource(u32);
+ #[derive(Resource)]
+ struct TestResource2(String);
+
+ #[derive(Resource)]
+ struct TestResource3;
+
#[test]
fn get_resource_by_id() {
let mut world = World::new();
@@ -2594,6 +2803,66 @@ mod tests {
assert_eq!(resource.0, 43);
}
+ #[test]
+ fn iter_resources() {
+ let mut world = World::new();
+ world.insert_resource(TestResource(42));
+ world.insert_resource(TestResource2("Hello, world!".to_string()));
+ world.insert_resource(TestResource3);
+ world.remove_resource::();
+
+ let mut iter = world.iter_resources();
+
+ let (info, ptr) = iter.next().unwrap();
+ assert_eq!(info.name(), std::any::type_name::());
+ // SAFETY: We know that the resource is of type `TestResource`
+ assert_eq!(unsafe { ptr.deref::().0 }, 42);
+
+ let (info, ptr) = iter.next().unwrap();
+ assert_eq!(info.name(), std::any::type_name::());
+ assert_eq!(
+ // SAFETY: We know that the resource is of type `TestResource2`
+ unsafe { &ptr.deref::().0 },
+ &"Hello, world!".to_string()
+ );
+
+ assert!(iter.next().is_none());
+ }
+
+ #[test]
+ fn iter_resources_mut() {
+ let mut world = World::new();
+ world.insert_resource(TestResource(42));
+ world.insert_resource(TestResource2("Hello, world!".to_string()));
+ world.insert_resource(TestResource3);
+ world.remove_resource::();
+
+ let mut iter = world.iter_resources_mut();
+
+ let (info, mut mut_untyped) = iter.next().unwrap();
+ assert_eq!(info.name(), std::any::type_name::());
+ // SAFETY: We know that the resource is of type `TestResource`
+ unsafe {
+ mut_untyped.as_mut().deref_mut::().0 = 43;
+ };
+
+ let (info, mut mut_untyped) = iter.next().unwrap();
+ assert_eq!(info.name(), std::any::type_name::());
+ // SAFETY: We know that the resource is of type `TestResource2`
+ unsafe {
+ mut_untyped.as_mut().deref_mut::().0 = "Hello, world?".to_string();
+ };
+
+ assert!(iter.next().is_none());
+ std::mem::drop(iter);
+
+ assert_eq!(world.resource::().0, 43);
+ assert_eq!(
+ world.resource::().0,
+ "Hello, world?".to_string()
+ );
+ }
+
#[test]
fn custom_resource_with_layout() {
static DROP_COUNT: AtomicU32 = AtomicU32::new(0);
From ba8d70288d178183f3e58aa010b4747490efd0fe Mon Sep 17 00:00:00 2001
From: Brett Striker
Date: Tue, 2 Apr 2024 22:48:06 -0400
Subject: [PATCH 4/4] [bevy_ui/layout] Update tests to get GlobalTransform
properly (#12802)
This is 2 of 5 iterative PR's that affect bevy_ui/layout
- [x] Blocked by https://github.com/bevyengine/bevy/pull/12801
[Diff to parent
PR](https://github.com/StrikeForceZero/bevy/compare/dev/bevy_ui/breakup_layout_mod..dev/bevy_ui/update_layout_tests)
---
# Objective
- Update a test in bevy_ui/layout to use the proper way to get an up to
date `GlobalTransform`
## Solution
- Adds `sync_simple_transforms`, and `propagate_transforms` to the test
schedule in bevy_ui/layout
---
---
crates/bevy_ui/src/layout/mod.rs | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/crates/bevy_ui/src/layout/mod.rs b/crates/bevy_ui/src/layout/mod.rs
index 62d60f50cbb18..ccff47ae38067 100644
--- a/crates/bevy_ui/src/layout/mod.rs
+++ b/crates/bevy_ui/src/layout/mod.rs
@@ -343,7 +343,8 @@ mod tests {
use bevy_render::camera::OrthographicProjection;
use bevy_render::prelude::Camera;
use bevy_render::texture::Image;
- use bevy_transform::prelude::{GlobalTransform, Transform};
+ use bevy_transform::prelude::GlobalTransform;
+ use bevy_transform::systems::{propagate_transforms, sync_simple_transforms};
use bevy_utils::prelude::default;
use bevy_utils::HashMap;
use bevy_window::PrimaryWindow;
@@ -399,6 +400,8 @@ mod tests {
update_target_camera_system,
apply_deferred,
ui_layout_system,
+ sync_simple_transforms,
+ propagate_transforms,
)
.chain(),
);
@@ -697,15 +700,11 @@ mod tests {
ui_schedule.run(&mut world);
let overlap_check = world
- .query_filtered::<(Entity, &Node, &mut GlobalTransform, &Transform), Without>()
- .iter_mut(&mut world)
+ .query_filtered::<(Entity, &Node, &GlobalTransform), Without>()
+ .iter(&world)
.fold(
Option::<(Rect, bool)>::None,
- |option_rect, (entity, node, mut global_transform, transform)| {
- // fix global transform - for some reason the global transform isn't populated yet.
- // might be related to how these specific tests are working directly with World instead of App
- *global_transform = GlobalTransform::from(transform.compute_affine());
- let global_transform = &*global_transform;
+ |option_rect, (entity, node, global_transform)| {
let current_rect = node.logical_rect(global_transform);
assert!(
current_rect.height().abs() + current_rect.width().abs() > 0.,