use std::{collections::HashMap, path::Path};
use xml::attribute::OwnedAttribute;
use crate::{
animation::{parse_animation, Frame},
error::Error,
image::Image,
layers::ObjectLayerData,
properties::{parse_properties, Properties},
util::{get_attrs, parse_tag, XmlEventResult},
ResourceCache, ResourceReader, Result, Tileset,
};
pub type TileId = u32;
#[derive(Debug, PartialEq, Clone, Copy, Default)]
pub struct ImageRect {
pub x: i32,
pub y: i32,
pub width: i32,
pub height: i32,
}
#[derive(Debug, PartialEq, Clone, Default)]
pub struct TileData {
pub image: Option<Image>,
pub properties: Properties,
pub collision: Option<ObjectLayerData>,
pub animation: Option<Vec<Frame>>,
pub user_type: Option<String>,
pub probability: f32,
pub image_rect: Option<ImageRect>,
}
#[derive(Debug)]
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 }
}
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
}
}
impl TileData {
pub(crate) fn new(
parser: &mut impl Iterator<Item = XmlEventResult>,
attrs: Vec<OwnedAttribute>,
path_relative_to: &Path,
reader: &mut impl ResourceReader,
cache: &mut impl ResourceCache,
) -> Result<(TileId, TileData)> {
let ((user_type, user_class, probability, x, y, width, height), id) = get_attrs!(
for v in attrs {
Some("type") => user_type ?= v.parse(),
Some("class") => user_class ?= v.parse(),
Some("probability") => probability ?= v.parse(),
Some("x") => x ?= v.parse(),
Some("y") => y ?= v.parse(),
Some("width") => width ?= v.parse(),
Some("height") => height ?= v.parse(),
"id" => id ?= v.parse::<u32>(),
}
((user_type, user_class, probability, x, y, width, height), id)
);
let user_type = user_type.or(user_class);
let mut image = Option::None;
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)?);
Ok(())
},
"properties" => |_| {
properties = parse_properties(parser)?;
Ok(())
},
"objectgroup" => |attrs| {
objectgroup = Some(ObjectLayerData::new(parser, attrs, None, None, path_relative_to, reader, cache)?.0);
Ok(())
},
"animation" => |_| {
animation = Some(parse_animation(parser)?);
Ok(())
},
});
let image_rect = image.as_ref().map(|image| {
let x = x.unwrap_or(0);
let y = y.unwrap_or(0);
let width = width.unwrap_or(image.width);
let height = height.unwrap_or(image.height);
ImageRect {
x,
y,
width,
height,
}
});
Ok((
id,
TileData {
image,
properties,
collision: objectgroup,
animation,
user_type,
probability: probability.unwrap_or(1.0),
image_rect,
},
))
}
}