amethyst / legion

High performance Rust ECS library
MIT License
1.63k stars 136 forks source link

Trying to deserialize from JSON file #268

Open dyedquartz opened 3 years ago

dyedquartz commented 3 years ago

Hi! I'm trying to follow the rust rogueliketoolkit tutorial and trying to convert it to legion.

I'm trying to deserialize a savegame.json file, but I'm getting errors. The deserializer isn't well documented, but I've tried my best:

pub fn load_game(world: &mut World, resources: &mut Resources) {
    /*{
        let mut cmd = CommandBuffer::new(world);
        let mut to_delete = Vec::new();
        for e in <Entity>::query().iter_mut(world) {
            to_delete.push(*e);
        }
        for del in to_delete.iter() {
            cmd.remove(*del);
        }
        cmd.flush(world, resources);
     } */

    let mut registry = Registry::<String>::default();

    register_components!(registry, BlocksTile, CombatStats, Player, Position, Monster, Name, Item, Renderable, SufferDamage, Viewshed, WantsToMelee, InBackpack, WantsToPickupItem, WantsToUseItem, WantsToDropItem, Consumable, ProvidesHealing, Ranged, InflictsDamage, AreaOfEffect, Confusion, SerializationHelper);

    let data = fs::read_to_string("./savegame.json").unwrap();
    let entity_serializer = Canon::default();
    let new_world: World = registry.as_deserialize(&entity_serializer).deserialize(data).expect("Unable to deserialize world");
    //let new_world: World = registry.as_deserialize(&entity_serializer).deserialize(data).unwrap();

    *world = new_world;

    let mut deleteme: Option<Entity> = None;
    {
        for (entity, helper) in <(Entity, &SerializationHelper)>::query().iter(world) {
            resources.insert(helper.map.clone());
            let mut map = resources.get_mut::<Map>().unwrap();
            map.tile_content = vec![Vec::new(); super::map::MAP_COUNT];
            deleteme = Some(*entity);
        }

        for (entity, _player, position) in <(Entity, &Player, &Position)>::query().iter(world) {
            resources.insert(rltk::Point::new(position.x, position.y));
            resources.insert(PlayerEntity { entity: *entity })
        }
    }
    let mut cmd = CommandBuffer::new(world);
    cmd.remove(deleteme.unwrap());
    cmd.flush(world, resources);
}

The register_components! macro is just a way to iterate over all my components and register them with a name of their lowercase struct name

error[E0277]: the trait bound `std::string::String: components::_::_serde::Deserializer<'_>` is not satisfied
  --> src\saveload_system.rs:58:84
   |
58 |     let new_world: World = registry.as_deserialize(&entity_serializer).deserialize(data).expect("Unable to deserialize world");
   |                                                                                    ^^^^ the trait `components::_::_serde::Deserializer<'_>` is not implemented for `std::string::String`

sorry for such a basic question, but I'm really having problems and I don't know how to fix it.

zedrian commented 3 years ago

Hi @dyedquartz, I haven't tried the deserialization by myself yet, but as I can see from documentation for legion::serialize module, they pass a serde_json::Value as an argument to deserialize(), not a String (because serde_json::to_value() returns serde_json::Value there). What you can try is adding something like let json = serde_json::from_str(data).unwrap(); and then passing that json to deserialize() instead of data.

singalen commented 3 years ago

Just solved the same issue by converting String to json::Value. However, I have a next issue now: after calling as_deserialize_into_world(...).deserialize(json_value), I don't have the id of the newly created Entities. How can I refer to the newly created entities?

singalen commented 3 years ago

@zedrian @dyedquartz Herbert, the author of the said tutorial and "Hands-on Rust" book (which is another tutorial), has created a forum. I've opened a topic about prefabs here (might take some time to pass pre-moderaion). I have also published a working deserializer in issue #269 in this repo.