1use std::collections::{BTreeMap, HashSet};
17
18use crate::error::{Result, RLibError};
19use crate::xml::{XmlElement, parse_elements};
20
21use super::*;
22use super::texture::Texture;
23use super::tile_link::TileLink;
24use super::tile_link_target::TileLinkTarget;
25use super::tile_variation::TileVariation;
26
27const RENDER_PARAMS_VERSION: u16 = 6;
29
30const USER_TILE_SET: &str = "user";
32
33struct Document {
35 elements: Vec<XmlElement>,
36 root: usize,
37}
38
39impl TileDatabase {
44
45 pub fn from_assembly_kit(settings: &str, tiles: &[&str], order: Option<&[String]>, add_user_tile_set: bool) -> Result<Self> {
65 let settings = Document::parse(settings)?;
66 let root = settings.root();
67 let mut database = Self::default();
68 database.set_serialise_version(1);
69 database.set_render_params(settings.render_params(settings.child(root, "RENDER_PARAMS")?)?);
70 database.set_conversion_params(settings.conversion_params(settings.child(root, "CONVERSION_PARAMS")?)?);
71
72 let climates = settings.children(settings.child(root, "CLIMATES")?);
73 database.set_climates(climates.into_iter().map(|climate| settings.climate(climate)).collect::<Result<_>>()?);
74
75 let tiles = tiles.iter().map(|tile| Document::parse(tile)).collect::<Result<Vec<_>>>()?;
76
77 let mut tile_sets = settings.children(settings.child(root, "TILE_SETS")?).into_iter()
78 .map(|tile_set| settings.tile_set(tile_set))
79 .collect::<Result<Vec<_>>>()?;
80
81 let mut known = tile_sets.iter().map(|tile_set| tile_set.name().to_owned()).collect::<HashSet<_>>();
82 let mut undefined = vec![];
83 for tile in &tiles {
84 let name = tile.attribute(tile.root(), "tile_set")?;
85 if known.insert(name.to_owned()) {
86 undefined.push(name.to_owned());
87 }
88 }
89
90 if add_user_tile_set && known.insert(USER_TILE_SET.to_owned()) {
91 undefined.push(USER_TILE_SET.to_owned());
92 }
93
94 for name in undefined {
95 let mut tile_set = TileSet::default();
96 tile_set.set_serialise_version(1);
97 tile_set.set_name(name);
98 tile_sets.push(tile_set);
99 }
100
101 database.set_tile_sets(tile_sets);
102
103 let mut tiles = tiles.iter().map(|tile| tile.tile()).collect::<Result<Vec<_>>>()?;
104 match order {
105 Some(order) => {
106 let rank = order.iter().enumerate().map(|(index, location)| (location.as_str(), index)).collect::<BTreeMap<_, _>>();
107 if let Some(tile) = tiles.iter().find(|tile| !rank.contains_key(tile.location().as_str())) {
108 return Err(xml_error(format!("tile missing from the order list: {}", tile.location())));
109 }
110
111 tiles.sort_by_key(|tile| rank[tile.location().as_str()]);
112 }
113 None => tiles.sort_by(|a, b| (b.width() * b.height()).cmp(&(a.width() * a.height())).then_with(|| a.location().cmp(b.location()))),
114 }
115
116 database.set_tiles(tiles);
117 Ok(database)
118 }
119}
120
121impl Document {
122
123 fn parse(xml: &str) -> Result<Self> {
124 let (elements, roots) = parse_elements(xml).map_err(xml_error)?;
125 let root = *roots.first().ok_or_else(|| xml_error("empty document".to_owned()))?;
126
127 Ok(Self { elements, root })
128 }
129
130 fn root(&self) -> usize {
131 self.root
132 }
133
134 fn attribute(&self, element: usize, name: &str) -> Result<&str> {
135 let element = &self.elements[element];
136 element.attributes.iter()
137 .find(|(attribute, _)| attribute == name)
138 .map(|(_, value)| value.as_str())
139 .ok_or_else(|| xml_error(format!("missing attribute '{name}' on <{}>", element.name)))
140 }
141
142 fn f32(&self, element: usize, name: &str) -> Result<f32> {
143 let value = self.attribute(element, name)?;
144 value.parse().map_err(|_| xml_error(format!("'{value}' of '{name}' is not a number")))
145 }
146
147 fn u32(&self, element: usize, name: &str) -> Result<u32> {
148 let value = self.attribute(element, name)?;
149 value.parse().map_err(|_| xml_error(format!("'{value}' of '{name}' is not an unsigned integer")))
150 }
151
152 fn i32(&self, element: usize, name: &str) -> Result<i32> {
153 let value = self.attribute(element, name)?;
154 value.parse().map_err(|_| xml_error(format!("'{value}' of '{name}' is not an integer")))
155 }
156
157 fn u16(&self, element: usize, name: &str) -> Result<u16> {
158 let value = self.attribute(element, name)?;
159 value.parse().map_err(|_| xml_error(format!("'{value}' of '{name}' is not a version")))
160 }
161
162 fn bool(&self, element: usize, name: &str) -> Result<bool> {
163 Ok(self.attribute(element, name)? == "true")
164 }
165
166 fn string(&self, element: usize, name: &str) -> Result<String> {
167 self.attribute(element, name).map(|value| value.to_owned())
168 }
169
170 fn child(&self, element: usize, name: &str) -> Result<usize> {
171 self.elements[element].children.iter().copied()
172 .find(|&child| self.elements[child].name == name)
173 .ok_or_else(|| xml_error(format!("missing <{name}> in <{}>", self.elements[element].name)))
174 }
175
176 fn children(&self, element: usize) -> Vec<usize> {
177 self.elements[element].children.clone()
178 }
179
180 fn render_params(&self, element: usize) -> Result<RenderParams> {
181 let mut params = RenderParams::default();
182 params.set_serialise_version(RENDER_PARAMS_VERSION);
183 params.set_lf_height(self.f32(element, "lf_height")?);
184 params.set_hf_height(self.f32(element, "hf_height")?);
185 params.set_blend_pixel_scale(self.f32(element, "blend_pixel_scale")?);
186 params.set_unit_scale(self.f32(element, "unit_scale")?);
187 params.set_mid_distance_detail_scale(self.f32(element, "mid_distance_detail_scale")?);
188 params.set_mid_distance_detail_strength(self.f32(element, "mid_distance_detail_strength")?);
189 params.set_mid_distance_normal_strength(self.f32(element, "mid_distance_normal_strength")?);
190 params.set_mid_distance_detail_near(self.f32(element, "mid_distance_detail_near")?);
191 params.set_mid_distance_detail_far(self.f32(element, "mid_distance_detail_far")?);
192 params.set_mid_distance_detail_slope_low(self.f32(element, "mid_distance_detail_slope_low")?);
193 params.set_mid_distance_detail_slope_high(self.f32(element, "mid_distance_detail_slope_high")?);
194 params.set_vertical_offset(self.f32(element, "vertical_offset")?);
195 params.set_normal_lf_scale(self.f32(element, "normal_lf_scale")?);
196 params.set_normal_tile_scale(self.f32(element, "normal_tile_scale")?);
197 params.set_normal_terrain_scale(self.f32(element, "normal_terrain_scale")?);
198 params.set_blend_contrast(self.f32(element, "blend_contrast")?);
199 params.set_layer_exempt_0(self.string(element, "layer_exempt_0")?);
200 params.set_layer_exempt_1(self.string(element, "layer_exempt_1")?);
201 params.set_layer_exempt_2(self.string(element, "layer_exempt_2")?);
202 params.set_layer_exempt_3(self.string(element, "layer_exempt_3")?);
203 params.set_campaign_sea_transparency_scale(self.f32(element, "campaign_sea_transparency_scale")?);
204 params.set_campaign_sea_uv_scale(self.f32(element, "campaign_sea_uv_scale")?);
205 params.set_campaign_lake_transparency_scale(self.f32(element, "campaign_lake_transparency_scale")?);
206 params.set_near_distance_detail_distance(self.f32(element, "near_distance_detail_distance")?);
207 params.set_near_distance_detail_scale(self.f32(element, "near_distance_detail_scale")?);
208 params.set_near_distance_detail_strength(self.f32(element, "near_distance_detail_strength")?);
209 params.set_mid_distance_detail_near_lq(self.f32(element, "mid_distance_detail_near_lq")?);
210 Ok(params)
211 }
212
213 fn conversion_params(&self, element: usize) -> Result<ConversionParams> {
214 let mut params = ConversionParams::default();
215 params.set_serialise_version(self.u16(element, "serialise_version")?);
216 params.set_triangle_density(self.i32(element, "triangle_density")?);
217 params.set_max_lf_heights_per_pixel(self.i32(element, "max_lf_heights_per_pixel")?);
218 params.set_triangle_decimation_size_factors0(self.f32(element, "triangle_decimation_size_factors0")?);
219 params.set_triangle_decimation_size_factors1(self.f32(element, "triangle_decimation_size_factors1")?);
220 params.set_triangle_decimation_size_factors2(self.f32(element, "triangle_decimation_size_factors2")?);
221 params.set_triangle_decimation_size_factors3(self.f32(element, "triangle_decimation_size_factors3")?);
222 params.set_triangle_decimation_size_factors4(self.f32(element, "triangle_decimation_size_factors4")?);
223 params.set_triangle_decimation_size_factors5(self.f32(element, "triangle_decimation_size_factors5")?);
224 params.set_triangle_decimation_angle_factors0(self.f32(element, "triangle_decimation_angle_factors0")?);
225 params.set_triangle_decimation_angle_factors1(self.f32(element, "triangle_decimation_angle_factors1")?);
226 params.set_triangle_decimation_angle_factors2(self.f32(element, "triangle_decimation_angle_factors2")?);
227 params.set_triangle_decimation_angle_factors3(self.f32(element, "triangle_decimation_angle_factors3")?);
228 params.set_triangle_decimation_angle_factors4(self.f32(element, "triangle_decimation_angle_factors4")?);
229 params.set_triangle_decimation_angle_factors5(self.f32(element, "triangle_decimation_angle_factors5")?);
230 Ok(params)
231 }
232
233 fn climate(&self, element: usize) -> Result<Climate> {
234 let mut climate = Climate::default();
235 climate.set_serialise_version(self.u16(element, "serialise_version")?);
236 climate.set_name(self.string(element, "name")?);
237 climate.set_texture_set(self.string(element, "texture_set")?);
238 climate.set_red(self.f32(element, "red")?);
239 climate.set_green(self.f32(element, "green")?);
240 climate.set_blue(self.f32(element, "blue")?);
241 climate.set_textures(self.children(self.child(element, "TEXTURES")?).into_iter().map(|texture| self.texture(texture)).collect::<Result<_>>()?);
242 climate.set_grass_alpha_add(self.f32(element, "grass_alpha_add")?);
243 climate.set_grass_alpha_mul(self.f32(element, "grass_alpha_mul")?);
244 climate.set_destruction_climate(self.string(element, "destruction_climate")?);
245 Ok(climate)
246 }
247
248 fn texture(&self, element: usize) -> Result<Texture> {
249 let mut texture = Texture::default();
250 texture.set_serialise_version(self.u16(element, "serialise_version")?);
251 texture.set_name(self.string(element, "name")?);
252 texture.set_mid_distance_strength(self.f32(element, "mid_distance_strength")?);
253 texture.set_lerp_reflectivity0(self.f32(element, "lerp_reflectivity0")?);
254 texture.set_lerp_smoothness0(self.f32(element, "lerp_smoothness0")?);
255 texture.set_lerp_reflectivity1(self.f32(element, "lerp_reflectivity1")?);
256 texture.set_lerp_smoothness1(self.f32(element, "lerp_smoothness1")?);
257 texture.set_lerp_reflectivity2(self.f32(element, "lerp_reflectivity2")?);
258 texture.set_lerp_smoothness2(self.f32(element, "lerp_smoothness2")?);
259 texture.set_lerp_reflectivity3(self.f32(element, "lerp_reflectivity3")?);
260 texture.set_lerp_smoothness3(self.f32(element, "lerp_smoothness3")?);
261 texture.set_blend_pixel_scale(self.f32(element, "blend_pixel_scale")?);
262 texture.set_outfield_blend_pixel_scale(self.f32(element, "outfield_blend_pixel_scale")?);
263 Ok(texture)
264 }
265
266 fn tile_set(&self, element: usize) -> Result<TileSet> {
267 let mut tile_set = TileSet::default();
268 tile_set.set_serialise_version(self.u16(element, "serialise_version")?);
269 tile_set.set_name(self.string(element, "name")?);
270 tile_set.set_linking_tile(self.string(element, "linking_tile")?);
271 tile_set.set_shared_geometry(self.string(element, "shared_geometry")?);
272 tile_set.set_also_place_tile_set(self.string(element, "also_place_tile_set")?);
273 tile_set.set_link_as_set(self.string(element, "link_as_set")?);
274 tile_set.set_red(self.f32(element, "red")?);
275 tile_set.set_green(self.f32(element, "green")?);
276 tile_set.set_blue(self.f32(element, "blue")?);
277 Ok(tile_set)
278 }
279
280 fn tile(&self) -> Result<Tile> {
281 let element = self.root;
282 let mut tile = Tile::default();
283 tile.set_serialise_version(self.u16(element, "serialise_version")?);
284 tile.set_location(self.string(element, "location")?);
285 tile.set_tile_set(self.string(element, "tile_set")?);
286 tile.set_mask(self.string(element, "mask")?);
287 tile.set_width(self.u32(element, "width")?);
288 tile.set_height(self.u32(element, "height")?);
289 tile.set_red(self.f32(element, "red")?);
290 tile.set_green(self.f32(element, "green")?);
291 tile.set_blue(self.f32(element, "blue")?);
292 tile.set_requires_infield_lodding(self.bool(element, "requires_infield_lodding")?);
293 tile.set_random_rotatable(self.bool(element, "random_rotatable")?);
294 tile.set_custom_alpha_blend_texture(self.string(element, "custom_alpha_blend_texture")?);
295 tile.set_scalable(self.bool(element, "scalable")?);
296 tile.set_encampable(self.bool(element, "encampable")?);
297 tile.set_custom_blend_tile(self.string(element, "custom_blend_tile")?);
298
299 let texture_group = self.child(element, "TEXTURE_GROUP")?;
300 tile.set_texture_red(self.string(texture_group, "red")?);
301 tile.set_texture_green(self.string(texture_group, "green")?);
302 tile.set_texture_blue(self.string(texture_group, "blue")?);
303 tile.set_texture_alpha(self.string(texture_group, "alpha")?);
304
305 tile.set_variations(self.children(self.child(element, "VARIATIONS")?).into_iter().map(|variation| self.tile_variation(variation)).collect::<Result<_>>()?);
306 tile.set_link_targets(self.children(self.child(element, "TILE_LINK_TARGETS")?).into_iter().map(|target| self.tile_link_target(target)).collect::<Result<_>>()?);
307 tile.set_links(self.children(self.child(element, "TILE_LINKS")?).into_iter().map(|link| self.tile_link(link)).collect::<Result<_>>()?);
308 Ok(tile)
309 }
310
311 fn tile_variation(&self, element: usize) -> Result<TileVariation> {
312 let mut variation = TileVariation::default();
313 variation.set_serialise_version(self.u16(element, "serialise_version")?);
314 variation.set_location(self.string(element, "location")?);
315 variation.set_min_height(self.f32(element, "min_height")?);
316 variation.set_scale(self.f32(element, "scale")?);
317 variation.set_normal_strength(self.f32(element, "normal_strength")?);
318 variation.set_overlap_border_size(self.f32(element, "overlap_border_size")?);
319 variation.set_raw_data_tri_density(self.u32(element, "raw_data_tri_density")?);
320 variation.set_blend_common(self.string(element, "blend_common")?);
321 variation.set_index_common(self.string(element, "index_common")?);
322 variation.set_normal_common(self.string(element, "normal_common")?);
323 variation.set_red(self.f32(element, "red")?);
324 variation.set_green(self.f32(element, "green")?);
325 variation.set_blue(self.f32(element, "blue")?);
326 variation.set_barbarian(self.bool(element, "barbarian")?);
327 Ok(variation)
328 }
329
330 fn tile_link_target(&self, element: usize) -> Result<TileLinkTarget> {
331 let mut target = TileLinkTarget::default();
332 target.set_serialise_version(self.u16(element, "serialise_version")?);
333 target.set_tile_set(self.string(element, "tile_set")?);
334 target.set_x(self.i32(element, "x")?);
335 target.set_y(self.i32(element, "y")?);
336 Ok(target)
337 }
338
339 fn tile_link(&self, element: usize) -> Result<TileLink> {
340 let mut link = TileLink::default();
341 link.set_serialise_version(self.u16(element, "serialise_version")?);
342 link.set_link_set(self.string(element, "link_set")?);
343 link.set_x(self.i32(element, "x")?);
344 link.set_y(self.i32(element, "y")?);
345 link.set_base_x(self.i32(element, "base_x")?);
346 link.set_base_y(self.i32(element, "base_y")?);
347 link.set_is_entry(self.bool(element, "is_entry")?);
348 link.set_blend_size(self.u32(element, "blend_size")?);
349 link.set_no_offline_blend(self.bool(element, "no_offline_blend")?);
350 link.set_test(self.string(element, "test")?);
351 Ok(link)
352 }
353}
354
355fn xml_error(reason: String) -> RLibError {
357 RLibError::DecodingTileDatabaseXml(reason)
358}