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:
parent
dfc0b8afe9
commit
a6d9ed216d
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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)]
|
||||||
|
|||||||
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
use std::char::MAX;
|
|
||||||
|
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
|
|||||||
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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>),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user