bevy/crates/bevy_component_registry/src/component_registry.rs

85 lines
2.7 KiB
Rust

use bevy_property::{Properties, Property, PropertyTypeRegistry};
use legion::{
prelude::{Entity, World},
storage::{Component, ComponentResourceSet, ComponentTypeId},
};
use std::{
collections::HashMap,
sync::{Arc, RwLock},
};
#[derive(Clone, Default)]
pub struct PropertyTypeRegistryContext {
pub value: Arc<RwLock<PropertyTypeRegistry>>,
}
#[derive(Default)]
pub struct ComponentRegistryContext {
pub value: Arc<RwLock<ComponentRegistry>>,
}
#[derive(Default)]
pub struct ComponentRegistry {
pub registrations: HashMap<ComponentTypeId, ComponentRegistration>,
pub short_names: HashMap<String, ComponentTypeId>,
pub full_names: HashMap<String, ComponentTypeId>,
}
impl ComponentRegistry {
pub fn register<T>(&mut self)
where
T: Properties + Component + Default,
{
let registration = ComponentRegistration::of::<T>();
self.short_names
.insert(registration.short_name.to_string(), registration.ty);
self.full_names
.insert(registration.ty.0.to_string(), registration.ty);
self.registrations.insert(registration.ty, registration);
}
pub fn get(&self, type_id: &ComponentTypeId) -> Option<&ComponentRegistration> {
self.registrations.get(type_id)
}
pub fn get_with_full_name(&self, full_name: &str) -> Option<&ComponentRegistration> {
self.full_names
.get(full_name)
.and_then(|id| self.registrations.get(id))
}
pub fn get_with_short_name(&self, short_name: &str) -> Option<&ComponentRegistration> {
self.short_names
.get(short_name)
.and_then(|id| self.registrations.get(id))
}
}
#[derive(Clone)]
pub struct ComponentRegistration {
pub ty: ComponentTypeId,
pub component_add_fn: fn(&mut World, Entity, &dyn Property),
pub component_properties_fn: fn(&ComponentResourceSet, usize) -> &dyn Properties,
pub short_name: &'static str,
}
impl ComponentRegistration {
pub fn of<T: Properties + Component + Default>() -> Self {
let ty = ComponentTypeId::of::<T>();
Self {
ty,
component_add_fn: |world: &mut World, entity: Entity, property: &dyn Property| {
let mut component = T::default();
component.apply(property);
world.add_component(entity, component).unwrap();
},
component_properties_fn: |component_resource_set: &ComponentResourceSet,
index: usize| {
// the type has been looked up by the caller, so this is safe
unsafe { &component_resource_set.data_slice::<T>()[index] }
},
short_name: ty.0.split("::").last().unwrap(),
}
}
}