use crate::{
layer::ObjectGroup,
parsers::{parse_color, parse_path, parse_property},
wangs::WangSet,
Color, TiledValue, Vec2,
};
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;
#[derive(Debug, PartialEq, Clone)]
pub struct TileSet {
pub columns: u32,
pub first_gid: u32,
pub image: PathBuf,
pub image_width: u32,
pub image_height: u32,
pub margin: u32,
pub spacing: u32,
pub name: String,
pub properties: HashMap<String, TiledValue>,
pub terrains: Option<Vec<Terrain>>,
pub tile_count: u32,
pub tile_height: u32,
pub tile_width: u32,
pub tile_offset: Option<Vec2<i32>>,
pub tiles: Option<Vec<Tile>>,
pub transparent_color: Color,
pub wang_sets: Option<Vec<WangSet>>,
}
impl<'de> Deserialize<'de> for TileSet {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
struct External {
#[serde(rename(deserialize = "firstgid"))]
first_gid: u32,
source: String,
}
#[derive(Deserialize)]
struct Internal {
columns: u32,
#[serde(rename(deserialize = "firstgid"), default)]
first_gid: u32,
#[serde(deserialize_with = "parse_path")]
image: PathBuf,
#[serde(rename(deserialize = "imagewidth"))]
image_width: u32,
#[serde(rename(deserialize = "imageheight"))]
image_height: u32,
margin: u32,
spacing: u32,
name: String,
#[serde(deserialize_with = "parse_property", default)]
properties: HashMap<String, TiledValue>,
terrains: Option<Vec<Terrain>>,
#[serde(rename(deserialize = "tilecount"))]
tile_count: u32,
#[serde(rename(deserialize = "tileheight"))]
tile_height: u32,
#[serde(rename(deserialize = "tilewidth"))]
tile_width: u32,
#[serde(rename(deserialize = "tileoffset"))]
tile_offset: Option<Vec2<i32>>,
tiles: Option<Vec<Tile>>,
#[serde(
rename(deserialize = "transparentcolor"),
deserialize_with = "parse_color",
default
)]
transparent_color: Color,
#[serde(rename(deserialize = "wangsets"))]
wang_sets: Option<Vec<WangSet>>,
}
#[derive(Deserialize)]
#[serde(untagged)]
enum Helper {
Internal(Internal),
External(External),
}
let v = serde_json::Value::deserialize(deserializer)?;
if let Ok(m) = Helper::deserialize(&v) {
let t = match m {
Helper::Internal(v) => v,
Helper::External(v) => {
let path = PathBuf::from(v.source);
let file = File::open(path)
.map_err(|e| Error::custom(format!("{:?}", e)))?;
let mut set: Internal = serde_json::from_reader(file)
.map_err(|e| Error::custom(format!("{:?}", e)))?;
set.first_gid = v.first_gid;
set
}
};
let tile_set = TileSet {
columns: t.columns,
first_gid: t.first_gid,
image: t.image,
image_width: t.image_width,
image_height: t.image_height,
margin: t.margin,
spacing: t.spacing,
name: t.name,
properties: t.properties,
terrains: t.terrains,
tile_count: t.tile_count,
tile_height: t.tile_height,
tile_width: t.tile_width,
tile_offset: t.tile_offset,
tiles: t.tiles,
transparent_color: t.transparent_color,
wang_sets: t.wang_sets,
};
return Ok(tile_set);
} else {
Err(Error::custom("could not parse tile-set"))
}
}
}
#[derive(Deserialize, Debug, PartialEq, Clone)]
pub struct Tile {
pub animation: Option<Vec<Frame>>,
pub id: u32,
pub image: Option<String>,
#[serde(rename(deserialize = "imagewidth"), default)]
pub image_width: u32,
#[serde(rename(deserialize = "imageheight"), default)]
pub image_height: u32,
#[serde(rename(deserialize = "objectgroup"))]
pub object_group: Option<ObjectGroup>,
#[serde(deserialize_with = "parse_property", default)]
pub properties: HashMap<String, TiledValue>,
pub terrain: Option<[i8; 4]>,
#[serde(rename(deserialize = "type"))]
pub tile_type: Option<String>,
}
#[derive(Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Frame {
pub duration: u32,
#[serde(rename(deserialize = "tileid"))]
pub tile_id: u32,
}
#[derive(Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Terrain {
pub name: String,
pub tile: u32,
}