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