1use std::collections::BTreeMap;
2use std::io::BufRead;
3
4use anyhow::Context;
5use bitflags::bitflags;
6use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
7use serde::{Serialize, Serializer};
8
9use crate::BinaryConverter;
10use crate::types::update_fields::{
11 ContainerField,
12 CorpseField,
13 DynamicObjectField,
14 FieldValue,
15 GameObjectField,
16 ItemField,
17 ObjectField,
18 PlayerField,
19 UnitField,
20};
21
22#[derive(Serialize, Clone, Default, Debug, PartialEq)]
23pub struct UpdateData {
24 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
25 pub object_fields: BTreeMap<ObjectField, FieldValue>,
26 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
27 pub unit_fields: BTreeMap<UnitField, FieldValue>,
28 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
29 pub player_fields: BTreeMap<PlayerField, FieldValue>,
30 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
31 pub item_fields: BTreeMap<ItemField, FieldValue>,
32 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
33 pub container_fields: BTreeMap<ContainerField, FieldValue>,
34 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
35 pub game_object_fields: BTreeMap<GameObjectField, FieldValue>,
36 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
37 pub dynamic_object_fields: BTreeMap<DynamicObjectField, FieldValue>,
38 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
39 pub corpse_fields: BTreeMap<CorpseField, FieldValue>,
40}
41
42impl UpdateData {
43 pub fn is_default(&self) -> bool {
44 *self == Self::default()
45 }
46
47 pub fn update_fields(&mut self, source: &mut UpdateData) {
48 self.player_fields.append(&mut source.player_fields);
49 self.unit_fields.append(&mut source.unit_fields);
50 self.object_fields.append(&mut source.object_fields);
51 self.item_fields.append(&mut source.item_fields);
52 self.game_object_fields.append(&mut source.game_object_fields);
53 self.dynamic_object_fields.append(&mut source.dynamic_object_fields);
54 self.container_fields.append(&mut source.container_fields);
55 self.corpse_fields.append(&mut source.corpse_fields);
56 }
57
58 pub fn parse_value(option: &FieldValue) -> Vec<u32> {
59 match option {
60 FieldValue::Long(value) => {
61 let high = (value >> 32) as u32;
62 let low = (value & 0xFFFFFFFF) as u32;
63 vec![low, high]
64 }
65 FieldValue::LongArray(values) => {
66 let mut result: Vec<u32> = vec![];
67 for value in values {
68 let high = (value >> 32) as u32;
69 let low = (value & 0xFFFFFFFF) as u32;
70 result.push(low);
71 result.push(high);
72 }
73
74 result
75 }
76 FieldValue::Integer(value) => {
77 vec![*value as u32]
78 }
79 FieldValue::IntegerArray(values) => {
80 values.iter().map(|&value| value as u32).collect()
81 }
82 FieldValue::Bytes(value) => vec![*value],
83 FieldValue::BytesArray(values) => values.clone(),
84 FieldValue::Float(value) => vec![value.to_bits()],
85 FieldValue::FloatArray(values) => values.iter().map(|value| value.to_bits()).collect(),
86 FieldValue::TwoShorts((first, second)) => {
87 vec![(*first as u32) << 16 | *second as u32]
88 }
89 FieldValue::TwoShortsArray(values) => {
90 values.iter()
91 .map(|&(first, second)| (first as u32) << 16 | second as u32)
92 .collect()
93 }
94 _ => { vec![] }
95 }
96 }
97
98 fn build_blocks(
99 update_blocks: &BTreeMap<u32, u32>,
100 start: u32,
101 end: u32,
102 ) -> BTreeMap<u32, u32> {
103 update_blocks.range(start..=end).map(|(&key, &value)| (key, value)).collect()
104 }
106}
107
108impl BinaryConverter for UpdateData {
109 fn write_into(&mut self, buffer: &mut Vec<u8>) -> anyhow::Result<()> {
110 let mut update_fields: BTreeMap<u32, u32> = BTreeMap::new();
111
112 for (key, option) in self.object_fields.iter() {
113 let values = Self::parse_value(option);
114 let start_index = ObjectField::get_index(key);
115
116 for (i, &value) in values.iter().enumerate() {
117 if value != 0 {
119 update_fields.insert(start_index + i as u32, value);
120 }
121 }
122 }
123
124 for (key, option) in self.unit_fields.iter() {
125 let values = Self::parse_value(option);
126 let start_index = UnitField::get_index(key);
127
128 for (i, &value) in values.iter().enumerate() {
129 if value != 0 {
130 update_fields.insert(start_index + i as u32, value);
131 }
132 }
133 }
134
135 for (key, option) in self.player_fields.iter() {
136 let values = Self::parse_value(option);
137 let start_index = PlayerField::get_index(key);
138
139 for (i, &value) in values.iter().enumerate() {
140 if value != 0 {
141 update_fields.insert(start_index + i as u32, value);
142 }
143 }
144 }
145
146 let values_limit = if !self.player_fields.is_empty() {
147 PlayerField::get_limit()
148 } else if !self.unit_fields.is_empty() {
149 UnitField::get_limit()
150 } else {
151 ObjectField::get_limit()
152 };
153
154 let blocks_amount = ((values_limit + 31) / 32) as u8;
155
156 buffer.write_u8(blocks_amount)?;
157
158 let mut update_mask: Vec<u32> = vec![0; blocks_amount as usize];
159 for index in update_fields.keys() {
160 let block_index = index / 32;
161 let bit_index = index % 32;
162 update_mask[block_index as usize] |= 1 << bit_index;
163 }
164
165 for value in update_mask {
166 buffer.extend(value.to_le_bytes());
167 }
168
169 for value in update_fields.values() {
170 buffer.extend(value.to_le_bytes());
171 }
172
173 Ok(())
174 }
175
176 fn read_from<R: BufRead>(reader: &mut R, _: &mut Vec<u8>) -> anyhow::Result<Self> {
177 let blocks_amount = u8::read_from(reader, &mut vec![])?;
178
179 let mut instance = Self::default();
180
181 if blocks_amount > 0 {
182 let mut update_mask = (0..blocks_amount)
183 .map(|_| reader
184 .read_u32::<LittleEndian>()
185 .context(format!("Failed to read MASK VAL from reader with {}", blocks_amount)))
186 .collect::<Result<Vec<_>, _>>()?
187 .into_iter()
188 .map(|mut mask| {
189 let mut bits = vec![];
190 for _ in 0..32 {
191 bits.push((mask & 1) == 1);
192 mask >>= 1;
193 }
194 bits
195 })
196 .flatten()
197 .collect::<Vec<bool>>();
198
199 let update_indices: Vec<u32> = update_mask.iter()
200 .enumerate()
201 .filter_map(|(index, &value)| if value { Some(index as u32) } else { None })
202 .collect();
203
204 let update_blocks: BTreeMap<u32, u32> = update_indices
205 .into_iter()
206 .map(|index| (index, reader.read_u32::<LittleEndian>().unwrap()))
207 .collect();
208
209 let object_fields: BTreeMap<ObjectField, FieldValue> = {
210 let blocks: BTreeMap<u32, u32> = update_blocks
211 .range(0..=ObjectField::get_limit())
212 .map(|(&key, &value)| (key, value))
213 .collect();
214
215 ObjectField::read_from(
216 blocks.values().copied().collect::<Vec<u32>>(),
217 &mut update_mask,
218 ).unwrap_or_default()
219 };
220
221 let mask = object_fields
222 .get(&ObjectField::Type)
223 .map_or(
224 ObjectTypeMask::NONE,
225 |field| if let FieldValue::Integer(mask) = field {
226 ObjectTypeMask::from_bits(*mask).unwrap()
227 } else {
228 ObjectTypeMask::NONE
229 },
230 );
231
232 if mask.contains(ObjectTypeMask::UNIT) || mask.is_empty() {
233 instance.unit_fields = {
234 let blocks = Self::build_blocks(
235 &update_blocks,
236 ObjectField::get_limit() + 1,
237 UnitField::get_limit(),
238 );
239
240 UnitField::read_from(
241 blocks.values().copied().collect::<Vec<u32>>(),
242 &mut update_mask,
243 ).unwrap_or_default()
244 };
245 }
246
247 if mask.contains(ObjectTypeMask::PLAYER) || mask.is_empty() {
248 instance.player_fields = {
249 let blocks = Self::build_blocks(
250 &update_blocks,
251 UnitField::get_limit() + 1,
252 PlayerField::get_limit(),
253 );
254
255 PlayerField::read_from(
256 blocks.values().copied().collect::<Vec<u32>>(),
257 &mut update_mask,
258 ).unwrap_or_default()
259 };
260 }
261
262 if mask.contains(ObjectTypeMask::ITEM) || mask.is_empty() {
263 instance.item_fields = {
264 let blocks = Self::build_blocks(
265 &update_blocks,
266 ObjectField::get_limit() + 1,
267 ItemField::get_limit(),
268 );
269
270 ItemField::read_from(
271 blocks.values().copied().collect::<Vec<u32>>(),
272 &mut update_mask,
273 ).unwrap_or_default()
274 };
275 }
276
277 if mask.contains(ObjectTypeMask::GAMEOBJECT) || mask.is_empty() {
278 instance.game_object_fields = {
279 let blocks = Self::build_blocks(
280 &update_blocks,
281 ObjectField::get_limit() + 1,
282 GameObjectField::get_limit(),
283 );
284
285 GameObjectField::read_from(
286 blocks.values().copied().collect::<Vec<u32>>(),
287 &mut update_mask,
288 ).unwrap_or_default()
289 };
290 }
291
292 if mask.contains(ObjectTypeMask::DYNAMICOBJECT) || mask.is_empty() {
293 instance.dynamic_object_fields = {
294 let blocks = Self::build_blocks(
295 &update_blocks,
296 ObjectField::get_limit() + 1,
297 DynamicObjectField::get_limit(),
298 );
299
300 DynamicObjectField::read_from(
301 blocks.values().copied().collect::<Vec<u32>>(),
302 &mut update_mask,
303 ).unwrap_or_default()
304 };
305 }
306
307 if mask.contains(ObjectTypeMask::CONTAINER) || mask.is_empty() {
308 instance.container_fields = {
309 let blocks = Self::build_blocks(
310 &update_blocks,
311 ItemField::get_limit() + 1,
312 ContainerField::get_limit(),
313 );
314
315 ContainerField::read_from(
316 blocks.values().copied().collect::<Vec<u32>>(),
317 &mut update_mask,
318 ).unwrap_or_default()
319 };
320 }
321
322 if mask.contains(ObjectTypeMask::CORPSE) || mask.is_empty() {
323 instance.corpse_fields = {
324 let blocks = Self::build_blocks(
325 &update_blocks,
326 ObjectField::get_limit() + 1,
327 CorpseField::get_limit(),
328 );
329
330 CorpseField::read_from(
331 blocks.values().copied().collect::<Vec<u32>>(),
332 &mut update_mask,
333 ).unwrap_or_default()
334 };
335 }
336
337 instance.object_fields = object_fields;
338 }
339
340 Ok(instance)
341 }
342}
343
344#[cfg(test)]
345mod tests {
346 use std::collections::BTreeMap;
347
348 use crate::BinaryConverter;
349 use crate::types::update_data::UpdateData;
350 use crate::types::update_fields::{FieldValue, ObjectField, PlayerField, UnitField};
351
352 #[test]
353 fn test_generated_update_mask_is_correct() {
354 const GUID: u64 = 1;
355 const TYPE: i32 = 2;
356 const SCALE_X: f32 = 3.;
357 const AURA_STATE: i32 = 35;
358 const HEALTH: i32 = 52;
359 const BASE_ATTACK_TIME_0: i32 = 100;
360 const BASE_ATTACK_TIME_1: i32 = 200;
361 const POWER_MANA: i32 = 10;
362 const POWER_RAGE: i32 = 11;
363 const POWER_FOCUS: i32 = 12;
364 const POWER_ENERGY: i32 = 13;
365 const POWER_HAPPINESS: i32 = 14;
366 const POWER_RUNES: i32 = 15;
367 const POWER_RUNIC_POWER: i32 = 16;
368 const BYTES: u32 = 213;
369 const XP: i32 = 152;
370 const SLOT_0: u64 = 5116089176692927345;
371 const SLOT_10: u64 = 2156389176699927345;
372 const CHAR_POINT_0: i32 = 2;
373 const CHAR_POINT_1: i32 = 4;
374 const KNOWN_TITLE_0: u64 = 13423323;
375 const KNOWN_TITLE_1: u64 = 21231324;
376 const KNOWN_TITLE_2: u64 = 33213225;
377
378 let inv_slots = {
379 let mut slots = vec![0u64; 23];
380 slots[0] = SLOT_0;
381 slots[10] = SLOT_10;
382
383 slots
384 };
385
386 let keyring_slots = {
387 let mut slots = vec![0u64; 32];
388 slots[0] = SLOT_0;
389 slots[10] = SLOT_10;
390
391 slots
392 };
393
394 let cur_token_slots = {
395 let mut slots = vec![0u64; 32];
396 slots[0] = SLOT_0;
397 slots[10] = SLOT_10;
398
399 slots
400 };
401
402 let character_points = vec![CHAR_POINT_0, CHAR_POINT_1];
403
404 let known_titles = vec![KNOWN_TITLE_0, KNOWN_TITLE_1, KNOWN_TITLE_2];
405
406 let mut update_data = UpdateData {
407 object_fields: {
408 let mut map: BTreeMap<ObjectField, FieldValue> = BTreeMap::new();
409 map.insert(ObjectField::Guid, FieldValue::Long(GUID));
410 map.insert(ObjectField::Type, FieldValue::Integer(TYPE));
411 map.insert(ObjectField::ScaleX, FieldValue::Float(SCALE_X));
412
413 map
414 },
415 unit_fields: {
416 let mut map: BTreeMap<UnitField, FieldValue> = BTreeMap::new();
417 map.insert(UnitField::AuraState, FieldValue::Integer(AURA_STATE));
418 map.insert(UnitField::Charm, FieldValue::Long(GUID));
419 map.insert(UnitField::Health, FieldValue::Integer(HEALTH));
420 map.insert(
421 UnitField::BaseAttackTime,
422 FieldValue::IntegerArray(vec![BASE_ATTACK_TIME_0, BASE_ATTACK_TIME_1]),
423 );
424 map.insert(
425 UnitField::Powers,
426 FieldValue::IntegerArray(
427 vec![POWER_MANA, POWER_RAGE, POWER_FOCUS, POWER_ENERGY,
428 POWER_HAPPINESS, POWER_RUNES, POWER_RUNIC_POWER]
429 ),
430 );
431
432 map
433 },
434 player_fields: {
435 let mut map: BTreeMap<PlayerField, FieldValue> = BTreeMap::new();
436 map.insert(PlayerField::Bytes, FieldValue::BytesArray(vec![BYTES, BYTES, BYTES]));
437 map.insert(PlayerField::Xp, FieldValue::Integer(XP));
438 map.insert(PlayerField::InvSlot, FieldValue::LongArray(inv_slots.clone()));
439 map.insert(PlayerField::KeyringSlot, FieldValue::LongArray(keyring_slots.clone()));
440 map.insert(
441 PlayerField::CurrencyTokenSlot,
442 FieldValue::LongArray(cur_token_slots.clone()),
443 );
444 map.insert(
445 PlayerField::CharacterPoints,
446 FieldValue::IntegerArray(character_points.clone()),
447 );
448 map.insert(
449 PlayerField::KnownTitles,
450 FieldValue::LongArray(known_titles.clone()),
451 );
452
453 map
454 },
455 ..UpdateData::default()
456 };
457
458 let mut buffer: Vec<u8> = vec![];
459 update_data.write_into(&mut buffer).unwrap();
460
461 let mut reader = std::io::Cursor::new(&buffer);
462
463 let result = UpdateData::read_from(&mut reader, &mut vec![]).unwrap();
464 assert_eq!(result.object_fields.get(&ObjectField::Guid), Some(&FieldValue::Long(GUID)));
465 assert_eq!(result.object_fields.get(&ObjectField::Type), Some(&FieldValue::Integer(TYPE)));
466 assert_eq!(
467 result.object_fields.get(&ObjectField::ScaleX), Some(&FieldValue::Float(SCALE_X))
468 );
469 assert_eq!(
470 result.unit_fields.get(&UnitField::AuraState), Some(&FieldValue::Integer(AURA_STATE))
471 );
472 assert_eq!(
473 result.unit_fields.get(&UnitField::Charm), Some(&FieldValue::Long(GUID))
474 );
475 assert_eq!(
476 result.unit_fields.get(&UnitField::Health), Some(&FieldValue::Integer(HEALTH))
477 );
478 assert_eq!(
479 result.unit_fields.get(&UnitField::BaseAttackTime),
480 Some(&FieldValue::IntegerArray(vec![BASE_ATTACK_TIME_0, BASE_ATTACK_TIME_1]))
481 );
482 assert_eq!(
483 result.unit_fields.get(&UnitField::Powers),
484 Some(&FieldValue::IntegerArray(vec![
485 POWER_MANA, POWER_RAGE, POWER_FOCUS, POWER_ENERGY,
486 POWER_HAPPINESS, POWER_RUNES, POWER_RUNIC_POWER,
487 ]))
488 );
489 assert_eq!(
490 result.player_fields.get(&PlayerField::Bytes),
491 Some(&FieldValue::BytesArray(vec![BYTES, BYTES, BYTES]))
492 );
493 assert_eq!(
494 result.player_fields.get(&PlayerField::Xp), Some(&FieldValue::Integer(XP))
495 );
496 assert_eq!(
497 result.player_fields.get(&PlayerField::InvSlot),
498 Some(&FieldValue::LongArray(inv_slots))
499 );
500 assert_eq!(
501 result.player_fields.get(&PlayerField::KeyringSlot),
502 Some(&FieldValue::LongArray(keyring_slots))
503 );
504 assert_eq!(
505 result.player_fields.get(&PlayerField::CurrencyTokenSlot),
506 Some(&FieldValue::LongArray(cur_token_slots))
507 );
508 assert_eq!(
509 result.player_fields.get(&PlayerField::CharacterPoints),
510 Some(&FieldValue::IntegerArray(character_points))
511 );
512 assert_eq!(
513 result.player_fields.get(&PlayerField::KnownTitles),
514 Some(&FieldValue::LongArray(known_titles))
515 );
516 }
517}
518
519bitflags! {
520 #[derive(Default, Debug)]
521 pub struct ObjectTypeMask: i32 {
522 const NONE = 0x0000;
523 const OBJECT = 0x0001;
524 const ITEM = 0x0002;
525 const CONTAINER = 0x0004;
526 const UNIT = 0x0008;
527 const PLAYER = 0x0010;
528 const GAMEOBJECT = 0x0020;
529 const DYNAMICOBJECT = 0x0040;
530 const CORPSE = 0x0080;
531 }
532}
533
534#[non_exhaustive]
535#[derive(Debug, Default, Clone, PartialEq)]
536pub struct BlockType(pub u8);
537
538#[allow(dead_code)]
539impl BlockType {
540 pub const VALUES: u8 = 0;
541 pub const MOVEMENT: u8 = 1;
542 pub const CREATE_OBJECT: u8 = 2;
543 pub const CREATE_OBJECT2: u8 = 3;
544 pub const OUT_OF_RANGE_OBJECTS: u8 = 4;
545 pub const NEAR_OBJECTS: u8 = 5;
546
547 pub fn new(value: u8) -> Self {
548 Self(value)
549 }
550}
551
552impl BinaryConverter for BlockType {
553 fn write_into(&mut self, buffer: &mut Vec<u8>) -> anyhow::Result<()> {
554 u8::write_into(&mut self.0, buffer)?;
555
556 Ok(())
557 }
558
559 fn read_from<R: BufRead>(reader: &mut R, dependencies: &mut Vec<u8>) -> anyhow::Result<Self> {
560 let value = u8::read_from(reader, dependencies)?;
561
562 Ok(Self(value))
563 }
564}
565
566impl Serialize for BlockType {
567 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
568 where
569 S: Serializer,
570 {
571 let field_name = match self.0 {
572 Self::VALUES => "VALUES",
573 Self::MOVEMENT => "MOVEMENT",
574 Self::CREATE_OBJECT => "CREATE_OBJECT",
575 Self::CREATE_OBJECT2 => "CREATE_OBJECT2",
576 Self::OUT_OF_RANGE_OBJECTS => "OUT_OF_RANGE_OBJECTS",
577 Self::NEAR_OBJECTS => "NEAR_OBJECTS",
578 _ => "NONE",
579 };
580
581 serializer.serialize_str(field_name)
582 }
583}
584
585#[non_exhaustive]
586#[derive(Debug, Clone, Copy, PartialEq)]
587pub struct ObjectTypeID(pub i8);
588
589#[allow(dead_code)]
590impl ObjectTypeID {
591 pub const NONE: i8 = -1;
592 pub const OBJECT: i8 = 0;
593 pub const ITEM: i8 = 1;
594 pub const CONTAINER: i8 = 2;
595 pub const UNIT: i8 = 3;
596 pub const PLAYER: i8 = 4;
597 pub const GAMEOBJECT: i8 = 5;
598 pub const DYNAMICOBJECT: i8 = 6;
599 pub const CORPSE: i8 = 7;
600
601 pub fn new(value: i8) -> Self {
602 Self(value)
603 }
604
605 pub fn is_none(instance: &Self) -> bool {
606 instance.0 == Self::NONE
607 }
608}
609
610impl Default for ObjectTypeID {
611 fn default() -> Self {
612 Self(ObjectTypeID::NONE)
613 }
614}
615
616impl BinaryConverter for ObjectTypeID {
617 fn write_into(&mut self, buffer: &mut Vec<u8>) -> anyhow::Result<()> {
618 i8::write_into(&mut self.0, buffer)?;
619
620 Ok(())
621 }
622
623 fn read_from<R: BufRead>(reader: &mut R, dependencies: &mut Vec<u8>) -> anyhow::Result<Self> {
624 let value = i8::read_from(reader, dependencies)?;
625
626 Ok(Self(value))
627 }
628}
629
630impl Serialize for ObjectTypeID {
631 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
632 where
633 S: Serializer,
634 {
635 let field_name = match self.0 {
636 Self::OBJECT => "OBJECT",
637 Self::ITEM => "ITEM",
638 Self::CONTAINER => "CONTAINER",
639 Self::UNIT => "UNIT",
640 Self::PLAYER => "PLAYER",
641 Self::GAMEOBJECT => "GAMEOBJECT",
642 Self::DYNAMICOBJECT => "DYNAMICOBJECT",
643 Self::CORPSE => "CORPSE",
644 _ => "NONE",
645 };
646
647 serializer.serialize_str(field_name)
648 }
649}