1use derive_more::{Deref, DerefMut};
4use indexmap::IndexMap;
5#[cfg(feature = "serialization")]
6use serde::{Deserialize, Serialize};
7
8use crate::utils::{To01String, get_key_ref, take_and_parse_key, take_key_owned};
9use crate::{
10 VmfBlock, VmfSerializable,
11 errors::{VmfError, VmfResult},
12};
13
14#[derive(Debug, Default, Clone, PartialEq, Deref, DerefMut)]
16#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
17pub struct Cameras {
18 pub active: i8,
20 #[deref]
22 #[deref_mut]
23 pub cams: Vec<Camera>,
24}
25
26impl TryFrom<VmfBlock> for Cameras {
27 type Error = VmfError;
28
29 fn try_from(mut block: VmfBlock) -> VmfResult<Self> {
30 let mut cams = Vec::with_capacity(block.blocks.len());
31 for group in block.blocks {
32 cams.push(Camera::try_from(group)?);
33 }
34
35 Ok(Self {
36 active: take_and_parse_key::<i8>(&mut block.key_values, "activecamera")?,
37 cams,
38 })
39 }
40}
41
42impl From<Cameras> for VmfBlock {
43 fn from(val: Cameras) -> Self {
44 let mut blocks = Vec::with_capacity(val.cams.len());
45
46 for cam in val.cams {
47 blocks.push(cam.into());
48 }
49
50 let mut key_values = IndexMap::new();
51 key_values.insert("active".to_string(), val.active.to_string());
52
53 VmfBlock {
54 name: "cameras".to_string(),
55 key_values,
56 blocks,
57 }
58 }
59}
60
61impl VmfSerializable for Cameras {
62 fn to_vmf_string(&self, indent_level: usize) -> String {
63 let indent: String = "\t".repeat(indent_level);
64 let mut output = String::with_capacity(64);
65
66 output.push_str(&format!("{0}cameras\n{0}{{\n", indent));
67 output.push_str(&format!(
68 "{}\t\"activecamera\" \"{}\"\n",
69 indent, self.active
70 ));
71
72 for cam in &self.cams {
73 output.push_str(&format!("{0}\tcamera\n{0}\t{{\n", indent));
74 output.push_str(&format!(
75 "{}\t\t\"position\" \"{}\"\n",
76 indent, cam.position
77 ));
78 output.push_str(&format!("{}\t\t\"look\" \"{}\"\n", indent, cam.look));
79 output.push_str(&format!("{}\t}}\n", indent));
80 }
81
82 output.push_str(&format!("{}}}\n", indent));
83 output
84 }
85}
86
87#[derive(Debug, Default, Clone, PartialEq)]
89#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
90pub struct Camera {
91 pub position: String, pub look: String, }
96
97impl TryFrom<VmfBlock> for Camera {
98 type Error = VmfError;
99
100 fn try_from(mut block: VmfBlock) -> VmfResult<Self> {
101 let kv = &mut block.key_values;
102 Ok(Self {
103 position: take_key_owned(kv, "position")?,
104 look: take_key_owned(kv, "look")?,
105 })
106 }
107}
108
109impl From<Camera> for VmfBlock {
110 fn from(val: Camera) -> Self {
111 let mut key_values = IndexMap::new();
112 key_values.insert("position".to_string(), val.position);
113 key_values.insert("look".to_string(), val.look);
114
115 VmfBlock {
116 name: "camera".to_string(),
117 key_values,
118 ..Default::default()
119 }
120 }
121}
122
123#[derive(Debug, Default, Clone, PartialEq, Deref, DerefMut)]
125#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
126pub struct Cordons {
127 pub active: i8,
129 #[deref]
131 #[deref_mut]
132 pub cordons: Vec<Cordon>,
133}
134
135impl TryFrom<VmfBlock> for Cordons {
136 type Error = VmfError;
137
138 fn try_from(mut block: VmfBlock) -> VmfResult<Self> {
139 let mut cordons = Vec::with_capacity(block.blocks.len());
140 for group in block.blocks {
141 cordons.push(Cordon::try_from(group)?);
142 }
143
144 Ok(Self {
145 active: take_and_parse_key::<i8>(&mut block.key_values, "active")?,
146 cordons,
147 })
148 }
149}
150
151impl From<Cordons> for VmfBlock {
152 fn from(val: Cordons) -> Self {
153 let mut blocks = Vec::new();
154
155 for cordon in val.cordons {
157 blocks.push(cordon.into());
158 }
159
160 let mut key_values = IndexMap::new();
162 key_values.insert("active".to_string(), val.active.to_string());
163
164 VmfBlock {
165 name: "cordons".to_string(),
166 key_values,
167 blocks,
168 }
169 }
170}
171
172impl VmfSerializable for Cordons {
173 fn to_vmf_string(&self, indent_level: usize) -> String {
174 let indent = "\t".repeat(indent_level);
175 let mut output = String::with_capacity(256);
176
177 output.push_str(&format!("{0}cordons\n{0}{{\n", indent));
179 output.push_str(&format!("{}\t\"active\" \"{}\"\n", indent, self.active));
180
181 for cordon in &self.cordons {
183 output.push_str(&cordon.to_vmf_string(indent_level + 1));
184 }
185
186 output.push_str(&format!("{}}}\n", indent));
187
188 output
189 }
190}
191
192#[derive(Debug, Default, Clone, PartialEq)]
194#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
195pub struct Cordon {
196 pub name: String,
198 pub active: bool,
200 pub min: String, pub max: String, }
205
206impl TryFrom<VmfBlock> for Cordon {
207 type Error = VmfError;
208
209 fn try_from(mut block: VmfBlock) -> VmfResult<Self> {
210 let sub_block_result: Option<(String, String)> =
212 block.blocks.get_mut(0).and_then(|sub_block| {
213 let maybe_min = sub_block.key_values.swap_remove("mins");
216 let maybe_max = sub_block.key_values.swap_remove("maxs");
217 maybe_min.zip(maybe_max)
218 });
219
220 let (min_string, max_string) = match sub_block_result {
222 Some((min_val, max_val)) => Ok((min_val, max_val)),
224 None => {
226 let min_res = take_key_owned(&mut block.key_values, "mins").map_err(|_| {
228 VmfError::InvalidFormat(
229 "Missing 'mins' key in Cordon block or its 'box' sub-block".to_string(),
230 )
231 });
232 let max_res = take_key_owned(&mut block.key_values, "maxs").map_err(|_| {
233 VmfError::InvalidFormat(
234 "Missing 'maxs' key in Cordon block or its 'box' sub-block".to_string(),
235 )
236 });
237
238 match (min_res, max_res) {
240 (Ok(min), Ok(max)) => Ok((min, max)),
241 (Err(e), _) => Err(e),
242 (_, Err(e)) => Err(e),
243 }
244 }
245 }?;
246
247 let name = take_key_owned(&mut block.key_values, "name")?;
249 let active = get_key_ref(&block.key_values, "active")? == "1";
250
251 Ok(Self {
252 name,
253 active,
254 min: min_string,
255 max: max_string,
256 })
257 }
258}
259
260impl From<Cordon> for VmfBlock {
261 fn from(val: Cordon) -> Self {
262 let mut key_values = IndexMap::new();
264 key_values.insert("name".to_string(), val.name);
265 key_values.insert("active".to_string(), val.active.to_01_string());
266
267 let mut box_block_key_values = IndexMap::new();
269 box_block_key_values.insert("mins".to_string(), val.min);
270 box_block_key_values.insert("maxs".to_string(), val.max);
271
272 let box_block = VmfBlock {
274 name: "box".to_string(),
275 key_values: box_block_key_values,
276 blocks: vec![],
277 };
278
279 VmfBlock {
281 name: "cordon".to_string(),
282 key_values,
283 blocks: vec![box_block],
284 }
285 }
286}
287
288impl VmfSerializable for Cordon {
289 fn to_vmf_string(&self, indent_level: usize) -> String {
290 let indent: String = "\t".repeat(indent_level);
291 let mut output = String::with_capacity(64);
292
293 output.push_str(&format!("{0}cordon\n{0}{{\n", indent));
295 output.push_str(&format!("{}\t\"name\" \"{}\"\n", indent, self.name));
296 output.push_str(&format!(
297 "{}\t\"active\" \"{}\"\n",
298 indent,
299 self.active.to_01_string()
300 ));
301
302 output.push_str(&format!("{0}\tbox\n{}\t{{\n", indent));
304 output.push_str(&format!("{}\t\t\"mins\" \"{}\"\n", indent, self.min));
305 output.push_str(&format!("{}\t\t\"maxs\" \"{}\"\n", indent, self.max));
306 output.push_str(&format!("{}\t}}\n", indent)); output.push_str(&format!("{}}}\n", indent));
310
311 output
312 }
313}