1use crate::{
6 layer::ObjectGroup,
7 parsers::{parse_color, parse_path, parse_property},
8 wangs::WangSet,
9 Color, TiledValue, Vec2,
10};
11use serde::de::Error;
12use serde::{Deserialize, Deserializer};
13use std::collections::HashMap;
14use std::fs::File;
15use std::path::PathBuf;
16
17#[derive(Debug, PartialEq, Clone)]
26pub struct TileSet {
27 pub columns: u32,
31 pub first_gid: u32,
33 pub image: PathBuf,
35 pub image_width: u32,
36 pub image_height: u32,
37 pub margin: u32,
39 pub spacing: u32,
41 pub name: String,
42 pub properties: HashMap<String, TiledValue>,
43 pub terrains: Option<Vec<Terrain>>,
44 pub tile_count: u32,
47 pub tile_height: u32,
48 pub tile_width: u32,
49 pub tile_offset: Option<Vec2<i32>>,
52 pub tiles: Option<Vec<Tile>>,
54 pub transparent_color: Color,
56 pub wang_sets: Option<Vec<WangSet>>,
57}
58
59impl<'de> Deserialize<'de> for TileSet {
60 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
61 where
62 D: Deserializer<'de>,
63 {
64 #[derive(Deserialize)]
65 #[serde(rename_all = "lowercase")]
66 struct External {
67 #[serde(rename(deserialize = "firstgid"))]
68 first_gid: u32,
69 source: String,
70 }
71
72 #[derive(Deserialize)]
73 struct Internal {
74 columns: u32,
75 #[serde(rename(deserialize = "firstgid"), default)]
76 first_gid: u32,
77 #[serde(deserialize_with = "parse_path")]
78 image: PathBuf,
79 #[serde(rename(deserialize = "imagewidth"))]
80 image_width: u32,
81 #[serde(rename(deserialize = "imageheight"))]
82 image_height: u32,
83 margin: u32,
84 spacing: u32,
85 name: String,
86 #[serde(deserialize_with = "parse_property", default)]
87 properties: HashMap<String, TiledValue>,
88 terrains: Option<Vec<Terrain>>,
89 #[serde(rename(deserialize = "tilecount"))]
90 tile_count: u32,
91 #[serde(rename(deserialize = "tileheight"))]
92 tile_height: u32,
93 #[serde(rename(deserialize = "tilewidth"))]
94 tile_width: u32,
95 #[serde(rename(deserialize = "tileoffset"))]
96 tile_offset: Option<Vec2<i32>>,
97 tiles: Option<Vec<Tile>>,
98 #[serde(
99 rename(deserialize = "transparentcolor"),
100 deserialize_with = "parse_color",
101 default
102 )]
103 transparent_color: Color,
104 #[serde(rename(deserialize = "wangsets"))]
105 wang_sets: Option<Vec<WangSet>>,
106 }
107
108 #[derive(Deserialize)]
109 #[serde(untagged)]
110 enum Helper {
111 Internal(Internal),
112 External(External),
113 }
114
115 let v = serde_json::Value::deserialize(deserializer)?;
116 if let Ok(m) = Helper::deserialize(&v) {
117 let t = match m {
118 Helper::Internal(v) => v,
119 Helper::External(v) => {
120 let path = PathBuf::from(v.source);
121 let file = File::open(path)
122 .map_err(|e| Error::custom(format!("{:?}", e)))?;
123 let mut set: Internal = serde_json::from_reader(file)
124 .map_err(|e| Error::custom(format!("{:?}", e)))?;
125 set.first_gid = v.first_gid;
126 set
127 }
128 };
129 let tile_set = TileSet {
130 columns: t.columns,
131 first_gid: t.first_gid,
132 image: t.image,
133 image_width: t.image_width,
134 image_height: t.image_height,
135 margin: t.margin,
136 spacing: t.spacing,
137 name: t.name,
138 properties: t.properties,
139 terrains: t.terrains,
140 tile_count: t.tile_count,
141 tile_height: t.tile_height,
142 tile_width: t.tile_width,
143 tile_offset: t.tile_offset,
144 tiles: t.tiles,
145 transparent_color: t.transparent_color,
146 wang_sets: t.wang_sets,
147 };
148 return Ok(tile_set);
149 } else {
150 Err(Error::custom("could not parse tile-set"))
151 }
152 }
153}
154
155#[derive(Deserialize, Debug, PartialEq, Clone)]
157pub struct Tile {
158 pub animation: Option<Vec<Frame>>,
159 pub id: u32,
163 pub image: Option<String>,
165 #[serde(rename(deserialize = "imagewidth"), default)]
167 pub image_width: u32,
168 #[serde(rename(deserialize = "imageheight"), default)]
170 pub image_height: u32,
171 #[serde(rename(deserialize = "objectgroup"))]
172 pub object_group: Option<ObjectGroup>,
173 #[serde(deserialize_with = "parse_property", default)]
174 pub properties: HashMap<String, TiledValue>,
175 pub terrain: Option<[i8; 4]>,
182 #[serde(rename(deserialize = "type"))]
184 pub tile_type: Option<String>,
185}
186
187#[derive(Deserialize, Debug, PartialEq, Eq, Clone)]
189pub struct Frame {
190 pub duration: u32,
192 #[serde(rename(deserialize = "tileid"))]
194 pub tile_id: u32,
195}
196
197#[derive(Deserialize, Debug, PartialEq, Eq, Clone)]
198pub struct Terrain {
199 pub name: String,
200 pub tile: u32,
202}