1use binrw::{BinRead, NullString};
2use std::io::{Read, Seek, SeekFrom};
3
4pub fn parse_smf<R: Read + Seek>(reader: &mut R) -> Result<SMF, binrw::Error> {
15 SMF::read(reader)
16}
17
18#[derive(BinRead, Debug, Clone)]
19#[br(magic = b"spring map file\0", little)]
20pub struct SMF {
21 pub header: SMFHeader,
22
23 #[br(count = header.extra_header_count)]
24 pub extra_headers: Vec<ExtraHeaders>,
25
26 #[br(
27 args { width: header.width, length: header.length },
28 seek_before = SeekFrom::Start(header.height_map_ptr as u64)
29 )]
30 pub height_map: HeightMap,
31
32 #[br(
33 args { width: header.width, length: header.length },
34 seek_before = SeekFrom::Start(header.type_map_ptr as u64)
35 )]
36 pub type_map: TypeMap,
37
38 #[br(seek_before = SeekFrom::Start(header.minimap_ptr as u64))]
39 pub mini_map: MiniMap,
40
41 #[br(
42 args { width: header.width, length: header.length },
43 seek_before = SeekFrom::Start(header.tiles_ptr as u64)
44 )]
45 pub smt_file_info: TileInfo,
46
47 #[br(
48 args { width: header.width, length: header.length },
49 seek_before = SeekFrom::Start(header.metal_map_ptr as u64)
50 )]
51 pub metal_map: MetalMap,
52
53 #[br(seek_before = SeekFrom::Start(header.feature_ptr as u64))]
54 pub features: Features,
55}
56
57#[derive(BinRead, Debug, Clone)]
58#[br()]
59pub struct SMFHeader {
60 pub version: u32,
61 pub id: u32,
62 pub width: u32,
63 pub length: u32,
64 pub square_size: u32,
65 pub texel_per_square: u32,
66 pub tile_size: u32,
67 pub min_height: f32,
68 pub max_height: f32,
69 pub height_map_ptr: u32,
70 pub type_map_ptr: u32,
71 pub tiles_ptr: u32,
72 pub minimap_ptr: u32,
73 pub metal_map_ptr: u32,
74 pub feature_ptr: u32,
75 pub extra_header_count: u32,
76}
77
78#[derive(BinRead, Debug, Clone)]
79#[br()]
80pub struct ExtraHeaders {
81 pub size_of_header: u32,
82 pub type_of_header: u32,
83
84 #[br(count = size_of_header)]
85 pub data: Vec<u8>,
86}
87
88#[derive(BinRead, Debug, Clone)]
89#[br(import { length: u32, width: u32 })]
90pub struct HeightMap(#[br(count = (width + 1) * (length + 1))] pub Vec<u16>);
91
92#[derive(BinRead, Debug, Clone)]
93#[br(import { length: u32, width: u32 })]
94pub struct TypeMap(#[br(count = (width / 2)*(length / 2))] pub Vec<u8>);
95
96#[derive(BinRead, Debug, Clone)]
97#[br()]
98pub struct MiniMap(#[br(count = 699048)] pub Vec<u8>); #[derive(BinRead, Debug, Clone)]
101#[br(import { length: u32, width: u32 })]
102pub struct TileInfo {
103 pub header: TileIndexHeader,
104
105 #[br(count = header.number_of_tile_files)]
106 pub smt_file_info: Vec<SMTFileInfos>,
107
108 #[br(args { width: width, length: length })]
109 pub tile_index: TileIndex,
110}
111
112#[derive(BinRead, Debug, Clone)]
113#[br()]
114pub struct TileIndexHeader {
115 pub number_of_tile_files: u32,
116 pub total_number_of_tiles_in_all_files: u32,
117}
118
119#[derive(BinRead, Debug, Clone)]
120pub struct SMTFileInfos {
121 pub number_of_tiles_in_this_file: u32,
122 pub smt_filename: NullString,
123}
124
125#[derive(BinRead, Debug, Clone)]
126#[br(import { length: u32, width: u32 })]
127pub struct TileIndex(#[br(count = (width / 4) * (length / 4))] pub Vec<u32>);
128
129#[derive(BinRead, Debug, Clone)]
130#[br(import { length: u32, width: u32 })]
131pub struct MetalMap(#[br(count = (width / 2)*(length / 2))] pub Vec<u8>);
132
133#[derive(BinRead, Debug, Clone)]
134#[br()]
135pub struct Features {
136 pub header: FeaturesHeader,
137
138 #[br(count = header.num_feature_types)]
139 pub features: Vec<Feature>,
140}
141
142#[derive(BinRead, Debug, Clone)]
143#[br()]
144pub struct FeaturesHeader {
145 pub num_features: i32,
146 pub num_feature_types: i32,
147
148 #[br(count = num_features)]
149 pub feature_names: Vec<NullString>,
150}
151
152#[derive(BinRead, Debug, Clone)]
153#[br()]
154pub struct Feature {
155 pub feature_type: u32,
156 pub x: f32,
157 pub y: f32,
158 pub z: f32,
159 pub rotation: f32,
160 pub relative_size: f32,
161}
162
163#[cfg(test)]
164mod test {
165 use super::*;
166
167 #[test]
168 fn test() {
169 let file = std::fs::File::open("assets/Great_Divide.smf").unwrap();
170 let mut buf_reader = std::io::BufReader::new(file);
171
172 let smf = parse_smf(&mut buf_reader).unwrap();
173
174 dbg!(smf.header);
175
176 dbg!(smf.smt_file_info.header);
177 dbg!(smf.smt_file_info.smt_file_info);
178 dbg!(smf.features);
179 }
180}