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