use super::from_reflect_with_fallback;
use crate::{
change_detection::Mut,
component::{ComponentId, ComponentMutability},
entity::{Entity, EntityMapper},
prelude::Component,
relationship::RelationshipHookMode,
world::{
unsafe_world_cell::UnsafeEntityCell, EntityMut, EntityWorldMut, FilteredEntityMut,
FilteredEntityRef, World,
},
};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
use bevy_utils::prelude::DebugName;
#[derive(Clone)]
pub struct ReflectComponent(ReflectComponentFns);
#[derive(Clone)]
pub struct ReflectComponentFns {
pub insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
pub apply: fn(EntityMut, &dyn PartialReflect),
pub apply_or_insert_mapped: fn(
&mut EntityWorldMut,
&dyn PartialReflect,
&TypeRegistry,
&mut dyn EntityMapper,
RelationshipHookMode,
),
pub remove: fn(&mut EntityWorldMut),
pub contains: fn(FilteredEntityRef) -> bool,
pub reflect: for<'w> fn(FilteredEntityRef<'w, '_>) -> Option<&'w dyn Reflect>,
pub reflect_mut: for<'w> fn(FilteredEntityMut<'w, '_>) -> Option<Mut<'w, dyn Reflect>>,
pub map_entities: fn(&mut dyn Reflect, &mut dyn EntityMapper),
pub reflect_unchecked_mut: unsafe fn(UnsafeEntityCell<'_>) -> Option<Mut<'_, dyn Reflect>>,
pub copy: fn(&World, &mut World, Entity, Entity, &TypeRegistry),
pub register_component: fn(&mut World) -> ComponentId,
}
impl ReflectComponentFns {
pub fn new<T: Component + FromReflect + TypePath>() -> Self {
<ReflectComponent as FromType<T>>::from_type().0
}
}
impl ReflectComponent {
pub fn insert(
&self,
entity: &mut EntityWorldMut,
component: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(entity, component, registry);
}
pub fn apply<'a>(&self, entity: impl Into<EntityMut<'a>>, component: &dyn PartialReflect) {
(self.0.apply)(entity.into(), component);
}
pub fn apply_or_insert_mapped(
&self,
entity: &mut EntityWorldMut,
component: &dyn PartialReflect,
registry: &TypeRegistry,
map: &mut dyn EntityMapper,
relationship_hook_mode: RelationshipHookMode,
) {
(self.0.apply_or_insert_mapped)(entity, component, registry, map, relationship_hook_mode);
}
pub fn remove(&self, entity: &mut EntityWorldMut) {
(self.0.remove)(entity);
}
pub fn contains<'w, 's>(&self, entity: impl Into<FilteredEntityRef<'w, 's>>) -> bool {
(self.0.contains)(entity.into())
}
pub fn reflect<'w, 's>(
&self,
entity: impl Into<FilteredEntityRef<'w, 's>>,
) -> Option<&'w dyn Reflect> {
(self.0.reflect)(entity.into())
}
pub fn reflect_mut<'w, 's>(
&self,
entity: impl Into<FilteredEntityMut<'w, 's>>,
) -> Option<Mut<'w, dyn Reflect>> {
(self.0.reflect_mut)(entity.into())
}
pub unsafe fn reflect_unchecked_mut<'a>(
&self,
entity: UnsafeEntityCell<'a>,
) -> Option<Mut<'a, dyn Reflect>> {
unsafe { (self.0.reflect_unchecked_mut)(entity) }
}
pub fn copy(
&self,
source_world: &World,
destination_world: &mut World,
source_entity: Entity,
destination_entity: Entity,
registry: &TypeRegistry,
) {
(self.0.copy)(
source_world,
destination_world,
source_entity,
destination_entity,
registry,
);
}
pub fn register_component(&self, world: &mut World) -> ComponentId {
(self.0.register_component)(world)
}
pub fn new(fns: ReflectComponentFns) -> Self {
Self(fns)
}
pub fn fn_pointers(&self) -> &ReflectComponentFns {
&self.0
}
pub fn map_entities(&self, component: &mut dyn Reflect, func: &mut dyn EntityMapper) {
(self.0.map_entities)(component, func);
}
}
impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
fn from_type() -> Self {
ReflectComponent(ReflectComponentFns {
insert: |entity, reflected_component, registry| {
let component = entity.world_scope(|world| {
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
entity.insert(component);
},
apply: |mut entity, reflected_component| {
if !C::Mutability::MUTABLE {
let name = DebugName::type_name::<C>();
let name = name.shortname();
panic!("Cannot call `ReflectComponent::apply` on component {name}. It is immutable, and cannot modified through reflection");
}
let mut component = unsafe { entity.get_mut_assume_mutable::<C>() }.unwrap();
component.apply(reflected_component);
},
apply_or_insert_mapped: |entity,
reflected_component,
registry,
mut mapper,
relationship_hook_mode| {
if C::Mutability::MUTABLE {
if let Some(mut component) = unsafe { entity.get_mut_assume_mutable::<C>() } {
component.apply(reflected_component.as_partial_reflect());
C::map_entities(&mut component, &mut mapper);
} else {
let mut component = entity.world_scope(|world| {
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
C::map_entities(&mut component, &mut mapper);
entity
.insert_with_relationship_hook_mode(component, relationship_hook_mode);
}
} else {
let mut component = entity.world_scope(|world| {
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
C::map_entities(&mut component, &mut mapper);
entity.insert_with_relationship_hook_mode(component, relationship_hook_mode);
}
},
remove: |entity| {
entity.remove::<C>();
},
contains: |entity| entity.contains::<C>(),
copy: |source_world, destination_world, source_entity, destination_entity, registry| {
let source_component = source_world.get::<C>(source_entity).unwrap();
let destination_component =
from_reflect_with_fallback::<C>(source_component, destination_world, registry);
destination_world
.entity_mut(destination_entity)
.insert(destination_component);
},
reflect: |entity| entity.get::<C>().map(|c| c as &dyn Reflect),
reflect_mut: |entity| {
if !C::Mutability::MUTABLE {
let name = DebugName::type_name::<C>();
let name = name.shortname();
panic!("Cannot call `ReflectComponent::reflect_mut` on component {name}. It is immutable, and cannot modified through reflection");
}
unsafe {
entity
.into_mut_assume_mutable::<C>()
.map(|c| c.map_unchanged(|value| value as &mut dyn Reflect))
}
},
reflect_unchecked_mut: |entity| {
if !C::Mutability::MUTABLE {
let name = DebugName::type_name::<C>();
let name = name.shortname();
panic!("Cannot call `ReflectComponent::reflect_unchecked_mut` on component {name}. It is immutable, and cannot modified through reflection");
}
let c = unsafe { entity.get_mut_assume_mutable::<C>() };
c.map(|c| c.map_unchanged(|value| value as &mut dyn Reflect))
},
register_component: |world: &mut World| -> ComponentId {
world.register_component::<C>()
},
map_entities: |reflect: &mut dyn Reflect, mut mapper: &mut dyn EntityMapper| {
let component = reflect.downcast_mut::<C>().unwrap();
Component::map_entities(component, &mut mapper);
},
})
}
}