/// `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 } 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) } 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, ) } 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: 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 } }