legion
legion copied to clipboard
as_deserialize_into_world(): provide a way to read a deserialized entities' IDs
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.
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(())
}
}