use std::{
any::TypeId,
collections::HashMap,
hash::{DefaultHasher, Hash, Hasher},
marker::PhantomData,
mem::take,
sync::Arc
};
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use cgmath::Vector2;
use lotus_proc_macros::Component;
use uuid::Uuid;
use crate::core::event::synchronizer;
use super::{
super::{
event::{
dispatcher::EventDispatcher,
},
super::Color,
camera::camera2d::Camera2d,
bindings::keyboard_input::KeyboardInput,
bindings::mouse_input::MouseInput,
bindings::gamepad::gamepad_input::GamepadInput,
draw_order::DrawOrder,
visibility::Visibility,
text::{text::{Text, TextHolder, TextRenderer}, font::{Font, Fonts}},
managers::render::manager::RenderState,
physics::transform::{Transform, Position, Strategy}
},
archetype::Archetype,
query::Query,
entity::Entity,
component::{Component, ComponentRefMut, ComponentRef, ComponentBorrowState},
resource::{Resource, ResourceRefMut, ResourceRef, ResourceBorrowState}
};
#[derive(Clone, Component)]
pub struct Fps();
pub struct World {
pub archetypes: HashMap<u64, Archetype>,
pub resources: HashMap<TypeId, Arc<AtomicRefCell<Box<dyn Resource>>>>,
pub resource_borrow_state: AtomicRefCell<ResourceBorrowState>,
pub component_borrow_state: AtomicRefCell<ComponentBorrowState>
}
impl World {
pub fn new() -> Self {
let mut resources: HashMap<TypeId, Arc<AtomicRefCell<Box<dyn Resource>>>> = HashMap::new();
resources.insert(TypeId::of::<EventDispatcher>(), Arc::new(AtomicRefCell::new(Box::new(EventDispatcher::new()))));
resources.insert(TypeId::of::<KeyboardInput>(), Arc::new(AtomicRefCell::new(Box::new(KeyboardInput::default()))));
resources.insert(TypeId::of::<MouseInput>(), Arc::new(AtomicRefCell::new(Box::new(MouseInput::default()))));
resources.insert(TypeId::of::<GamepadInput>(), Arc::new(AtomicRefCell::new(Box::new(GamepadInput::default()))));
resources.insert(TypeId::of::<Camera2d>(), Arc::new(AtomicRefCell::new(Box::new(Camera2d::default()))));
resources.insert(TypeId::of::<TextHolder>(), Arc::new(AtomicRefCell::new(Box::new(TextHolder::default()))));
return Self {
archetypes: HashMap::new(),
resources,
resource_borrow_state: ResourceBorrowState::new().into(),
component_borrow_state: ComponentBorrowState::new().into()
};
}
pub fn add_resource(&mut self, resource: Box<dyn Resource>) {
self.resources.insert(
resource.type_id(),
Arc::new(AtomicRefCell::new(resource))
);
}
pub fn add_resources(&mut self, resources: Vec<Box<dyn Resource>>) {
for resource in resources {
self.resources.insert(
resource.type_id(),
Arc::new(AtomicRefCell::new(resource))
);
}
}
pub fn show_fps(&mut self, render_state: &mut RenderState, current_fps: u32, color: Color) {
let mut query: Query = Query::new(&self).with::<Fps>();
if let Some(fps_entity) = query.entities_with_components().unwrap().first() {
if let Some(mut text_holder) = self.get_resource_mut::<TextHolder>() {
if let Some(text_renderer) = text_holder.text_renderers.get_mut(&fps_entity.0) {
text_renderer.content(current_fps.to_string(), render_state.queue.clone(), render_state.physical_size);
}
}
} else {
let fps_text: Text = Text::new(
render_state,
Font::new(Fonts::RobotoMono.get_path(), 21.0),
Position::new(Vector2::new(0.0, 0.0), Strategy::Pixelated),
color,
current_fps.to_string()
);
self.spawn(render_state, vec![Box::new(fps_text), Box::new(DrawOrder(99999)), Box::new(Fps())]);
}
}
pub fn hide_fps(&mut self, render_state: &mut RenderState) {
let mut query: Query = Query::new(&self).with::<Fps>();
if let Some(fps_entity) = query.entities_with_components().unwrap().first() {
self.despawn(render_state, fps_entity);
}
}
pub(crate) fn spawn(&mut self, render_state: &mut RenderState, components: Vec<Box<dyn Component>>) -> Entity {
let entity: Entity = Entity(Uuid::new_v4());
if components.iter().any(|component| component.as_any().is::<Text>()) {
let text: &Text = components.iter()
.find_map(|component| component.as_any().downcast_ref::<Text>()
).unwrap();
let mut text_holder: ResourceRefMut<'_, TextHolder> = self.get_resource_mut::<TextHolder>().unwrap();
let text_renderer: TextRenderer = TextRenderer::new(render_state, &text);
text_holder.text_renderers.insert(entity.0, text_renderer);
}
let mut components_refs: Vec<AtomicRefCell<Box<dyn Component>>> = Vec::with_capacity(components.len());
for component in components {
components_refs.push(AtomicRefCell::new(component));
}
if !components_refs.iter().any(|component| component.borrow().as_any().is::<Transform>()) {
components_refs.push(AtomicRefCell::new(Box::new(Transform::default())));
}
if !components_refs.iter().any(|component| component.borrow().as_any().is::<Visibility>()) {
components_refs.push(AtomicRefCell::new(Box::new(Visibility::default())));
}
if !components_refs.iter().any(|component| component.borrow().as_any().is::<DrawOrder>()) {
components_refs.push(AtomicRefCell::new(Box::new(DrawOrder::default())));
}
let mut components_types_ids: Vec<TypeId> = components_refs.iter().map(|c| c.borrow().type_id()).collect();
let archetype_unique_key: u64 = self.get_archetype_unique_key(&mut components_types_ids);
let archetype: &mut Archetype = self.archetypes.entry(archetype_unique_key).or_insert_with(Archetype::new);
let moved_components: Vec<AtomicRefCell<Box<dyn Component>>> = take(&mut components_refs);
archetype.add_entity(entity, moved_components);
render_state.add_entity_to_render(entity);
return entity;
}
pub(crate) fn despawn(&mut self, render_state: &mut RenderState, entity: &Entity) {
render_state.remove_entity_to_render(entity);
render_state.clean_entity_buffer_cache(entity);
render_state.clean_entity_bind_group_cache(entity);
for archetype in self.archetypes.values_mut() {
if let Some(index) = archetype.entities.iter().position(|e| e.0 == entity.0) {
for components in archetype.components.values_mut() {
if index < components.len() {
components.remove(index);
}
}
archetype.entities.remove(index);
break;
}
}
}
pub(crate) fn synchronize(&mut self, render_state: &mut RenderState, delta: f32) {
synchronizer::events(self, render_state);
synchronizer::camera(self, render_state);
synchronizer::animations(self, delta);
synchronizer::collisions(self);
synchronizer::gravity(self, render_state, delta);
}
pub fn get_archetype_unique_key(&self, components_types_ids: &mut Vec<TypeId>) -> u64 {
components_types_ids.sort();
return self.get_hash_from_ids(&components_types_ids);
}
pub fn get_hash_from_ids(&self, type_ids: &[TypeId]) -> u64 {
let mut default_hasher: DefaultHasher = DefaultHasher::new();
for type_id in type_ids {
type_id.hash(&mut default_hasher);
}
return default_hasher.finish();
}
pub fn get_resource<T: Resource + 'static>(&self) -> Option<ResourceRef<'_, T>> {
let type_id: TypeId = TypeId::of::<T>();
let mut resource_borrow_state: AtomicRefMut<'_, ResourceBorrowState> = self.resource_borrow_state.borrow_mut();
if resource_borrow_state.try_borrow_immutable(type_id) {
if let Some(resource) = self.resources.get(&type_id) {
return Some(ResourceRef {
inner: resource.borrow(),
type_id,
resource_borrow_state: &self.resource_borrow_state,
phantom_data: PhantomData
});
} else {
resource_borrow_state.release_immutable(type_id);
return None;
}
} else {
return None;
}
}
pub fn get_resource_cloned<T: Resource + Clone + 'static>(&self) -> Option<T> {
return self.get_resource::<T>().map(|resource| resource.clone());
}
pub fn get_resource_mut<T: Resource + 'static>(&self) -> Option<ResourceRefMut<'_, T>> {
let type_id: TypeId = TypeId::of::<T>();
let mut resource_borrow_state: AtomicRefMut<'_, ResourceBorrowState> = self.resource_borrow_state.borrow_mut();
if resource_borrow_state.try_borrow_mutable(type_id) {
if let Some(resource) = self.resources.get(&type_id) {
return Some(
ResourceRefMut {
inner: resource.borrow_mut(),
type_id,
resource_borrow_state: &self.resource_borrow_state,
phantom_data: PhantomData
}
);
} else {
resource_borrow_state.release_mutable(type_id);
return None;
}
} else {
return None;
}
}
pub fn get_entity_component<T: Component + 'static>(&self, entity: &Entity) -> Option<ComponentRef<'_, T>> {
for archetype in self.archetypes.values() {
if archetype.entities.contains(entity) {
let type_id: TypeId = TypeId::of::<T>();
let mut component_borrow_state: AtomicRefMut<'_, ComponentBorrowState> = self.component_borrow_state.borrow_mut();
if component_borrow_state.try_borrow_immutable(type_id, entity.0) {
if let Some(components) = archetype.components.get(&type_id) {
if let Some(index) = archetype.entities.iter().position(|e| e == entity) {
return Some(ComponentRef {
inner: components[index].borrow(),
type_id,
entity_id: entity.0,
component_borrow_state: &self.component_borrow_state,
phantom_data: std::marker::PhantomData
});
} else {
component_borrow_state.release_immutable(type_id, entity.0);
return None;
}
}
} else {
return None;
}
}
}
return None;
}
pub fn get_entity_component_mut<T: Component + 'static>(&self, entity: &Entity) -> Option<ComponentRefMut<'_, T>> {
for archetype in self.archetypes.values() {
if archetype.entities.contains(entity) {
let type_id: TypeId = TypeId::of::<T>();
let mut component_borrow_state: AtomicRefMut<'_, ComponentBorrowState> = self.component_borrow_state.borrow_mut();
if component_borrow_state.try_borrow_mutable(type_id, entity.0) {
if let Some(components) = archetype.components.get(&type_id) {
if let Some(index) = archetype.entities.iter().position(|e| e == entity) {
return Some(ComponentRefMut {
inner: components[index].borrow_mut(),
type_id,
entity_id: entity.0,
component_borrow_state: &self.component_borrow_state,
phantom_data: std::marker::PhantomData
});
} else {
component_borrow_state.release_mutable(type_id, entity.0);
return None;
}
}
} else {
return None;
}
}
}
return None;
}
pub fn get_entity_components<'a>(&'a self, entity: &'a Entity) -> Option<Vec<AtomicRef<'a, Box<dyn Component>>>> {
if let Some((_, archetype)) = self.archetypes.iter().find(|(_, arch)| arch.entities.contains(entity)) {
if let Some(index) = archetype.entities.iter().position(|e| e == entity) {
let mut entity_components: Vec<AtomicRef<'a, Box<dyn Component>>> = Vec::new();
for component_vec in archetype.components.values() {
if let Some(component) = component_vec.get(index) {
let borrowed: AtomicRef<'_, Box<dyn Component>> = component.borrow();
entity_components.push(borrowed);
}
}
return Some(entity_components);
}
}
return None;
}
pub fn get_entity_components_mut<'a>(&'a self, entity: &'a Entity) -> Option<Vec<AtomicRefMut<'a, Box<dyn Component>>>> {
if let Some((_, archetype)) = self.archetypes.iter().find(|(_, arch)| arch.entities.contains(entity)) {
if let Some(index) = archetype.entities.iter().position(|e| e == entity) {
let mut entity_components: Vec<AtomicRefMut<'a, Box<dyn Component>>> = Vec::new();
for component_vec in archetype.components.values() {
if let Some(component) = component_vec.get(index) {
let borrowed: AtomicRefMut<'_, Box<dyn Component>> = component.borrow_mut();
entity_components.push(borrowed);
}
}
return Some(entity_components);
}
}
return None;
}
pub fn is_entity_alive(&self, entity: Entity) -> bool {
return self.archetypes.values().any(|archetype| archetype.entities.iter().any(|e| e.0 == entity.0));
}
pub fn is_entity_visible(&self, entity: Entity) -> bool {
let visibility: ComponentRef<'_, Visibility> = self.get_entity_component::<Visibility>(&entity).unwrap();
return visibility.0;
}
}