azalea_protocol/packets/game/
c_player_chat.rs1use std::io::{Cursor, Write};
2
3use azalea_buf::{AzBuf, AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
4use azalea_chat::{
5 FormattedText,
6 translatable_component::{StringOrComponent, TranslatableComponent},
7};
8use azalea_core::bitset::BitSet;
9use azalea_crypto::MessageSignature;
10use azalea_protocol_macros::ClientboundGamePacket;
11use azalea_registry::Holder;
12use simdnbt::owned::NbtCompound;
13use uuid::Uuid;
14
15#[derive(Clone, Debug, AzBuf, ClientboundGamePacket, PartialEq)]
16pub struct ClientboundPlayerChat {
17 #[var]
18 pub global_index: u32,
19 pub sender: Uuid,
20 #[var]
21 pub index: u32,
22 pub signature: Option<MessageSignature>,
23 pub body: PackedSignedMessageBody,
24 pub unsigned_content: Option<FormattedText>,
25 pub filter_mask: FilterMask,
26 pub chat_type: ChatTypeBound,
27}
28
29#[derive(Clone, Debug, PartialEq, AzBuf)]
30pub struct PackedSignedMessageBody {
31 pub content: String,
34 pub timestamp: u64,
35 pub salt: u64,
36 pub last_seen: PackedLastSeenMessages,
37}
38
39#[derive(Clone, Debug, PartialEq, AzBuf)]
40pub struct PackedLastSeenMessages {
41 pub entries: Vec<PackedMessageSignature>,
42}
43
44#[derive(Clone, Debug, PartialEq)]
46pub enum PackedMessageSignature {
47 Signature(Box<MessageSignature>),
48 Id(u32),
49}
50
51#[derive(Clone, Debug, PartialEq, AzBuf)]
52pub enum FilterMask {
53 PassThrough,
54 FullyFiltered,
55 PartiallyFiltered(BitSet),
56}
57
58#[derive(Clone, Debug, PartialEq, AzBuf)]
59pub struct ChatTypeBound {
60 pub chat_type: Holder<azalea_registry::ChatType, DirectChatType>,
61 pub name: FormattedText,
62 pub target_name: Option<FormattedText>,
63}
64
65#[derive(Clone, Debug, PartialEq, AzBuf)]
66pub struct DirectChatType {
67 pub chat: ChatTypeDecoration,
68 pub narration: ChatTypeDecoration,
69}
70#[derive(Clone, Debug, PartialEq, AzBuf)]
71pub struct ChatTypeDecoration {
72 pub translation_key: String,
73 pub parameters: Vec<ChatTypeDecorationParameter>,
74 pub style: NbtCompound,
75}
76
77#[derive(Clone, Copy, Debug, PartialEq, AzBuf)]
78pub enum ChatTypeDecorationParameter {
79 Sender = 0,
80 Target = 1,
81 Content = 2,
82}
83
84#[derive(Clone, Debug, PartialEq)]
86pub struct MessageSignatureCache {
87 pub entries: Vec<Option<MessageSignature>>,
88}
89
90impl ClientboundPlayerChat {
91 #[must_use]
95 pub fn content(&self) -> FormattedText {
96 self.unsigned_content
97 .clone()
98 .unwrap_or_else(|| FormattedText::from(self.body.content.clone()))
99 }
100
101 #[must_use]
103 pub fn message(&self) -> FormattedText {
104 let sender = self.chat_type.name.clone();
105 let content = self.content();
106 let target = self.chat_type.target_name.clone();
107
108 let mut args = vec![
109 StringOrComponent::FormattedText(sender),
110 StringOrComponent::FormattedText(content),
111 ];
112 if let Some(target) = target {
113 args.push(StringOrComponent::FormattedText(target));
114 }
115
116 let translation_key = self.chat_type.translation_key();
117 let component = TranslatableComponent::new(translation_key.to_string(), args);
118
119 FormattedText::Translatable(component)
120 }
121}
122
123impl ChatTypeBound {
124 pub fn translation_key(&self) -> &str {
125 match &self.chat_type {
126 Holder::Reference(r) => r.chat_translation_key(),
127 Holder::Direct(d) => d.chat.translation_key.as_str(),
128 }
129 }
130}
131
132impl AzaleaRead for PackedMessageSignature {
133 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
134 let id = u32::azalea_read_var(buf)?;
135 if id == 0 {
136 let full_signature = MessageSignature::azalea_read(buf)?;
137
138 Ok(PackedMessageSignature::Signature(Box::new(full_signature)))
139 } else {
140 Ok(PackedMessageSignature::Id(id - 1))
141 }
142 }
143}
144impl AzaleaWrite for PackedMessageSignature {
145 fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
146 match self {
147 PackedMessageSignature::Signature(full_signature) => {
148 0u32.azalea_write_var(buf)?;
149 full_signature.azalea_write(buf)?;
150 }
151 PackedMessageSignature::Id(id) => {
152 (id + 1).azalea_write_var(buf)?;
153 }
154 }
155 Ok(())
156 }
157}