Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

as_deserialize_into_world(): provide a way to read a deserialized entities' IDs #269

Open
singalen opened this issue Jul 20, 2021 · 1 comment

Comments

@singalen
Copy link

I'm implementing prefabs, and I feel like as_deserialize() would result in at least one excess copy of the new instance.
as_deserialize_into_world() looks just right, but currently I see no way to know - which exactly Entities were deserialized?
It would be nice to have a callback or to return a collection of ids.

@singalen
Copy link
Author

singalen commented Jul 22, 2021

I have poked around World methods, and here's an inefficient implementation using World::clone_from() and a Duplicate Merger. Leaving it here in case anyone else comes looking for it.

use std::{fs, fmt, io};
use std::ops::Range;
use std::path::Path;
use std::error::Error;
use std::fmt::{Display, Formatter};

use serde::de::DeserializeSeed;

use legion::{Entity, World};
use legion::serialize::Canon;
use legion::world::{Merger, Duplicate, Allocate};

use crate::item::{Item, Headwear};
use crate::components::Render;
use crate::prelude::storage::{Archetype, Components, ArchetypeWriter};


impl Registry {
    
    pub fn new() -> Self {
        let mut result = Self { registry: legion::Registry::<String>::default() };

        result.registry.register::<Render>("render".to_string());
        result.registry.register::<Item>("item".to_string());
        result.registry.register::<Headwear>("headwear".to_string());

        result
    }
    
    fn deser(&self, item_name: &str) -> Result<World, PrefabError> {
        let path = Path::new("data/items").join(item_name).with_extension("json");
        let json = fs::read_to_string(path)?;
        let json_val: serde_json::Value = serde_json::from_str(&json)?;

        let entity_serializer = Canon::default();

        let w = self.registry
            .as_deserialize(&entity_serializer)
            .deserialize(json_val)?;

        Ok(w)
    }

    pub fn load(&self, item_name: &str, world: &mut World) -> Result<Vec<Entity>, PrefabError> {
        struct PrefabMerger {
            pub dup: Duplicate,
            pub entities: Vec<Entity>,
        }
        
        impl Merger for PrefabMerger {
            fn assign_id(&mut self, existing: Entity, allocator: &mut Allocate) -> Entity {
                let id = self.dup.assign_id(existing, allocator);
                self.entities.push(id);
                id
            }

            fn merge_archetype(&mut self, src_entity_range: Range<usize>, src_arch: &Archetype, src_components: &Components, dst: &mut ArchetypeWriter) {
                self.dup.merge_archetype(src_entity_range, src_arch, src_components, dst)
            }
        }
        
        impl PrefabMerger {
            pub fn new() -> Self {
                let mut dup = Duplicate::default();
                dup.register_clone::<Item>();
                dup.register_copy::<Headwear>();
                dup.register_copy::<Render>();
                Self { 
                    dup,
                    entities: vec![] 
                } 
            }
        }

        let mut mirage_world = self.deser(item_name)?;
        let mut merger = PrefabMerger::new();
        world.clone_from(&mut mirage_world, &legion::any(), &mut merger);

        Ok(merger.entities)
    }
}


#[cfg(test)]
mod tests {    
    #[test] 
    fn cask() -> Result<(), PrefabError> {
        let mut world = World::default();
        let reg = Registry::new();
        let entities = reg.load("one_cask", &mut world)?;
        assert_eq!(1, entities.len());
        
        Ok(())
    }
}

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant