wow_dbc/wrath_tables/
game_object_display_info.rs

1use crate::{
2    DbcTable, Indexable,
3};
4use crate::header::{
5    DbcHeader, HEADER_SIZE, parse_header,
6};
7use crate::wrath_tables::object_effect_package::ObjectEffectPackageKey;
8use std::io::Write;
9
10#[derive(Debug, Clone, PartialEq, PartialOrd)]
11pub struct GameObjectDisplayInfo {
12    pub rows: Vec<GameObjectDisplayInfoRow>,
13}
14
15impl DbcTable for GameObjectDisplayInfo {
16    type Row = GameObjectDisplayInfoRow;
17
18    const FILENAME: &'static str = "GameObjectDisplayInfo.dbc";
19
20    fn rows(&self) -> &[Self::Row] { &self.rows }
21    fn rows_mut(&mut self) -> &mut [Self::Row] { &mut self.rows }
22
23    fn read(b: &mut impl std::io::Read) -> Result<Self, crate::DbcError> {
24        let mut header = [0_u8; HEADER_SIZE];
25        b.read_exact(&mut header)?;
26        let header = parse_header(&header)?;
27
28        if header.record_size != 76 {
29            return Err(crate::DbcError::InvalidHeader(
30                crate::InvalidHeaderError::RecordSize {
31                    expected: 76,
32                    actual: header.record_size,
33                },
34            ));
35        }
36
37        if header.field_count != 19 {
38            return Err(crate::DbcError::InvalidHeader(
39                crate::InvalidHeaderError::FieldCount {
40                    expected: 19,
41                    actual: header.field_count,
42                },
43            ));
44        }
45
46        let mut r = vec![0_u8; (header.record_count * header.record_size) as usize];
47        b.read_exact(&mut r)?;
48        let mut string_block = vec![0_u8; header.string_block_size as usize];
49        b.read_exact(&mut string_block)?;
50
51        let mut rows = Vec::with_capacity(header.record_count as usize);
52
53        for mut chunk in r.chunks(header.record_size as usize) {
54            let chunk = &mut chunk;
55
56            // id: primary_key (GameObjectDisplayInfo) int32
57            let id = GameObjectDisplayInfoKey::new(crate::util::read_i32_le(chunk)?);
58
59            // model_name: string_ref
60            let model_name = {
61                let s = crate::util::get_string_as_vec(chunk, &string_block)?;
62                String::from_utf8(s)?
63            };
64
65            // sound: int32[10]
66            let sound = crate::util::read_array_i32::<10>(chunk)?;
67
68            // geo_box_min: float[3]
69            let geo_box_min = crate::util::read_array_f32::<3>(chunk)?;
70
71            // geo_box_max: float[3]
72            let geo_box_max = crate::util::read_array_f32::<3>(chunk)?;
73
74            // object_effect_package_id: foreign_key (ObjectEffectPackage) int32
75            let object_effect_package_id = ObjectEffectPackageKey::new(crate::util::read_i32_le(chunk)?.into());
76
77
78            rows.push(GameObjectDisplayInfoRow {
79                id,
80                model_name,
81                sound,
82                geo_box_min,
83                geo_box_max,
84                object_effect_package_id,
85            });
86        }
87
88        Ok(GameObjectDisplayInfo { 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: 19,
95            record_size: 76,
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 (GameObjectDisplayInfo) int32
104            b.write_all(&row.id.id.to_le_bytes())?;
105
106            // model_name: string_ref
107            if !row.model_name.is_empty() {
108                b.write_all(&(string_index as u32).to_le_bytes())?;
109                string_index += row.model_name.len() + 1;
110            }
111            else {
112                b.write_all(&(0_u32).to_le_bytes())?;
113            }
114
115            // sound: int32[10]
116            for i in row.sound {
117                b.write_all(&i.to_le_bytes())?;
118            }
119
120
121            // geo_box_min: float[3]
122            for i in row.geo_box_min {
123                b.write_all(&i.to_le_bytes())?;
124            }
125
126
127            // geo_box_max: float[3]
128            for i in row.geo_box_max {
129                b.write_all(&i.to_le_bytes())?;
130            }
131
132
133            // object_effect_package_id: foreign_key (ObjectEffectPackage) int32
134            b.write_all(&(row.object_effect_package_id.id as i32).to_le_bytes())?;
135
136        }
137
138        self.write_string_block(b)?;
139
140        Ok(())
141    }
142
143}
144
145impl Indexable for GameObjectDisplayInfo {
146    type PrimaryKey = GameObjectDisplayInfoKey;
147    fn get(&self, key: impl TryInto<Self::PrimaryKey>) -> Option<&Self::Row> {
148        let key = key.try_into().ok()?;
149        self.rows.iter().find(|a| a.id.id == key.id)
150    }
151
152    fn get_mut(&mut self, key: impl TryInto<Self::PrimaryKey>) -> Option<&mut Self::Row> {
153        let key = key.try_into().ok()?;
154        self.rows.iter_mut().find(|a| a.id.id == key.id)
155    }
156}
157
158impl GameObjectDisplayInfo {
159    fn write_string_block(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
160        b.write_all(&[0])?;
161
162        for row in &self.rows {
163            if !row.model_name.is_empty() { b.write_all(row.model_name.as_bytes())?; b.write_all(&[0])?; };
164        }
165
166        Ok(())
167    }
168
169    fn string_block_size(&self) -> u32 {
170        let mut sum = 1;
171        for row in &self.rows {
172            if !row.model_name.is_empty() { sum += row.model_name.len() + 1; };
173        }
174
175        sum as u32
176    }
177
178}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
181pub struct GameObjectDisplayInfoKey {
182    pub id: i32
183}
184
185impl GameObjectDisplayInfoKey {
186    pub const fn new(id: i32) -> Self {
187        Self { id }
188    }
189
190}
191
192impl From<u8> for GameObjectDisplayInfoKey {
193    fn from(v: u8) -> Self {
194        Self::new(v.into())
195    }
196}
197
198impl From<u16> for GameObjectDisplayInfoKey {
199    fn from(v: u16) -> Self {
200        Self::new(v.into())
201    }
202}
203
204impl From<i8> for GameObjectDisplayInfoKey {
205    fn from(v: i8) -> Self {
206        Self::new(v.into())
207    }
208}
209
210impl From<i16> for GameObjectDisplayInfoKey {
211    fn from(v: i16) -> Self {
212        Self::new(v.into())
213    }
214}
215
216impl From<i32> for GameObjectDisplayInfoKey {
217    fn from(v: i32) -> Self {
218        Self::new(v)
219    }
220}
221
222impl TryFrom<u32> for GameObjectDisplayInfoKey {
223    type Error = u32;
224    fn try_from(v: u32) -> Result<Self, Self::Error> {
225        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
226    }
227}
228
229impl TryFrom<usize> for GameObjectDisplayInfoKey {
230    type Error = usize;
231    fn try_from(v: usize) -> Result<Self, Self::Error> {
232        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
233    }
234}
235
236impl TryFrom<u64> for GameObjectDisplayInfoKey {
237    type Error = u64;
238    fn try_from(v: u64) -> Result<Self, Self::Error> {
239        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
240    }
241}
242
243impl TryFrom<i64> for GameObjectDisplayInfoKey {
244    type Error = i64;
245    fn try_from(v: i64) -> Result<Self, Self::Error> {
246        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
247    }
248}
249
250impl TryFrom<isize> for GameObjectDisplayInfoKey {
251    type Error = isize;
252    fn try_from(v: isize) -> Result<Self, Self::Error> {
253        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
254    }
255}
256
257#[derive(Debug, Clone, PartialEq, PartialOrd)]
258pub struct GameObjectDisplayInfoRow {
259    pub id: GameObjectDisplayInfoKey,
260    pub model_name: String,
261    pub sound: [i32; 10],
262    pub geo_box_min: [f32; 3],
263    pub geo_box_max: [f32; 3],
264    pub object_effect_package_id: ObjectEffectPackageKey,
265}
266