use core::ops::BitOr;
use crate::Entity;
use crate::Host;
use crate::engine_ids as ids;
use crate::world::{ComponentType, Placed, World};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ContainerKinds(u32);
impl ContainerKinds {
pub const PLACED: Self = Self(1);
pub const LOOT: Self = Self(1 << 1);
pub const DROPS: Self = Self(1 << 2);
pub const CHARACTERS: Self = Self(1 << 3);
pub const NPCS: Self = Self(1 << 4);
pub const ANIMALS: Self = Self(1 << 5);
pub const PLANTS: Self = Self(1 << 6);
pub const OTHER: Self = Self(1 << 31);
pub const ALL: Self = Self(u32::MAX);
#[must_use]
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
}
impl Default for ContainerKinds {
fn default() -> Self {
Self::PLACED
}
}
impl BitOr for ContainerKinds {
type Output = Self;
fn bitor(self, other: Self) -> Self {
self.union(other)
}
}
const MARKERS: [(ContainerKinds, &str); 7] = [
(ContainerKinds::CHARACTERS, ids::PLAYER_INPUT),
(ContainerKinds::NPCS, ids::NPC),
(ContainerKinds::ANIMALS, ids::ANIMAL),
(ContainerKinds::PLACED, ids::USED_ITEM),
(ContainerKinds::DROPS, ids::DESTROY_ON_LOOT),
(ContainerKinds::LOOT, ids::LOOT_FILL),
(ContainerKinds::PLANTS, ids::RESOURCE_NODE),
];
#[derive(Clone, Copy, Debug)]
pub(crate) struct Containers {
setup: ComponentType,
markers: [(ContainerKinds, ComponentType); MARKERS.len()],
}
impl Containers {
pub(crate) fn resolve(host: Host) -> Option<Self> {
let resolve = |id| {
ComponentType::named(host, id)
.inspect_err(|off| crate::debug!("container queries off: {off}"))
.ok()
};
let setup = resolve(ids::INVENTORY_SETUP)?;
let mut markers = [(ContainerKinds::OTHER, ComponentType::from_hash(0)); MARKERS.len()];
for (slot, (kind, id)) in markers.iter_mut().zip(MARKERS) {
*slot = (kind, resolve(id)?);
}
Some(Self { setup, markers })
}
fn kind(&self, world: World, entity: Entity) -> ContainerKinds {
self.markers
.iter()
.find(|&&(_, ty)| world.component(entity, ty).is_some())
.map_or(ContainerKinds::OTHER, |&(kind, _)| kind)
}
pub(crate) fn of(&self, world: World, kinds: ContainerKinds) -> Vec<Placed> {
let mut found = world.entities(self.setup);
found.retain(|placed| kinds.contains(self.kind(world, placed.entity)));
found
}
}