Skip to content
New issue

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

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

Already on GitHub? Sign in 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(())
    }
}

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

No branches or pull requests

1 participant