wow_world_messages/world/wrath/
smsg_group_list.rs

1use std::io::{Read, Write};
2
3use crate::Guid;
4use crate::wrath::{
5    DungeonDifficulty, GroupListMember, GroupLootSetting, ItemQuality, RaidDifficulty,
6};
7
8/// Auto generated from the original `wowm` in file [`wow_message_parser/wowm/world/social/smsg_group_list.wowm:88`](https://github.com/gtker/wow_messages/tree/main/wow_message_parser/wowm/world/social/smsg_group_list.wowm#L88):
9/// ```text
10/// smsg SMSG_GROUP_LIST = 0x007D {
11///     u8 group_type;
12///     u8 group_id;
13///     u8 flags;
14///     u8 roles;
15///     Guid group;
16///     u32 counter;
17///     u32 amount_of_members;
18///     GroupListMember[amount_of_members] members;
19///     Guid leader;
20///     optional group_not_empty {
21///         GroupLootSetting loot_setting;
22///         Guid master_loot;
23///         ItemQuality loot_threshold;
24///         DungeonDifficulty difficulty;
25///         RaidDifficulty raid_difficulty;
26///         Bool heroic;
27///     }
28/// }
29/// ```
30#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
31pub struct SMSG_GROUP_LIST {
32    pub group_type: u8,
33    pub group_id: u8,
34    /// mangoszero/cmangos/vmangos: own flags (groupid | (assistant?0x80:0))
35    pub flags: u8,
36    pub roles: u8,
37    pub group: Guid,
38    /// azerothcore: 3.3, value increases every time this packet gets sent
39    pub counter: u32,
40    pub members: Vec<GroupListMember>,
41    pub leader: Guid,
42    pub group_not_empty: Option<SMSG_GROUP_LIST_group_not_empty>,
43}
44
45impl crate::private::Sealed for SMSG_GROUP_LIST {}
46impl SMSG_GROUP_LIST {
47    fn read_inner(mut r: &mut &[u8], body_size: u32) -> Result<Self, crate::errors::ParseErrorKind> {
48        if !(28..=16777215).contains(&body_size) {
49            return Err(crate::errors::ParseErrorKind::InvalidSize);
50        }
51
52        // group_type: u8
53        let group_type = crate::util::read_u8_le(&mut r)?;
54
55        // group_id: u8
56        let group_id = crate::util::read_u8_le(&mut r)?;
57
58        // flags: u8
59        let flags = crate::util::read_u8_le(&mut r)?;
60
61        // roles: u8
62        let roles = crate::util::read_u8_le(&mut r)?;
63
64        // group: Guid
65        let group = crate::util::read_guid(&mut r)?;
66
67        // counter: u32
68        let counter = crate::util::read_u32_le(&mut r)?;
69
70        // amount_of_members: u32
71        let amount_of_members = crate::util::read_u32_le(&mut r)?;
72
73        // members: GroupListMember[amount_of_members]
74        let members = {
75            let mut members = Vec::with_capacity(amount_of_members as usize);
76
77            let allocation_size = u64::from(amount_of_members) * 13;
78            if allocation_size > crate::errors::MAX_ALLOCATION_SIZE_WRATH {
79                return Err(crate::errors::ParseErrorKind::AllocationTooLargeError(allocation_size));
80            }
81
82            for _ in 0..amount_of_members {
83                members.push(GroupListMember::read(&mut r)?);
84            }
85            members
86        };
87
88        // leader: Guid
89        let leader = crate::util::read_guid(&mut r)?;
90
91        // optional group_not_empty
92        let current_size = {
93            1 // group_type: u8
94            + 1 // group_id: u8
95            + 1 // flags: u8
96            + 1 // roles: u8
97            + 8 // group: Guid
98            + 4 // counter: u32
99            + 4 // amount_of_members: u32
100            + members.iter().fold(0, |acc, x| acc + x.size()) // members: GroupListMember[amount_of_members]
101            + 8 // leader: Guid
102        };
103        let group_not_empty = if current_size < body_size as usize {
104            // loot_setting: GroupLootSetting
105            let loot_setting = crate::util::read_u8_le(&mut r)?.try_into()?;
106
107            // master_loot: Guid
108            let master_loot = crate::util::read_guid(&mut r)?;
109
110            // loot_threshold: ItemQuality
111            let loot_threshold = crate::util::read_u8_le(&mut r)?.try_into()?;
112
113            // difficulty: DungeonDifficulty
114            let difficulty = crate::util::read_u8_le(&mut r)?.try_into()?;
115
116            // raid_difficulty: RaidDifficulty
117            let raid_difficulty = crate::util::read_u8_le(&mut r)?.try_into()?;
118
119            // heroic: Bool
120            let heroic = crate::util::read_bool_u8(&mut r)?;
121
122            Some(SMSG_GROUP_LIST_group_not_empty {
123                loot_setting,
124                master_loot,
125                loot_threshold,
126                difficulty,
127                raid_difficulty,
128                heroic,
129            })
130        } else {
131            None
132        };
133
134        Ok(Self {
135            group_type,
136            group_id,
137            flags,
138            roles,
139            group,
140            counter,
141            members,
142            leader,
143            group_not_empty,
144        })
145    }
146
147}
148
149impl crate::Message for SMSG_GROUP_LIST {
150    const OPCODE: u32 = 0x007d;
151
152    #[cfg(feature = "print-testcase")]
153    fn message_name(&self) -> &'static str {
154        "SMSG_GROUP_LIST"
155    }
156
157    #[cfg(feature = "print-testcase")]
158    fn to_test_case_string(&self) -> Option<String> {
159        use std::fmt::Write;
160        use crate::traits::Message;
161
162        let mut s = String::new();
163
164        writeln!(s, "test SMSG_GROUP_LIST {{").unwrap();
165        // Members
166        writeln!(s, "    group_type = {};", self.group_type).unwrap();
167        writeln!(s, "    group_id = {};", self.group_id).unwrap();
168        writeln!(s, "    flags = {};", self.flags).unwrap();
169        writeln!(s, "    roles = {};", self.roles).unwrap();
170        writeln!(s, "    group = {};", self.group.guid()).unwrap();
171        writeln!(s, "    counter = {};", self.counter).unwrap();
172        writeln!(s, "    amount_of_members = {};", self.members.len()).unwrap();
173        writeln!(s, "    members = [").unwrap();
174        for v in self.members.as_slice() {
175            writeln!(s, "        {{").unwrap();
176            // Members
177            writeln!(s, "            name = \"{}\";", v.name).unwrap();
178            writeln!(s, "            guid = {};", v.guid.guid()).unwrap();
179            writeln!(s, "            is_online = {};", if v.is_online { "TRUE" } else { "FALSE" }).unwrap();
180            writeln!(s, "            group_id = {};", v.group_id).unwrap();
181            writeln!(s, "            flags = {};", v.flags).unwrap();
182            writeln!(s, "            lfg_roles = {};", v.lfg_roles).unwrap();
183
184            writeln!(s, "        }},").unwrap();
185        }
186        writeln!(s, "    ];").unwrap();
187        writeln!(s, "    leader = {};", self.leader.guid()).unwrap();
188        if let Some(group_not_empty) = &self.group_not_empty {
189            writeln!(s, "    loot_setting = {};", group_not_empty.loot_setting.as_test_case_value()).unwrap();
190            writeln!(s, "    master_loot = {};", group_not_empty.master_loot.guid()).unwrap();
191            writeln!(s, "    loot_threshold = {};", group_not_empty.loot_threshold.as_test_case_value()).unwrap();
192            writeln!(s, "    difficulty = {};", group_not_empty.difficulty.as_test_case_value()).unwrap();
193            writeln!(s, "    raid_difficulty = {};", group_not_empty.raid_difficulty.as_test_case_value()).unwrap();
194            writeln!(s, "    heroic = {};", if group_not_empty.heroic { "TRUE" } else { "FALSE" }).unwrap();
195        }
196
197        writeln!(s, "}} [").unwrap();
198
199        let [a, b] = (u16::try_from(self.size() + 2).unwrap()).to_be_bytes();
200        writeln!(s, "    {a:#04X}, {b:#04X}, /* size */").unwrap();
201        let [a, b] = 125_u16.to_le_bytes();
202        writeln!(s, "    {a:#04X}, {b:#04X}, /* opcode */").unwrap();
203        let mut bytes: Vec<u8> = Vec::new();
204        self.write_into_vec(&mut bytes).unwrap();
205        let mut bytes = bytes.into_iter();
206
207        crate::util::write_bytes(&mut s, &mut bytes, 1, "group_type", "    ");
208        crate::util::write_bytes(&mut s, &mut bytes, 1, "group_id", "    ");
209        crate::util::write_bytes(&mut s, &mut bytes, 1, "flags", "    ");
210        crate::util::write_bytes(&mut s, &mut bytes, 1, "roles", "    ");
211        crate::util::write_bytes(&mut s, &mut bytes, 8, "group", "    ");
212        crate::util::write_bytes(&mut s, &mut bytes, 4, "counter", "    ");
213        crate::util::write_bytes(&mut s, &mut bytes, 4, "amount_of_members", "    ");
214        if !self.members.is_empty() {
215            writeln!(s, "    /* members: GroupListMember[amount_of_members] start */").unwrap();
216            for (i, v) in self.members.iter().enumerate() {
217                writeln!(s, "    /* members: GroupListMember[amount_of_members] {i} start */").unwrap();
218                crate::util::write_bytes(&mut s, &mut bytes, v.name.len() + 1, "name", "        ");
219                crate::util::write_bytes(&mut s, &mut bytes, 8, "guid", "        ");
220                crate::util::write_bytes(&mut s, &mut bytes, 1, "is_online", "        ");
221                crate::util::write_bytes(&mut s, &mut bytes, 1, "group_id", "        ");
222                crate::util::write_bytes(&mut s, &mut bytes, 1, "flags", "        ");
223                crate::util::write_bytes(&mut s, &mut bytes, 1, "lfg_roles", "        ");
224                writeln!(s, "    /* members: GroupListMember[amount_of_members] {i} end */").unwrap();
225            }
226            writeln!(s, "    /* members: GroupListMember[amount_of_members] end */").unwrap();
227        }
228        crate::util::write_bytes(&mut s, &mut bytes, 8, "leader", "    ");
229        if let Some(group_not_empty) = &self.group_not_empty {
230            crate::util::write_bytes(&mut s, &mut bytes, 1, "loot_setting", "    ");
231            crate::util::write_bytes(&mut s, &mut bytes, 8, "master_loot", "    ");
232            crate::util::write_bytes(&mut s, &mut bytes, 1, "loot_threshold", "    ");
233            crate::util::write_bytes(&mut s, &mut bytes, 1, "difficulty", "    ");
234            crate::util::write_bytes(&mut s, &mut bytes, 1, "raid_difficulty", "    ");
235            crate::util::write_bytes(&mut s, &mut bytes, 1, "heroic", "    ");
236        }
237
238
239        writeln!(s, "] {{").unwrap();
240        writeln!(s, "    versions = \"{}\";", std::env::var("WOWM_TEST_CASE_WORLD_VERSION").unwrap_or("3.3.5".to_string())).unwrap();
241        writeln!(s, "}}\n").unwrap();
242
243        Some(s)
244    }
245
246    fn size_without_header(&self) -> u32 {
247        self.size() as u32
248    }
249
250    fn write_into_vec(&self, mut w: impl Write) -> Result<(), std::io::Error> {
251        // group_type: u8
252        w.write_all(&self.group_type.to_le_bytes())?;
253
254        // group_id: u8
255        w.write_all(&self.group_id.to_le_bytes())?;
256
257        // flags: u8
258        w.write_all(&self.flags.to_le_bytes())?;
259
260        // roles: u8
261        w.write_all(&self.roles.to_le_bytes())?;
262
263        // group: Guid
264        w.write_all(&self.group.guid().to_le_bytes())?;
265
266        // counter: u32
267        w.write_all(&self.counter.to_le_bytes())?;
268
269        // amount_of_members: u32
270        w.write_all(&(self.members.len() as u32).to_le_bytes())?;
271
272        // members: GroupListMember[amount_of_members]
273        for i in self.members.iter() {
274            i.write_into_vec(&mut w)?;
275        }
276
277        // leader: Guid
278        w.write_all(&self.leader.guid().to_le_bytes())?;
279
280        // optional group_not_empty
281        if let Some(v) = &self.group_not_empty {
282            // loot_setting: GroupLootSetting
283            w.write_all(&(v.loot_setting.as_int().to_le_bytes()))?;
284
285            // master_loot: Guid
286            w.write_all(&v.master_loot.guid().to_le_bytes())?;
287
288            // loot_threshold: ItemQuality
289            w.write_all(&(v.loot_threshold.as_int().to_le_bytes()))?;
290
291            // difficulty: DungeonDifficulty
292            w.write_all(&(v.difficulty.as_int().to_le_bytes()))?;
293
294            // raid_difficulty: RaidDifficulty
295            w.write_all(&(v.raid_difficulty.as_int().to_le_bytes()))?;
296
297            // heroic: Bool
298            w.write_all(u8::from(v.heroic).to_le_bytes().as_slice())?;
299
300        }
301
302        Ok(())
303    }
304
305    fn read_body<S: crate::private::Sealed>(r: &mut &[u8], body_size: u32) -> Result<Self, crate::errors::ParseError> {
306        Self::read_inner(r, body_size).map_err(|a| crate::errors::ParseError::new(125, "SMSG_GROUP_LIST", body_size, a))
307    }
308
309}
310
311#[cfg(feature = "wrath")]
312impl crate::wrath::ServerMessage for SMSG_GROUP_LIST {}
313
314impl SMSG_GROUP_LIST {
315    pub(crate) fn size(&self) -> usize {
316        1 // group_type: u8
317        + 1 // group_id: u8
318        + 1 // flags: u8
319        + 1 // roles: u8
320        + 8 // group: Guid
321        + 4 // counter: u32
322        + 4 // amount_of_members: u32
323        + self.members.iter().fold(0, |acc, x| acc + x.size()) // members: GroupListMember[amount_of_members]
324        + 8 // leader: Guid
325        + if let Some(group_not_empty) = &self.group_not_empty {
326            1 // loot_setting: GroupLootSetting
327            + 8 // master_loot: Guid
328            + 1 // loot_threshold: ItemQuality
329            + 1 // difficulty: DungeonDifficulty
330            + 1 // raid_difficulty: RaidDifficulty
331            + 1 // heroic: Bool
332        } else {
333            0
334        }
335    }
336}
337
338#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
339pub struct SMSG_GROUP_LIST_group_not_empty {
340    pub loot_setting: GroupLootSetting,
341    pub master_loot: Guid,
342    pub loot_threshold: ItemQuality,
343    pub difficulty: DungeonDifficulty,
344    pub raid_difficulty: RaidDifficulty,
345    pub heroic: bool,
346}
347