From 1a652ae57ec090ac308f035a7b1d6da1e3bc3f3b Mon Sep 17 00:00:00 2001
From: Louis Capitanchik <contact@louiscap.co>
Date: Fri, 18 Nov 2022 11:05:05 +0000
Subject: [PATCH] Import from Cryptikkvania

---
 .gitignore |   2 +
 Cargo.toml |   8 ++
 src/lib.rs | 247 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 257 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Cargo.toml
 create mode 100644 src/lib.rs

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4fffb2f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/target
+/Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..e0187a8
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "micro_bevy_world_utils"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..3d9a02f
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,247 @@
+/// `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
+	}
+}
-- 
GitLab