diff --git a/Cargo.toml b/Cargo.toml index d491ab22448e9..fe1695c58f936 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1249,10 +1249,15 @@ description = "Meshlet rendering for dense high-poly scenes (experimental)" category = "3D Rendering" wasm = false setup = [ + [ + "mkdir", + "-p", + "assets/external/models", + ], [ "curl", "-o", - "assets/models/bunny.meshlet_mesh", + "assets/external/models/bunny.meshlet_mesh", "https://raw.githubusercontent.com/JMS55/bevy_meshlet_asset/7a7c14138021f63904b584d5f7b73b695c7f4bbf/bunny.meshlet_mesh", ], ] diff --git a/assets/external/.gitignore b/assets/external/.gitignore new file mode 100644 index 0000000000000..d6b7ef32c8478 --- /dev/null +++ b/assets/external/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/crates/bevy_ecs/src/schedule/config.rs b/crates/bevy_ecs/src/schedule/config.rs index 20308578a4726..3d9deeceff5f9 100644 --- a/crates/bevy_ecs/src/schedule/config.rs +++ b/crates/bevy_ecs/src/schedule/config.rs @@ -247,6 +247,12 @@ impl NodeConfigs { /// [`SystemParam`](crate::system::SystemParam)), or tuples thereof. /// It is a common entry point for system configurations. /// +/// # Usage notes +/// +/// This trait should only be used as a bound for trait implementations or as an +/// argument to a function. If system configs need to be returned from a +/// function or stored somewhere, use [`SystemConfigs`] instead of this trait. +/// /// # Examples /// /// ``` @@ -617,6 +623,12 @@ impl SystemSetConfig { pub type SystemSetConfigs = NodeConfigs; /// Types that can convert into a [`SystemSetConfigs`]. +/// +/// # Usage notes +/// +/// This trait should only be used as a bound for trait implementations or as an +/// argument to a function. If system set configs need to be returned from a +/// function or stored somewhere, use [`SystemSetConfigs`] instead of this trait. #[diagnostic::on_unimplemented( message = "`{Self}` does not describe a valid system set configuration", label = "invalid system set configuration" diff --git a/crates/bevy_ecs/src/schedule/set.rs b/crates/bevy_ecs/src/schedule/set.rs index cbe1011e782a2..623e0a2211a69 100644 --- a/crates/bevy_ecs/src/schedule/set.rs +++ b/crates/bevy_ecs/src/schedule/set.rs @@ -152,6 +152,12 @@ impl SystemSet for AnonymousSet { } /// Types that can be converted into a [`SystemSet`]. +/// +/// # Usage notes +/// +/// This trait should only be used as a bound for trait implementations or as an +/// argument to a function. If a system set needs to be returned from a function +/// or stored somewhere, use [`SystemSet`] instead of this trait. #[diagnostic::on_unimplemented( message = "`{Self}` is not a system set", label = "invalid system set" diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index 360ed03c9b1b8..72dcbfb11e996 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -160,6 +160,12 @@ use crate::world::World; /// Use this to get a system from a function. Also note that every system implements this trait as /// well. /// +/// # Usage notes +/// +/// This trait should only be used as a bound for trait implementations or as an +/// argument to a function. If a system needs to be returned from a function or +/// stored somewhere, use [`System`] instead of this trait. +/// /// # Examples /// /// ``` diff --git a/crates/bevy_ecs/src/system/observer_system.rs b/crates/bevy_ecs/src/system/observer_system.rs index aa247d493964a..fa4f6035b8884 100644 --- a/crates/bevy_ecs/src/system/observer_system.rs +++ b/crates/bevy_ecs/src/system/observer_system.rs @@ -21,6 +21,12 @@ impl< } /// Implemented for systems that convert into [`ObserverSystem`]. +/// +/// # Usage notes +/// +/// This trait should only be used as a bound for trait implementations or as an +/// argument to a function. If an observer system needs to be returned from a +/// function or stored somewhere, use [`ObserverSystem`] instead of this trait. #[diagnostic::on_unimplemented( message = "`{Self}` cannot become an `ObserverSystem`", label = "the trait `IntoObserverSystem` is not implemented", diff --git a/crates/bevy_input_focus/src/directional_navigation.rs b/crates/bevy_input_focus/src/directional_navigation.rs index 17114ef11a075..fd64cd41a732c 100644 --- a/crates/bevy_input_focus/src/directional_navigation.rs +++ b/crates/bevy_input_focus/src/directional_navigation.rs @@ -186,10 +186,11 @@ impl DirectionalNavigationMap { /// /// This is useful for creating a circular navigation path between a set of entities, such as a menu. pub fn add_looping_edges(&mut self, entities: &[Entity], direction: CompassOctant) { - for i in 0..entities.len() { - let a = entities[i]; - let b = entities[(i + 1) % entities.len()]; - self.add_symmetrical_edge(a, b, direction); + self.add_edges(entities, direction); + if let Some((first_entity, rest)) = entities.split_first() { + if let Some(last_entity) = rest.last() { + self.add_symmetrical_edge(*last_entity, *first_entity, direction); + } } } @@ -227,14 +228,17 @@ impl DirectionalNavigation<'_> { /// If the result was `Ok`, the [`InputFocus`] resource is updated to the new focus as part of this method call. pub fn navigate( &mut self, - octant: CompassOctant, + direction: CompassOctant, ) -> Result { if let Some(current_focus) = self.focus.0 { - if let Some(new_focus) = self.map.get_neighbor(current_focus, octant) { + if let Some(new_focus) = self.map.get_neighbor(current_focus, direction) { self.focus.set(new_focus); Ok(new_focus) } else { - Err(DirectionalNavigationError::NoNeighborInDirection) + Err(DirectionalNavigationError::NoNeighborInDirection { + current_focus, + direction, + }) } } else { Err(DirectionalNavigationError::NoFocus) @@ -249,8 +253,13 @@ pub enum DirectionalNavigationError { #[error("No focusable entity is currently set.")] NoFocus, /// No neighbor in the requested direction. - #[error("No neighbor in the requested direction.")] - NoNeighborInDirection, + #[error("No neighbor from {current_focus} in the {direction:?} direction.")] + NoNeighborInDirection { + /// The entity that was the focus when the error occurred. + current_focus: Entity, + /// The direction in which the navigation was attempted. + direction: CompassOctant, + }, } #[cfg(test)] diff --git a/crates/bevy_state/src/state_scoped.rs b/crates/bevy_state/src/state_scoped.rs index 3e9f49f51734d..02a8c75cdc6a6 100644 --- a/crates/bevy_state/src/state_scoped.rs +++ b/crates/bevy_state/src/state_scoped.rs @@ -60,6 +60,15 @@ use crate::state::{StateTransitionEvent, States}; #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Component))] pub struct StateScoped(pub S); +impl Default for StateScoped +where + S: States + Default, +{ + fn default() -> Self { + Self(S::default()) + } +} + /// Removes entities marked with [`StateScoped`] /// when their state no longer matches the world state. /// diff --git a/examples/3d/meshlet.rs b/examples/3d/meshlet.rs index 5db69a4a7995a..0bab7d750198c 100644 --- a/examples/3d/meshlet.rs +++ b/examples/3d/meshlet.rs @@ -20,8 +20,8 @@ const ASSET_URL: &str = "https://raw.githubusercontent.com/JMS55/bevy_meshlet_asset/7a7c14138021f63904b584d5f7b73b695c7f4bbf/bunny.meshlet_mesh"; fn main() -> ExitCode { - if !Path::new("./assets/models/bunny.meshlet_mesh").exists() { - eprintln!("ERROR: Asset at path /assets/models/bunny.meshlet_mesh is missing. Please download it from {ASSET_URL}"); + if !Path::new("./assets/external/models/bunny.meshlet_mesh").exists() { + eprintln!("ERROR: Asset at path /assets/external/models/bunny.meshlet_mesh is missing. Please download it from {ASSET_URL}"); return ExitCode::FAILURE; } @@ -80,7 +80,7 @@ fn setup( // that has been converted to a [`bevy_pbr::meshlet::MeshletMesh`] // using [`bevy_pbr::meshlet::MeshletMesh::from_mesh`], which is // a function only available when the `meshlet_processor` cargo feature is enabled. - let meshlet_mesh_handle = asset_server.load("models/bunny.meshlet_mesh"); + let meshlet_mesh_handle = asset_server.load("external/models/bunny.meshlet_mesh"); let debug_material = debug_materials.add(MeshletDebugMaterial::default()); for x in -2..=2 { diff --git a/examples/ui/directional_navigation.rs b/examples/ui/directional_navigation.rs index b62c2875c5679..b228df6dd4889 100644 --- a/examples/ui/directional_navigation.rs +++ b/examples/ui/directional_navigation.rs @@ -5,6 +5,8 @@ //! //! In this example, we will set up a simple UI with a grid of buttons that can be navigated using the arrow keys or gamepad input. +use std::time::Duration; + use bevy::{ input_focus::{ directional_navigation::{ @@ -65,9 +67,7 @@ const FOCUSED_BORDER: Srgba = bevy::color::palettes::tailwind::BLUE_50; // In a real project, each button would also have its own unique behavior, // to capture the actual intent of the user fn universal_button_click_behavior( - // We're using an on-mouse-down trigger to improve responsiveness; - // Clicked is better when you want roll-off cancellation - mut trigger: Trigger>, + mut trigger: Trigger>, mut button_query: Query<(&mut BackgroundColor, &mut ResetTimer)>, ) { let button_entity = trigger.target(); @@ -368,7 +368,7 @@ fn highlight_focused_element( } } -// By sending a Pointer trigger rather than directly handling button-like interactions, +// By sending a Pointer trigger rather than directly handling button-like interactions, // we can unify our handling of pointer and keyboard/gamepad interactions fn interact_with_focused_button( action_state: Res, @@ -381,7 +381,7 @@ fn interact_with_focused_button( { if let Some(focused_entity) = input_focus.0 { commands.trigger_targets( - Pointer:: { + Pointer:: { target: focused_entity, // We're pretending that we're a mouse pointer_id: PointerId::Mouse, @@ -395,7 +395,7 @@ fn interact_with_focused_button( ), position: Vec2::ZERO, }, - event: Pressed { + event: Click { button: PointerButton::Primary, // This field isn't used, so we're just setting it to a placeholder value hit: HitData { @@ -404,6 +404,7 @@ fn interact_with_focused_button( position: None, normal: None, }, + duration: Duration::from_secs_f32(0.1), }, }, focused_entity,