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

Failed World::clone_from(), because of missing Duplicate::register_clone(), asserts #271

Open
singalen opened this issue Jul 22, 2021 · 0 comments

Comments

@singalen
Copy link

This code tries to implement the request from #269 – to deserialize into an existing World and to find out what exactly we have deserialized.

I didn't realize one needs Duplicate::register_clone() or Duplicate::register_copy() in order to copy/clone anything between Worlds.

As a result, the following crashes:

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 { 
                Self { dup: Duplicate::default(), 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(())
    }
}

It fails with the following stack:

   3: core::panicking::assert_failed
             at /Users/vic/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/panicking.rs:143:5
   4: <legion::internals::insert::ArchetypeWriter as core::ops::drop::Drop>::drop
             at /Users/vic/.cargo/registry/src/github.com-1ecc6299db9ec823/legion-0.4.0/src/internals/insert.rs:113:9
   5: core::ptr::drop_in_place<legion::internals::insert::ArchetypeWriter>
             at /Users/vic/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:192:1
   6: legion::internals::world::World::clone_from
             at /Users/vic/.cargo/registry/src/github.com-1ecc6299db9ec823/legion-0.4.0/src/internals/world.rs:691:9
   7: rifrl::item::prefabs::Registry::load
             at ./src/item/prefabs.rs:103:9
   8: rifrl::item::prefabs::tests::cask
             at ./src/item/prefabs.rs:183:24

in impl Drop for ArchetypeWriter::drop():

        assert_eq!(
            self.claimed.count_ones() as usize,
            self.archetype.layout().component_types().len()
        );

I guess this should not crash, but instead just clone nothing. Or, maybe, it should, but with a more clear error message.

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