chunkedge_protocol/packets/play/
player_chat_s2c.rs

1use 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}