use std::{collections::HashMap, fmt::Debug, hash::Hash, marker::PhantomData};
use derivative::Derivative;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{
prelude::*,
world::{EntitiesRes, EntityResBuilder, LazyBuilder},
};
pub trait MarkedBuilder {
fn marked<M: Marker>(self) -> Self;
}
impl<'a> MarkedBuilder for EntityBuilder<'a> {
fn marked<M>(self) -> Self
where
M: Marker,
{
let mut alloc = self.world.write_resource::<M::Allocator>();
alloc.mark(self.entity, &mut self.world.write_storage::<M>());
self
}
}
impl<'a> MarkedBuilder for LazyBuilder<'a> {
fn marked<M>(self) -> Self
where
M: Marker,
{
let entity = self.entity;
self.lazy.exec(move |world| {
let mut alloc = world.write_resource::<M::Allocator>();
alloc.mark(entity, &mut world.write_storage::<M>());
});
self
}
}
impl<'a> EntityResBuilder<'a> {
pub fn marked<M>(self, storage: &mut WriteStorage<M>, alloc: &mut M::Allocator) -> Self
where
M: Marker,
{
alloc.mark(self.entity, storage);
self
}
}
pub trait Marker: Clone + Component + Debug + Eq + Hash + DeserializeOwned + Serialize {
type Identifier;
type Allocator: MarkerAllocator<Self>;
fn id(&self) -> Self::Identifier;
fn update(&mut self, new_revision: Self) {
*self = new_revision;
}
}
pub trait MarkerAllocator<M: Marker>: Resource {
fn allocate(&mut self, entity: Entity, id: Option<M::Identifier>) -> M;
fn retrieve_entity_internal(&self, id: M::Identifier) -> Option<Entity>;
fn retrieve_entity(
&mut self,
marker: M,
storage: &mut WriteStorage<M>,
entities: &EntitiesRes,
) -> Entity {
if let Some(entity) = self.retrieve_entity_internal(marker.id()) {
if let Some(marker_comp) = storage.get_mut(entity) {
marker_comp.update(marker);
return entity;
}
}
let entity = entities.create();
let marker = self.allocate(entity, Some(marker.id()));
storage.insert(entity, marker).unwrap();
entity
}
fn mark<'m>(
&mut self,
entity: Entity,
storage: &'m mut WriteStorage<M>,
) -> Option<(&'m M, bool)> {
if let Ok(entry) = storage.entry(entity) {
let mut new = false;
let marker = entry.or_insert_with(|| {
new = true;
self.allocate(entity, None)
});
Some((marker, new))
} else {
None
}
}
fn maintain(&mut self, _entities: &EntitiesRes, _storage: &ReadStorage<M>);
}
#[derive(Derivative, Serialize, Deserialize)]
#[derivative(Clone, Copy, Debug, Hash, PartialEq, Eq)]
#[repr(transparent)]
pub struct SimpleMarker<T: ?Sized>(u64, #[serde(skip)] PhantomData<T>);
impl<T> Component for SimpleMarker<T>
where
T: 'static + ?Sized + Send + Sync,
{
type Storage = DenseVecStorage<Self>;
}
impl<T> Marker for SimpleMarker<T>
where
T: 'static + ?Sized + Send + Sync,
{
type Allocator = SimpleMarkerAllocator<T>;
type Identifier = u64;
fn id(&self) -> u64 {
self.0
}
}
#[derive(Derivative)]
#[derivative(Clone, Debug)]
pub struct SimpleMarkerAllocator<T: ?Sized> {
index: u64,
mapping: HashMap<u64, Entity>,
_phantom_data: PhantomData<T>,
}
impl<T> Default for SimpleMarkerAllocator<T> {
fn default() -> Self {
SimpleMarkerAllocator::new()
}
}
impl<T> SimpleMarkerAllocator<T> {
pub fn new() -> Self {
SimpleMarkerAllocator {
index: 0,
mapping: HashMap::new(),
_phantom_data: PhantomData,
}
}
}
impl<T> MarkerAllocator<SimpleMarker<T>> for SimpleMarkerAllocator<T>
where
T: 'static + ?Sized + Send + Sync,
{
fn allocate(&mut self, entity: Entity, id: Option<u64>) -> SimpleMarker<T> {
let marker = if let Some(id) = id {
if id >= self.index {
self.index = id + 1;
}
SimpleMarker(id, PhantomData)
} else {
self.index += 1;
SimpleMarker(self.index - 1, PhantomData)
};
self.mapping.insert(marker.id(), entity);
marker
}
fn retrieve_entity_internal(&self, id: u64) -> Option<Entity> {
self.mapping.get(&id).cloned()
}
fn maintain(&mut self, entities: &EntitiesRes, storage: &ReadStorage<SimpleMarker<T>>) {
self.mapping = (entities, storage)
.join()
.map(|(e, m)| (m.id(), e))
.collect();
}
}