Skip to content
Snippets Groups Projects
tile.rs 3.26 KiB
Newer Older
use std::{collections::HashMap, path::Path};
alexdevteam's avatar
alexdevteam committed

use xml::attribute::OwnedAttribute;
alexdevteam's avatar
alexdevteam committed

use crate::{
    animation::{parse_animation, Frame},
alexdevteam's avatar
alexdevteam committed
    image::Image,
    layers::ObjectLayerData,
alexdevteam's avatar
alexdevteam committed
    properties::{parse_properties, Properties},
    util::{get_attrs, parse_tag, XmlEventResult},
alexdevteam's avatar
alexdevteam committed
};

/// A tile ID, local to a tileset.
pub type TileId = u32;

/// Raw data belonging to a tile.
#[derive(Debug, PartialEq, Clone, Default)]
pub struct TileData {
    /// The image of the tile. Only set when the tile is part of an "image collection" tileset.
    pub image: Option<Image>,
    /// The custom properties of this tile.
    pub properties: Properties,
    /// The collision shapes of this tile.
    pub collision: Option<ObjectLayerData>,
    /// The animation frames of this tile.
    pub animation: Option<Vec<Frame>>,
    /// The type of this tile.
    pub tile_type: Option<String>,
    /// The probability of this tile.
    pub probability: f32,
alexdevteam's avatar
alexdevteam committed
}

/// Points to a tile belonging to a tileset.
#[derive(Debug)]
Alejandro Perea's avatar
Alejandro Perea committed
pub struct Tile<'tileset> {
    pub(crate) tileset: &'tileset Tileset,
    pub(crate) data: &'tileset TileData,
}

impl<'tileset> Tile<'tileset> {
    pub(crate) fn new(tileset: &'tileset Tileset, data: &'tileset TileData) -> Self {
        Self { tileset, data }
    }

    /// Get the tileset this tile is from.
    pub fn tileset(&self) -> &'tileset Tileset {
        self.tileset
    }
impl<'tileset> std::ops::Deref for Tile<'tileset> {
    type Target = TileData;
    #[inline]
    fn deref(&self) -> &'tileset Self::Target {
        self.data
Alejandro Perea's avatar
Alejandro Perea committed
    }
}

impl TileData {
    pub(crate) fn new(
        parser: &mut impl Iterator<Item = XmlEventResult>,
alexdevteam's avatar
alexdevteam committed
        attrs: Vec<OwnedAttribute>,
        path_relative_to: &Path,
    ) -> Result<(TileId, TileData)> {
alexdevteam's avatar
alexdevteam committed
        let ((tile_type, probability), id) = get_attrs!(
            attrs,
            optionals: [
                ("type", tile_type, |v:String| v.parse().ok()),
                ("probability", probability, |v:String| v.parse().ok()),
            ],
            required: [
                ("id", id, |v:String| v.parse::<u32>().ok()),
            ],
            Error::MalformedAttributes("tile must have an id with the correct type".to_string())
alexdevteam's avatar
alexdevteam committed
        );

alexdevteam's avatar
alexdevteam committed
        let mut properties = HashMap::new();
        let mut objectgroup = None;
        let mut animation = None;
        parse_tag!(parser, "tile", {
            "image" => |attrs| {
                image = Some(Image::new(parser, attrs, path_relative_to)?);
alexdevteam's avatar
alexdevteam committed
                Ok(())
            },
            "properties" => |_| {
                properties = parse_properties(parser)?;
                Ok(())
            },
            "objectgroup" => |attrs| {
                objectgroup = Some(ObjectLayerData::new(parser, attrs, None)?.0);
alexdevteam's avatar
alexdevteam committed
                Ok(())
            },
            "animation" => |_| {
                animation = Some(parse_animation(parser)?);
                Ok(())
            },
        });
alexdevteam's avatar
alexdevteam committed
            id,
Alejandro Perea's avatar
Alejandro Perea committed
            TileData {
                image,
                properties,
                collision: objectgroup,
                animation,
                tile_type,
                probability: probability.unwrap_or(1.0),
            },
        ))
alexdevteam's avatar
alexdevteam committed
    }
}