assembly_maps/luz/
parser.rs

1use assembly_core::nom::{
2    call,
3    combinator::map,
4    cond, count, do_parse, length_count, map, map_res, named, named_args,
5    number::complete::{le_u32, le_u64, le_u8},
6    switch, take, value, IResult,
7};
8use std::convert::TryFrom;
9
10use super::core::{
11    FileVersion, SceneRef, SceneTransition, SceneTransitionInfo, SceneTransitionPoint, ZoneFile,
12};
13use assembly_core::nom_ext::{count_2, count_5};
14use assembly_core::parser::{parse_quat, parse_u8_string, parse_vec3f, parse_world_id};
15use assembly_core::types::Placement3D;
16
17named!(pub parse_file_version<FileVersion>,
18    map!(le_u32, FileVersion::from)
19);
20
21named_args!(pub parse_file_revision(version: FileVersion)<Option<u32>>,
22    cond!(version.id() >= 0x24, call!(le_u32))
23);
24
25named_args!(pub parse_spawn_point(version: FileVersion)<Option<Placement3D>>,
26    cond!(version.id() >= 0x26,
27        do_parse!(a: parse_vec3f >> b: parse_quat >> (Placement3D{pos: a, rot: b}))
28    )
29);
30
31named_args!(pub parse_scene_count(version: FileVersion)<usize>,
32    switch!(value!(version.id() >= 0x25),
33        true => map_res!(le_u32, usize::try_from) |
34        false => map_res!(le_u8, usize::try_from)
35    )
36);
37
38named!(
39    parse_scene_ref<SceneRef>,
40    do_parse!(
41        file_name: parse_u8_string
42            >> id: le_u32
43            >> layer: le_u32
44            >> name: parse_u8_string
45            >> take!(3)
46            >> (SceneRef {
47                file_name,
48                id,
49                layer,
50                name
51            })
52    )
53);
54
55named!(
56    parse_scene_transition_point<SceneTransitionPoint>,
57    do_parse!(
58        a: le_u64
59            >> b: parse_vec3f
60            >> (SceneTransitionPoint {
61                scene_id: a,
62                point: b
63            })
64    )
65);
66
67fn parse_scene_transition_info<'a>(
68    i: &'a [u8],
69    version: FileVersion,
70) -> IResult<&'a [u8], SceneTransitionInfo> {
71    if version.id() <= 0x21 || version.id() >= 0x27 {
72        map(
73            count_2(parse_scene_transition_point),
74            SceneTransitionInfo::from,
75        )(i)
76    } else {
77        map(
78            count_5(parse_scene_transition_point),
79            SceneTransitionInfo::from,
80        )(i)
81    }
82}
83
84named_args!(parse_scene_transition(version: FileVersion)<SceneTransition>,
85    do_parse!(
86        name: cond!(version.id() < 0x25, parse_u8_string) >>
87        points: call!(parse_scene_transition_info, version) >>
88        (SceneTransition{ name, points })
89    )
90);
91
92named_args!(parse_scene_transitions(version: FileVersion)<Option<Vec<SceneTransition>>>,
93    cond!(version.id() >= 0x20,
94        length_count!(le_u32, call!(parse_scene_transition, version))
95    )
96);
97
98named!(pub parse_zone_file<ZoneFile<Vec<u8>>>,
99    do_parse!(
100        file_version: parse_file_version >>
101        b: call!(parse_file_revision, file_version) >>
102        c: parse_world_id >>
103        d: call!(parse_spawn_point, file_version) >>
104        e: call!(parse_scene_count, file_version) >>
105        f: count!(parse_scene_ref, e) >>
106        g: parse_u8_string >>
107        h: parse_u8_string >>
108        i: parse_u8_string >>
109        j: parse_u8_string >>
110        k: call!(parse_scene_transitions, file_version) >>
111        l: cond!(file_version.min(0x23), length_count!(le_u32, le_u8)) >>
112        (ZoneFile{
113            file_version,
114            file_revision: b,
115            world_id: c,
116            spawn_point: d,
117            scene_refs: f,
118
119            something: g,
120            map_filename: h,
121            map_name: i,
122            map_description: j,
123
124            scene_transitions: k,
125            path_data: l,
126        })
127    )
128);
129
130#[test]
131fn test_parse() {
132    use assembly_core::nom::error::ErrorKind;
133
134    assert_eq!(
135        parse_file_revision(&[20, 0, 0, 0], FileVersion::from(0x24)),
136        Ok((&[][..], Some(20)))
137    );
138    assert_eq!(
139        parse_file_revision(&[20, 0, 0, 0], FileVersion::from(0x23)),
140        Ok((&[20, 0, 0, 0][..], None))
141    );
142    assert_eq!(
143        parse_scene_count(&[20], FileVersion::from(0x24)),
144        Ok((&[][..], 20))
145    );
146    assert_eq!(
147        parse_scene_count(&[20, 0, 0, 0], FileVersion::from(0x25)),
148        Ok((&[][..], 20))
149    );
150    assert_eq!(
151        parse_u8_string::<(&[u8], ErrorKind)>(&[2, 65, 66]),
152        Ok((&[][..], String::from("AB")))
153    );
154}