Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use std::{collections::HashMap, fmt, io::Read, path::Path, str::FromStr};
use xml::{attribute::OwnedAttribute, EventReader};
use crate::{
error::{ParseTileError, TiledError},
layers::{ImageLayer, Layer},
objects::ObjectGroup,
properties::{parse_properties, Colour, Properties},
tileset::Tileset,
util::*,
};
/// All Tiled files will be parsed into this. Holds all the layers and tilesets
#[derive(Debug, PartialEq, Clone)]
pub struct Map {
pub version: String,
pub orientation: Orientation,
/// Width of the map, in tiles
pub width: u32,
/// Height of the map, in tiles
pub height: u32,
pub tile_width: u32,
pub tile_height: u32,
pub tilesets: Vec<Tileset>,
pub layers: Vec<Layer>,
pub image_layers: Vec<ImageLayer>,
pub object_groups: Vec<ObjectGroup>,
pub properties: Properties,
pub background_colour: Option<Colour>,
pub infinite: bool,
}
impl Map {
pub(crate) fn new<R: Read>(
parser: &mut EventReader<R>,
attrs: Vec<OwnedAttribute>,
map_path: Option<&Path>,
) -> Result<Map, TiledError> {
let ((c, infinite), (v, o, w, h, tw, th)) = get_attrs!(
attrs,
optionals: [
("backgroundcolor", colour, |v:String| v.parse().ok()),
("infinite", infinite, |v:String| Some(v == "1")),
],
required: [
("version", version, |v| Some(v)),
("orientation", orientation, |v:String| v.parse().ok()),
("width", width, |v:String| v.parse().ok()),
("height", height, |v:String| v.parse().ok()),
("tilewidth", tile_width, |v:String| v.parse().ok()),
("tileheight", tile_height, |v:String| v.parse().ok()),
],
TiledError::MalformedAttributes("map must have a version, width and height with correct types".to_string())
);
let mut tilesets = Vec::new();
let mut layers = Vec::new();
let mut image_layers = Vec::new();
let mut properties = HashMap::new();
let mut object_groups = Vec::new();
let mut layer_index = 0;
parse_tag!(parser, "map", {
"tileset" => |attrs| {
tilesets.push(Tileset::new(parser, attrs, map_path)?);
Ok(())
},
"layer" => |attrs| {
layers.push(Layer::new(parser, attrs, w, layer_index, infinite.unwrap_or(false))?);
layer_index += 1;
Ok(())
},
"imagelayer" => |attrs| {
image_layers.push(ImageLayer::new(parser, attrs, layer_index)?);
layer_index += 1;
Ok(())
},
"properties" => |_| {
properties = parse_properties(parser)?;
Ok(())
},
"objectgroup" => |attrs| {
object_groups.push(ObjectGroup::new(parser, attrs, Some(layer_index))?);
layer_index += 1;
Ok(())
},
});
Ok(Map {
version: v,
orientation: o,
width: w,
height: h,
tile_width: tw,
tile_height: th,
tilesets,
layers,
image_layers,
object_groups,
properties,
background_colour: c,
infinite: infinite.unwrap_or(false),
})
}
/// This function will return the correct Tileset given a GID.
pub fn get_tileset_by_gid(&self, gid: u32) -> Option<&Tileset> {
let mut maximum_gid: i32 = -1;
let mut maximum_ts = None;
for tileset in self.tilesets.iter() {
if tileset.first_gid as i32 > maximum_gid && tileset.first_gid <= gid {
maximum_gid = tileset.first_gid as i32;
maximum_ts = Some(tileset);
}
}
maximum_ts
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Orientation {
Orthogonal,
Isometric,
Staggered,
Hexagonal,
}
impl FromStr for Orientation {
type Err = ParseTileError;
fn from_str(s: &str) -> Result<Orientation, ParseTileError> {
match s {
"orthogonal" => Ok(Orientation::Orthogonal),
"isometric" => Ok(Orientation::Isometric),
"staggered" => Ok(Orientation::Staggered),
"hexagonal" => Ok(Orientation::Hexagonal),
_ => Err(ParseTileError::OrientationError),
}
}
}
impl fmt::Display for Orientation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Orientation::Orthogonal => write!(f, "orthogonal"),
Orientation::Isometric => write!(f, "isometric"),
Orientation::Staggered => write!(f, "staggered"),
Orientation::Hexagonal => write!(f, "hexagonal"),
}
}
}