ryot 0.2.2

MMORPG library based on the concepts of open tibia written in rust and bevy.
Documentation
use crate::layer::Layer;
use crate::lmdb;
use crate::lmdb::*;
use crate::position::{Sector, TilePosition};
use heed::types::Bytes;
use rayon::prelude::*;
use std::collections::HashMap;

pub fn build_keys_for_area(initial_pos: TilePosition, final_pos: TilePosition) -> Vec<Vec<u8>> {
    let mut keys = vec![];

    for x in initial_pos.x..=final_pos.x {
        for y in initial_pos.y..=final_pos.y {
            for z in initial_pos.z..=final_pos.z {
                keys.push(TilePosition::new(x, y, z).get_binary_key());
            }
        }
    }

    keys
}

pub trait ItemRepository {
    fn get_for_area(&self, sector: &Sector) -> error::Result<Vec<Tile>>;
    fn get_for_keys(&self, keys: Vec<Vec<u8>>) -> error::Result<Vec<Tile>>;
    fn save_from_tiles(&self, items: Vec<Tile>) -> error::Result<()>;
    fn delete(&self, key: Vec<u8>) -> error::Result<()>;
    fn delete_multiple(&self, keys: Vec<Vec<u8>>) -> error::Result<()>;
}

#[derive(Clone)]
pub struct ItemsFromHeedLmdb {
    env: heed::Env,
}

impl ItemsFromHeedLmdb {
    pub fn new(env: heed::Env) -> Self {
        Self { env }
    }
}

impl ItemRepository for ItemsFromHeedLmdb {
    fn get_for_area(&self, sector: &Sector) -> error::Result<Vec<Tile>> {
        let chunks = get_chunks_per_z(sector);

        let result: Vec<Tile> = chunks
            .par_iter()
            .flat_map(|sector| {
                self.get_for_keys(build_keys_for_area(sector.min, sector.max))
                    .unwrap_or_else(|_| Vec::new())
            })
            .collect();

        Ok(result)
    }

    fn get_for_keys(&self, keys: Vec<Vec<u8>>) -> error::Result<Vec<Tile>> {
        let mut tiles = vec![];

        let (rtxn, rodb) =
            lmdb::ro::<Bytes, SerdePostcard<HashMap<Layer, Item>>>(&self.env, DatabaseName::Tiles)?;

        for key in keys {
            let tile: Option<HashMap<Layer, Item>> = rodb.get(&rtxn, &key)?;
            if let Some(tile) = tile {
                tiles.push(Tile::new(TilePosition::from_binary_key(&key), tile));
            }
        }

        rtxn.commit()?;

        Ok(tiles)
    }

    fn save_from_tiles(&self, tiles: Vec<Tile>) -> error::Result<()> {
        let (mut wtxn, db) =
            lmdb::rw::<Bytes, SerdePostcard<HashMap<Layer, Item>>>(&self.env, DatabaseName::Tiles)?;

        for tile in tiles {
            let item = tile.items;
            let key = tile.position.get_binary_key();

            db.delete(&mut wtxn, &key)?;
            db.put(&mut wtxn, &key, &item)?;
        }

        wtxn.commit()?;

        Ok(())
    }

    fn delete(&self, key: Vec<u8>) -> error::Result<()> {
        let (mut wtxn, db) =
            lmdb::rw::<Bytes, SerdePostcard<HashMap<Layer, Item>>>(&self.env, DatabaseName::Tiles)?;

        db.delete(&mut wtxn, &key)?;

        wtxn.commit()?;

        Ok(())
    }

    fn delete_multiple(&self, keys: Vec<Vec<u8>>) -> error::Result<()> {
        let (mut wtxn, db) =
            lmdb::rw::<Bytes, SerdePostcard<HashMap<Layer, Item>>>(&self.env, DatabaseName::Tiles)?;

        for key in keys {
            db.delete(&mut wtxn, &key)?;
        }

        wtxn.commit()?;

        Ok(())
    }
}