1use std::borrow::Cow;
2use std::io::Write;
3
4use anyhow::bail;
5use bitfield_struct::bitfield;
6use valence_text::Text;
7
8use crate::{Decode, Encode, Packet};
9
10#[derive(Clone, Debug, Encode, Decode, Packet)]
11pub struct TeamS2c<'a> {
12 pub team_name: &'a str,
13 pub mode: Mode<'a>,
14}
15
16#[derive(Clone, PartialEq, Debug)]
17pub enum Mode<'a> {
18 CreateTeam {
19 team_display_name: Cow<'a, Text>,
20 friendly_flags: TeamFlags,
21 name_tag_visibility: NameTagVisibility,
22 collision_rule: CollisionRule,
23 team_color: TeamColor,
24 team_prefix: Cow<'a, Text>,
25 team_suffix: Cow<'a, Text>,
26 entities: Vec<&'a str>,
27 },
28 RemoveTeam,
29 UpdateTeamInfo {
30 team_display_name: Cow<'a, Text>,
31 friendly_flags: TeamFlags,
32 name_tag_visibility: NameTagVisibility,
33 collision_rule: CollisionRule,
34 team_color: TeamColor,
35 team_prefix: Cow<'a, Text>,
36 team_suffix: Cow<'a, Text>,
37 },
38 AddEntities {
39 entities: Vec<&'a str>,
40 },
41 RemoveEntities {
42 entities: Vec<&'a str>,
43 },
44}
45
46impl Encode for Mode<'_> {
47 fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
48 match self {
49 Mode::CreateTeam {
50 team_display_name,
51 friendly_flags,
52 name_tag_visibility,
53 collision_rule,
54 team_color,
55 team_prefix,
56 team_suffix,
57 entities,
58 } => {
59 0_i8.encode(&mut w)?;
60 team_display_name.encode(&mut w)?;
61 friendly_flags.encode(&mut w)?;
62 match name_tag_visibility {
63 NameTagVisibility::Always => "always",
64 NameTagVisibility::Never => "never",
65 NameTagVisibility::HideForOtherTeams => "hideForOtherTeams",
66 NameTagVisibility::HideForOwnTeam => "hideForOwnTeam",
67 }
68 .encode(&mut w)?;
69 match collision_rule {
70 CollisionRule::Always => "always",
71 CollisionRule::Never => "never",
72 CollisionRule::PushOtherTeams => "pushOtherTeams",
73 CollisionRule::PushOwnTeam => "pushOwnTeam",
74 }
75 .encode(&mut w)?;
76 team_color.encode(&mut w)?;
77 team_prefix.encode(&mut w)?;
78 team_suffix.encode(&mut w)?;
79 entities.encode(&mut w)?;
80 }
81 Mode::RemoveTeam => 1_i8.encode(&mut w)?,
82 Mode::UpdateTeamInfo {
83 team_display_name,
84 friendly_flags,
85 name_tag_visibility,
86 collision_rule,
87 team_color,
88 team_prefix,
89 team_suffix,
90 } => {
91 2_i8.encode(&mut w)?;
92 team_display_name.encode(&mut w)?;
93 friendly_flags.encode(&mut w)?;
94 match name_tag_visibility {
95 NameTagVisibility::Always => "always",
96 NameTagVisibility::Never => "never",
97 NameTagVisibility::HideForOtherTeams => "hideForOtherTeams",
98 NameTagVisibility::HideForOwnTeam => "hideForOwnTeam",
99 }
100 .encode(&mut w)?;
101 match collision_rule {
102 CollisionRule::Always => "always",
103 CollisionRule::Never => "never",
104 CollisionRule::PushOtherTeams => "pushOtherTeams",
105 CollisionRule::PushOwnTeam => "pushOwnTeam",
106 }
107 .encode(&mut w)?;
108 team_color.encode(&mut w)?;
109 team_prefix.encode(&mut w)?;
110 team_suffix.encode(&mut w)?;
111 }
112 Mode::AddEntities { entities } => {
113 3_i8.encode(&mut w)?;
114 entities.encode(&mut w)?;
115 }
116 Mode::RemoveEntities { entities } => {
117 4_i8.encode(&mut w)?;
118 entities.encode(&mut w)?;
119 }
120 }
121 Ok(())
122 }
123}
124
125impl<'a> Decode<'a> for Mode<'a> {
126 fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
127 Ok(match i8::decode(r)? {
128 0 => Self::CreateTeam {
129 team_display_name: Decode::decode(r)?,
130 friendly_flags: Decode::decode(r)?,
131 name_tag_visibility: match <&str>::decode(r)? {
132 "always" => NameTagVisibility::Always,
133 "never" => NameTagVisibility::Never,
134 "hideForOtherTeams" => NameTagVisibility::HideForOtherTeams,
135 "hideForOwnTeam" => NameTagVisibility::HideForOwnTeam,
136 other => bail!("unknown name tag visibility type \"{other}\""),
137 },
138 collision_rule: match <&str>::decode(r)? {
139 "always" => CollisionRule::Always,
140 "never" => CollisionRule::Never,
141 "pushOtherTeams" => CollisionRule::PushOtherTeams,
142 "pushOwnTeam" => CollisionRule::PushOwnTeam,
143 other => bail!("unknown collision rule type \"{other}\""),
144 },
145 team_color: Decode::decode(r)?,
146 team_prefix: Decode::decode(r)?,
147 team_suffix: Decode::decode(r)?,
148 entities: Decode::decode(r)?,
149 },
150 1 => Self::RemoveTeam,
151 2 => Self::UpdateTeamInfo {
152 team_display_name: Decode::decode(r)?,
153 friendly_flags: Decode::decode(r)?,
154 name_tag_visibility: match <&str>::decode(r)? {
155 "always" => NameTagVisibility::Always,
156 "never" => NameTagVisibility::Never,
157 "hideForOtherTeams" => NameTagVisibility::HideForOtherTeams,
158 "hideForOwnTeam" => NameTagVisibility::HideForOwnTeam,
159 other => bail!("unknown name tag visibility type \"{other}\""),
160 },
161 collision_rule: match <&str>::decode(r)? {
162 "always" => CollisionRule::Always,
163 "never" => CollisionRule::Never,
164 "pushOtherTeams" => CollisionRule::PushOtherTeams,
165 "pushOwnTeam" => CollisionRule::PushOwnTeam,
166 other => bail!("unknown collision rule type \"{other}\""),
167 },
168 team_color: Decode::decode(r)?,
169 team_prefix: Decode::decode(r)?,
170 team_suffix: Decode::decode(r)?,
171 },
172 3 => Self::AddEntities {
173 entities: Decode::decode(r)?,
174 },
175 4 => Self::RemoveEntities {
176 entities: Decode::decode(r)?,
177 },
178 n => bail!("unknown update teams action of {n}"),
179 })
180 }
181}
182
183#[bitfield(u8)]
184#[derive(PartialEq, Eq, Encode, Decode)]
185pub struct TeamFlags {
186 pub friendly_fire: bool,
187 pub see_invisible_teammates: bool,
188 #[bits(6)]
189 _pad: u8,
190}
191
192#[derive(Copy, Clone, PartialEq, Eq, Debug)]
193pub enum NameTagVisibility {
194 Always,
195 Never,
196 HideForOtherTeams,
197 HideForOwnTeam,
198}
199
200#[derive(Copy, Clone, PartialEq, Eq, Debug)]
201pub enum CollisionRule {
202 Always,
203 Never,
204 PushOtherTeams,
205 PushOwnTeam,
206}
207
208#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
209pub enum TeamColor {
210 Black,
211 DarkBlue,
212 DarkGreen,
213 DarkCyan,
214 DarkRed,
215 Purple,
216 Gold,
217 Gray,
218 DarkGray,
219 Blue,
220 BrightGreen,
221 Cyan,
222 Red,
223 Pink,
224 Yellow,
225 White,
226 Obfuscated,
227 Bold,
228 Strikethrough,
229 Underlined,
230 Italic,
231 Reset,
232}