use bevy_ecs::prelude::*;
use bevy_platform::collections::HashMap;
use bevy_reflect::prelude::*;
#[derive(Component, Reflect)]
#[reflect(Component)]
pub struct FloatingOrigin;
#[derive(Debug, Default, Component, Reflect)]
#[reflect(Component)]
pub struct BigSpace {
pub floating_origin: Option<Entity>,
}
impl BigSpace {
pub(crate) fn validate_floating_origin(
&self,
this_entity: Entity,
parents: &Query<&ChildOf>,
) -> Option<Entity> {
let floating_origin = self.floating_origin?;
let origin_root_entity = parents.iter_ancestors(floating_origin).last()?;
Some(floating_origin).filter(|_| origin_root_entity == this_entity)
}
pub fn find_floating_origin(
floating_origins: Query<Entity, With<FloatingOrigin>>,
parent_query: Query<&ChildOf>,
mut big_spaces: Query<(Entity, &mut BigSpace)>,
) {
let mut spaces_set = HashMap::<_, _>::default();
for (entity, mut space) in &mut big_spaces {
space.floating_origin = None;
spaces_set.insert(entity, 0);
}
for origin in &floating_origins {
let maybe_root = parent_query.iter_ancestors(origin).last();
if let Some((root, mut space)) =
maybe_root.and_then(|root| big_spaces.get_mut(root).ok())
{
let space_origins = spaces_set.entry(root).or_default();
*space_origins += 1;
if *space_origins > 1 {
bevy_log::error!(
"BigSpace {root:#?} has multiple floating origins. There must be exactly one. Resetting this big space and disabling the floating origin to avoid unexpected propagation behavior.",
);
space.floating_origin = None;
} else {
space.floating_origin = Some(origin);
}
continue;
}
}
for space in spaces_set
.iter()
.filter(|(_k, v)| **v == 0)
.map(|(k, _v)| k)
{
bevy_log::error!("BigSpace {space:#} has no floating origins. There must be exactly one. Transform propagation will not work until there is a FloatingOrigin in the hierarchy.",);
}
}
}