use bevy::{ecs::entity::EntityHashMap, platform::collections::hash_map::Entry, prelude::*};
use super::filters_mask::{FilterBit, FiltersMask};
#[derive(Component, Reflect, Default)]
pub struct ClientVisibility {
hidden: EntityHashMap<FiltersMask>,
lost: EntityHashMap<FiltersMask>,
}
impl ClientVisibility {
pub(crate) fn iter_lost(&self) -> impl Iterator<Item = (Entity, FiltersMask)> {
self.lost.iter().map(|(&e, &m)| (e, m))
}
pub(crate) fn drain_lost(&mut self) -> impl Iterator<Item = (Entity, FiltersMask)> {
self.lost.drain()
}
pub(crate) fn remove_despawned(&mut self, entity: Entity) {
self.hidden.remove(&entity);
self.lost.remove(&entity);
}
pub fn set(&mut self, entity: Entity, bit: FilterBit, visible: bool) {
if visible {
if let Entry::Occupied(mut mask) = self.hidden.entry(entity) {
mask.get_mut().remove(bit);
if mask.get().is_empty() {
mask.remove();
}
if let Entry::Occupied(mut lost_mask) = self.lost.entry(entity) {
lost_mask.get_mut().remove(bit);
if lost_mask.get().is_empty() {
lost_mask.remove();
}
}
}
} else {
let mask = self.hidden.entry(entity).or_default();
if !mask.contains(bit) {
mask.insert(bit);
self.lost.entry(entity).or_default().insert(bit);
}
}
}
pub(crate) fn get(&self, entity: Entity) -> FiltersMask {
self.hidden.get(&entity).copied().unwrap_or_default()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn single() {
let mut visibility = ClientVisibility::default();
visibility.set(Entity::PLACEHOLDER, FilterBit::new(0), false);
assert!(!visibility.get(Entity::PLACEHOLDER).is_empty());
assert!(visibility.lost.contains_key(&Entity::PLACEHOLDER));
visibility.set(Entity::PLACEHOLDER, FilterBit::new(0), true);
assert!(visibility.get(Entity::PLACEHOLDER).is_empty());
assert!(!visibility.lost.contains_key(&Entity::PLACEHOLDER));
}
#[test]
fn multiple() {
let mut visibility = ClientVisibility::default();
visibility.set(Entity::PLACEHOLDER, FilterBit::new(0), false);
visibility.set(Entity::PLACEHOLDER, FilterBit::new(1), false);
assert!(!visibility.get(Entity::PLACEHOLDER).is_empty());
assert!(visibility.lost.contains_key(&Entity::PLACEHOLDER));
visibility.set(Entity::PLACEHOLDER, FilterBit::new(0), true);
assert!(!visibility.get(Entity::PLACEHOLDER).is_empty());
assert!(visibility.lost.contains_key(&Entity::PLACEHOLDER));
visibility.set(Entity::PLACEHOLDER, FilterBit::new(1), true);
assert!(visibility.get(Entity::PLACEHOLDER).is_empty());
assert!(!visibility.lost.contains_key(&Entity::PLACEHOLDER));
}
#[test]
fn already_visible() {
let mut visibility = ClientVisibility::default();
assert!(visibility.get(Entity::PLACEHOLDER).is_empty());
visibility.set(Entity::PLACEHOLDER, FilterBit::new(0), true);
assert!(visibility.get(Entity::PLACEHOLDER).is_empty());
assert!(!visibility.lost.contains_key(&Entity::PLACEHOLDER));
}
}