wow_dbc/wrath_tables/
item_display_info.rs1use crate::{
2 DbcTable, Indexable,
3};
4use crate::header::{
5 DbcHeader, HEADER_SIZE, parse_header,
6};
7use crate::wrath_tables::particle_color::ParticleColorKey;
8use crate::wrath_tables::spell_visual::SpellVisualKey;
9use std::io::Write;
10
11#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct ItemDisplayInfo {
13 pub rows: Vec<ItemDisplayInfoRow>,
14}
15
16impl DbcTable for ItemDisplayInfo {
17 type Row = ItemDisplayInfoRow;
18
19 const FILENAME: &'static str = "ItemDisplayInfo.dbc";
20
21 fn rows(&self) -> &[Self::Row] { &self.rows }
22 fn rows_mut(&mut self) -> &mut [Self::Row] { &mut self.rows }
23
24 fn read(b: &mut impl std::io::Read) -> Result<Self, crate::DbcError> {
25 let mut header = [0_u8; HEADER_SIZE];
26 b.read_exact(&mut header)?;
27 let header = parse_header(&header)?;
28
29 if header.record_size != 100 {
30 return Err(crate::DbcError::InvalidHeader(
31 crate::InvalidHeaderError::RecordSize {
32 expected: 100,
33 actual: header.record_size,
34 },
35 ));
36 }
37
38 if header.field_count != 25 {
39 return Err(crate::DbcError::InvalidHeader(
40 crate::InvalidHeaderError::FieldCount {
41 expected: 25,
42 actual: header.field_count,
43 },
44 ));
45 }
46
47 let mut r = vec![0_u8; (header.record_count * header.record_size) as usize];
48 b.read_exact(&mut r)?;
49 let mut string_block = vec![0_u8; header.string_block_size as usize];
50 b.read_exact(&mut string_block)?;
51
52 let mut rows = Vec::with_capacity(header.record_count as usize);
53
54 for mut chunk in r.chunks(header.record_size as usize) {
55 let chunk = &mut chunk;
56
57 let id = ItemDisplayInfoKey::new(crate::util::read_i32_le(chunk)?);
59
60 let model_name = {
62 let mut arr = Vec::with_capacity(2);
63 for _ in 0..2 {
64 let i ={
65 let s = crate::util::get_string_as_vec(chunk, &string_block)?;
66 String::from_utf8(s)?
67 };
68 arr.push(i);
69 }
70
71 arr.try_into().unwrap()
72 };
73
74 let model_texture = {
76 let mut arr = Vec::with_capacity(2);
77 for _ in 0..2 {
78 let i ={
79 let s = crate::util::get_string_as_vec(chunk, &string_block)?;
80 String::from_utf8(s)?
81 };
82 arr.push(i);
83 }
84
85 arr.try_into().unwrap()
86 };
87
88 let inventory_icon = {
90 let mut arr = Vec::with_capacity(2);
91 for _ in 0..2 {
92 let i ={
93 let s = crate::util::get_string_as_vec(chunk, &string_block)?;
94 String::from_utf8(s)?
95 };
96 arr.push(i);
97 }
98
99 arr.try_into().unwrap()
100 };
101
102 let geoset_group = crate::util::read_array_i32::<3>(chunk)?;
104
105 let flags = crate::util::read_i32_le(chunk)?;
107
108 let spell_visual_id = SpellVisualKey::new(crate::util::read_i32_le(chunk)?.into());
110
111 let group_sound_index = crate::util::read_i32_le(chunk)?;
113
114 let helmet_geoset_vis_id = crate::util::read_array_i32::<2>(chunk)?;
116
117 let texture = {
119 let mut arr = Vec::with_capacity(8);
120 for _ in 0..8 {
121 let i ={
122 let s = crate::util::get_string_as_vec(chunk, &string_block)?;
123 String::from_utf8(s)?
124 };
125 arr.push(i);
126 }
127
128 arr.try_into().unwrap()
129 };
130
131 let item_visual = crate::util::read_i32_le(chunk)?;
133
134 let particle_color_id = ParticleColorKey::new(crate::util::read_i32_le(chunk)?.into());
136
137
138 rows.push(ItemDisplayInfoRow {
139 id,
140 model_name,
141 model_texture,
142 inventory_icon,
143 geoset_group,
144 flags,
145 spell_visual_id,
146 group_sound_index,
147 helmet_geoset_vis_id,
148 texture,
149 item_visual,
150 particle_color_id,
151 });
152 }
153
154 Ok(ItemDisplayInfo { rows, })
155 }
156
157 fn write(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
158 let header = DbcHeader {
159 record_count: self.rows.len() as u32,
160 field_count: 25,
161 record_size: 100,
162 string_block_size: self.string_block_size(),
163 };
164
165 b.write_all(&header.write_header())?;
166
167 let mut string_index = 1;
168 for row in &self.rows {
169 b.write_all(&row.id.id.to_le_bytes())?;
171
172 for i in &row.model_name {
174 if !i.is_empty() {
175 b.write_all(&(string_index as u32).to_le_bytes())?;
176 string_index += i.len() + 1;
177 }
178 else {
179 b.write_all(&(0_u32).to_le_bytes())?;
180 }
181 }
182
183
184 for i in &row.model_texture {
186 if !i.is_empty() {
187 b.write_all(&(string_index as u32).to_le_bytes())?;
188 string_index += i.len() + 1;
189 }
190 else {
191 b.write_all(&(0_u32).to_le_bytes())?;
192 }
193 }
194
195
196 for i in &row.inventory_icon {
198 if !i.is_empty() {
199 b.write_all(&(string_index as u32).to_le_bytes())?;
200 string_index += i.len() + 1;
201 }
202 else {
203 b.write_all(&(0_u32).to_le_bytes())?;
204 }
205 }
206
207
208 for i in row.geoset_group {
210 b.write_all(&i.to_le_bytes())?;
211 }
212
213
214 b.write_all(&row.flags.to_le_bytes())?;
216
217 b.write_all(&(row.spell_visual_id.id as i32).to_le_bytes())?;
219
220 b.write_all(&row.group_sound_index.to_le_bytes())?;
222
223 for i in row.helmet_geoset_vis_id {
225 b.write_all(&i.to_le_bytes())?;
226 }
227
228
229 for i in &row.texture {
231 if !i.is_empty() {
232 b.write_all(&(string_index as u32).to_le_bytes())?;
233 string_index += i.len() + 1;
234 }
235 else {
236 b.write_all(&(0_u32).to_le_bytes())?;
237 }
238 }
239
240
241 b.write_all(&row.item_visual.to_le_bytes())?;
243
244 b.write_all(&(row.particle_color_id.id as i32).to_le_bytes())?;
246
247 }
248
249 self.write_string_block(b)?;
250
251 Ok(())
252 }
253
254}
255
256impl Indexable for ItemDisplayInfo {
257 type PrimaryKey = ItemDisplayInfoKey;
258 fn get(&self, key: impl TryInto<Self::PrimaryKey>) -> Option<&Self::Row> {
259 let key = key.try_into().ok()?;
260 self.rows.iter().find(|a| a.id.id == key.id)
261 }
262
263 fn get_mut(&mut self, key: impl TryInto<Self::PrimaryKey>) -> Option<&mut Self::Row> {
264 let key = key.try_into().ok()?;
265 self.rows.iter_mut().find(|a| a.id.id == key.id)
266 }
267}
268
269impl ItemDisplayInfo {
270 fn write_string_block(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
271 b.write_all(&[0])?;
272
273 for row in &self.rows {
274 for s in &row.model_name {
275 if !s.is_empty() { b.write_all(s.as_bytes())?; b.write_all(&[0])?; };
276 }
277
278 for s in &row.model_texture {
279 if !s.is_empty() { b.write_all(s.as_bytes())?; b.write_all(&[0])?; };
280 }
281
282 for s in &row.inventory_icon {
283 if !s.is_empty() { b.write_all(s.as_bytes())?; b.write_all(&[0])?; };
284 }
285
286 for s in &row.texture {
287 if !s.is_empty() { b.write_all(s.as_bytes())?; b.write_all(&[0])?; };
288 }
289
290 }
291
292 Ok(())
293 }
294
295 fn string_block_size(&self) -> u32 {
296 let mut sum = 1;
297 for row in &self.rows {
298 for s in &row.model_name {
299 if !s.is_empty() { sum += s.len() + 1; };
300 }
301
302 for s in &row.model_texture {
303 if !s.is_empty() { sum += s.len() + 1; };
304 }
305
306 for s in &row.inventory_icon {
307 if !s.is_empty() { sum += s.len() + 1; };
308 }
309
310 for s in &row.texture {
311 if !s.is_empty() { sum += s.len() + 1; };
312 }
313
314 }
315
316 sum as u32
317 }
318
319}
320
321#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
322pub struct ItemDisplayInfoKey {
323 pub id: i32
324}
325
326impl ItemDisplayInfoKey {
327 pub const fn new(id: i32) -> Self {
328 Self { id }
329 }
330
331}
332
333impl From<u8> for ItemDisplayInfoKey {
334 fn from(v: u8) -> Self {
335 Self::new(v.into())
336 }
337}
338
339impl From<u16> for ItemDisplayInfoKey {
340 fn from(v: u16) -> Self {
341 Self::new(v.into())
342 }
343}
344
345impl From<i8> for ItemDisplayInfoKey {
346 fn from(v: i8) -> Self {
347 Self::new(v.into())
348 }
349}
350
351impl From<i16> for ItemDisplayInfoKey {
352 fn from(v: i16) -> Self {
353 Self::new(v.into())
354 }
355}
356
357impl From<i32> for ItemDisplayInfoKey {
358 fn from(v: i32) -> Self {
359 Self::new(v)
360 }
361}
362
363impl TryFrom<u32> for ItemDisplayInfoKey {
364 type Error = u32;
365 fn try_from(v: u32) -> Result<Self, Self::Error> {
366 Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
367 }
368}
369
370impl TryFrom<usize> for ItemDisplayInfoKey {
371 type Error = usize;
372 fn try_from(v: usize) -> Result<Self, Self::Error> {
373 Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
374 }
375}
376
377impl TryFrom<u64> for ItemDisplayInfoKey {
378 type Error = u64;
379 fn try_from(v: u64) -> Result<Self, Self::Error> {
380 Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
381 }
382}
383
384impl TryFrom<i64> for ItemDisplayInfoKey {
385 type Error = i64;
386 fn try_from(v: i64) -> Result<Self, Self::Error> {
387 Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
388 }
389}
390
391impl TryFrom<isize> for ItemDisplayInfoKey {
392 type Error = isize;
393 fn try_from(v: isize) -> Result<Self, Self::Error> {
394 Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
395 }
396}
397
398#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
399pub struct ItemDisplayInfoRow {
400 pub id: ItemDisplayInfoKey,
401 pub model_name: [String; 2],
402 pub model_texture: [String; 2],
403 pub inventory_icon: [String; 2],
404 pub geoset_group: [i32; 3],
405 pub flags: i32,
406 pub spell_visual_id: SpellVisualKey,
407 pub group_sound_index: i32,
408 pub helmet_geoset_vis_id: [i32; 2],
409 pub texture: [String; 8],
410 pub item_visual: i32,
411 pub particle_color_id: ParticleColorKey,
412}
413