1use std::io::{self, Cursor};
2
3use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite};
4use azalea_core::bitset::FixedBitSet;
5use bevy_ecs::component::Component;
6
7#[derive(Clone, Debug, AzBuf, PartialEq, Eq, Component)]
12pub struct ClientInformation {
13 pub language: String,
15 pub view_distance: u8,
18 pub chat_visibility: ChatVisibility,
22 pub chat_colors: bool,
26 pub model_customization: ModelCustomization,
27 pub main_hand: HumanoidArm,
28 pub text_filtering_enabled: bool,
29 pub allows_listing: bool,
32 pub particle_status: ParticleStatus,
33}
34
35impl Default for ClientInformation {
36 fn default() -> Self {
37 Self {
38 language: "en_us".to_string(),
39 view_distance: 8,
40 chat_visibility: ChatVisibility::default(),
41 chat_colors: true,
42 model_customization: ModelCustomization::default(),
43 main_hand: HumanoidArm::Right,
44 text_filtering_enabled: false,
45 allows_listing: false,
46 particle_status: ParticleStatus::default(),
47 }
48 }
49}
50
51#[derive(AzBuf, Clone, Copy, Debug, PartialEq, Eq, Default)]
52pub enum ChatVisibility {
53 #[default]
55 Full = 0,
56 System = 1,
59 Hidden = 2,
61}
62
63#[derive(AzBuf, Clone, Copy, Debug, PartialEq, Eq, Default)]
64pub enum HumanoidArm {
65 Left = 0,
66 #[default]
67 Right = 1,
68}
69
70#[derive(Clone, Copy, Debug, PartialEq, Eq)]
71pub struct ModelCustomization {
72 pub cape: bool,
73 pub jacket: bool,
74 pub left_sleeve: bool,
75 pub right_sleeve: bool,
76 pub left_pants: bool,
77 pub right_pants: bool,
78 pub hat: bool,
79}
80
81#[derive(AzBuf, Clone, Copy, Debug, PartialEq, Eq, Default)]
82pub enum ParticleStatus {
83 #[default]
84 All,
85 Decreased,
86 Minimal,
87}
88
89impl Default for ModelCustomization {
90 fn default() -> Self {
91 Self {
92 cape: true,
93 jacket: true,
94 left_sleeve: true,
95 right_sleeve: true,
96 left_pants: true,
97 right_pants: true,
98 hat: true,
99 }
100 }
101}
102
103impl AzaleaRead for ModelCustomization {
104 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, azalea_buf::BufReadError> {
105 let set = FixedBitSet::<7>::azalea_read(buf)?;
106 Ok(Self {
107 cape: set.index(0),
108 jacket: set.index(1),
109 left_sleeve: set.index(2),
110 right_sleeve: set.index(3),
111 left_pants: set.index(4),
112 right_pants: set.index(5),
113 hat: set.index(6),
114 })
115 }
116}
117
118impl AzaleaWrite for ModelCustomization {
119 fn azalea_write(&self, buf: &mut impl io::Write) -> io::Result<()> {
120 let mut set = FixedBitSet::<7>::new();
121 if self.cape {
122 set.set(0);
123 }
124 if self.jacket {
125 set.set(1);
126 }
127 if self.left_sleeve {
128 set.set(2);
129 }
130 if self.right_sleeve {
131 set.set(3);
132 }
133 if self.left_pants {
134 set.set(4);
135 }
136 if self.right_pants {
137 set.set(5);
138 }
139 if self.hat {
140 set.set(6);
141 }
142 set.azalea_write(buf)
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use std::io::Cursor;
149
150 use azalea_buf::{AzaleaRead, AzaleaWrite};
151
152 use super::*;
153
154 #[test]
155 fn test_client_information() {
156 {
157 let data = ClientInformation::default();
158 let mut buf = Vec::new();
159 data.azalea_write(&mut buf).unwrap();
160 let mut data_cursor: Cursor<&[u8]> = Cursor::new(&buf);
161
162 let read_data = ClientInformation::azalea_read(&mut data_cursor).unwrap();
163 assert_eq!(read_data, data);
164 }
165
166 let data = ClientInformation {
167 language: "en_gb".to_string(),
168 view_distance: 24,
169 chat_visibility: ChatVisibility::Hidden,
170 chat_colors: false,
171 model_customization: ModelCustomization {
172 cape: false,
173 jacket: false,
174 left_sleeve: true,
175 right_sleeve: false,
176 left_pants: true,
177 right_pants: false,
178 hat: true,
179 },
180 main_hand: HumanoidArm::Left,
181 text_filtering_enabled: true,
182 allows_listing: true,
183 particle_status: ParticleStatus::Decreased,
184 };
185 let mut buf = Vec::new();
186 data.azalea_write(&mut buf).unwrap();
187 let mut data_cursor: Cursor<&[u8]> = Cursor::new(&buf);
188
189 let read_data = ClientInformation::azalea_read(&mut data_cursor).unwrap();
190 assert_eq!(read_data, data);
191 }
192}