Skip to main content

tentacli_traits/types/
update_data.rs

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        // update_blocks.range(start..=end).copied().collect()
105    }
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                // zero values exists in arrays (when some items omitted)
118                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}