wow_dbc/wrath_tables/
exhaustion.rs

1use crate::{
2    DbcTable, ExtendedLocalizedString, 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 Exhaustion {
11    pub rows: Vec<ExhaustionRow>,
12}
13
14impl DbcTable for Exhaustion {
15    type Row = ExhaustionRow;
16
17    const FILENAME: &'static str = "Exhaustion.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 != 92 {
28            return Err(crate::DbcError::InvalidHeader(
29                crate::InvalidHeaderError::RecordSize {
30                    expected: 92,
31                    actual: header.record_size,
32                },
33            ));
34        }
35
36        if header.field_count != 23 {
37            return Err(crate::DbcError::InvalidHeader(
38                crate::InvalidHeaderError::FieldCount {
39                    expected: 23,
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 (Exhaustion) int32
56            let id = ExhaustionKey::new(crate::util::read_i32_le(chunk)?);
57
58            // xp: int32
59            let xp = crate::util::read_i32_le(chunk)?;
60
61            // factor: float
62            let factor = crate::util::read_f32_le(chunk)?;
63
64            // outdoor_hours: float
65            let outdoor_hours = crate::util::read_f32_le(chunk)?;
66
67            // inn_hours: float
68            let inn_hours = crate::util::read_f32_le(chunk)?;
69
70            // name_lang: string_ref_loc (Extended)
71            let name_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
72
73            // threshold: float
74            let threshold = crate::util::read_f32_le(chunk)?;
75
76
77            rows.push(ExhaustionRow {
78                id,
79                xp,
80                factor,
81                outdoor_hours,
82                inn_hours,
83                name_lang,
84                threshold,
85            });
86        }
87
88        Ok(Exhaustion { rows, })
89    }
90
91    fn write(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
92        let header = DbcHeader {
93            record_count: self.rows.len() as u32,
94            field_count: 23,
95            record_size: 92,
96            string_block_size: self.string_block_size(),
97        };
98
99        b.write_all(&header.write_header())?;
100
101        let mut string_index = 1;
102        for row in &self.rows {
103            // id: primary_key (Exhaustion) int32
104            b.write_all(&row.id.id.to_le_bytes())?;
105
106            // xp: int32
107            b.write_all(&row.xp.to_le_bytes())?;
108
109            // factor: float
110            b.write_all(&row.factor.to_le_bytes())?;
111
112            // outdoor_hours: float
113            b.write_all(&row.outdoor_hours.to_le_bytes())?;
114
115            // inn_hours: float
116            b.write_all(&row.inn_hours.to_le_bytes())?;
117
118            // name_lang: string_ref_loc (Extended)
119            b.write_all(&row.name_lang.string_indices_as_array(&mut string_index))?;
120
121            // threshold: float
122            b.write_all(&row.threshold.to_le_bytes())?;
123
124        }
125
126        self.write_string_block(b)?;
127
128        Ok(())
129    }
130
131}
132
133impl Indexable for Exhaustion {
134    type PrimaryKey = ExhaustionKey;
135    fn get(&self, key: impl TryInto<Self::PrimaryKey>) -> Option<&Self::Row> {
136        let key = key.try_into().ok()?;
137        self.rows.iter().find(|a| a.id.id == key.id)
138    }
139
140    fn get_mut(&mut self, key: impl TryInto<Self::PrimaryKey>) -> Option<&mut Self::Row> {
141        let key = key.try_into().ok()?;
142        self.rows.iter_mut().find(|a| a.id.id == key.id)
143    }
144}
145
146impl Exhaustion {
147    fn write_string_block(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
148        b.write_all(&[0])?;
149
150        for row in &self.rows {
151            row.name_lang.string_block_as_array(b)?;
152        }
153
154        Ok(())
155    }
156
157    fn string_block_size(&self) -> u32 {
158        let mut sum = 1;
159        for row in &self.rows {
160            sum += row.name_lang.string_block_size();
161        }
162
163        sum as u32
164    }
165
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
169pub struct ExhaustionKey {
170    pub id: i32
171}
172
173impl ExhaustionKey {
174    pub const fn new(id: i32) -> Self {
175        Self { id }
176    }
177
178}
179
180impl From<u8> for ExhaustionKey {
181    fn from(v: u8) -> Self {
182        Self::new(v.into())
183    }
184}
185
186impl From<u16> for ExhaustionKey {
187    fn from(v: u16) -> Self {
188        Self::new(v.into())
189    }
190}
191
192impl From<i8> for ExhaustionKey {
193    fn from(v: i8) -> Self {
194        Self::new(v.into())
195    }
196}
197
198impl From<i16> for ExhaustionKey {
199    fn from(v: i16) -> Self {
200        Self::new(v.into())
201    }
202}
203
204impl From<i32> for ExhaustionKey {
205    fn from(v: i32) -> Self {
206        Self::new(v)
207    }
208}
209
210impl TryFrom<u32> for ExhaustionKey {
211    type Error = u32;
212    fn try_from(v: u32) -> Result<Self, Self::Error> {
213        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
214    }
215}
216
217impl TryFrom<usize> for ExhaustionKey {
218    type Error = usize;
219    fn try_from(v: usize) -> Result<Self, Self::Error> {
220        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
221    }
222}
223
224impl TryFrom<u64> for ExhaustionKey {
225    type Error = u64;
226    fn try_from(v: u64) -> Result<Self, Self::Error> {
227        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
228    }
229}
230
231impl TryFrom<i64> for ExhaustionKey {
232    type Error = i64;
233    fn try_from(v: i64) -> Result<Self, Self::Error> {
234        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
235    }
236}
237
238impl TryFrom<isize> for ExhaustionKey {
239    type Error = isize;
240    fn try_from(v: isize) -> Result<Self, Self::Error> {
241        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
242    }
243}
244
245#[derive(Debug, Clone, PartialEq, PartialOrd)]
246pub struct ExhaustionRow {
247    pub id: ExhaustionKey,
248    pub xp: i32,
249    pub factor: f32,
250    pub outdoor_hours: f32,
251    pub inn_hours: f32,
252    pub name_lang: ExtendedLocalizedString,
253    pub threshold: f32,
254}
255