assembly_maps/luz/
core.rs

1use super::paths::core::ZonePaths;
2use crate::luz::paths::parser::parse_zone_paths;
3use assembly_core::{
4    nom::{error::ErrorKind, Finish, Offset},
5    types::{Placement3D, Vector3f, WorldID},
6};
7
8#[cfg(feature = "serde-derives")]
9use serde::Serialize;
10
11/// Version of the zone file
12#[derive(Debug, Clone, Copy)]
13#[cfg_attr(feature = "serde-derives", derive(Serialize))]
14pub struct FileVersion(u32);
15
16impl FileVersion {
17    pub fn id(&self) -> u32 {
18        self.0
19    }
20
21    pub fn min(&self, val: u32) -> bool {
22        self.0 >= val
23    }
24}
25
26impl From<u32> for FileVersion {
27    fn from(val: u32) -> Self {
28        FileVersion(val)
29    }
30}
31
32/// Reference to a scene file
33#[derive(Debug)]
34#[cfg_attr(feature = "serde-derives", derive(Serialize))]
35pub struct SceneRef {
36    /// Name of the scene file
37    pub file_name: String,
38    /// ID of the scene
39    pub id: u32,
40    /// 0: default, 1: audio
41    pub layer: u32,
42    /// Name of the scene
43    pub name: String,
44}
45
46/// Scene Transition at a single point
47#[derive(Copy, Clone, Debug)]
48#[cfg_attr(feature = "serde-derives", derive(Serialize))]
49pub struct SceneTransitionPoint {
50    /// ID of the scene
51    pub scene_id: u64,
52    /// Position of the transition
53    pub point: Vector3f,
54}
55
56/// Transition Points
57#[derive(Debug)]
58#[cfg_attr(feature = "serde-derives", derive(Serialize))]
59pub enum SceneTransitionInfo {
60    Point2([SceneTransitionPoint; 2]),
61    Point5([SceneTransitionPoint; 5]),
62}
63
64impl From<[SceneTransitionPoint; 2]> for SceneTransitionInfo {
65    fn from(val: [SceneTransitionPoint; 2]) -> Self {
66        SceneTransitionInfo::Point2(val)
67    }
68}
69
70impl From<[SceneTransitionPoint; 5]> for SceneTransitionInfo {
71    fn from(val: [SceneTransitionPoint; 5]) -> Self {
72        SceneTransitionInfo::Point5(val)
73    }
74}
75
76/// Transitions between scenes
77#[derive(Debug)]
78#[cfg_attr(feature = "serde-derives", derive(Serialize))]
79pub struct SceneTransition {
80    /// Name of the transition
81    pub name: Option<String>,
82    /// Points of the transition
83    pub points: SceneTransitionInfo,
84}
85
86/// A type that can represent path data
87pub trait PathData {}
88
89impl PathData for Vec<u8> {}
90impl PathData for ZonePaths {}
91
92/// The data in a luz file
93#[derive(Debug)]
94#[cfg_attr(feature = "serde-derives", derive(Serialize))]
95pub struct ZoneFile<P: PathData> {
96    /// Version of this file
97    pub file_version: FileVersion,
98    /// Revision of this file
99    pub file_revision: Option<u32>,
100    /// ID of the world described
101    pub world_id: WorldID,
102    /// Spawining placement of the player
103    pub spawn_point: Option<Placement3D>,
104    /// List of scenes
105    pub scene_refs: Vec<SceneRef>,
106
107    /// Unknown
108    pub something: String,
109    /// Relative filename of the map
110    pub map_filename: String,
111    /// Internal name of the map
112    pub map_name: String,
113    /// Internal description of the map
114    pub map_description: String,
115
116    /// List of transitions
117    pub scene_transitions: Option<Vec<SceneTransition>>,
118    /// Path data
119    pub path_data: Option<P>,
120}
121
122impl<P: PathData> ZoneFile<P> {
123    fn set_path_data<N: PathData>(self, new: Option<N>) -> ZoneFile<N> {
124        ZoneFile {
125            file_version: self.file_version,
126            file_revision: self.file_revision,
127            world_id: self.world_id,
128            spawn_point: self.spawn_point,
129            scene_refs: self.scene_refs,
130            something: self.something,
131            map_filename: self.map_filename,
132            map_name: self.map_name,
133            map_description: self.map_description,
134            scene_transitions: self.scene_transitions,
135            path_data: new,
136        }
137    }
138}
139
140pub type ParsePathErr = (ZoneFile<Vec<u8>>, (usize, ErrorKind));
141
142impl ZoneFile<Vec<u8>> {
143    pub fn parse_paths(self) -> Result<ZoneFile<ZonePaths>, ParsePathErr> {
144        if let Some(path_data) = &self.path_data {
145            match parse_zone_paths(&path_data).finish() {
146                Ok((_rest, path_data)) => Ok(self.set_path_data(Some(path_data))),
147                Err(e) => {
148                    let len = path_data.offset(e.input);
149                    let code = e.code;
150                    Err((self, (len, code)))
151                }
152            }
153        } else {
154            Ok(self.set_path_data(None))
155        }
156    }
157}