use std::any::TypeId;
use hecs::{Archetype, ColumnBatchBuilder, ColumnBatchType, Component, TypeIdMap, TypeInfo, World};
struct ComponentCloneMetadata {
type_info: TypeInfo,
insert_into_batch_func: &'static dyn Fn(&Archetype, &mut ColumnBatchBuilder),
}
#[derive(Default)]
struct WorldCloner {
registry: TypeIdMap<ComponentCloneMetadata>,
}
impl WorldCloner {
pub fn register<T: Component + Clone>(&mut self) {
self.registry.insert(
TypeId::of::<T>(),
ComponentCloneMetadata {
type_info: TypeInfo::of::<T>(),
insert_into_batch_func: &|src, dest| {
let mut column = dest.writer::<T>().unwrap();
for component in &*src.get::<&T>().unwrap() {
_ = column.push(component.clone());
}
},
},
);
}
fn clone_world(&self, world: &World) -> World {
let mut cloned = World::new();
for archetype in world.archetypes() {
let mut batch_type = ColumnBatchType::new();
for (&type_id, clone_metadata) in self.registry.iter() {
if archetype.has_dynamic(type_id) {
batch_type.add_dynamic(clone_metadata.type_info);
}
}
let mut batch_builder = batch_type.into_batch(archetype.ids().len() as u32);
for (&type_id, clone_metadata) in self.registry.iter() {
if archetype.has_dynamic(type_id) {
(clone_metadata.insert_into_batch_func)(archetype, &mut batch_builder)
}
}
let batch = batch_builder.build().expect("batch should be complete");
let handles = &cloned
.reserve_entities(archetype.ids().len() as u32)
.collect::<Vec<_>>();
cloned.flush();
cloned.spawn_column_batch_at(handles, batch);
}
cloned
}
}
pub fn main() {
let int0 = 0;
let int1 = 1;
let str0 = "Ada".to_owned();
let str1 = "Bob".to_owned();
let str2 = "Cal".to_owned();
let mut world0 = World::new();
let entity0 = world0.spawn((int0, str0));
let entity1 = world0.spawn((int1, str1));
let entity2 = world0.spawn((str2,));
let entity3 = world0.spawn((0u8,));
let mut cloner = WorldCloner::default();
cloner.register::<i32>();
cloner.register::<String>();
let world1 = cloner.clone_world(&world0);
assert_eq!(
world0.len(),
world1.len(),
"cloned world should have same entity count as original world"
);
assert!(
world0
.entity(entity3)
.expect("w0 entity3 should exist")
.has::<u8>(),
"original world entity has u8 component"
);
assert!(
!world1
.entity(entity3)
.expect("w1 entity3 should exist")
.has::<u8>(),
"cloned world entity does not have u8 component because it was not registered"
);
type AllRegisteredComponentsQuery = (&'static i32, &'static String);
for entity in [entity0, entity1] {
let w0_e = world0.entity(entity).expect("w0 entity should exist");
let w1_e = world1.entity(entity).expect("w1 entity should exist");
assert!(w0_e.satisfies::<AllRegisteredComponentsQuery>());
assert!(w1_e.satisfies::<AllRegisteredComponentsQuery>());
assert_eq!(
w0_e.query::<AllRegisteredComponentsQuery>().get().unwrap(),
w1_e.query::<AllRegisteredComponentsQuery>().get().unwrap()
);
}
type SomeRegisteredComponentsQuery = (&'static String,);
let w0_e = world0.entity(entity2).expect("w0 entity2 should exist");
let w1_e = world1.entity(entity2).expect("w1 entity2 should exist");
assert!(w0_e.satisfies::<SomeRegisteredComponentsQuery>());
assert!(w1_e.satisfies::<SomeRegisteredComponentsQuery>());
assert_eq!(
w0_e.query::<SomeRegisteredComponentsQuery>().get().unwrap(),
w1_e.query::<SomeRegisteredComponentsQuery>().get().unwrap()
);
}