Use Cow's in TextComponent

We now don't always convert &str to Strings allowing us to use stack allocations
This commit is contained in:
Snowiiii 2024-08-19 20:05:18 +02:00
parent dfc0b8afe9
commit a6d9ed216d
26 changed files with 134 additions and 149 deletions

View File

@ -7,7 +7,7 @@ use crate::{BitSet, ClientPacket, ServerPacket, VarInt, VarIntType};
use super::{deserializer, serializer, ByteBuffer, DeserializerError}; use super::{deserializer, serializer, ByteBuffer, DeserializerError};
impl Serialize for BitSet<'static> { impl<'a> Serialize for BitSet<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,

View File

@ -11,7 +11,7 @@ pub struct CConfigAddResourcePack<'a> {
url: &'a str, url: &'a str,
hash: &'a str, // max 40 hash: &'a str, // max 40
forced: bool, forced: bool,
prompt_message: Option<TextComponent>, prompt_message: Option<TextComponent<'a>>,
} }
impl<'a> CConfigAddResourcePack<'a> { impl<'a> CConfigAddResourcePack<'a> {
@ -20,7 +20,7 @@ impl<'a> CConfigAddResourcePack<'a> {
url: &'a str, url: &'a str,
hash: &'a str, hash: &'a str,
forced: bool, forced: bool,
prompt_message: Option<TextComponent>, prompt_message: Option<TextComponent<'a>>,
) -> Self { ) -> Self {
Self { Self {
uuid, uuid,

View File

@ -1,7 +1,6 @@
use pumpkin_macros::packet; use pumpkin_macros::packet;
use serde::Serialize; use serde::Serialize;
use crate::{bytebuf::ByteBuffer, ClientPacket};
#[derive(Serialize)] #[derive(Serialize)]
#[packet(0x01)] #[packet(0x01)]

View File

@ -4,12 +4,12 @@ use serde::Serialize;
#[derive(Serialize)] #[derive(Serialize)]
#[packet(0x4C)] #[packet(0x4C)]
pub struct CActionBar { pub struct CActionBar<'a> {
action_bar: TextComponent, action_bar: TextComponent<'a>,
} }
impl CActionBar { impl<'a> CActionBar<'a> {
pub fn new(action_bar: TextComponent) -> Self { pub fn new(action_bar: TextComponent<'a>) -> Self {
Self { action_bar } Self { action_bar }
} }
} }

View File

@ -6,19 +6,19 @@ use crate::VarInt;
#[derive(Serialize)] #[derive(Serialize)]
#[packet(0x1E)] #[packet(0x1E)]
pub struct CDisguisedChatMessage { pub struct CDisguisedChatMessage<'a> {
message: TextComponent, message: TextComponent<'a>,
chat_type: VarInt, chat_type: VarInt,
sender_name: TextComponent, sender_name: TextComponent<'a>,
target_name: Option<TextComponent>, target_name: Option<TextComponent<'a>>,
} }
impl CDisguisedChatMessage { impl<'a> CDisguisedChatMessage<'a> {
pub fn new( pub fn new(
message: TextComponent, message: TextComponent<'a>,
chat_type: VarInt, chat_type: VarInt,
sender_name: TextComponent, sender_name: TextComponent<'a>,
target_name: Option<TextComponent>, target_name: Option<TextComponent<'a>>,
) -> Self { ) -> Self {
Self { Self {
message, message,

View File

@ -1,7 +1,7 @@
use pumpkin_macros::packet; use pumpkin_macros::packet;
use serde::Serialize; use serde::Serialize;
use crate::VarInt; use crate::{position::WorldPosition, VarInt};
#[derive(Serialize)] #[derive(Serialize)]
#[packet(0x2B)] #[packet(0x2B)]
@ -23,7 +23,7 @@ pub struct CLogin<'a> {
previous_gamemode: i8, previous_gamemode: i8,
debug: bool, debug: bool,
is_flat: bool, is_flat: bool,
death_dimension_name: Option<(String, i64)>, // POSITION NOT STRING death_dimension_name: Option<(WorldPosition, i64)>,
portal_cooldown: VarInt, portal_cooldown: VarInt,
enforce_secure_chat: bool, enforce_secure_chat: bool,
} }
@ -47,7 +47,7 @@ impl<'a> CLogin<'a> {
previous_gamemode: i8, previous_gamemode: i8,
debug: bool, debug: bool,
is_flat: bool, is_flat: bool,
death_dimension_name: Option<(String, i64)>, death_dimension_name: Option<(WorldPosition, i64)>,
portal_cooldown: VarInt, portal_cooldown: VarInt,
enforce_secure_chat: bool, enforce_secure_chat: bool,
) -> Self { ) -> Self {

View File

@ -6,14 +6,14 @@ use crate::VarInt;
#[derive(Serialize)] #[derive(Serialize)]
#[packet(0x33)] #[packet(0x33)]
pub struct COpenScreen { pub struct COpenScreen<'a> {
window_id: VarInt, window_id: VarInt,
window_type: VarInt, window_type: VarInt,
window_title: TextComponent, window_title: TextComponent<'a>,
} }
impl COpenScreen { impl<'a> COpenScreen<'a> {
pub fn new(window_id: VarInt, window_type: VarInt, window_title: TextComponent) -> Self { pub fn new(window_id: VarInt, window_type: VarInt, window_title: TextComponent<'a>) -> Self {
Self { Self {
window_id, window_id,
window_type, window_type,

View File

@ -4,12 +4,12 @@ use serde::Serialize;
#[derive(Serialize)] #[derive(Serialize)]
#[packet(0x1D)] #[packet(0x1D)]
pub struct CPlayDisconnect { pub struct CPlayDisconnect<'a> {
reason: TextComponent, reason: TextComponent<'a>,
} }
impl CPlayDisconnect { impl<'a> CPlayDisconnect<'a> {
pub fn new(reason: TextComponent) -> Self { pub fn new(reason: TextComponent<'a>) -> Self {
Self { reason } Self { reason }
} }
} }

View File

@ -11,19 +11,18 @@ pub struct CPlayerChatMessage<'a> {
sender: UUID, sender: UUID,
index: VarInt, index: VarInt,
message_signature: Option<&'a [u8]>, message_signature: Option<&'a [u8]>,
message: String, message: &'a str,
timestamp: i64, timestamp: i64,
salt: i64, salt: i64,
previous_messages_count: VarInt, previous_messages_count: VarInt,
previous_messages: &'a [PreviousMessage<'a>], // max 20 previous_messages: &'a [PreviousMessage<'a>], // max 20
unsigned_content: Option<TextComponent>, unsigned_content: Option<TextComponent<'a>>,
/// See `FilterType` /// See `FilterType`
filter_type: VarInt, filter_type: VarInt,
// TODO: THIS IS A HACK, We currently don't support writing or reading bitsets filter_type_bits: Option<BitSet<'a>>,
filter_type_bits: bool,
chat_type: VarInt, chat_type: VarInt,
sender_name: TextComponent, sender_name: TextComponent<'a>,
target_name: Option<TextComponent>, target_name: Option<TextComponent<'a>>,
} }
impl<'a> CPlayerChatMessage<'a> { impl<'a> CPlayerChatMessage<'a> {
@ -32,15 +31,16 @@ impl<'a> CPlayerChatMessage<'a> {
sender: UUID, sender: UUID,
index: VarInt, index: VarInt,
message_signature: Option<&'a [u8]>, message_signature: Option<&'a [u8]>,
message: String, message: &'a str,
timestamp: i64, timestamp: i64,
salt: i64, salt: i64,
previous_messages: &'a [PreviousMessage<'a>], previous_messages: &'a [PreviousMessage<'a>],
unsigned_content: Option<TextComponent>, unsigned_content: Option<TextComponent<'a>>,
filter_type: VarInt, filter_type: VarInt,
filter_type_bits: Option<BitSet<'a>>,
chat_type: VarInt, chat_type: VarInt,
sender_name: TextComponent, sender_name: TextComponent<'a>,
target_name: Option<TextComponent>, target_name: Option<TextComponent<'a>>,
) -> Self { ) -> Self {
Self { Self {
sender, sender,
@ -53,7 +53,7 @@ impl<'a> CPlayerChatMessage<'a> {
previous_messages, previous_messages,
unsigned_content, unsigned_content,
filter_type, filter_type,
filter_type_bits: false, filter_type_bits,
chat_type, chat_type,
sender_name, sender_name,
target_name, target_name,

View File

@ -4,12 +4,12 @@ use serde::Serialize;
#[derive(Serialize)] #[derive(Serialize)]
#[packet(0x65)] #[packet(0x65)]
pub struct CTitleText { pub struct CTitleText<'a> {
title: TextComponent, title: TextComponent<'a>,
} }
impl CTitleText { impl<'a> CTitleText<'a> {
pub fn new(title: TextComponent) -> Self { pub fn new(title: TextComponent<'a>) -> Self {
Self { title } Self { title }
} }
} }

View File

@ -4,12 +4,12 @@ use serde::Serialize;
#[derive(Serialize)] #[derive(Serialize)]
#[packet(0x63)] #[packet(0x63)]
pub struct CSubtitle { pub struct CSubtitle<'a> {
subtitle: TextComponent, subtitle: TextComponent<'a>,
} }
impl CSubtitle { impl<'a> CSubtitle<'a> {
pub fn new(subtitle: TextComponent) -> Self { pub fn new(subtitle: TextComponent<'a>) -> Self {
Self { subtitle } Self { subtitle }
} }
} }

View File

@ -4,13 +4,13 @@ use serde::Serialize;
#[derive(Serialize)] #[derive(Serialize)]
#[packet(0x6C)] #[packet(0x6C)]
pub struct CSystemChatMessge { pub struct CSystemChatMessge<'a> {
content: TextComponent, content: TextComponent<'a>,
overlay: bool, overlay: bool,
} }
impl CSystemChatMessge { impl<'a> CSystemChatMessge<'a> {
pub fn new(content: TextComponent, overlay: bool) -> Self { pub fn new(content: TextComponent<'a>, overlay: bool) -> Self {
Self { content, overlay } Self { content, overlay }
} }
} }

View File

@ -1,6 +1,6 @@
use bytebuf::{packet_id::Packet, ByteBuffer, DeserializerError}; use bytebuf::{packet_id::Packet, ByteBuffer, DeserializerError};
use bytes::Buf; use bytes::Buf;
use serde::{Deserialize, Serialize, Serializer}; use serde::{Deserialize, Serialize};
use std::io::{self, Write}; use std::io::{self, Write};
use thiserror::Error; use thiserror::Error;

View File

@ -2,7 +2,7 @@ use pumpkin_macros::packet;
use crate::{ use crate::{
bytebuf::{ByteBuffer, DeserializerError}, bytebuf::{ByteBuffer, DeserializerError},
ServerPacket, ServerPacket, VarInt,
}; };
// derive(Deserialize)] // derive(Deserialize)]
@ -12,7 +12,7 @@ pub struct SChatMessage {
pub timestamp: i64, pub timestamp: i64,
pub salt: i64, pub salt: i64,
pub signature: Option<Vec<u8>>, pub signature: Option<Vec<u8>>,
// pub messagee_count: VarInt, pub messagee_count: VarInt,
// acknowledged: BitSet, // acknowledged: BitSet,
} }
@ -24,7 +24,7 @@ impl ServerPacket for SChatMessage {
timestamp: bytebuf.get_i64(), timestamp: bytebuf.get_i64(),
salt: bytebuf.get_i64(), salt: bytebuf.get_i64(),
signature: bytebuf.get_option(|v| v.get_slice().to_vec()), signature: bytebuf.get_option(|v| v.get_slice().to_vec()),
//messagee_count: bytebuf.get_var_int(), messagee_count: bytebuf.get_var_int(),
}) })
} }
} }

View File

@ -1,4 +1,3 @@
use std::char::MAX;
use num_derive::FromPrimitive; use num_derive::FromPrimitive;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;

View File

@ -11,7 +11,7 @@ pub struct ChatType {
pub struct Decoration { pub struct Decoration {
translation_key: String, translation_key: String,
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
style: Option<Style>, style: Option<Style<'static>>,
parameters: Vec<String>, parameters: Vec<String>,
} }

View File

@ -1,19 +1,21 @@
use std::borrow::Cow;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Action to take on click of the text. /// Action to take on click of the text.
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
#[serde(tag = "action", content = "value", rename_all = "snake_case")] #[serde(tag = "action", content = "value", rename_all = "snake_case")]
pub enum ClickEvent { pub enum ClickEvent<'a> {
/// Opens a URL /// Opens a URL
OpenUrl(String), OpenUrl(Cow<'a, str>),
/// Works in signs, but only on the root text component /// Works in signs, but only on the root text component
RunCommand(String), RunCommand(Cow<'a, str>),
/// Replaces the contents of the chat box with the text, not necessarily a /// Replaces the contents of the chat box with the text, not necessarily a
/// command. /// command.
SuggestCommand(String), SuggestCommand(Cow<'a, str>),
/// Only usable within written books. Changes the page of the book. Indexing /// Only usable within written books. Changes the page of the book. Indexing
/// starts at 1. /// starts at 1.
ChangePage(i32), ChangePage(i32),
/// Copies the given text to system clipboard /// Copies the given text to system clipboard
CopyToClipboard(String), CopyToClipboard(Cow<'a, str>),
} }

View File

@ -1,3 +1,5 @@
use std::borrow::Cow;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::Text; use crate::Text;
@ -5,17 +7,17 @@ use crate::Text;
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "action", content = "contents", rename_all = "snake_case")] #[serde(tag = "action", content = "contents", rename_all = "snake_case")]
#[allow(clippy::enum_variant_names)] #[allow(clippy::enum_variant_names)]
pub enum HoverEvent { pub enum HoverEvent<'a> {
/// Displays a tooltip with the given text. /// Displays a tooltip with the given text.
ShowText(Text), ShowText(Text<'a>),
/// Shows an item. /// Shows an item.
ShowItem { ShowItem {
/// Resource identifier of the item /// Resource identifier of the item
id: String, id: Cow<'a, str>,
/// Number of the items in the stack /// Number of the items in the stack
count: Option<i32>, count: Option<i32>,
/// NBT information about the item (sNBT format) /// NBT information about the item (sNBT format)
tag: String, tag: Cow<'a, str>,
}, },
/// Shows an entity. /// Shows an entity.
ShowEntity { ShowEntity {
@ -24,9 +26,9 @@ pub enum HoverEvent {
/// Resource identifier of the entity /// Resource identifier of the entity
#[serde(rename = "type")] #[serde(rename = "type")]
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
kind: Option<String>, kind: Option<Cow<'a, str>>,
/// Optional custom name for the entity /// Optional custom name for the entity
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
name: Option<Text>, name: Option<Text<'a>>,
}, },
} }

View File

@ -1,4 +1,5 @@
use core::str; use core::str;
use std::borrow::Cow;
use click::ClickEvent; use click::ClickEvent;
use color::Color; use color::Color;
@ -12,25 +13,34 @@ pub mod color;
pub mod hover; pub mod hover;
pub mod style; pub mod style;
#[derive(Clone, Default, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(transparent)] #[serde(transparent)]
pub struct Text(pub Box<TextComponent>); pub struct Text<'a>(pub Box<TextComponent<'a>>);
// Represents a Text component // Represents a Text component
// Reference: https://wiki.vg/Text_formatting#Text_components // Reference: https://wiki.vg/Text_formatting#Text_components
#[derive(Clone, Default, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct TextComponent { pub struct TextComponent<'a> {
/// The actual text /// The actual text
#[serde(flatten)] #[serde(flatten)]
pub content: TextContent, pub content: TextContent<'a>,
/// Style of the text. Bold, Italic, underline, Color... /// Style of the text. Bold, Italic, underline, Color...
/// Also has `ClickEvent /// Also has `ClickEvent
#[serde(flatten)] #[serde(flatten)]
pub style: Style, pub style: Style<'a>,
} }
impl serde::Serialize for TextComponent { impl<'a> TextComponent<'a> {
pub fn text(text: &'a str) -> Self {
Self {
content: TextContent::Text { text: text.into() },
style: Style::default(),
}
}
}
impl<'a> serde::Serialize for TextComponent<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: serde::Serializer, S: serde::Serializer,
@ -39,7 +49,7 @@ impl serde::Serialize for TextComponent {
} }
} }
impl TextComponent { impl<'a> TextComponent<'a> {
pub fn color(mut self, color: Color) -> Self { pub fn color(mut self, color: Color) -> Self {
self.style.color = Some(color); self.style.color = Some(color);
self self
@ -87,13 +97,13 @@ impl TextComponent {
} }
/// Allows for events to occur when the player clicks on text. Only work in chat. /// Allows for events to occur when the player clicks on text. Only work in chat.
pub fn click_event(mut self, event: ClickEvent) -> Self { pub fn click_event(mut self, event: ClickEvent<'a>) -> Self {
self.style.click_event = Some(event); self.style.click_event = Some(event);
self self
} }
/// Allows for a tooltip to be displayed when the player hovers their mouse over text. /// Allows for a tooltip to be displayed when the player hovers their mouse over text.
pub fn hover_event(mut self, event: HoverEvent) -> Self { pub fn hover_event(mut self, event: HoverEvent<'a>) -> Self {
self.style.hover_event = Some(event); self.style.hover_event = Some(event);
self self
} }
@ -104,9 +114,9 @@ impl TextComponent {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct TempStruct<'a> { struct TempStruct<'a> {
#[serde(flatten)] #[serde(flatten)]
text: &'a TextContent, text: &'a TextContent<'a>,
#[serde(flatten)] #[serde(flatten)]
style: &'a Style, style: &'a Style<'a>,
} }
let astruct = TempStruct { let astruct = TempStruct {
text: &self.content, text: &self.content,
@ -118,50 +128,24 @@ impl TextComponent {
} }
} }
impl From<String> for TextComponent {
fn from(value: String) -> Self {
Self {
content: TextContent::Text { text: value },
style: Style::default(),
}
}
}
impl From<&str> for TextComponent {
fn from(value: &str) -> Self {
Self {
content: TextContent::Text {
text: value.to_string(),
},
style: Style::default(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum TextContent { pub enum TextContent<'a> {
/// Raw Text /// Raw Text
Text { text: String }, Text { text: Cow<'a, str> },
/// Translated text /// Translated text
Translate { Translate {
translate: String, translate: Cow<'a, str>,
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
with: Vec<Text>, with: Vec<Text<'a>>,
}, },
/// Displays the name of one or more entities found by a selector. /// Displays the name of one or more entities found by a selector.
EntityNames { EntityNames {
selector: String, selector: Cow<'a, str>,
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
separator: Option<Text>, separator: Option<Cow<'a, str>>,
}, },
/// A keybind identifier /// A keybind identifier
/// https://minecraft.fandom.com/wiki/Controls#Configurable_controls /// https://minecraft.fandom.com/wiki/Controls#Configurable_controls
Keybind { keybind: String }, Keybind { keybind: Cow<'a, str> },
}
impl Default for TextContent {
fn default() -> Self {
Self::Text { text: "".into() }
}
} }

View File

@ -7,7 +7,7 @@ use crate::{
}; };
#[derive(Clone, Debug, Serialize, Deserialize, Default)] #[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct Style { pub struct Style<'a> {
/// Changes the color to render the content /// Changes the color to render the content
pub color: Option<Color>, pub color: Option<Color>,
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
@ -33,13 +33,13 @@ pub struct Style {
pub insertion: Option<String>, pub insertion: Option<String>,
/// Allows for events to occur when the player clicks on text. Only work in chat. /// Allows for events to occur when the player clicks on text. Only work in chat.
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
pub click_event: Option<ClickEvent>, pub click_event: Option<ClickEvent<'a>>,
/// Allows for a tooltip to be displayed when the player hovers their mouse over text. /// Allows for a tooltip to be displayed when the player hovers their mouse over text.
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
pub hover_event: Option<HoverEvent>, pub hover_event: Option<HoverEvent<'a>>,
} }
impl Style { impl<'a> Style<'a> {
pub fn color(mut self, color: Color) -> Self { pub fn color(mut self, color: Color) -> Self {
self.color = Some(color); self.color = Some(color);
self self
@ -87,13 +87,13 @@ impl Style {
} }
/// Allows for events to occur when the player clicks on text. Only work in chat. /// Allows for events to occur when the player clicks on text. Only work in chat.
pub fn click_event(mut self, event: ClickEvent) -> Self { pub fn click_event(mut self, event: ClickEvent<'a>) -> Self {
self.click_event = Some(event); self.click_event = Some(event);
self self
} }
/// Allows for a tooltip to be displayed when the player hovers their mouse over text. /// Allows for a tooltip to be displayed when the player hovers their mouse over text.
pub fn hover_event(mut self, event: HoverEvent) -> Self { pub fn hover_event(mut self, event: HoverEvent<'a>) -> Self {
self.hover_event = Some(event); self.hover_event = Some(event);
self self
} }

View File

@ -1,4 +1,3 @@
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use pumpkin_protocol::{ use pumpkin_protocol::{
client::{ client::{
@ -199,7 +198,7 @@ impl Client {
let prompt_message = if resource_config.prompt_message.is_empty() { let prompt_message = if resource_config.prompt_message.is_empty() {
None None
} else { } else {
Some(TextComponent::from(resource_config.prompt_message.clone())) Some(TextComponent::text(&resource_config.prompt_message))
}; };
self.send_packet(&CConfigAddResourcePack::new( self.send_packet(&CConfigAddResourcePack::new(
pumpkin_protocol::uuid::UUID(uuid::Uuid::new_v3( pumpkin_protocol::uuid::UUID(uuid::Uuid::new_v3(

View File

@ -375,7 +375,7 @@ impl Client {
.unwrap_or_else(|_| self.close()); .unwrap_or_else(|_| self.close());
} }
ConnectionState::Play => { ConnectionState::Play => {
self.try_send_packet(&CPlayDisconnect::new(TextComponent::from(reason))) self.try_send_packet(&CPlayDisconnect::new(TextComponent::text(reason)))
.unwrap_or_else(|_| self.close()); .unwrap_or_else(|_| self.close());
} }
_ => { _ => {

View File

@ -5,7 +5,8 @@ use pumpkin_entity::EntityId;
use pumpkin_protocol::{ use pumpkin_protocol::{
client::play::{ client::play::{
Animation, CBlockUpdate, CEntityAnimation, CEntityVelocity, CHeadRot, CHurtAnimation, Animation, CBlockUpdate, CEntityAnimation, CEntityVelocity, CHeadRot, CHurtAnimation,
CSystemChatMessge, CUpdateEntityPos, CUpdateEntityPosRot, CUpdateEntityRot, CPlayerChatMessage, CUpdateEntityPos, CUpdateEntityPosRot,
CUpdateEntityRot, FilterType,
}, },
position::WorldPosition, position::WorldPosition,
server::play::{ server::play::{
@ -209,38 +210,30 @@ impl Client {
} }
pub fn handle_chat_message(&mut self, server: &mut Server, chat_message: SChatMessage) { pub fn handle_chat_message(&mut self, server: &mut Server, chat_message: SChatMessage) {
dbg!("got message");
let message = chat_message.message; let message = chat_message.message;
// TODO: filter message & validation // TODO: filter message & validation
let gameprofile = self.gameprofile.as_ref().unwrap(); let gameprofile = self.gameprofile.as_ref().unwrap();
dbg!("got message");
// yeah a "raw system message", the ugly way to do that, but it works
server.broadcast_packet( server.broadcast_packet(
self, self,
&CSystemChatMessge::new( &CPlayerChatMessage::new(
TextComponent::from(format!("{}: {}", gameprofile.name, message)),
false,
),
);
/* server.broadcast_packet(
self,
CPlayerChatMessage::new(
pumpkin_protocol::uuid::UUID(gameprofile.id), pumpkin_protocol::uuid::UUID(gameprofile.id),
0.into(), chat_message.messagee_count,
None, chat_message.signature.as_deref(),
message.clone(), &message,
chat_message.timestamp, chat_message.timestamp,
chat_message.salt, chat_message.salt,
&[], &[],
Some(TextComponent::from(message.clone())), Some(TextComponent::text(&message)),
pumpkin_protocol::VarInt(FilterType::PassThrough as i32), pumpkin_protocol::VarInt(FilterType::PassThrough as i32),
0.into(), None,
TextComponent::from(gameprofile.name.clone()), 1.into(),
TextComponent::text(&gameprofile.name.clone()),
None, None,
), ),
) )
*/
/* server.broadcast_packet( /* server.broadcast_packet(
self, self,
&CDisguisedChatMessage::new( &CDisguisedChatMessage::new(
@ -272,12 +265,13 @@ impl Client {
pub fn handle_interact(&mut self, server: &mut Server, interact: SInteract) { pub fn handle_interact(&mut self, server: &mut Server, interact: SInteract) {
let action = ActionType::from_i32(interact.typ.0).unwrap(); let action = ActionType::from_i32(interact.typ.0).unwrap();
if action == ActionType::Attack { if action == ActionType::Attack {
let attacker_player = self.player.as_ref().unwrap();
let entity_id = interact.entity_id; let entity_id = interact.entity_id;
// TODO: do validation and stuff // TODO: do validation and stuff
let config = &server.advanced_config.pvp; let config = &server.advanced_config.pvp;
if config.enabled { if config.enabled {
let attacked_client = server.get_by_entityid(self, entity_id.0 as EntityId); let attacked_client = server.get_by_entityid(self, entity_id.0 as EntityId);
let attacker_player = self.player.as_mut().unwrap();
attacker_player.sneaking = interact.sneaking;
if let Some(mut client) = attacked_client { if let Some(mut client) = attacked_client {
let token = client.token.clone(); let token = client.token.clone();
let player = client.player.as_mut().unwrap(); let player = client.player.as_mut().unwrap();
@ -299,9 +293,10 @@ impl Client {
player.velocity.y as f32, player.velocity.y as f32,
player.velocity.z as f32, player.velocity.z as f32,
); );
attacker_player.velocity = attacker_player.velocity.multiply(0.6, 1.0, 0.6);
player.velocity = velo; player.velocity = velo;
client.send_packet(packet); client.send_packet(packet);
// attacker_player.velocity = attacker_player.velocity.multiply(0.6, 1.0, 0.6);
} }
if config.hurt_animation { if config.hurt_animation {
// TODO // TODO

View File

@ -18,7 +18,7 @@ impl<'a> Command<'a> for GamemodeCommand {
if args.len() != 2 { if args.len() != 2 {
player.send_system_message( player.send_system_message(
TextComponent::from("Usage: /gamemode <mode>") TextComponent::text("Usage: /gamemode <mode>")
.color_named(pumpkin_text::color::NamedColor::Red), .color_named(pumpkin_text::color::NamedColor::Red),
); );
return; return;
@ -28,21 +28,26 @@ impl<'a> Command<'a> for GamemodeCommand {
match mode_str.parse() { match mode_str.parse() {
Ok(mode) => { Ok(mode) => {
player.set_gamemode(mode); player.set_gamemode(mode);
player.send_system_message(format!("Set own game mode to {:?}", mode).into()); player.send_system_message(TextComponent::text(&format!(
"Set own game mode to {:?}",
mode
)));
} }
Err(_) => { Err(_) => {
// try to parse from number // try to parse from number
if let Ok(i) = mode_str.parse::<u8>() { if let Ok(i) = mode_str.parse::<u8>() {
if let Some(mode) = GameMode::from_u8(i) { if let Some(mode) = GameMode::from_u8(i) {
player.set_gamemode(mode); player.set_gamemode(mode);
player player.send_system_message(TextComponent::text(&format!(
.send_system_message(format!("Set own game mode to {:?}", mode).into()); "Set own game mode to {:?}",
mode
)));
return; return;
} }
} }
player.send_system_message( player.send_system_message(
TextComponent::from("Invalid gamemode") TextComponent::text("Invalid gamemode")
.color_named(pumpkin_text::color::NamedColor::Red), .color_named(pumpkin_text::color::NamedColor::Red),
); );
} }

View File

@ -79,5 +79,5 @@ pub fn handle_command(sender: &mut CommandSender, command: &str) {
return; return;
} }
// TODO: red color // TODO: red color
sender.send_message("Command not Found".into()); sender.send_message(TextComponent::text("Command not Found"));
} }

View File

@ -15,6 +15,6 @@ impl<'a> Command<'a> for PumpkinCommand {
fn on_execute(sender: &mut super::CommandSender<'a>, _command: String) { fn on_execute(sender: &mut super::CommandSender<'a>, _command: String) {
let version = env!("CARGO_PKG_VERSION"); let version = env!("CARGO_PKG_VERSION");
let description = env!("CARGO_PKG_DESCRIPTION"); let description = env!("CARGO_PKG_DESCRIPTION");
sender.send_message(TextComponent::from(format!("Pumpkin {version}, {description} (Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL})")).color_named(NamedColor::Green)) sender.send_message(TextComponent::text(&format!("Pumpkin {version}, {description} (Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL})")).color_named(NamedColor::Green))
} }
} }