Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chat packet updates + Serialization additions #53

Merged
merged 3 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions 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 Expand Up @@ -168,7 +172,9 @@ impl ByteBuffer {
/// some, then it also calls the `write` closure.
pub fn put_option<T>(&mut self, val: &Option<T>, write: impl FnOnce(&mut Self, &T)) {
self.put_bool(val.is_some());
if let Some(v) = val { write(self, v) }
if let Some(v) = val {
write(self, v)
}
}

pub fn get_list<T>(&mut self, val: impl Fn(&mut Self) -> T) -> Vec<T> {
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