use super::{ffi, ComponentTrait, Entity, Layer, Transform, WorldData};
pub struct WorldEntityQuery {
data: WorldData,
}
impl WorldEntityQuery {
pub fn new(query: &ffi::WorldEntityQuery) -> Self {
Self {
data: WorldData::create_struct(ffi::CreateDataType::WorldEntityQuery, query),
}
}
pub fn entities(&self) -> Vec<Entity> {
let handle = self.data.get_data_handle();
handle.read_vec()
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "with_serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "with_speedy", derive(speedy::Writable, speedy::Readable))]
#[repr(transparent)]
pub struct EntityLayerMask(u64);
impl EntityLayerMask {
pub const fn layer(layer: usize) -> Self {
Self(Layer::mask_from_index(layer))
}
pub const fn with(self, other: Self) -> Self {
Self(self.0 | other.0)
}
pub const fn except(self, other: Self) -> Self {
Self(self.0 & !other.0)
}
pub const fn with_layer(self, layer: usize) -> Self {
Self(self.0 | Layer::mask_from_index(layer))
}
pub const fn except_layer(self, layer: usize) -> Self {
Self(self.0 & !Layer::mask_from_index(layer))
}
pub const fn from_value(value: u64) -> Self {
Self(value)
}
pub const fn value(&self) -> u64 {
self.0
}
#[inline]
pub const fn everything() -> Self {
Self(!0)
}
#[inline]
pub const fn nothing() -> Self {
Self(0)
}
}
impl std::ops::BitOr for EntityLayerMask {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign<Self> for EntityLayerMask {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl std::fmt::Debug for EntityLayerMask {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
x if x == Self::everything() => write!(f, "LayerMask(everything)"),
x if x == Self::nothing() => write!(f, "LayerMask(nothing)"),
x if x.0.count_ones() == 1 => write!(f, "LayerMask(layer {})", self.0.trailing_zeros()),
_ => write!(f, "LayerMask({:#b})", self.0),
}
}
}
#[derive(Copy, Clone)]
pub enum EntityQueryType {
AllEntities,
TransformChildren(Entity),
TransformDescendants(Entity),
}
#[derive(Copy, Clone)]
pub struct WorldEntityQueryBuilder {
query: ffi::WorldEntityQuery,
layer_filter: Option<EntityLayerMask>,
}
impl Default for WorldEntityQueryBuilder {
fn default() -> Self {
Self::new(EntityQueryType::AllEntities)
}
}
impl WorldEntityQueryBuilder {
pub fn new(query_type: EntityQueryType) -> Self {
let (query_type, root_entity) = match query_type {
EntityQueryType::AllEntities => {
(ffi::WorldEntityQueryType::AllEntities, Entity::invalid())
}
EntityQueryType::TransformChildren(entity) => {
(ffi::WorldEntityQueryType::TransformChildren, entity)
}
EntityQueryType::TransformDescendants(entity) => {
(ffi::WorldEntityQueryType::TransformDescendants, entity)
}
};
Self {
query: ffi::WorldEntityQuery {
layer_mask: !0u64,
num_include_tags: 0,
num_exclude_tags: 0,
include_tags: Default::default(),
exclude_tags: Default::default(),
query_type,
root_entity: root_entity.as_ffi(),
_pad0: Default::default(),
_pad1: Default::default(),
},
layer_filter: None,
}
}
pub fn with_layer_filter(&mut self, layer_filter: EntityLayerMask) -> &mut Self {
self.layer_filter = Some(layer_filter);
self
}
pub fn with_tag(&mut self, tag: u64) -> &mut Self {
if (self.query.num_include_tags as usize) >= self.query.include_tags.len() {
log::warn!(
"WorldEntityQueryBuilder: Trying to include more tags than allowed. Max {}",
self.query.include_tags.len()
);
return self;
}
self.query.include_tags[self.query.num_include_tags as usize] = tag;
self.query.num_include_tags += 1;
self
}
pub fn without_tag(&mut self, tag: u64) -> &mut Self {
if (self.query.num_exclude_tags as usize) >= self.query.exclude_tags.len() {
log::warn!(
"WorldEntityQueryBuilder: Trying to exclude more tags than allowed. Max {}",
self.query.exclude_tags.len()
);
return self;
}
self.query.exclude_tags[self.query.num_exclude_tags as usize] = tag;
self.query.num_exclude_tags += 1;
self
}
pub fn build(&mut self) -> WorldEntityQuery {
if let Some(layer_mask) = self.layer_filter {
self.query.layer_mask = layer_mask.value();
} else if self.query.query_type == ffi::WorldEntityQueryType::AllEntities {
self.query.query_type = ffi::WorldEntityQueryType::AllEntitiesNoLayerFilter;
} else if self.query.query_type == ffi::WorldEntityQueryType::TransformChildren {
self.query.query_type = ffi::WorldEntityQueryType::TransformChildrenNoLayerFilter;
} else if self.query.query_type == ffi::WorldEntityQueryType::TransformDescendants {
self.query.query_type = ffi::WorldEntityQueryType::TransformDescendantsNoLayerFilter;
} else {
self.query.layer_mask = !0u64;
}
WorldEntityQuery::new(&self.query)
}
}
impl Transform {
pub fn children(&self) -> Vec<Entity> {
WorldEntityQueryBuilder::new(EntityQueryType::TransformChildren(self.entity()))
.build()
.entities()
}
pub fn descendants(&self) -> Vec<Entity> {
WorldEntityQueryBuilder::new(EntityQueryType::TransformDescendants(self.entity()))
.build()
.entities()
}
}