use std::{
collections::HashMap,
fmt::{self, Debug},
hash::{Hash, Hasher},
marker::PhantomData,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{
prelude::*,
storage::AccessMut,
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(mut marker_comp) = storage.get_mut(entity) {
marker_comp.access_mut().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)> {
let new = if let Ok(entry) = storage.entry(entity) {
let mut new = false;
let _marker = entry.or_insert_with(|| {
new = true;
self.allocate(entity, None)
});
new
} else {
return None;
};
Some((storage.get(entity).unwrap(), new))
}
fn maintain(&mut self, _entities: &EntitiesRes, _storage: &ReadStorage<M>);
}
#[derive(Serialize, Deserialize)]
#[repr(transparent)]
pub struct SimpleMarker<T: ?Sized>(u64, #[serde(skip)] PhantomData<T>);
impl<T: ?Sized> Clone for SimpleMarker<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for SimpleMarker<T> {}
impl<T: ?Sized> PartialEq for SimpleMarker<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T: ?Sized> Eq for SimpleMarker<T> {}
impl<T: ?Sized> Hash for SimpleMarker<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T: ?Sized> Debug for SimpleMarker<T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_tuple("SimpleMarker")
.field(&self.0)
.field(&self.1)
.finish()
}
}
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
}
}
pub struct SimpleMarkerAllocator<T: ?Sized> {
index: u64,
mapping: HashMap<u64, Entity>,
_phantom_data: PhantomData<T>,
}
impl<T: ?Sized> Debug for SimpleMarkerAllocator<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("SimpleMarkerAllocator")
.field("index", &self.index)
.field("mapping", &self.mapping)
.field("_phantom_data", &self._phantom_data)
.finish()
}
}
impl<T: ?Sized> Clone for SimpleMarkerAllocator<T> {
fn clone(&self) -> Self {
Self {
index: self.index,
mapping: self.mapping.clone(),
_phantom_data: PhantomData,
}
}
}
impl<T: ?Sized> Default for SimpleMarkerAllocator<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: ?Sized> SimpleMarkerAllocator<T> {
pub fn new() -> Self {
Self {
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();
}
}