1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use std::io::{Read, Write};
use crate::shared::level_vanilla_tbc_wrath::Level;
use crate::tbc::{
Area, Class, Gender, Race,
};
/// Auto generated from the original `wowm` in file [`wow_message_parser/wowm/world/social/smsg_who.wowm:13`](https://github.com/gtker/wow_messages/tree/main/wow_message_parser/wowm/world/social/smsg_who.wowm#L13):
/// ```text
/// struct WhoPlayer {
/// CString name;
/// CString guild;
/// Level32 level;
/// Class class;
/// Race race;
/// Gender gender;
/// Area area;
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
pub struct WhoPlayer {
pub name: String,
pub guild: String,
pub level: Level,
pub class: Class,
pub race: Race,
pub gender: Gender,
pub area: Area,
}
impl WhoPlayer {
pub(crate) fn write_into_vec(&self, mut w: impl Write) -> Result<(), std::io::Error> {
// name: CString
// TODO: Guard against strings that are already null-terminated
assert_ne!(self.name.as_bytes().iter().next_back(), Some(&0_u8), "String `name` must not be null-terminated.");
w.write_all(self.name.as_bytes())?;
// Null terminator
w.write_all(&[0])?;
// guild: CString
// TODO: Guard against strings that are already null-terminated
assert_ne!(self.guild.as_bytes().iter().next_back(), Some(&0_u8), "String `guild` must not be null-terminated.");
w.write_all(self.guild.as_bytes())?;
// Null terminator
w.write_all(&[0])?;
// level: Level32
w.write_all(&u32::from(self.level.as_int()).to_le_bytes())?;
// class: Class
w.write_all(&(self.class.as_int().to_le_bytes()))?;
// race: Race
w.write_all(&(self.race.as_int().to_le_bytes()))?;
// gender: Gender
w.write_all(&(self.gender.as_int().to_le_bytes()))?;
// area: Area
w.write_all(&(self.area.as_int().to_le_bytes()))?;
Ok(())
}
}
impl WhoPlayer {
pub(crate) fn read<R: std::io::Read>(mut r: R) -> Result<Self, crate::errors::ParseErrorKind> {
// name: CString
let name = {
let name = crate::util::read_c_string_to_vec(&mut r)?;
String::from_utf8(name)?
};
// guild: CString
let guild = {
let guild = crate::util::read_c_string_to_vec(&mut r)?;
String::from_utf8(guild)?
};
// level: Level32
let level = Level::new(crate::util::read_u32_le(&mut r)? as u8);
// class: Class
let class = crate::util::read_u8_le(&mut r)?.try_into()?;
// race: Race
let race = crate::util::read_u8_le(&mut r)?.try_into()?;
// gender: Gender
let gender = crate::util::read_u8_le(&mut r)?.try_into()?;
// area: Area
let area = crate::util::read_u32_le(&mut r)?.try_into()?;
Ok(Self {
name,
guild,
level,
class,
race,
gender,
area,
})
}
}
impl WhoPlayer {
pub(crate) fn size(&self) -> usize {
self.name.len() + 1 // name: CString
+ self.guild.len() + 1 // guild: CString
+ 4 // level: Level32
+ 1 // class: Class
+ 1 // race: Race
+ 1 // gender: Gender
+ 4 // area: Area
}
}