1use derive_more::{Deref, DerefMut};
4use indexmap::IndexMap;
5use serde::{Deserialize, Serialize};
6
7use crate::utils::{get_key, parse_hs_key, To01String};
8use crate::{
9 errors::{VmfError, VmfResult},
10 VmfBlock, VmfSerializable,
11};
12
13#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Deref, DerefMut)]
15pub struct Cameras {
16 pub active: i8,
18 #[deref]
20 #[deref_mut]
21 pub cams: Vec<Camera>,
22}
23
24impl TryFrom<VmfBlock> for Cameras {
25 type Error = VmfError;
26
27 fn try_from(block: VmfBlock) -> VmfResult<Self> {
28 let mut cams = Vec::with_capacity(12);
29 for group in block.blocks {
30 cams.push(Camera::try_from(group)?);
31 }
32
33 Ok(Self {
34 active: parse_hs_key!(&block.key_values, "activecamera", i8)?,
35 cams,
36 })
37 }
38}
39
40impl From<Cameras> for VmfBlock {
41 fn from(val: Cameras) -> Self {
42 let mut blocks = Vec::with_capacity(val.cams.len());
43
44 for cam in val.cams {
45 blocks.push(cam.into());
46 }
47
48 let mut key_values = IndexMap::new();
49 key_values.insert("active".to_string(), val.active.to_string());
50
51 VmfBlock {
52 name: "cameras".to_string(),
53 key_values,
54 blocks,
55 }
56 }
57}
58
59impl VmfSerializable for Cameras {
60 fn to_vmf_string(&self, indent_level: usize) -> String {
61 let indent: String = "\t".repeat(indent_level);
62 let mut output = String::with_capacity(64);
63
64 output.push_str(&format!("{0}cameras\n{0}{{\n", indent));
65 output.push_str(&format!(
66 "{}\t\"activecamera\" \"{}\"\n",
67 indent, self.active
68 ));
69
70 for cam in &self.cams {
71 output.push_str(&format!("{0}\tcamera\n{0}\t{{\n", indent));
72 output.push_str(&format!(
73 "{}\t\t\"position\" \"{}\"\n",
74 indent, cam.position
75 ));
76 output.push_str(&format!("{}\t\t\"look\" \"{}\"\n", indent, cam.look));
77 output.push_str(&format!("{}\t}}\n", indent));
78 }
79
80 output.push_str(&format!("{}}}\n", indent));
81 output
82 }
83}
84
85#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
87pub struct Camera {
88 pub position: String, pub look: String, }
93
94impl TryFrom<VmfBlock> for Camera {
95 type Error = VmfError;
96
97 fn try_from(block: VmfBlock) -> VmfResult<Self> {
98 Ok(Self {
99 position: get_key!(&block.key_values, "position")?.to_owned(),
100 look: get_key!(&block.key_values, "look")?.to_owned(),
101 })
102 }
103}
104
105impl From<Camera> for VmfBlock {
106 fn from(val: Camera) -> Self {
107 let mut key_values = IndexMap::new();
108 key_values.insert("position".to_string(), val.position);
109 key_values.insert("look".to_string(), val.look);
110
111 VmfBlock {
112 name: "camera".to_string(),
113 key_values,
114 ..Default::default()
115 }
116 }
117}
118
119#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Deref, DerefMut)]
121pub struct Cordons {
122 pub active: i8,
124 #[deref]
126 #[deref_mut]
127 pub cordons: Vec<Cordon>,
128}
129
130impl TryFrom<VmfBlock> for Cordons {
131 type Error = VmfError;
132
133 fn try_from(block: VmfBlock) -> VmfResult<Self> {
134 let mut cordons = Vec::with_capacity(12);
135 for group in block.blocks {
136 cordons.push(Cordon::try_from(group)?);
137 }
138
139 Ok(Self {
140 active: parse_hs_key!(&block.key_values, "active", i8)?,
141 cordons,
142 })
143 }
144}
145
146impl From<Cordons> for VmfBlock {
147 fn from(val: Cordons) -> Self {
148 let mut blocks = Vec::new();
149
150 for cordon in val.cordons {
152 blocks.push(cordon.into());
153 }
154
155 let mut key_values = IndexMap::new();
157 key_values.insert("active".to_string(), val.active.to_string());
158
159 VmfBlock {
160 name: "cordons".to_string(),
161 key_values,
162 blocks,
163 }
164 }
165}
166
167impl VmfSerializable for Cordons {
168 fn to_vmf_string(&self, indent_level: usize) -> String {
169 let indent = "\t".repeat(indent_level);
170 let mut output = String::with_capacity(256);
171
172 output.push_str(&format!("{0}cordons\n{0}{{\n", indent));
174 output.push_str(&format!("{}\t\"active\" \"{}\"\n", indent, self.active));
175
176 for cordon in &self.cordons {
178 output.push_str(&cordon.to_vmf_string(indent_level + 1));
179 }
180
181 output.push_str(&format!("{}}}\n", indent));
182
183 output
184 }
185}
186
187#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
189pub struct Cordon {
190 pub name: String,
192 pub active: bool,
194 pub min: String, pub max: String, }
199
200impl TryFrom<VmfBlock> for Cordon {
201 type Error = VmfError;
202
203 fn try_from(block: VmfBlock) -> VmfResult<Self> {
204 let (min, max) = block
205 .blocks
206 .first()
207 .ok_or_else(|| VmfError::InvalidFormat("Missing 'box' block in Cordon".to_string()))
208 .and_then(|sub_block| {
209 Ok((
210 get_key!(&sub_block.key_values, "mins")?,
211 get_key!(&sub_block.key_values, "maxs")?,
212 ))
213 })
214 .or_else(|_| {
215 Ok::<(_, _), VmfError>((
216 get_key!(&block.key_values, "mins")?,
217 get_key!(&block.key_values, "maxs")?,
218 ))
219 })?;
220
221 Ok(Self {
222 name: get_key!(&block.key_values, "name")?.to_owned(),
223 active: get_key!(&block.key_values, "active")? == "1",
224 min: min.to_owned(),
225 max: max.to_owned(),
226 })
227 }
228}
229
230impl From<Cordon> for VmfBlock {
231 fn from(val: Cordon) -> Self {
232 let mut key_values = IndexMap::new();
234 key_values.insert("name".to_string(), val.name);
235 key_values.insert("active".to_string(), val.active.to_01_string());
236
237 let mut box_block_key_values = IndexMap::new();
239 box_block_key_values.insert("mins".to_string(), val.min);
240 box_block_key_values.insert("maxs".to_string(), val.max);
241
242 let box_block = VmfBlock {
244 name: "box".to_string(),
245 key_values: box_block_key_values,
246 blocks: vec![],
247 };
248
249 VmfBlock {
251 name: "cordon".to_string(),
252 key_values,
253 blocks: vec![box_block],
254 }
255 }
256}
257
258impl VmfSerializable for Cordon {
259 fn to_vmf_string(&self, indent_level: usize) -> String {
260 let indent: String = "\t".repeat(indent_level);
261 let mut output = String::with_capacity(64);
262
263 output.push_str(&format!("{0}cordon\n{0}{{\n", indent));
265 output.push_str(&format!("{}\t\"name\" \"{}\"\n", indent, self.name));
266 output.push_str(&format!(
267 "{}\t\"active\" \"{}\"\n",
268 indent,
269 self.active.to_01_string()
270 ));
271
272 output.push_str(&format!("{0}\tbox\n{}\t{{\n", indent));
274 output.push_str(&format!("{}\t\t\"mins\" \"{}\"\n", indent, self.min));
275 output.push_str(&format!("{}\t\t\"maxs\" \"{}\"\n", indent, self.max));
276 output.push_str(&format!("{}\t}}\n", indent)); output.push_str(&format!("{}}}\n", indent));
280
281 output
282 }
283}