//! `micro_bevy_world_utils` packages some common functions used to interrogate the world state from //! exclusive bevy systems. One frequent use case for these functions is in implementing a monolithic //! physics collisions processor. //! //! ## World Interrogation //! //! ## World Mutation //! //! - `send_event`: Send an event //! //! ## Entity Sorting //! //! There are several functions that take the form "get_{specifier}_{specifier}_entities", such as //! `get_left_right_entities`. These are used to sort two entities according to which specified //! components they contain, or to fetch the _parent_ of one or both entities matching the criteria. //! //! `{specifier}` takes the following form: `[any_](left|right)[[_any]_parent]` //! //! - `any_` implies that no components need to be matched for that side of the query to be //! successful. This would be equivalent to supplying `()` to the version without `any_` //! - `_parent` implies that the returned entity for that side will, if a match is found, be the //! _parent_ entity of the matching input entity. //! //! **N.B.** The left component will always be queried first //! //! ### Examples //! //! - `get_left_right_entities`: Match entities to the left and right components //! - `get_left_any_right_parent`: Match against the left component, and match the parent of the second entity against the right component //! - `get_left_right_any_parent`: Match entities to the left and right components, but return the _parent_ entity of the right entity //! use bevy_ecs::{ component::Component, entity::Entity, event::EventWriter, query::{With, ReadOnlyWorldQuery}, system::{Query, SystemState}, world::World, }; use bevy_hierarchy::Parent; pub type Left = Entity; pub type Right = Entity; pub type SortedEntities = (Left, Right); fn inner_get_left_right_entities< LeftSide: ReadOnlyWorldQuery + 'static, RightSide: ReadOnlyWorldQuery + 'static, >( world: &mut World, first: &Entity, second: &Entity, ) -> Option<SortedEntities> { let mut state = SystemState::<(Query<(), LeftSide>, Query<(), RightSide>)>::new(world); let (left_query, right_query) = state.get(world); if left_query.contains(*first) && right_query.contains(*second) { Some((*first, *second)) } else if left_query.contains(*second) && right_query.contains(*first) { Some((*second, *first)) } else { None } } fn inner_get_left_right_parent_entities< LeftSide: ReadOnlyWorldQuery + 'static, RightSide: ReadOnlyWorldQuery + 'static, ParentSide: ReadOnlyWorldQuery + 'static, >( world: &mut World, first: &Entity, second: &Entity, ) -> Option<SortedEntities> { let mut state = SystemState::<( Query<(), LeftSide>, Query<&Parent, RightSide>, Query<(), ParentSide>, )>::new(world); let (left_query, right_query, parent_query) = state.get(world); if left_query.contains(*first) { if let Ok(parent) = right_query.get(*second) { let parent = parent.get(); if parent_query.contains(parent) { return Some((*first, parent)); } } } else if left_query.contains(*second) { if let Ok(parent) = right_query.get(*first) { let parent = parent.get(); if parent_query.contains(parent) { return Some((*second, parent)); } } } None } fn inner_get_left_parent_right_parent_entities< LeftSide: ReadOnlyWorldQuery + 'static, LeftParent: ReadOnlyWorldQuery + 'static, RightSide: ReadOnlyWorldQuery + 'static, RightParent: ReadOnlyWorldQuery + 'static, >( world: &mut World, first: &Entity, second: &Entity, ) -> Option<SortedEntities> { let mut state = SystemState::<( Query<&Parent, LeftSide>, Query<&Parent, RightSide>, Query<(), LeftParent>, Query<(), RightParent>, )>::new(world); let (left_query, right_query, left_parent_query, right_parent_query) = state.get(world); if let Ok(left_parent) = left_query.get(*first) { if left_parent_query.contains(left_parent.get()) { if let Ok(right_parent) = right_query.get(*second) { if right_parent_query.contains(right_parent.get()) { return Some((left_parent.get(), right_parent.get())); } } } } else if let Ok(left_parent) = left_query.get(*second) { if left_parent_query.contains(left_parent.get()) { if let Ok(right_parent) = right_query.get(*first) { if right_parent_query.contains(right_parent.get()) { return Some((left_parent.get(), right_parent.get())); } } } } None } /// Given two entities and two component types, order those entities based on which entity contains /// which component. /// /// The generic parameters `LeftSide` and `RightSide` determine the components being queried for, /// and will place their matching entity in positions `0` and `1` of the tuple, respectively. If /// one of both entities do not match with a distinct component type, this function will return `None`; i.e. /// each entity must match exactly one component, and those matches must be unique. pub fn get_left_right_entities<LeftSide: Component, RightSide: Component>( world: &mut World, first: &Entity, second: &Entity, ) -> Option<SortedEntities> { inner_get_left_right_entities::<With<LeftSide>, With<RightSide>>(world, first, second) } /// Given two entities and three component types, order those entities based on which entity contains /// the left hand component, and which entity contains the right hand component while having a parent /// that contains the right hand component. The resulting tuple will contain the left component and /// the parent component, but _not_ the right component. /// /// The generic parameters `LeftSide` and `ParentSide` determine the components being queried for, /// and will place their matching entity in positions `0` and `1` of the tuple, respectively. `RightSide` /// will be used to determine which entity should have its parent fetched. If one of both entities do not /// match with a distinct component type, this function will return `None`; i.e. each entity must match /// exactly one component, and those matches must be unique. pub fn get_left_right_parent_entities< LeftSide: Component, RightSide: Component, ParentSide: Component, >( world: &mut World, first: &Entity, second: &Entity, ) -> Option<SortedEntities> { inner_get_left_right_parent_entities::<With<LeftSide>, With<RightSide>, With<ParentSide>>( world, first, second, ) } /// Given two entities and a Component type, order those entities based on which one matches the /// Component type. /// /// The first entity to contain `LeftComponent` will be in position `0` of the /// resulting tuple, and the other will be in position `1`, regardless of whether they both match /// or just one matches. Returns `None` if neither match pub fn get_left_any_right_entities<LeftComponent: Component>( world: &mut World, first: &Entity, second: &Entity, ) -> Option<SortedEntities> { inner_get_left_right_entities::<With<LeftComponent>, ()>(world, first, second) } pub fn get_left_parent_right_parent_entities< LeftSide: Component, LeftParent: Component, RightSide: Component, RightParent: Component, >( world: &mut World, first: &Entity, second: &Entity, ) -> Option<SortedEntities> { inner_get_left_parent_right_parent_entities::< With<LeftSide>, With<LeftParent>, With<RightSide>, With<RightParent>, >(world, first, second) } pub fn get_any_left_parent_any_right_parent_entities< LeftParent: Component, RightParent: Component, >( world: &mut World, first: &Entity, second: &Entity, ) -> Option<SortedEntities> { inner_get_left_parent_right_parent_entities::<(), With<LeftParent>, (), With<RightParent>>( world, first, second, ) } /// Send an event to the appropriate event writer. Writer type is derived from the /// second parameter passed in, and must be registered with the application before /// trying to send. /// /// ## Example /// /// ```rust /// # use bevy_ecs::world::World; /// /// struct MyEventType { /// message: usize /// } /// /// // Do some app setup /// /// use micro_bevy_world_utils::send_event; /// pub fn my_world_system(world: &mut World) { /// // Do some processing here /// send_event(world, MyEventType { message: 1234 }); /// } /// ``` pub fn send_event<Event: bevy_ecs::event::Event + Sync + Send + 'static>(world: &mut World, event: Event) { SystemState::<EventWriter<Event>>::new(world) .get_mut(world) .send(event); } /// Clone the data from a specific component of the target entity, as long as that entity /// has that component and the component itself implements `Clone` /// /// ## Example /// /// ```rust /// /// ``` pub fn clone_entity_component<C: Component + Clone>( world: &mut World, entity: &Entity, ) -> Option<C> { let mut state = SystemState::<Query<&'static C>>::new(world); let query = state.get(world); let item = query.get(*entity); if let Ok(value) = item { Some(value.clone()) } else { None } }