Create pumpkin-text
This commit is contained in:
parent
5f3a4d34d1
commit
f122b47e50
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -1155,6 +1155,7 @@ dependencies = [
|
||||
"pumpkin-entity",
|
||||
"pumpkin-protocol",
|
||||
"pumpkin-registry",
|
||||
"pumpkin-text",
|
||||
"pumpkin-world",
|
||||
"rand",
|
||||
"reqwest",
|
||||
@ -1194,12 +1195,12 @@ dependencies = [
|
||||
"aes",
|
||||
"bytes",
|
||||
"cfb8",
|
||||
"fastnbt 2.5.0 (git+https://github.com/owengage/fastnbt.git)",
|
||||
"flate2",
|
||||
"log",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"pumpkin-macros",
|
||||
"pumpkin-text",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"take_mut",
|
||||
@ -1217,6 +1218,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pumpkin-text"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fastnbt 2.5.0 (git+https://github.com/owengage/fastnbt.git)",
|
||||
"serde",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pumpkin-world"
|
||||
version = "0.1.0"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [ "pumpkin-entity", "pumpkin-macros/", "pumpkin-protocol/", "pumpkin-registry/", "pumpkin-world", "pumpkin/" ]
|
||||
members = [ "pumpkin-entity", "pumpkin-macros/", "pumpkin-protocol/", "pumpkin-registry/", "pumpkin-text", "pumpkin-world", "pumpkin/" ]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.0"
|
||||
|
||||
@ -4,8 +4,8 @@ version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
|
||||
pumpkin-macros = { path = "../pumpkin-macros" }
|
||||
pumpkin-text = { path = "../pumpkin-text" }
|
||||
|
||||
bytes = "1.7"
|
||||
|
||||
@ -22,9 +22,6 @@ log = "0.4"
|
||||
num-traits = "0.2"
|
||||
num-derive = "0.4"
|
||||
|
||||
# for text component
|
||||
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
||||
|
||||
# encryption
|
||||
aes = "0.8.4"
|
||||
cfb8 = "0.8.1"
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_text::TextComponent;
|
||||
|
||||
use crate::{text::TextComponent, ClientPacket, VarInt};
|
||||
use crate::{ClientPacket, VarInt};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[packet(0x1E)]
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_text::TextComponent;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::text::TextComponent;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(0x1D)]
|
||||
pub struct CPlayDisconnect {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_text::TextComponent;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{text::TextComponent, VarInt};
|
||||
use crate::{ VarInt};
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
#[packet(0x39)]
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_text::TextComponent;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::text::TextComponent;
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
#[packet(0x6C)]
|
||||
pub struct CSystemChatMessge {
|
||||
|
||||
@ -8,7 +8,6 @@ use thiserror::Error;
|
||||
pub mod bytebuf;
|
||||
pub mod client;
|
||||
pub mod server;
|
||||
pub mod text;
|
||||
|
||||
pub mod packet_decoder;
|
||||
pub mod packet_encoder;
|
||||
|
||||
9
pumpkin-text/Cargo.toml
Normal file
9
pumpkin-text/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "pumpkin-text"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
||||
uuid = "1.10"
|
||||
19
pumpkin-text/src/click.rs
Normal file
19
pumpkin-text/src/click.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Action to take on click of the text.
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
#[serde(tag = "action", content = "value", rename_all = "snake_case")]
|
||||
pub enum ClickEvent {
|
||||
/// Opens an URL
|
||||
OpenUrl(String),
|
||||
/// Works in signs, but only on the root text component
|
||||
RunCommand(String),
|
||||
/// Replaces the contents of the chat box with the text, not necessarily a
|
||||
/// command.
|
||||
SuggestCommand(String),
|
||||
/// Only usable within written books. Changes the page of the book. Indexing
|
||||
/// starts at 1.
|
||||
ChangePage(i32),
|
||||
/// Copies the given text to system clipboard
|
||||
CopyToClipboard(String),
|
||||
}
|
||||
36
pumpkin-text/src/color.rs
Normal file
36
pumpkin-text/src/color.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Text color
|
||||
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Color {
|
||||
/// The default color for the text will be used, which varies by context
|
||||
/// (in some cases, it's white; in others, it's black; in still others, it
|
||||
/// is a shade of gray that isn't normally used on text).
|
||||
#[default]
|
||||
Reset,
|
||||
/// One of the 16 named Minecraft colors
|
||||
Named(NamedColor),
|
||||
}
|
||||
|
||||
/// Named Minecraft color
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum NamedColor {
|
||||
Black = 0,
|
||||
DarkBlue,
|
||||
DarkGreen,
|
||||
DarkAqua,
|
||||
DarkRed,
|
||||
DarkPurple,
|
||||
Gold,
|
||||
Gray,
|
||||
DarkGray,
|
||||
Blue,
|
||||
Green,
|
||||
Aqua,
|
||||
Red,
|
||||
LightPurple,
|
||||
Yellow,
|
||||
White,
|
||||
}
|
||||
32
pumpkin-text/src/hover.rs
Normal file
32
pumpkin-text/src/hover.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::Text;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(tag = "action", content = "contents", rename_all = "snake_case")]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum HoverEvent {
|
||||
/// Displays a tooltip with the given text.
|
||||
ShowText(Text),
|
||||
/// Shows an item.
|
||||
ShowItem {
|
||||
/// Resource identifier of the item
|
||||
id: String,
|
||||
/// Number of the items in the stack
|
||||
count: Option<i32>,
|
||||
/// NBT information about the item (sNBT format)
|
||||
tag: String,
|
||||
},
|
||||
/// Shows an entity.
|
||||
ShowEntity {
|
||||
/// The entity's UUID
|
||||
id: uuid::Uuid,
|
||||
/// Resource identifier of the entity
|
||||
#[serde(rename = "type")]
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
kind: Option<String>,
|
||||
/// Optional custom name for the entity
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
name: Option<Text>,
|
||||
},
|
||||
}
|
||||
@ -1,11 +1,18 @@
|
||||
use core::str;
|
||||
|
||||
use click::ClickEvent;
|
||||
use color::Color;
|
||||
use fastnbt::SerOpts;
|
||||
use hover::HoverEvent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod color;
|
||||
pub mod click;
|
||||
pub mod hover;
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Text(Box<TextComponent>);
|
||||
pub struct Text(pub Box<TextComponent>);
|
||||
|
||||
// Fepresents a Text component
|
||||
// Reference: https://wiki.vg/Text_formatting#Text_components
|
||||
@ -42,6 +49,12 @@ pub struct TextComponent {
|
||||
/// When the text is shift-clicked by a player, this string is inserted in their chat input. It does not overwrite any existing text the player was writing. This only works in chat messages
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub insertion: Option<String>,
|
||||
/// Allows for events to occur when the player clicks on text. Only work in chat.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub click_event: Option<ClickEvent>,
|
||||
/// Allows for a tooltip to be displayed when the player hovers their mouse over text.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub hover_event: Option<HoverEvent>,
|
||||
}
|
||||
|
||||
impl serde::Serialize for TextComponent {
|
||||
@ -59,7 +72,7 @@ impl TextComponent {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn color_named(mut self, color: NamedColor) -> Self {
|
||||
pub fn color_named(mut self, color: color::NamedColor) -> Self {
|
||||
self.color = Some(Color::Named(color));
|
||||
self
|
||||
}
|
||||
@ -100,6 +113,18 @@ impl TextComponent {
|
||||
self
|
||||
}
|
||||
|
||||
/// Allows for events to occur when the player clicks on text. Only work in chat.
|
||||
pub fn click_event(mut self, event: ClickEvent) -> Self {
|
||||
self.click_event = Some(event);
|
||||
self
|
||||
}
|
||||
|
||||
/// Allows for a tooltip to be displayed when the player hovers their mouse over text.
|
||||
pub fn hover_event(mut self, event: HoverEvent) -> Self {
|
||||
self.hover_event = Some(event);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
// TODO: Somehow fix this ugly mess
|
||||
#[derive(serde::Serialize, Debug)]
|
||||
@ -121,6 +146,10 @@ impl TextComponent {
|
||||
pub obfuscated: &'a Option<u8>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub insertion: &'a Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub click_event: &'a Option<ClickEvent>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub hover_event: &'a Option<HoverEvent>,
|
||||
}
|
||||
let astruct = TempStruct {
|
||||
text: &self.content,
|
||||
@ -131,7 +160,10 @@ impl TextComponent {
|
||||
strikethrough: &self.strikethrough,
|
||||
obfuscated: &self.obfuscated,
|
||||
insertion: &self.insertion,
|
||||
click_event: &self.click_event,
|
||||
hover_event: &self.hover_event,
|
||||
};
|
||||
// dbg!(&serde_json::to_string(&astruct));
|
||||
let nbt = fastnbt::to_bytes_with_opts(&astruct, SerOpts::network_nbt()).unwrap();
|
||||
nbt
|
||||
}
|
||||
@ -148,6 +180,8 @@ impl From<String> for TextComponent {
|
||||
strikethrough: None,
|
||||
obfuscated: None,
|
||||
insertion: None,
|
||||
click_event: None,
|
||||
hover_event: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,6 +199,8 @@ impl From<&str> for TextComponent {
|
||||
strikethrough: None,
|
||||
obfuscated: None,
|
||||
insertion: None,
|
||||
click_event: None,
|
||||
hover_event: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -196,38 +232,3 @@ impl Default for TextContent {
|
||||
Self::Text { text: "".into() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Text color
|
||||
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Color {
|
||||
/// The default color for the text will be used, which varies by context
|
||||
/// (in some cases, it's white; in others, it's black; in still others, it
|
||||
/// is a shade of gray that isn't normally used on text).
|
||||
#[default]
|
||||
Reset,
|
||||
/// One of the 16 named Minecraft colors
|
||||
Named(NamedColor),
|
||||
}
|
||||
|
||||
/// Named Minecraft color
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum NamedColor {
|
||||
Black = 0,
|
||||
DarkBlue,
|
||||
DarkGreen,
|
||||
DarkAqua,
|
||||
DarkRed,
|
||||
DarkPurple,
|
||||
Gold,
|
||||
Gray,
|
||||
DarkGray,
|
||||
Blue,
|
||||
Green,
|
||||
Aqua,
|
||||
Red,
|
||||
LightPurple,
|
||||
Yellow,
|
||||
White,
|
||||
}
|
||||
@ -5,6 +5,7 @@ description = "Empowering everyone to host fast and efficient Minecraft servers.
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
pumpkin-text = { path = "../pumpkin-text" }
|
||||
pumpkin-world = { path = "../pumpkin-world"}
|
||||
pumpkin-entity = { path = "../pumpkin-entity"}
|
||||
pumpkin-protocol = { path = "../pumpkin-protocol"}
|
||||
|
||||
@ -32,9 +32,9 @@ use pumpkin_protocol::{
|
||||
},
|
||||
status::{SPingRequest, SStatusRequest},
|
||||
},
|
||||
text::TextComponent,
|
||||
ClientPacket, ConnectionState, PacketError, RawPacket, ServerPacket,
|
||||
};
|
||||
use pumpkin_text::TextComponent;
|
||||
|
||||
use std::io::Read;
|
||||
use thiserror::Error;
|
||||
|
||||
@ -8,8 +8,8 @@ use pumpkin_protocol::{
|
||||
SChatCommand, SChatMessage, SConfirmTeleport, SPlayerCommand, SPlayerPosition,
|
||||
SPlayerPositionRotation, SPlayerRotation, SSwingArm,
|
||||
},
|
||||
text::TextComponent,
|
||||
};
|
||||
use pumpkin_text::TextComponent;
|
||||
|
||||
use crate::{
|
||||
commands::{handle_command, CommandSender},
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use gamemode::GamemodeCommand;
|
||||
use pumpkin::PumpkinCommand;
|
||||
use pumpkin_protocol::text::TextComponent;
|
||||
use pumpkin_text::TextComponent;
|
||||
|
||||
use crate::client::Client;
|
||||
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
use pumpkin_protocol::{text::TextComponent, CURRENT_MC_PROTOCOL};
|
||||
use pumpkin_protocol::{
|
||||
CURRENT_MC_PROTOCOL,
|
||||
};
|
||||
use pumpkin_text::{click::ClickEvent, color::NamedColor, hover::HoverEvent, TextComponent};
|
||||
|
||||
use crate::server::CURRENT_MC_VERSION;
|
||||
|
||||
@ -20,92 +23,6 @@ impl<'a> Command<'a> for PumpkinCommand {
|
||||
fn on_execute(sender: &mut super::CommandSender<'a>, _command: String) {
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
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(pumpkin_protocol::text::NamedColor::Green))
|
||||
|
||||
// test
|
||||
sender.send_message(
|
||||
TextComponent::from("Pumpkin")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::Black)
|
||||
.bold(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("is")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::DarkBlue)
|
||||
.italic(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("such")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::DarkGreen)
|
||||
.underlined(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("a")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::DarkAqua)
|
||||
.strikethrough(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("super")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::DarkRed)
|
||||
.obfuscated(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("mega")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::DarkPurple)
|
||||
.bold(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("great")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::Gold)
|
||||
.italic(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("project")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::Gray)
|
||||
.underlined(),
|
||||
);
|
||||
sender.send_message(TextComponent::from(""));
|
||||
sender.send_message(
|
||||
TextComponent::from("no")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::DarkGray)
|
||||
.bold(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("worries")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::Blue)
|
||||
.bold(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("there")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::Green)
|
||||
.underlined(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("will")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::Aqua)
|
||||
.italic(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("be")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::Red)
|
||||
.obfuscated(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("chunk")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::LightPurple)
|
||||
.bold(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("loading")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::Yellow)
|
||||
.strikethrough(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("soon")
|
||||
.color_named(pumpkin_protocol::text::NamedColor::White)
|
||||
.bold(),
|
||||
);
|
||||
sender.send_message(
|
||||
TextComponent::from("soon").color_named(pumpkin_protocol::text::NamedColor::White),
|
||||
);
|
||||
sender.send_message(TextComponent::from(format!("Pumpkin {version}, {description} (Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL})")).color_named(NamedColor::Green))
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user