Created
May 17, 2024 05:48
-
-
Save caspark/62a092d3068ffba7781008b2828b5320 to your computer and use it in GitHub Desktop.
Example of how to clone world in hecs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use hecs::{ColumnBatchBuilder, ColumnBatchType, Component, TypeUnknownToCloner, World}; | |
fn try_add_type_to_batch<T: Component>( | |
archetype: &hecs::Archetype, | |
batch_type: &mut ColumnBatchType, | |
) { | |
if archetype.has::<T>() { | |
batch_type.add::<T>(); | |
} | |
} | |
fn try_clone_column<T: Component + Clone>( | |
archetype: &hecs::Archetype, | |
batch: &mut ColumnBatchBuilder, | |
) { | |
if let Some((column, mut writer)) = archetype.get::<&T>().zip(batch.writer::<T>()) { | |
for item in column.iter() { | |
if let Err(_) = writer.push(item.clone()) { | |
unreachable!("push should always succeed since batch was sized to match archetype"); | |
} | |
} | |
} | |
} | |
fn try_copy_column<T: Component + Copy>( | |
archetype: &hecs::Archetype, | |
batch: &mut ColumnBatchBuilder, | |
) { | |
if let Some((column, mut writer)) = archetype.get::<&T>().zip(batch.writer::<T>()) { | |
//FIXME would want to add writer.extend() to add column in batch | |
for item in column.iter() { | |
if let Err(_) = writer.push(*item) { | |
unreachable!("push should always succeed since batch was sized to match archetype"); | |
} | |
} | |
} | |
} | |
fn clone_world(world: &World) -> Result<World, TypeUnknownToCloner> { | |
let mut cloned = World::new(); | |
//FIXME need to have a way to update `cloned`'s entity allocater state to match that of `world` | |
// (or implement this as World::try_clone(), or accept entity ids can be different) | |
for archetype in world.archetypes() { | |
let mut batch = ColumnBatchType::new(); | |
// types have to be listed one by one here | |
try_add_type_to_batch::<String>(archetype, &mut batch); | |
try_add_type_to_batch::<i32>(archetype, &mut batch); | |
let mut batch = batch.into_batch(archetype.ids().len() as u32); | |
//FIXME and types need to be listed again here. Seems like this requires a macro to DRY? | |
// (which then means we can't have entity ids be the same... unless we rework this | |
// function to accept a struct for building batch type) | |
try_clone_column::<String>(archetype, &mut batch); | |
try_copy_column::<i32>(archetype, &mut batch); | |
let batch = batch.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); | |
} | |
Ok(cloned) | |
} | |
pub fn main() { | |
let int0 = 0; | |
let int1 = 1; | |
let str0 = "Ada".to_owned(); | |
let str1 = "Bob".to_owned(); | |
let mut world0 = World::new(); | |
let entity0 = world0.spawn((int0, str0)); | |
let entity1 = world0.spawn((int1, str1)); | |
let world1 = clone_world(&world0).expect("clone should succeed"); | |
assert_eq!( | |
world0.len(), | |
world1.len(), | |
"cloned world should have same entity count as original world" | |
); | |
type AllComponentsQuery = (&'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::<AllComponentsQuery>()); | |
assert!(w1_e.satisfies::<AllComponentsQuery>()); | |
assert_eq!( | |
w0_e.query::<AllComponentsQuery>().get().unwrap(), | |
w1_e.query::<AllComponentsQuery>().get().unwrap() | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment