1use crate::{
2 DbcTable, Indexable,
3};
4use crate::header::{
5 DbcHeader, HEADER_SIZE, parse_header,
6};
7use std::io::Write;
8
9#[derive(Debug, Clone, PartialEq, PartialOrd)]
10pub struct SoundProviderPreferences {
11 pub rows: Vec<SoundProviderPreferencesRow>,
12}
13
14impl DbcTable for SoundProviderPreferences {
15 type Row = SoundProviderPreferencesRow;
16
17 const FILENAME: &'static str = "SoundProviderPreferences.dbc";
18
19 fn rows(&self) -> &[Self::Row] { &self.rows }
20 fn rows_mut(&mut self) -> &mut [Self::Row] { &mut self.rows }
21
22 fn read(b: &mut impl std::io::Read) -> Result<Self, crate::DbcError> {
23 let mut header = [0_u8; HEADER_SIZE];
24 b.read_exact(&mut header)?;
25 let header = parse_header(&header)?;
26
27 if header.record_size != 96 {
28 return Err(crate::DbcError::InvalidHeader(
29 crate::InvalidHeaderError::RecordSize {
30 expected: 96,
31 actual: header.record_size,
32 },
33 ));
34 }
35
36 if header.field_count != 24 {
37 return Err(crate::DbcError::InvalidHeader(
38 crate::InvalidHeaderError::FieldCount {
39 expected: 24,
40 actual: header.field_count,
41 },
42 ));
43 }
44
45 let mut r = vec![0_u8; (header.record_count * header.record_size) as usize];
46 b.read_exact(&mut r)?;
47 let mut string_block = vec![0_u8; header.string_block_size as usize];
48 b.read_exact(&mut string_block)?;
49
50 let mut rows = Vec::with_capacity(header.record_count as usize);
51
52 for mut chunk in r.chunks(header.record_size as usize) {
53 let chunk = &mut chunk;
54
55 let id = SoundProviderPreferencesKey::new(crate::util::read_u32_le(chunk)?);
57
58 let description = {
60 let s = crate::util::get_string_as_vec(chunk, &string_block)?;
61 String::from_utf8(s)?
62 };
63
64 let flags = crate::util::read_i32_le(chunk)?;
66
67 let eax_environment_selection = crate::util::read_i32_le(chunk)?;
69
70 let eax_decay_time = crate::util::read_f32_le(chunk)?;
72
73 let eax2_environment_size = crate::util::read_f32_le(chunk)?;
75
76 let eax_environment_diffusion = crate::util::read_f32_le(chunk)?;
78
79 let eax2_room = crate::util::read_i32_le(chunk)?;
81
82 let eax2_room_hf = crate::util::read_i32_le(chunk)?;
84
85 let eax2_decay_hf_ratio = crate::util::read_f32_le(chunk)?;
87
88 let eax2_reflections = crate::util::read_i32_le(chunk)?;
90
91 let eax2_reflections_delay = crate::util::read_f32_le(chunk)?;
93
94 let eax2_reverb = crate::util::read_i32_le(chunk)?;
96
97 let eax2_reverb_delay = crate::util::read_f32_le(chunk)?;
99
100 let eax2_room_rolloff = crate::util::read_f32_le(chunk)?;
102
103 let eax2_air_absorption = crate::util::read_f32_le(chunk)?;
105
106 let eax3_room_lf = crate::util::read_i32_le(chunk)?;
108
109 let eax3_delay_lf_ratio = crate::util::read_f32_le(chunk)?;
111
112 let eax3_echo_time = crate::util::read_f32_le(chunk)?;
114
115 let eax3_echo_depth = crate::util::read_f32_le(chunk)?;
117
118 let eax3_modulation_time = crate::util::read_f32_le(chunk)?;
120
121 let eax3_modulation_depth = crate::util::read_f32_le(chunk)?;
123
124 let eax3_hf_reference = crate::util::read_f32_le(chunk)?;
126
127 let eax3_lf_reference = crate::util::read_f32_le(chunk)?;
129
130
131 rows.push(SoundProviderPreferencesRow {
132 id,
133 description,
134 flags,
135 eax_environment_selection,
136 eax_decay_time,
137 eax2_environment_size,
138 eax_environment_diffusion,
139 eax2_room,
140 eax2_room_hf,
141 eax2_decay_hf_ratio,
142 eax2_reflections,
143 eax2_reflections_delay,
144 eax2_reverb,
145 eax2_reverb_delay,
146 eax2_room_rolloff,
147 eax2_air_absorption,
148 eax3_room_lf,
149 eax3_delay_lf_ratio,
150 eax3_echo_time,
151 eax3_echo_depth,
152 eax3_modulation_time,
153 eax3_modulation_depth,
154 eax3_hf_reference,
155 eax3_lf_reference,
156 });
157 }
158
159 Ok(SoundProviderPreferences { rows, })
160 }
161
162 fn write(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
163 let header = DbcHeader {
164 record_count: self.rows.len() as u32,
165 field_count: 24,
166 record_size: 96,
167 string_block_size: self.string_block_size(),
168 };
169
170 b.write_all(&header.write_header())?;
171
172 let mut string_index = 1;
173 for row in &self.rows {
174 b.write_all(&row.id.id.to_le_bytes())?;
176
177 if !row.description.is_empty() {
179 b.write_all(&(string_index as u32).to_le_bytes())?;
180 string_index += row.description.len() + 1;
181 }
182 else {
183 b.write_all(&(0_u32).to_le_bytes())?;
184 }
185
186 b.write_all(&row.flags.to_le_bytes())?;
188
189 b.write_all(&row.eax_environment_selection.to_le_bytes())?;
191
192 b.write_all(&row.eax_decay_time.to_le_bytes())?;
194
195 b.write_all(&row.eax2_environment_size.to_le_bytes())?;
197
198 b.write_all(&row.eax_environment_diffusion.to_le_bytes())?;
200
201 b.write_all(&row.eax2_room.to_le_bytes())?;
203
204 b.write_all(&row.eax2_room_hf.to_le_bytes())?;
206
207 b.write_all(&row.eax2_decay_hf_ratio.to_le_bytes())?;
209
210 b.write_all(&row.eax2_reflections.to_le_bytes())?;
212
213 b.write_all(&row.eax2_reflections_delay.to_le_bytes())?;
215
216 b.write_all(&row.eax2_reverb.to_le_bytes())?;
218
219 b.write_all(&row.eax2_reverb_delay.to_le_bytes())?;
221
222 b.write_all(&row.eax2_room_rolloff.to_le_bytes())?;
224
225 b.write_all(&row.eax2_air_absorption.to_le_bytes())?;
227
228 b.write_all(&row.eax3_room_lf.to_le_bytes())?;
230
231 b.write_all(&row.eax3_delay_lf_ratio.to_le_bytes())?;
233
234 b.write_all(&row.eax3_echo_time.to_le_bytes())?;
236
237 b.write_all(&row.eax3_echo_depth.to_le_bytes())?;
239
240 b.write_all(&row.eax3_modulation_time.to_le_bytes())?;
242
243 b.write_all(&row.eax3_modulation_depth.to_le_bytes())?;
245
246 b.write_all(&row.eax3_hf_reference.to_le_bytes())?;
248
249 b.write_all(&row.eax3_lf_reference.to_le_bytes())?;
251
252 }
253
254 self.write_string_block(b)?;
255
256 Ok(())
257 }
258
259}
260
261impl Indexable for SoundProviderPreferences {
262 type PrimaryKey = SoundProviderPreferencesKey;
263 fn get(&self, key: impl TryInto<Self::PrimaryKey>) -> Option<&Self::Row> {
264 let key = key.try_into().ok()?;
265 self.rows.iter().find(|a| a.id.id == key.id)
266 }
267
268 fn get_mut(&mut self, key: impl TryInto<Self::PrimaryKey>) -> Option<&mut Self::Row> {
269 let key = key.try_into().ok()?;
270 self.rows.iter_mut().find(|a| a.id.id == key.id)
271 }
272}
273
274impl SoundProviderPreferences {
275 fn write_string_block(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
276 b.write_all(&[0])?;
277
278 for row in &self.rows {
279 if !row.description.is_empty() { b.write_all(row.description.as_bytes())?; b.write_all(&[0])?; };
280 }
281
282 Ok(())
283 }
284
285 fn string_block_size(&self) -> u32 {
286 let mut sum = 1;
287 for row in &self.rows {
288 if !row.description.is_empty() { sum += row.description.len() + 1; };
289 }
290
291 sum as u32
292 }
293
294}
295
296#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
297pub struct SoundProviderPreferencesKey {
298 pub id: u32
299}
300
301impl SoundProviderPreferencesKey {
302 pub const fn new(id: u32) -> Self {
303 Self { id }
304 }
305
306}
307
308impl From<u8> for SoundProviderPreferencesKey {
309 fn from(v: u8) -> Self {
310 Self::new(v.into())
311 }
312}
313
314impl From<u16> for SoundProviderPreferencesKey {
315 fn from(v: u16) -> Self {
316 Self::new(v.into())
317 }
318}
319
320impl From<u32> for SoundProviderPreferencesKey {
321 fn from(v: u32) -> Self {
322 Self::new(v)
323 }
324}
325
326impl TryFrom<u64> for SoundProviderPreferencesKey {
327 type Error = u64;
328 fn try_from(v: u64) -> Result<Self, Self::Error> {
329 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
330 }
331}
332
333impl TryFrom<usize> for SoundProviderPreferencesKey {
334 type Error = usize;
335 fn try_from(v: usize) -> Result<Self, Self::Error> {
336 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
337 }
338}
339
340impl TryFrom<i8> for SoundProviderPreferencesKey {
341 type Error = i8;
342 fn try_from(v: i8) -> Result<Self, Self::Error> {
343 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
344 }
345}
346
347impl TryFrom<i16> for SoundProviderPreferencesKey {
348 type Error = i16;
349 fn try_from(v: i16) -> Result<Self, Self::Error> {
350 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
351 }
352}
353
354impl TryFrom<i32> for SoundProviderPreferencesKey {
355 type Error = i32;
356 fn try_from(v: i32) -> Result<Self, Self::Error> {
357 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
358 }
359}
360
361impl TryFrom<i64> for SoundProviderPreferencesKey {
362 type Error = i64;
363 fn try_from(v: i64) -> Result<Self, Self::Error> {
364 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
365 }
366}
367
368impl TryFrom<isize> for SoundProviderPreferencesKey {
369 type Error = isize;
370 fn try_from(v: isize) -> Result<Self, Self::Error> {
371 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
372 }
373}
374
375#[derive(Debug, Clone, PartialEq, PartialOrd)]
376pub struct SoundProviderPreferencesRow {
377 pub id: SoundProviderPreferencesKey,
378 pub description: String,
379 pub flags: i32,
380 pub eax_environment_selection: i32,
381 pub eax_decay_time: f32,
382 pub eax2_environment_size: f32,
383 pub eax_environment_diffusion: f32,
384 pub eax2_room: i32,
385 pub eax2_room_hf: i32,
386 pub eax2_decay_hf_ratio: f32,
387 pub eax2_reflections: i32,
388 pub eax2_reflections_delay: f32,
389 pub eax2_reverb: i32,
390 pub eax2_reverb_delay: f32,
391 pub eax2_room_rolloff: f32,
392 pub eax2_air_absorption: f32,
393 pub eax3_room_lf: i32,
394 pub eax3_delay_lf_ratio: f32,
395 pub eax3_echo_time: f32,
396 pub eax3_echo_depth: f32,
397 pub eax3_modulation_time: f32,
398 pub eax3_modulation_depth: f32,
399 pub eax3_hf_reference: f32,
400 pub eax3_lf_reference: f32,
401}
402