chunkedge_protocol/packets/play/
player_chat_s2c.rs1use std::borrow::Cow;
2use std::io::Write;
3
4use chunkedge_binary::{Bounded, Decode, Encode, IdOr, TextComponent, VarInt};
5use chunkedge_nbt::Compound;
6use uuid::Uuid;
7
8use crate::{Packet, VariableBitSet};
9
10#[derive(Clone, PartialEq, Debug, Packet)]
11pub struct PlayerChatS2c<'a> {
12 pub global_index: VarInt,
13 pub sender: Uuid,
14 pub index: VarInt,
15 pub message_signature: Option<&'a [u8; 256]>,
16 pub message: Bounded<&'a str, 256>,
17 pub timestamp: u64,
18 pub salt: u64,
19 pub previous_messages: Vec<MessageSignature<'a>>,
20 pub unsigned_content: Option<Cow<'a, TextComponent>>,
21 pub filter_type: MessageFilterType,
22 pub filter_type_bits: Option<VariableBitSet>,
23 pub chat_type: ChatType<'a>,
24 pub network_name: Cow<'a, TextComponent>,
25 pub network_target_name: Option<Cow<'a, TextComponent>>,
26}
27
28pub type ChatType<'a> = IdOr<DirectChatType<'a>>;
29
30#[derive(Clone, PartialEq, Debug, Encode, Decode)]
31pub struct DirectChatType<'a> {
32 pub chat: ChatTypeDecoration<'a>,
33 pub narration: ChatTypeDecoration<'a>,
34}
35
36#[derive(Clone, PartialEq, Debug, Encode, Decode)]
37pub struct ChatTypeDecoration<'a> {
38 pub translation_key: Cow<'a, str>,
39 pub parameters: Vec<ChatTypeParameter>,
40 pub style: Compound,
41}
42
43#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
44pub enum ChatTypeParameter {
45 Sender,
46 Target,
47 Content,
48}
49
50#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
51pub enum MessageFilterType {
52 PassThrough,
53 FullyFiltered,
54 PartiallyFiltered,
55}
56
57impl Encode for PlayerChatS2c<'_> {
58 fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
59 self.global_index.encode(&mut w)?;
60 self.sender.encode(&mut w)?;
61 self.index.encode(&mut w)?;
62 self.message_signature.encode(&mut w)?;
63 self.message.encode(&mut w)?;
64 self.timestamp.encode(&mut w)?;
65 self.salt.encode(&mut w)?;
66 self.previous_messages.encode(&mut w)?;
67 self.unsigned_content.encode(&mut w)?;
68 self.filter_type.encode(&mut w)?;
69
70 if self.filter_type == MessageFilterType::PartiallyFiltered {
71 self.filter_type_bits
72 .clone()
73 .unwrap_or_default()
74 .encode(&mut w)?;
75 }
76
77 self.chat_type.encode(&mut w)?;
78 self.network_name.encode(&mut w)?;
79 self.network_target_name.encode(&mut w)?;
80
81 Ok(())
82 }
83}
84
85impl<'a> Decode<'a> for PlayerChatS2c<'a> {
86 fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
87 let global_index = VarInt::decode(r)?;
88 let sender = Uuid::decode(r)?;
89 let index = VarInt::decode(r)?;
90 let message_signature = Option::<&'a [u8; 256]>::decode(r)?;
91 let message = Decode::decode(r)?;
92 let time_stamp = u64::decode(r)?;
93 let salt = u64::decode(r)?;
94 let previous_messages = Vec::<MessageSignature>::decode(r)?;
95 let unsigned_content = Option::<Cow<'a, TextComponent>>::decode(r)?;
96 let filter_type = MessageFilterType::decode(r)?;
97
98 let filter_type_bits = match filter_type {
99 MessageFilterType::PartiallyFiltered => Some(VariableBitSet::decode(r)?),
100 _ => None,
101 };
102
103 let chat_type = ChatType::decode(r)?;
104 let network_name = <Cow<'a, TextComponent>>::decode(r)?;
105 let network_target_name = Option::<Cow<'a, TextComponent>>::decode(r)?;
106
107 Ok(Self {
108 global_index,
109 sender,
110 index,
111 message_signature,
112 message,
113 timestamp: time_stamp,
114 salt,
115 previous_messages,
116 unsigned_content,
117 filter_type,
118 filter_type_bits,
119 chat_type,
120 network_name,
121 network_target_name,
122 })
123 }
124}
125
126#[derive(Copy, Clone, PartialEq, Debug)]
127pub struct MessageSignature<'a> {
128 pub message_id: i32,
129 pub signature: Option<&'a [u8; 256]>,
130}
131
132impl Encode for MessageSignature<'_> {
133 fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
134 VarInt(self.message_id + 1).encode(&mut w)?;
135
136 match self.signature {
137 None => {}
138 Some(signature) => signature.encode(&mut w)?,
139 }
140
141 Ok(())
142 }
143}
144
145impl<'a> Decode<'a> for MessageSignature<'a> {
146 fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
147 let encoded_message_id = VarInt::decode(r)?.0;
148 anyhow::ensure!(encoded_message_id != i32::MIN, "message id underflow");
149 let message_id = encoded_message_id - 1;
150
151 let signature = if message_id == -1 {
152 Some(<&[u8; 256]>::decode(r)?)
153 } else {
154 None
155 };
156
157 Ok(Self {
158 message_id,
159 signature,
160 })
161 }
162}