wow_dbc/vanilla_tables/
world_state_ui.rs1use crate::{
2 DbcTable, Indexable, LocalizedString,
3};
4use crate::header::{
5 DbcHeader, HEADER_SIZE, parse_header,
6};
7use crate::vanilla_tables::area_table::AreaTableKey;
8use crate::vanilla_tables::map::MapKey;
9use std::io::Write;
10
11#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct WorldStateUI {
13 pub rows: Vec<WorldStateUIRow>,
14}
15
16impl DbcTable for WorldStateUI {
17 type Row = WorldStateUIRow;
18
19 const FILENAME: &'static str = "WorldStateUI.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 != 156 {
30 return Err(crate::DbcError::InvalidHeader(
31 crate::InvalidHeaderError::RecordSize {
32 expected: 156,
33 actual: header.record_size,
34 },
35 ));
36 }
37
38 if header.field_count != 39 {
39 return Err(crate::DbcError::InvalidHeader(
40 crate::InvalidHeaderError::FieldCount {
41 expected: 39,
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 = WorldStateUIKey::new(crate::util::read_u32_le(chunk)?);
59
60 let map = MapKey::new(crate::util::read_u32_le(chunk)?.into());
62
63 let area_table = AreaTableKey::new(crate::util::read_u32_le(chunk)?.into());
65
66 let icon = {
68 let s = crate::util::get_string_as_vec(chunk, &string_block)?;
69 String::from_utf8(s)?
70 };
71
72 let state_variable = crate::util::read_localized_string(chunk, &string_block)?;
74
75 let tooltip = crate::util::read_localized_string(chunk, &string_block)?;
77
78 let state = crate::util::read_i32_le(chunk)?;
80
81 let world_state = crate::util::read_u32_le(chunk)?;
83
84 let ty = crate::util::read_i32_le(chunk)?;
86
87 let dynamic_icon = {
89 let s = crate::util::get_string_as_vec(chunk, &string_block)?;
90 String::from_utf8(s)?
91 };
92
93 let dynamic_tooltip = crate::util::read_localized_string(chunk, &string_block)?;
95
96 let extended_ui = {
98 let s = crate::util::get_string_as_vec(chunk, &string_block)?;
99 String::from_utf8(s)?
100 };
101
102 let unknown = crate::util::read_array_u32::<3>(chunk)?;
104
105
106 rows.push(WorldStateUIRow {
107 id,
108 map,
109 area_table,
110 icon,
111 state_variable,
112 tooltip,
113 state,
114 world_state,
115 ty,
116 dynamic_icon,
117 dynamic_tooltip,
118 extended_ui,
119 unknown,
120 });
121 }
122
123 Ok(WorldStateUI { rows, })
124 }
125
126 fn write(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
127 let header = DbcHeader {
128 record_count: self.rows.len() as u32,
129 field_count: 39,
130 record_size: 156,
131 string_block_size: self.string_block_size(),
132 };
133
134 b.write_all(&header.write_header())?;
135
136 let mut string_index = 1;
137 for row in &self.rows {
138 b.write_all(&row.id.id.to_le_bytes())?;
140
141 b.write_all(&(row.map.id as u32).to_le_bytes())?;
143
144 b.write_all(&(row.area_table.id as u32).to_le_bytes())?;
146
147 if !row.icon.is_empty() {
149 b.write_all(&(string_index as u32).to_le_bytes())?;
150 string_index += row.icon.len() + 1;
151 }
152 else {
153 b.write_all(&(0_u32).to_le_bytes())?;
154 }
155
156 b.write_all(&row.state_variable.string_indices_as_array(&mut string_index))?;
158
159 b.write_all(&row.tooltip.string_indices_as_array(&mut string_index))?;
161
162 b.write_all(&row.state.to_le_bytes())?;
164
165 b.write_all(&row.world_state.to_le_bytes())?;
167
168 b.write_all(&row.ty.to_le_bytes())?;
170
171 if !row.dynamic_icon.is_empty() {
173 b.write_all(&(string_index as u32).to_le_bytes())?;
174 string_index += row.dynamic_icon.len() + 1;
175 }
176 else {
177 b.write_all(&(0_u32).to_le_bytes())?;
178 }
179
180 b.write_all(&row.dynamic_tooltip.string_indices_as_array(&mut string_index))?;
182
183 if !row.extended_ui.is_empty() {
185 b.write_all(&(string_index as u32).to_le_bytes())?;
186 string_index += row.extended_ui.len() + 1;
187 }
188 else {
189 b.write_all(&(0_u32).to_le_bytes())?;
190 }
191
192 for i in row.unknown {
194 b.write_all(&i.to_le_bytes())?;
195 }
196
197
198 }
199
200 self.write_string_block(b)?;
201
202 Ok(())
203 }
204
205}
206
207impl Indexable for WorldStateUI {
208 type PrimaryKey = WorldStateUIKey;
209 fn get(&self, key: impl TryInto<Self::PrimaryKey>) -> Option<&Self::Row> {
210 let key = key.try_into().ok()?;
211 self.rows.iter().find(|a| a.id.id == key.id)
212 }
213
214 fn get_mut(&mut self, key: impl TryInto<Self::PrimaryKey>) -> Option<&mut Self::Row> {
215 let key = key.try_into().ok()?;
216 self.rows.iter_mut().find(|a| a.id.id == key.id)
217 }
218}
219
220impl WorldStateUI {
221 fn write_string_block(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
222 b.write_all(&[0])?;
223
224 for row in &self.rows {
225 if !row.icon.is_empty() { b.write_all(row.icon.as_bytes())?; b.write_all(&[0])?; };
226 row.state_variable.string_block_as_array(b)?;
227 row.tooltip.string_block_as_array(b)?;
228 if !row.dynamic_icon.is_empty() { b.write_all(row.dynamic_icon.as_bytes())?; b.write_all(&[0])?; };
229 row.dynamic_tooltip.string_block_as_array(b)?;
230 if !row.extended_ui.is_empty() { b.write_all(row.extended_ui.as_bytes())?; b.write_all(&[0])?; };
231 }
232
233 Ok(())
234 }
235
236 fn string_block_size(&self) -> u32 {
237 let mut sum = 1;
238 for row in &self.rows {
239 if !row.icon.is_empty() { sum += row.icon.len() + 1; };
240 sum += row.state_variable.string_block_size();
241 sum += row.tooltip.string_block_size();
242 if !row.dynamic_icon.is_empty() { sum += row.dynamic_icon.len() + 1; };
243 sum += row.dynamic_tooltip.string_block_size();
244 if !row.extended_ui.is_empty() { sum += row.extended_ui.len() + 1; };
245 }
246
247 sum as u32
248 }
249
250}
251
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
253pub struct WorldStateUIKey {
254 pub id: u32
255}
256
257impl WorldStateUIKey {
258 pub const fn new(id: u32) -> Self {
259 Self { id }
260 }
261
262}
263
264impl From<u8> for WorldStateUIKey {
265 fn from(v: u8) -> Self {
266 Self::new(v.into())
267 }
268}
269
270impl From<u16> for WorldStateUIKey {
271 fn from(v: u16) -> Self {
272 Self::new(v.into())
273 }
274}
275
276impl From<u32> for WorldStateUIKey {
277 fn from(v: u32) -> Self {
278 Self::new(v)
279 }
280}
281
282impl TryFrom<u64> for WorldStateUIKey {
283 type Error = u64;
284 fn try_from(v: u64) -> Result<Self, Self::Error> {
285 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
286 }
287}
288
289impl TryFrom<usize> for WorldStateUIKey {
290 type Error = usize;
291 fn try_from(v: usize) -> Result<Self, Self::Error> {
292 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
293 }
294}
295
296impl TryFrom<i8> for WorldStateUIKey {
297 type Error = i8;
298 fn try_from(v: i8) -> Result<Self, Self::Error> {
299 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
300 }
301}
302
303impl TryFrom<i16> for WorldStateUIKey {
304 type Error = i16;
305 fn try_from(v: i16) -> Result<Self, Self::Error> {
306 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
307 }
308}
309
310impl TryFrom<i32> for WorldStateUIKey {
311 type Error = i32;
312 fn try_from(v: i32) -> Result<Self, Self::Error> {
313 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
314 }
315}
316
317impl TryFrom<i64> for WorldStateUIKey {
318 type Error = i64;
319 fn try_from(v: i64) -> Result<Self, Self::Error> {
320 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
321 }
322}
323
324impl TryFrom<isize> for WorldStateUIKey {
325 type Error = isize;
326 fn try_from(v: isize) -> Result<Self, Self::Error> {
327 Ok(TryInto::<u32>::try_into(v).ok().ok_or(v)?.into())
328 }
329}
330
331#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
332pub struct WorldStateUIRow {
333 pub id: WorldStateUIKey,
334 pub map: MapKey,
335 pub area_table: AreaTableKey,
336 pub icon: String,
337 pub state_variable: LocalizedString,
338 pub tooltip: LocalizedString,
339 pub state: i32,
340 pub world_state: u32,
341 pub ty: i32,
342 pub dynamic_icon: String,
343 pub dynamic_tooltip: LocalizedString,
344 pub extended_ui: String,
345 pub unknown: [u32; 3],
346}
347