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
use std::collections::HashMap;
use anyhow::Context;
use common::{Chunk, Point, TileIndex, World, CHUNKS_X, CHUNKS_Y, CHUNK_HEIGHT, CHUNK_WIDTH};
use roxmltree::Document;
#[derive(Clone, Copy)]
enum Layer {
Spawns,
Floor,
Wall,
}
pub fn load_map(tmx_file: &str) -> anyhow::Result<World> {
let mut chunks = vec![
Some(Chunk {
walls: vec![None; CHUNK_WIDTH * CHUNK_HEIGHT],
floors: vec![None; CHUNK_WIDTH * CHUNK_HEIGHT],
spawns: Vec::new(),
pcs: HashMap::new(),
});
CHUNKS_X * CHUNKS_Y
];
let mut set_tile = |x: usize, y: usize, tile_index: u32, layer: Layer| {
let chunk_x = x / CHUNK_WIDTH;
let chunk_y = y / CHUNK_HEIGHT;
let tile_x = x % CHUNK_WIDTH;
let tile_y = y % CHUNK_HEIGHT;
let tile_i = tile_x + tile_y * CHUNK_WIDTH;
let chunk = chunks[chunk_x + chunk_y * CHUNKS_X].as_mut().unwrap();
match layer {
Layer::Spawns => chunk.spawns.push(Point(tile_x as i32, tile_y as i32)),
Layer::Floor => chunk.floors[tile_i] = Some(TileIndex(tile_index)),
Layer::Wall => chunk.walls[tile_i] = Some(TileIndex(tile_index)),
}
};
let tmx =
Document::parse(tmx_file).context("Could not parse the .tmx file as an XML document")?;
for tmx_descendant in tmx.descendants() {
if !tmx_descendant.has_tag_name("layer") {
continue;
}
let layer = match tmx_descendant.attribute("name") {
Some("Spawns") => Layer::Spawns,
Some("Floors") => Layer::Floor,
Some("Walls") => Layer::Wall,
_ => continue,
};
let csv_text = match tmx_descendant
.descendants()
.find(|node| node.has_tag_name("data") && node.attribute("encoding") == Some("csv"))
.and_then(|node| node.text())
{
Some(node_text) => node_text,
None => continue,
};
for (y, line) in csv_text.lines().skip_while(|s| s.is_empty()).enumerate() {
if y >= CHUNKS_Y * CHUNK_HEIGHT {
break;
}
for (x, tile_number) in line.split(',').enumerate() {
if x >= CHUNKS_X * CHUNK_WIDTH {
break;
}
let tile_number = match tile_number.parse::<u32>() {
Ok(i) => i,
Err(err) => {
log::warn!("Map csv contains non-number tile: {err}");
continue;
}
};
if tile_number > 0 {
set_tile(x, y, tile_number - 1, layer);
}
}
}
}
Ok(World { time: 0, chunks })
}