bevy_entitiles 0.4.0

A 2d tilemap library for bevy. With many useful algorithms/tools built in.
Documentation
use bevy::{
    app::{App, Plugin, Update},
    ecs::entity::Entity,
    math::UVec2,
    render::render_resource::FilterMode,
};
use serde::{Deserialize, Serialize};

use crate::tilemap::{
    bundles::{PureColorTilemapBundle, TilemapBundle},
    chunking::storage::ChunkedStorage,
    map::{
        TilePivot, TileRenderSize, TilemapAnimations, TilemapLayerOpacities, TilemapName,
        TilemapRotation, TilemapSlotSize, TilemapStorage, TilemapTexture, TilemapTextureDescriptor,
        TilemapTransform, TilemapType,
    },
    tile::TileBuilder,
};

use self::save::TilemapSaver;

pub const TILEMAP_META: &str = "tilemap.ron";
pub const TILES: &str = "tiles.ron";
pub const PATH_TILES: &str = "path_tiles.ron";
pub const PHYSICS_TILES: &str = "physics_tiles.ron";

pub mod load;
pub mod save;

pub struct EntiTilesTilemapSerializingPlugin;

impl Plugin for EntiTilesTilemapSerializingPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(Update, (save::save, load::load));
    }
}

#[derive(Serialize, Deserialize)]
pub struct SerializedTilemapData {
    pub tilemap: SerializedTilemap,
    pub tiles: Vec<TileBuilder>,
}

#[derive(Serialize, Deserialize)]
pub struct SerializedTilemap {
    pub name: TilemapName,
    pub tile_render_size: TileRenderSize,
    pub slot_size: TilemapSlotSize,
    pub ty: TilemapType,
    pub tile_pivot: TilePivot,
    pub layer_opacities: TilemapLayerOpacities,
    pub tilemap_transform: TilemapTransform,
    pub texture: Option<SerializedTilemapTexture>,
    pub animations: Option<TilemapAnimations>,
    pub layers: TilemapLayer,
    pub chunk_size: u32,
}

impl SerializedTilemap {
    pub fn from_tilemap(
        name: TilemapName,
        tile_render_size: TileRenderSize,
        slot_size: TilemapSlotSize,
        ty: TilemapType,
        tile_pivot: TilePivot,
        layer_opacities: TilemapLayerOpacities,
        storage: TilemapStorage,
        tilemap_transform: TilemapTransform,
        texture: Option<TilemapTexture>,
        animations: Option<TilemapAnimations>,
        saver: &TilemapSaver,
    ) -> Self {
        SerializedTilemap {
            name: name.clone(),
            ty,
            tile_render_size,
            slot_size,
            tile_pivot,
            texture: texture.and_then(|tex| {
                Some(SerializedTilemapTexture {
                    path: saver.texture_path.clone().unwrap(),
                    desc: tex.desc.into(),
                    rotation: tex.rotation,
                })
            }),
            layer_opacities,
            tilemap_transform,
            layers: saver.layers,
            animations,
            chunk_size: storage.storage.chunk_size,
        }
    }

    pub fn into_tilemap(&self, tilemap: Entity, texture: TilemapTexture) -> TilemapBundle {
        TilemapBundle {
            name: self.name.clone(),
            ty: self.ty,
            tile_render_size: self.tile_render_size,
            slot_size: self.slot_size,
            tile_pivot: self.tile_pivot,
            layer_opacities: self.layer_opacities,
            storage: TilemapStorage {
                tilemap,
                storage: ChunkedStorage::new(self.chunk_size),
                ..Default::default()
            },
            transform: self.tilemap_transform,
            texture,
            animations: self.animations.clone().unwrap(),
            ..Default::default()
        }
    }

    pub fn into_pure_color_tilemap(&self, tilemap: Entity) -> PureColorTilemapBundle {
        PureColorTilemapBundle {
            name: self.name.clone(),
            ty: self.ty,
            tile_render_size: self.tile_render_size,
            slot_size: self.slot_size,
            tile_pivot: self.tile_pivot,
            layer_opacities: self.layer_opacities,
            storage: TilemapStorage {
                tilemap,
                storage: ChunkedStorage::new(self.chunk_size),
                ..Default::default()
            },
            transform: self.tilemap_transform,
            ..Default::default()
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct SerializedTilemapTexture {
    pub path: String,
    pub desc: SerializedTilemapTextureDescriptor,
    pub rotation: TilemapRotation,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct SerializedTilemapTextureDescriptor {
    pub size: UVec2,
    pub tile_size: UVec2,
    pub filter_mode: SerializedFilterMode,
}

impl From<TilemapTextureDescriptor> for SerializedTilemapTextureDescriptor {
    fn from(value: TilemapTextureDescriptor) -> Self {
        Self {
            size: value.size,
            tile_size: value.tile_size,
            filter_mode: value.filter_mode.into(),
        }
    }
}

impl Into<TilemapTextureDescriptor> for SerializedTilemapTextureDescriptor {
    fn into(self) -> TilemapTextureDescriptor {
        TilemapTextureDescriptor {
            size: self.size,
            tile_size: self.tile_size,
            filter_mode: self.filter_mode.into(),
        }
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub enum SerializedFilterMode {
    Nearest = 0,
    Linear = 1,
}

impl From<FilterMode> for SerializedFilterMode {
    fn from(value: FilterMode) -> Self {
        match value {
            FilterMode::Nearest => Self::Nearest,
            FilterMode::Linear => Self::Linear,
        }
    }
}

impl Into<FilterMode> for SerializedFilterMode {
    fn into(self) -> FilterMode {
        match self {
            Self::Nearest => FilterMode::Nearest,
            Self::Linear => FilterMode::Linear,
        }
    }
}

bitflags::bitflags! {
    #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Clone, Copy, Debug)]
    pub struct TilemapLayer: u32 {
        const COLOR = 1;
        const PATH = 1 << 1;
        const PHYSICS = 1 << 2;
    }
}