aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock12
-rwxr-xr-xazalea-chat/Cargo.toml8
-rwxr-xr-xazalea-chat/src/base_component.rs5
-rwxr-xr-xazalea-chat/src/component.rs14
-rwxr-xr-xazalea-chat/src/style.rs68
-rwxr-xr-xazalea-chat/src/text_component.rs19
-rwxr-xr-xazalea-chat/src/translatable_component.rs17
-rwxr-xr-xazalea-protocol/src/packets/status/clientbound_status_response_packet.rs32
8 files changed, 143 insertions, 32 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 132e2eb1..f8a5fb7b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1690,9 +1690,9 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.147"
+version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
dependencies = [
"serde_derive",
]
@@ -1709,9 +1709,9 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.147"
+version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
dependencies = [
"proc-macro2",
"quote",
@@ -1800,9 +1800,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.103"
+version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
dependencies = [
"proc-macro2",
"quote",
diff --git a/azalea-chat/Cargo.toml b/azalea-chat/Cargo.toml
index b85726a3..a1caccf2 100755
--- a/azalea-chat/Cargo.toml
+++ b/azalea-chat/Cargo.toml
@@ -3,14 +3,14 @@ description = "Parse Minecraft chat messages."
edition = "2021"
license = "MIT"
name = "azalea-chat"
-version = "0.4.0"
repository = "https://github.com/mat-1/azalea/tree/main/azalea-chat"
+version = "0.4.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-azalea-buf = {path = "../azalea-buf", features = ["serde_json"], version = "^0.4.0" }
-azalea-language = {path = "../azalea-language", version = "^0.4.0" }
+azalea-buf = {path = "../azalea-buf", features = ["serde_json"], version = "^0.4.0"}
+azalea-language = {path = "../azalea-language", version = "^0.4.0"}
once_cell = "1.16.0"
-serde = "^1.0.130"
+serde = {version = "^1.0.148", features = ["derive"]}
serde_json = "^1.0.72"
diff --git a/azalea-chat/src/base_component.rs b/azalea-chat/src/base_component.rs
index e532de11..ab4f5e5d 100755
--- a/azalea-chat/src/base_component.rs
+++ b/azalea-chat/src/base_component.rs
@@ -1,9 +1,12 @@
use crate::{style::Style, Component};
+use serde::Serialize;
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct BaseComponent {
// implements mutablecomponent
+ #[serde(skip_serializing_if = "Vec::is_empty")]
pub siblings: Vec<Component>,
+ #[serde(flatten)]
pub style: Style,
}
diff --git a/azalea-chat/src/component.rs b/azalea-chat/src/component.rs
index 9362a66b..95387248 100755
--- a/azalea-chat/src/component.rs
+++ b/azalea-chat/src/component.rs
@@ -6,14 +6,15 @@ use crate::{
};
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
use once_cell::sync::Lazy;
-use serde::{de, Deserialize, Deserializer};
+use serde::{de, Deserialize, Deserializer, Serialize};
use std::{
fmt::Display,
io::{Cursor, Write},
};
/// A chat component, basically anything you can see in chat.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Serialize)]
+#[serde(untagged)]
pub enum Component {
Text(TextComponent),
Translatable(TranslatableComponent),
@@ -262,11 +263,10 @@ impl McBufReadable for Component {
}
impl McBufWritable for Component {
- fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
- // let json = serde_json::to_string(self).unwrap();
- // json.write_into(_buf);
- // Ok(())
- todo!()
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ let json = serde_json::to_string(self).unwrap();
+ json.write_into(buf)?;
+ Ok(())
}
}
diff --git a/azalea-chat/src/style.rs b/azalea-chat/src/style.rs
index cdf8f86f..cb708982 100755
--- a/azalea-chat/src/style.rs
+++ b/azalea-chat/src/style.rs
@@ -2,6 +2,7 @@ use std::{collections::HashMap, fmt};
use azalea_buf::McBuf;
use once_cell::sync::Lazy;
+use serde::{ser::SerializeStruct, Serialize, Serializer};
use serde_json::Value;
#[derive(Clone, PartialEq, Eq, Debug)]
@@ -10,6 +11,19 @@ pub struct TextColor {
pub name: Option<String>,
}
+impl Serialize for TextColor {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ if self.name.is_some() {
+ serializer.serialize_str(&self.name.as_ref().unwrap().to_ascii_lowercase())
+ } else {
+ serializer.serialize_str(&self.format())
+ }
+ }
+}
+
impl TextColor {
pub fn parse(value: String) -> Option<TextColor> {
if value.starts_with('#') {
@@ -276,17 +290,67 @@ impl TryFrom<ChatFormatting> for TextColor {
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Style {
- // these are options instead of just bools because None is different than false in this case
+ // These are options instead of just bools because None is different than false in this case
pub color: Option<TextColor>,
pub bold: Option<bool>,
pub italic: Option<bool>,
pub underlined: Option<bool>,
pub strikethrough: Option<bool>,
pub obfuscated: Option<bool>,
- /// Whether it should reset the formatting before applying these styles
+ /// Whether formatting should be reset before applying these styles
pub reset: bool,
}
+impl Serialize for Style {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let len = if self.reset {
+ 6
+ } else {
+ usize::from(self.color.is_some())
+ + usize::from(self.bold.is_some())
+ + usize::from(self.italic.is_some())
+ + usize::from(self.underlined.is_some())
+ + usize::from(self.strikethrough.is_some())
+ + usize::from(self.obfuscated.is_some())
+ };
+ let mut state = serializer.serialize_struct("Style", len)?;
+ if let Some(color) = &self.color {
+ state.serialize_field("color", color)?;
+ } else if self.reset {
+ state.serialize_field("color", "white")?;
+ }
+ if let Some(bold) = &self.bold {
+ state.serialize_field("bold", bold)?;
+ } else if self.reset {
+ state.serialize_field("bold", &false)?;
+ }
+ if let Some(italic) = &self.italic {
+ state.serialize_field("italic", italic)?;
+ } else if self.reset {
+ state.serialize_field("italic", &false)?;
+ }
+ if let Some(underlined) = &self.underlined {
+ state.serialize_field("underlined", underlined)?;
+ } else if self.reset {
+ state.serialize_field("underlined", &false)?;
+ }
+ if let Some(strikethrough) = &self.strikethrough {
+ state.serialize_field("strikethrough", strikethrough)?;
+ } else if self.reset {
+ state.serialize_field("strikethrough", &false)?;
+ }
+ if let Some(obfuscated) = &self.obfuscated {
+ state.serialize_field("obfuscated", obfuscated)?;
+ } else if self.reset {
+ state.serialize_field("obfuscated", &false)?;
+ }
+ state.end()
+ }
+}
+
impl Style {
pub fn empty() -> Self {
Self::default()
diff --git a/azalea-chat/src/text_component.rs b/azalea-chat/src/text_component.rs
index 0d88ca05..6715c93e 100755
--- a/azalea-chat/src/text_component.rs
+++ b/azalea-chat/src/text_component.rs
@@ -1,6 +1,6 @@
-use std::fmt::Display;
-
use crate::{base_component::BaseComponent, style::ChatFormatting, Component};
+use serde::{ser::SerializeMap, Serialize, Serializer, __private::ser::FlatMapSerializer};
+use std::fmt::Display;
/// A component that contains text that's the same in all locales.
#[derive(Clone, Debug, Default, PartialEq)]
@@ -9,6 +9,21 @@ pub struct TextComponent {
pub text: String,
}
+impl Serialize for TextComponent {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let mut state = serializer.serialize_map(None)?;
+ state.serialize_entry("text", &self.text)?;
+ Serialize::serialize(&self.base, FlatMapSerializer(&mut state))?;
+ if !self.base.siblings.is_empty() {
+ state.serialize_entry("extra", &self.base.siblings)?;
+ }
+ state.end()
+ }
+}
+
const LEGACY_FORMATTING_CODE_SYMBOL: char = 'ยง';
/// Convert a legacy color code string into a Component
diff --git a/azalea-chat/src/translatable_component.rs b/azalea-chat/src/translatable_component.rs
index 28725c44..7819d5ff 100755
--- a/azalea-chat/src/translatable_component.rs
+++ b/azalea-chat/src/translatable_component.rs
@@ -3,8 +3,10 @@ use std::fmt::{self, Display, Formatter};
use crate::{
base_component::BaseComponent, style::Style, text_component::TextComponent, Component,
};
+use serde::{ser::SerializeMap, Serialize, Serializer, __private::ser::FlatMapSerializer};
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Serialize)]
+#[serde(untagged)]
pub enum StringOrComponent {
String(String),
Component(Component),
@@ -18,6 +20,19 @@ pub struct TranslatableComponent {
pub args: Vec<StringOrComponent>,
}
+impl Serialize for TranslatableComponent {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let mut state = serializer.serialize_map(None)?;
+ state.serialize_entry("translate", &self.key)?;
+ Serialize::serialize(&self.base, FlatMapSerializer(&mut state))?;
+ state.serialize_entry("with", &self.args)?;
+ state.end()
+ }
+}
+
impl TranslatableComponent {
pub fn new(key: String, args: Vec<StringOrComponent>) -> Self {
Self {
diff --git a/azalea-protocol/src/packets/status/clientbound_status_response_packet.rs b/azalea-protocol/src/packets/status/clientbound_status_response_packet.rs
index 64ea14f9..efa6080c 100755
--- a/azalea-protocol/src/packets/status/clientbound_status_response_packet.rs
+++ b/azalea-protocol/src/packets/status/clientbound_status_response_packet.rs
@@ -1,23 +1,23 @@
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
use azalea_chat::Component;
use azalea_protocol_macros::ClientboundStatusPacket;
-use serde::Deserialize;
-use serde_json::Value;
+use serde::{Deserialize, Serialize};
+use serde_json::{value::Serializer, Value};
use std::io::{Cursor, Write};
-#[derive(Clone, Debug, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Version {
- pub name: Component,
+ pub name: String,
pub protocol: i32,
}
-#[derive(Clone, Debug, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SamplePlayer {
pub id: String,
pub name: String,
}
-#[derive(Clone, Debug, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Players {
pub max: i32,
pub online: i32,
@@ -26,12 +26,22 @@ pub struct Players {
}
// the entire packet is just json, which is why it has deserialize
-#[derive(Clone, Debug, Deserialize, ClientboundStatusPacket)]
+#[derive(Clone, Debug, Serialize, Deserialize, ClientboundStatusPacket)]
pub struct ClientboundStatusResponsePacket {
pub description: Component,
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
pub favicon: Option<String>,
pub players: Players,
pub version: Version,
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(rename = "previewsChat")]
+ pub previews_chat: Option<bool>,
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(rename = "enforcesSecureChat")]
+ pub enforces_secure_chat: Option<bool>,
}
impl McBufReadable for ClientboundStatusResponsePacket {
@@ -44,7 +54,11 @@ impl McBufReadable for ClientboundStatusResponsePacket {
}
impl McBufWritable for ClientboundStatusResponsePacket {
- fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
- todo!()
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ let status_string = ClientboundStatusResponsePacket::serialize(self, Serializer)
+ .unwrap()
+ .to_string();
+ status_string.write_into(buf)?;
+ Ok(())
}
}