Skip to content

Commit

Permalink
Merge pull request #53 from kralverde/chat-packet-updates
Browse files Browse the repository at this point in the history
Chat packet updates + Serialization additions
  • Loading branch information
Snowiiii authored Aug 22, 2024
2 parents 290e0ed + c07ea94 commit 84464c3
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 81 deletions.
6 changes: 5 additions & 1 deletion pumpkin-protocol/src/bytebuf/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{BitSet, VarInt, VarLongType};
use crate::{BitSet, FixedBitSet, VarInt, VarLongType};
use bytes::{Buf, BufMut, BytesMut};
use core::str;
use std::io::{self, Error, ErrorKind};
Expand Down Expand Up @@ -107,6 +107,10 @@ impl ByteBuffer {
uuid::Uuid::from_slice(&bytes).expect("Failed to parse UUID")
}

pub fn get_fixed_bitset(&mut self, bits: usize) -> FixedBitSet {
self.copy_to_bytes(bits.div_ceil(8))
}

pub fn put_bool(&mut self, v: bool) {
if v {
self.buffer.put_u8(1);
Expand Down
35 changes: 24 additions & 11 deletions pumpkin-protocol/src/bytebuf/serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ impl ser::Error for SerializerError {
}
}

// General notes on the serializer:
//
// Primitives are written as-is
// Strings automatically pre-pend a varint
// Enums are written as a varint of the index
// Structs are ignored
// Iterables' values are written in order, but NO information (e.g. size) about the
// iterable itself is written (list sizes should be a seperate field)
impl<'a> ser::Serializer for &'a mut Serializer {
type Ok = ();
type Error = SerializerError;
Expand Down Expand Up @@ -114,14 +122,15 @@ impl<'a> ser::Serializer for &'a mut Serializer {
fn serialize_newtype_variant<T>(
self,
_name: &'static str,
_variant_index: u32,
variant_index: u32,
_variant: &'static str,
_value: &T,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: ?Sized + Serialize,
{
unimplemented!()
self.output.put_var_int(&variant_index.into());
value.serialize(self)
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
self.output.put_bool(false);
Expand Down Expand Up @@ -160,7 +169,7 @@ impl<'a> ser::Serializer for &'a mut Serializer {
unimplemented!()
}
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
unimplemented!()
Ok(self)
}
fn serialize_tuple_struct(
self,
Expand All @@ -172,11 +181,13 @@ impl<'a> ser::Serializer for &'a mut Serializer {
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
unimplemented!()
// Serialize ENUM index as varint
self.output.put_var_int(&variant_index.into());
Ok(self)
}
fn serialize_u128(self, _v: u128) -> Result<Self::Ok, Self::Error> {
unimplemented!()
Expand Down Expand Up @@ -206,10 +217,12 @@ impl<'a> ser::Serializer for &'a mut Serializer {
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
variant_index: u32,
_variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
todo!()
// For ENUMs, only write enum index as varint
self.output.put_var_int(&variant_index.into());
Ok(())
}
}

Expand Down Expand Up @@ -237,15 +250,15 @@ impl<'a> ser::SerializeTuple for &'a mut Serializer {
type Ok = ();
type Error = SerializerError;

fn serialize_element<T>(&mut self, _value: &T) -> Result<(), Self::Error>
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
todo!()
value.serialize(&mut **self)
}

fn end(self) -> Result<(), Self::Error> {
todo!()
Ok(())
}
}

Expand Down
74 changes: 10 additions & 64 deletions pumpkin-protocol/src/client/play/c_player_chat_message.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive;
use pumpkin_core::text::TextComponent;
use pumpkin_macros::packet;
use serde::Serialize;

use crate::{bytebuf::ByteBuffer, uuid::UUID, BitSet, ClientPacket, VarInt};

use crate::{uuid::UUID, BitSet, VarInt};
#[derive(Serialize)]
#[packet(0x39)]
pub struct CPlayerChatMessage<'a> {
sender: UUID,
Expand All @@ -17,12 +15,7 @@ pub struct CPlayerChatMessage<'a> {
previous_messages_count: VarInt,
previous_messages: &'a [PreviousMessage<'a>], // max 20
unsigned_content: Option<TextComponent<'a>>,
/// See `FilterType`
filter_type: VarInt,

// TODO: Implement
#[allow(dead_code)]
filter_type_bits: Option<BitSet<'a>>,
filter_type: FilterType<'a>,
chat_type: VarInt,
sender_name: TextComponent<'a>,
target_name: Option<TextComponent<'a>>,
Expand All @@ -39,8 +32,7 @@ impl<'a> CPlayerChatMessage<'a> {
salt: i64,
previous_messages: &'a [PreviousMessage<'a>],
unsigned_content: Option<TextComponent<'a>>,
filter_type: VarInt,
filter_type_bits: Option<BitSet<'a>>,
filter_type: FilterType<'a>,
chat_type: VarInt,
sender_name: TextComponent<'a>,
target_name: Option<TextComponent<'a>>,
Expand All @@ -56,72 +48,26 @@ impl<'a> CPlayerChatMessage<'a> {
previous_messages,
unsigned_content,
filter_type,
filter_type_bits,
chat_type,
sender_name,
target_name,
}
}
}

impl<'a> ClientPacket for CPlayerChatMessage<'a> {
fn write(&self, bytebuf: &mut ByteBuffer) {
bytebuf.put_uuid(self.sender.0);
bytebuf.put_var_int(&self.index);
bytebuf.put_option(&self.message_signature, |p, v| p.put_slice(v));
bytebuf.put_string(self.message);
bytebuf.put_i64(self.timestamp);
bytebuf.put_i64(self.salt);

if self.previous_messages_count.0 > 20 {
// TODO: Assert this is <=20
}

bytebuf.put_var_int(&self.previous_messages_count);
for previous_message in self.previous_messages {
bytebuf.put_var_int(&previous_message.message_id);
if let Some(prev_sig) = previous_message.signature {
// TODO: validate whether this should be None or not
bytebuf.put_slice(prev_sig);
}
}

bytebuf.put_option(&self.unsigned_content, |p, v| {
p.put_slice(v.encode().as_slice())
});

bytebuf.put_var_int(&self.filter_type);
match FilterType::from_i32(self.filter_type.0) {
Some(FilterType::PassThrough) => (),
Some(FilterType::FullyFiltered) => {
// TODO: Implement
}
Some(FilterType::PartiallyFiltered) => {
// TODO: Implement
}
None => {
// TODO: Implement
}
}

bytebuf.put_var_int(&self.chat_type);
bytebuf.put_slice(self.sender_name.encode().as_slice());
bytebuf.put_option(&self.target_name, |p, v| p.put_slice(v.encode().as_slice()));
}
}

#[derive(Serialize)]
pub struct PreviousMessage<'a> {
message_id: VarInt,
signature: Option<&'a [u8]>,
}

#[derive(FromPrimitive, ToPrimitive)]
pub enum FilterType {
#[derive(Serialize)]
#[repr(i32)]
pub enum FilterType<'a> {
/// Message is not filtered at all
PassThrough,
PassThrough = 0,
/// Message is fully filtered
FullyFiltered,
FullyFiltered = 1,
/// Only some characters in the message are filtered
PartiallyFiltered,
PartiallyFiltered(BitSet<'a>) = 2,
}
1 change: 1 addition & 0 deletions pumpkin-protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub const MAX_PACKET_SIZE: i32 = 2097152;
pub type Identifier = String;
pub type VarIntType = i32;
pub type VarLongType = i64;
pub type FixedBitSet = bytes::Bytes;

pub struct BitSet<'a>(pub VarInt, pub &'a [i64]);

Expand Down
6 changes: 3 additions & 3 deletions pumpkin-protocol/src/server/play/s_chat_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use pumpkin_macros::packet;

use crate::{
bytebuf::{ByteBuffer, DeserializerError},
ServerPacket, VarInt,
FixedBitSet, ServerPacket, VarInt,
};

// derive(Deserialize)]
Expand All @@ -14,8 +14,7 @@ pub struct SChatMessage {
pub salt: i64,
pub signature: Option<Bytes>,
pub messagee_count: VarInt,
// TODO: Properly implement BitSet decoding
// acknowledged: BitSet,
pub acknowledged: FixedBitSet,
}

// TODO
Expand All @@ -27,6 +26,7 @@ impl ServerPacket for SChatMessage {
salt: bytebuf.get_i64(),
signature: bytebuf.get_option(|v| v.copy_to_bytes(256)),
messagee_count: bytebuf.get_var_int(),
acknowledged: bytebuf.get_fixed_bitset(20),
})
}
}
9 changes: 7 additions & 2 deletions pumpkin/src/client/player_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,13 @@ impl Client {

pub fn handle_chat_message(&mut self, server: &mut Server, chat_message: SChatMessage) {
dbg!("got message");

let message = chat_message.message;
if message.len() > 256 {
self.kick("Oversized message");
return;
}

// TODO: filter message & validation
let gameprofile = self.gameprofile.as_ref().unwrap();

Expand All @@ -227,8 +233,7 @@ impl Client {
chat_message.salt,
&[],
Some(TextComponent::text(&message)),
pumpkin_protocol::VarInt(FilterType::PassThrough as i32),
None,
FilterType::PassThrough,
1.into(),
TextComponent::text(&gameprofile.name.clone()),
None,
Expand Down

0 comments on commit 84464c3

Please sign in to comment.