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
151
152
153
154
155
156
157
use super::paths::core::ZonePaths;
use crate::luz::paths::parser::parse_zone_paths;
use assembly_core::{
    nom::{error::ErrorKind, Finish, Offset},
    types::{Placement3D, Vector3f, WorldID},
};

#[cfg(feature = "serde-derives")]
use serde::Serialize;

/// Version of the zone file
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde-derives", derive(Serialize))]
pub struct FileVersion(u32);

impl FileVersion {
    pub fn id(&self) -> u32 {
        self.0
    }

    pub fn min(&self, val: u32) -> bool {
        self.0 >= val
    }
}

impl From<u32> for FileVersion {
    fn from(val: u32) -> Self {
        FileVersion(val)
    }
}

/// Reference to a scene file
#[derive(Debug)]
#[cfg_attr(feature = "serde-derives", derive(Serialize))]
pub struct SceneRef {
    /// Name of the scene file
    pub file_name: String,
    /// ID of the scene
    pub id: u32,
    /// 0: default, 1: audio
    pub layer: u32,
    /// Name of the scene
    pub name: String,
}

/// Scene Transition at a single point
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-derives", derive(Serialize))]
pub struct SceneTransitionPoint {
    /// ID of the scene
    pub scene_id: u64,
    /// Position of the transition
    pub point: Vector3f,
}

/// Transition Points
#[derive(Debug)]
#[cfg_attr(feature = "serde-derives", derive(Serialize))]
pub enum SceneTransitionInfo {
    Point2([SceneTransitionPoint; 2]),
    Point5([SceneTransitionPoint; 5]),
}

impl From<[SceneTransitionPoint; 2]> for SceneTransitionInfo {
    fn from(val: [SceneTransitionPoint; 2]) -> Self {
        SceneTransitionInfo::Point2(val)
    }
}

impl From<[SceneTransitionPoint; 5]> for SceneTransitionInfo {
    fn from(val: [SceneTransitionPoint; 5]) -> Self {
        SceneTransitionInfo::Point5(val)
    }
}

/// Transitions between scenes
#[derive(Debug)]
#[cfg_attr(feature = "serde-derives", derive(Serialize))]
pub struct SceneTransition {
    /// Name of the transition
    pub name: Option<String>,
    /// Points of the transition
    pub points: SceneTransitionInfo,
}

/// A type that can represent path data
pub trait PathData {}

impl PathData for Vec<u8> {}
impl PathData for ZonePaths {}

/// The data in a luz file
#[derive(Debug)]
#[cfg_attr(feature = "serde-derives", derive(Serialize))]
pub struct ZoneFile<P: PathData> {
    /// Version of this file
    pub file_version: FileVersion,
    /// Revision of this file
    pub file_revision: Option<u32>,
    /// ID of the world described
    pub world_id: WorldID,
    /// Spawining placement of the player
    pub spawn_point: Option<Placement3D>,
    /// List of scenes
    pub scene_refs: Vec<SceneRef>,

    /// Unknown
    pub something: String,
    /// Relative filename of the map
    pub map_filename: String,
    /// Internal name of the map
    pub map_name: String,
    /// Internal description of the map
    pub map_description: String,

    /// List of transitions
    pub scene_transitions: Option<Vec<SceneTransition>>,
    /// Path data
    pub path_data: Option<P>,
}

impl<P: PathData> ZoneFile<P> {
    fn set_path_data<N: PathData>(self, new: Option<N>) -> ZoneFile<N> {
        ZoneFile {
            file_version: self.file_version,
            file_revision: self.file_revision,
            world_id: self.world_id,
            spawn_point: self.spawn_point,
            scene_refs: self.scene_refs,
            something: self.something,
            map_filename: self.map_filename,
            map_name: self.map_name,
            map_description: self.map_description,
            scene_transitions: self.scene_transitions,
            path_data: new,
        }
    }
}

pub type ParsePathErr = Box<(ZoneFile<Vec<u8>>, (usize, ErrorKind))>;

impl ZoneFile<Vec<u8>> {
    pub fn parse_paths(self) -> Result<ZoneFile<ZonePaths>, ParsePathErr> {
        if let Some(path_data) = &self.path_data {
            match parse_zone_paths(path_data).finish() {
                Ok((_rest, path_data)) => Ok(self.set_path_data(Some(path_data))),
                Err(e) => {
                    let len = path_data.offset(e.input);
                    let code = e.code;
                    Err(Box::new((self, (len, code))))
                }
            }
        } else {
            Ok(self.set_path_data(None))
        }
    }
}