wow_dbc/vanilla_tables/
sound_provider_preferences.rs

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            // id: primary_key (SoundProviderPreferences) uint32
56            let id = SoundProviderPreferencesKey::new(crate::util::read_u32_le(chunk)?);
57
58            // description: string_ref
59            let description = {
60                let s = crate::util::get_string_as_vec(chunk, &string_block)?;
61                String::from_utf8(s)?
62            };
63
64            // flags: int32
65            let flags = crate::util::read_i32_le(chunk)?;
66
67            // eax_environment_selection: int32
68            let eax_environment_selection = crate::util::read_i32_le(chunk)?;
69
70            // eax_decay_time: float
71            let eax_decay_time = crate::util::read_f32_le(chunk)?;
72
73            // eax2_environment_size: float
74            let eax2_environment_size = crate::util::read_f32_le(chunk)?;
75
76            // eax_environment_diffusion: float
77            let eax_environment_diffusion = crate::util::read_f32_le(chunk)?;
78
79            // eax2_room: int32
80            let eax2_room = crate::util::read_i32_le(chunk)?;
81
82            // eax2_room_hf: int32
83            let eax2_room_hf = crate::util::read_i32_le(chunk)?;
84
85            // eax2_decay_hf_ratio: float
86            let eax2_decay_hf_ratio = crate::util::read_f32_le(chunk)?;
87
88            // eax2_reflections: int32
89            let eax2_reflections = crate::util::read_i32_le(chunk)?;
90
91            // eax2_reflections_delay: float
92            let eax2_reflections_delay = crate::util::read_f32_le(chunk)?;
93
94            // eax2_reverb: int32
95            let eax2_reverb = crate::util::read_i32_le(chunk)?;
96
97            // eax2_reverb_delay: float
98            let eax2_reverb_delay = crate::util::read_f32_le(chunk)?;
99
100            // eax2_room_rolloff: float
101            let eax2_room_rolloff = crate::util::read_f32_le(chunk)?;
102
103            // eax2_air_absorption: float
104            let eax2_air_absorption = crate::util::read_f32_le(chunk)?;
105
106            // eax3_room_lf: int32
107            let eax3_room_lf = crate::util::read_i32_le(chunk)?;
108
109            // eax3_delay_lf_ratio: float
110            let eax3_delay_lf_ratio = crate::util::read_f32_le(chunk)?;
111
112            // eax3_echo_time: float
113            let eax3_echo_time = crate::util::read_f32_le(chunk)?;
114
115            // eax3_echo_depth: float
116            let eax3_echo_depth = crate::util::read_f32_le(chunk)?;
117
118            // eax3_modulation_time: float
119            let eax3_modulation_time = crate::util::read_f32_le(chunk)?;
120
121            // eax3_modulation_depth: float
122            let eax3_modulation_depth = crate::util::read_f32_le(chunk)?;
123
124            // eax3_hf_reference: float
125            let eax3_hf_reference = crate::util::read_f32_le(chunk)?;
126
127            // eax3_lf_reference: float
128            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            // id: primary_key (SoundProviderPreferences) uint32
175            b.write_all(&row.id.id.to_le_bytes())?;
176
177            // description: string_ref
178            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            // flags: int32
187            b.write_all(&row.flags.to_le_bytes())?;
188
189            // eax_environment_selection: int32
190            b.write_all(&row.eax_environment_selection.to_le_bytes())?;
191
192            // eax_decay_time: float
193            b.write_all(&row.eax_decay_time.to_le_bytes())?;
194
195            // eax2_environment_size: float
196            b.write_all(&row.eax2_environment_size.to_le_bytes())?;
197
198            // eax_environment_diffusion: float
199            b.write_all(&row.eax_environment_diffusion.to_le_bytes())?;
200
201            // eax2_room: int32
202            b.write_all(&row.eax2_room.to_le_bytes())?;
203
204            // eax2_room_hf: int32
205            b.write_all(&row.eax2_room_hf.to_le_bytes())?;
206
207            // eax2_decay_hf_ratio: float
208            b.write_all(&row.eax2_decay_hf_ratio.to_le_bytes())?;
209
210            // eax2_reflections: int32
211            b.write_all(&row.eax2_reflections.to_le_bytes())?;
212
213            // eax2_reflections_delay: float
214            b.write_all(&row.eax2_reflections_delay.to_le_bytes())?;
215
216            // eax2_reverb: int32
217            b.write_all(&row.eax2_reverb.to_le_bytes())?;
218
219            // eax2_reverb_delay: float
220            b.write_all(&row.eax2_reverb_delay.to_le_bytes())?;
221
222            // eax2_room_rolloff: float
223            b.write_all(&row.eax2_room_rolloff.to_le_bytes())?;
224
225            // eax2_air_absorption: float
226            b.write_all(&row.eax2_air_absorption.to_le_bytes())?;
227
228            // eax3_room_lf: int32
229            b.write_all(&row.eax3_room_lf.to_le_bytes())?;
230
231            // eax3_delay_lf_ratio: float
232            b.write_all(&row.eax3_delay_lf_ratio.to_le_bytes())?;
233
234            // eax3_echo_time: float
235            b.write_all(&row.eax3_echo_time.to_le_bytes())?;
236
237            // eax3_echo_depth: float
238            b.write_all(&row.eax3_echo_depth.to_le_bytes())?;
239
240            // eax3_modulation_time: float
241            b.write_all(&row.eax3_modulation_time.to_le_bytes())?;
242
243            // eax3_modulation_depth: float
244            b.write_all(&row.eax3_modulation_depth.to_le_bytes())?;
245
246            // eax3_hf_reference: float
247            b.write_all(&row.eax3_hf_reference.to_le_bytes())?;
248
249            // eax3_lf_reference: float
250            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