use bevy::{ecs::entity::hash_map::EntityHashMap, prelude::*, scene::DynamicEntity};
use log::debug;
use crate::{prelude::*, shared::replication::rules::ReplicationRules};
pub fn replicate_into(scene: &mut DynamicScene, world: &World) {
let Some(marker_id) = world.component_id::<Replicated>() else {
return;
};
let mut entities: EntityHashMap<_> = scene
.entities
.drain(..)
.map(|dyn_entity| (dyn_entity.entity, dyn_entity.components))
.collect();
let registry = world.resource::<AppTypeRegistry>();
let rules = world.resource::<ReplicationRules>();
let registry = registry.read();
for archetype in world
.archetypes()
.iter()
.filter(|archetype| archetype.contains(marker_id))
{
for entity in archetype.entities() {
entities.entry(entity.id()).or_default();
}
for rule in rules.iter().filter(|rule| rule.matches(archetype)) {
for component in &rule.components {
let replicated_component =
unsafe { world.components().get_info_unchecked(component.id) };
let type_name = replicated_component.name();
let type_id = replicated_component
.type_id()
.unwrap_or_else(|| panic!("`{type_name}` should be a Rust type"));
let Some(registration) = registry.get(type_id) else {
debug!("ignoring `{type_name}` because it's not registered");
continue;
};
let Some(reflect_component) = registration.data::<ReflectComponent>() else {
debug!("ignoring `{type_name}` because it's missing `#[reflect(Component)]`");
continue;
};
let from_reflect = registration
.data::<ReflectFromReflect>()
.unwrap_or_else(|| panic!("`{type_name}` should reflect `FromReflect`"));
for entity in archetype.entities() {
let component = reflect_component
.reflect(world.entity(entity.id()))
.unwrap_or_else(|| panic!("entity should have `{type_name}`"));
let component = from_reflect
.from_reflect(component.as_partial_reflect())
.unwrap_or_else(|| panic!("`{type_name}` should be dynamically cloneable"));
let components = entities
.get_mut(&entity.id())
.expect("all entities should be populated ahead of time");
debug!("adding `{type_name}` to `{}`", entity.id());
components.push(component.into_partial_reflect());
}
}
}
}
let dyn_entities_iter = entities
.drain()
.map(|(entity, components)| DynamicEntity { entity, components });
scene.entities.extend(dyn_entities_iter);
}