aboutsummaryrefslogtreecommitdiff
path: root/azalea-chat/src
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-09-26 06:16:33 +0800
committermat <git@matdoes.dev>2025-09-25 19:20:09 -0300
commit730297cf561d42fd9132eb201d1aec0d3d7c7e00 (patch)
treed26f63b8a4553cc1b07c41a5b1a06aba773e60c4 /azalea-chat/src
parent8927a0fe65f5f89b4459956f19989f27f1e0981c (diff)
downloadazalea-drasl-730297cf561d42fd9132eb201d1aec0d3d7c7e00.tar.xz
fix compile error with new serde version, and update deps
Diffstat (limited to 'azalea-chat/src')
-rw-r--r--azalea-chat/src/base_component.rs30
-rw-r--r--azalea-chat/src/click_event.rs47
-rw-r--r--azalea-chat/src/hover_event.rs28
-rw-r--r--azalea-chat/src/style.rs237
-rw-r--r--azalea-chat/src/text_component.rs6
-rw-r--r--azalea-chat/src/translatable_component.rs21
6 files changed, 208 insertions, 161 deletions
diff --git a/azalea-chat/src/base_component.rs b/azalea-chat/src/base_component.rs
index 27666c17..be7e9656 100644
--- a/azalea-chat/src/base_component.rs
+++ b/azalea-chat/src/base_component.rs
@@ -1,18 +1,38 @@
-use serde::Serialize;
+use serde::{Serialize, ser::SerializeMap};
use crate::{FormattedText, style::Style};
-#[derive(Clone, Debug, PartialEq, Serialize)]
+#[derive(Clone, Debug, PartialEq)]
pub struct BaseComponent {
- // implements mutablecomponent
/// Components in the "extra" field.
- #[serde(skip_serializing_if = "Vec::is_empty")]
pub siblings: Vec<FormattedText>,
- #[serde(flatten)]
pub style: Box<Style>,
}
impl BaseComponent {
+ pub fn serialize_map<S>(&self, state: &mut S::SerializeMap) -> Result<(), S::Error>
+ where
+ S: serde::Serializer,
+ {
+ if !self.siblings.is_empty() {
+ state.serialize_entry("extra", &self.siblings)?;
+ }
+ self.style.serialize_map::<S>(state)?;
+ Ok(())
+ }
+}
+impl Serialize for BaseComponent {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ let mut state = serializer.serialize_map(None)?;
+ self.serialize_map::<S>(&mut state)?;
+ state.end()
+ }
+}
+
+impl BaseComponent {
pub fn new() -> Self {
Self {
siblings: Vec::new(),
diff --git a/azalea-chat/src/click_event.rs b/azalea-chat/src/click_event.rs
index dddaff74..a61e2561 100644
--- a/azalea-chat/src/click_event.rs
+++ b/azalea-chat/src/click_event.rs
@@ -1,6 +1,6 @@
use serde::Serialize;
#[cfg(feature = "simdnbt")]
-use simdnbt::owned::Nbt;
+use simdnbt::owned::{Nbt, NbtCompound, NbtTag};
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(rename_all = "snake_case", tag = "action")]
@@ -31,3 +31,48 @@ pub enum ClickEvent {
payload: Nbt,
},
}
+
+#[cfg(feature = "simdnbt")]
+impl simdnbt::Serialize for ClickEvent {
+ fn to_compound(self) -> NbtCompound {
+ let mut compound = NbtCompound::new();
+ let mut action = |s: &str| {
+ compound.insert("action", s);
+ };
+ match self {
+ ClickEvent::OpenUrl { url } => {
+ action("open_url");
+ compound.insert("url", url);
+ }
+ ClickEvent::OpenFile { path } => {
+ action("open_file");
+ compound.insert("path", path);
+ }
+ ClickEvent::RunCommand { command } => {
+ action("run_command");
+ compound.insert("command", command);
+ }
+ ClickEvent::SuggestCommand { command } => {
+ action("suggest_command");
+ compound.insert("command", command);
+ }
+ ClickEvent::ShowDialog => {
+ action("show_dialog");
+ }
+ ClickEvent::ChangePage { page } => {
+ action("change_page");
+ compound.insert("page", NbtTag::Int(page));
+ }
+ ClickEvent::CopyToClipboard { value } => {
+ action("copy_to_clipboard");
+ compound.insert("value", value);
+ }
+ ClickEvent::Custom { id, payload } => {
+ action("custom");
+ compound.insert("id", id);
+ compound.insert("payload", (**payload).clone());
+ }
+ }
+ compound
+ }
+}
diff --git a/azalea-chat/src/hover_event.rs b/azalea-chat/src/hover_event.rs
index a18a3047..825c253b 100644
--- a/azalea-chat/src/hover_event.rs
+++ b/azalea-chat/src/hover_event.rs
@@ -1,4 +1,6 @@
use serde::Serialize;
+#[cfg(feature = "simdnbt")]
+use simdnbt::owned::NbtCompound;
use crate::FormattedText;
@@ -18,3 +20,29 @@ pub enum HoverEvent {
name: Box<FormattedText>,
},
}
+
+#[cfg(feature = "simdnbt")]
+impl simdnbt::Serialize for HoverEvent {
+ fn to_compound(self) -> NbtCompound {
+ let mut compound = NbtCompound::new();
+ let mut action = |s: &str| {
+ compound.insert("action", s);
+ };
+ match self {
+ HoverEvent::ShowText { value } => {
+ action("show_text");
+ compound.insert("value", value.to_compound());
+ }
+ HoverEvent::ShowItem { .. } => {
+ action("show_item");
+ }
+ HoverEvent::ShowEntity { id, name } => {
+ action("show_entity");
+ compound.insert("id", id);
+ // compound.insert("uuid", uuid.to_string());
+ compound.insert("name", name.to_compound());
+ }
+ }
+ compound
+ }
+}
diff --git a/azalea-chat/src/style.rs b/azalea-chat/src/style.rs
index b67dcf89..c43b7791 100644
--- a/azalea-chat/src/style.rs
+++ b/azalea-chat/src/style.rs
@@ -2,7 +2,7 @@ use std::{collections::HashMap, fmt, sync::LazyLock};
#[cfg(feature = "azalea-buf")]
use azalea_buf::AzBuf;
-use serde::{Serialize, Serializer};
+use serde::{Serialize, Serializer, ser::SerializeMap};
use serde_json::Value;
#[cfg(feature = "simdnbt")]
use simdnbt::owned::{NbtCompound, NbtTag};
@@ -304,136 +304,119 @@ impl TryFrom<ChatFormatting> for TextColor {
}
}
-#[derive(Clone, Debug, Default, PartialEq, serde::Serialize)]
-#[non_exhaustive]
-pub struct Style {
- #[serde(skip_serializing_if = "Option::is_none")]
- pub color: Option<TextColor>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub shadow_color: Option<u32>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub bold: Option<bool>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub italic: Option<bool>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub underlined: Option<bool>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub strikethrough: Option<bool>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub obfuscated: Option<bool>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub click_event: Option<ClickEvent>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub hover_event: Option<HoverEvent>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub insertion: Option<String>,
+macro_rules! define_style_struct {
+ ($($(#[$doc:meta])* $field:ident : $type:ty),* $(,)?) => {
+ #[derive(Clone, Debug, Default, PartialEq, serde::Serialize)]
+ #[non_exhaustive]
+ pub struct Style {
+ $(
+ #[serde(skip_serializing_if = "Option::is_none")]
+ $(#[$doc])*
+ pub $field: Option<$type>,
+ )*
+ }
+
+ impl Style {
+ $(
+ pub fn $field(mut self, value: impl Into<Option<$type>>) -> Self {
+ self.$field = value.into();
+ self
+ }
+ )*
+
+ pub fn serialize_map<S>(&self, state: &mut S::SerializeMap) -> Result<(), S::Error>
+ where
+ S: serde::Serializer,
+ {
+ $(
+ if let Some(value) = &self.$field {
+ state.serialize_entry(stringify!($field), value)?;
+ }
+ )*
+ Ok(())
+ }
+
+ /// Apply another style to this one
+ pub fn apply(&mut self, style: &Style) {
+ $(
+ if let Some(value) = &style.$field {
+ self.$field = Some(value.clone());
+ }
+ )*
+ }
+ }
+
+ #[cfg(feature = "simdnbt")]
+ impl simdnbt::Serialize for Style {
+ fn to_compound(self) -> NbtCompound {
+ let mut compound = NbtCompound::new();
+
+ $(
+ if let Some(value) = self.$field {
+ compound.insert(stringify!($field), value);
+ }
+ )*
+
+ compound
+ }
+ }
+ };
+}
+
+define_style_struct! {
+ color: TextColor,
+ shadow_color: u32,
+ bold: bool,
+ italic: bool,
+ underlined: bool,
+ strikethrough: bool,
+ obfuscated: bool,
+ click_event: ClickEvent,
+ hover_event: HoverEvent,
+ insertion: String,
/// Represented as a `ResourceLocation`.
- #[serde(skip_serializing_if = "Option::is_none")]
- pub font: Option<String>,
+ font: String,
}
+
impl Style {
pub fn new() -> Self {
Self::default()
}
- pub fn color(mut self, color: impl Into<Option<TextColor>>) -> Self {
- self.color = color.into();
- self
- }
- pub fn shadow_color(mut self, color: impl Into<Option<u32>>) -> Self {
- self.shadow_color = color.into();
- self
- }
- pub fn bold(mut self, bold: impl Into<Option<bool>>) -> Self {
- self.bold = bold.into();
- self
- }
- pub fn italic(mut self, italic: impl Into<Option<bool>>) -> Self {
- self.italic = italic.into();
- self
- }
- pub fn underlined(mut self, underlined: impl Into<Option<bool>>) -> Self {
- self.underlined = underlined.into();
- self
- }
- pub fn strikethrough(mut self, strikethrough: impl Into<Option<bool>>) -> Self {
- self.strikethrough = strikethrough.into();
- self
- }
- pub fn obfuscated(mut self, obfuscated: impl Into<Option<bool>>) -> Self {
- self.obfuscated = obfuscated.into();
- self
- }
- pub fn click_event(mut self, click_event: impl Into<Option<ClickEvent>>) -> Self {
- self.click_event = click_event.into();
- self
- }
- pub fn hover_event(mut self, hover_event: impl Into<Option<HoverEvent>>) -> Self {
- self.hover_event = hover_event.into();
- self
- }
- pub fn insertion(mut self, insertion: impl Into<Option<String>>) -> Self {
- self.insertion = insertion.into();
- self
- }
- pub fn font(mut self, font: impl Into<Option<String>>) -> Self {
- self.font = font.into();
- self
- }
-}
-#[cfg(feature = "simdnbt")]
-fn simdnbt_serialize_field(
- compound: &mut simdnbt::owned::NbtCompound,
- name: &'static str,
- value: Option<impl simdnbt::ToNbtTag>,
-) {
- if let Some(value) = value {
- compound.insert(name, value);
- }
-}
-
-#[cfg(feature = "simdnbt")]
-impl simdnbt::Serialize for Style {
- fn to_compound(self) -> NbtCompound {
- let mut compound = NbtCompound::new();
-
- simdnbt_serialize_field(&mut compound, "color", self.color);
- simdnbt_serialize_field(&mut compound, "bold", self.bold);
- simdnbt_serialize_field(&mut compound, "italic", self.italic);
- simdnbt_serialize_field(&mut compound, "underlined", self.underlined);
- simdnbt_serialize_field(&mut compound, "strikethrough", self.strikethrough);
- simdnbt_serialize_field(&mut compound, "obfuscated", self.obfuscated);
-
- compound
- }
-}
-
-impl Style {
pub fn empty() -> Self {
Self::default()
}
pub fn deserialize(json: &Value) -> Style {
- let Some(json_object) = json.as_object() else {
+ let Some(j) = json.as_object() else {
return Style::default();
};
- let bold = json_object.get("bold").and_then(|v| v.as_bool());
- let italic = json_object.get("italic").and_then(|v| v.as_bool());
- let underlined = json_object.get("underlined").and_then(|v| v.as_bool());
- let strikethrough = json_object.get("strikethrough").and_then(|v| v.as_bool());
- let obfuscated = json_object.get("obfuscated").and_then(|v| v.as_bool());
- let color: Option<TextColor> = json_object
- .get("color")
- .and_then(|v| v.as_str())
- .and_then(TextColor::parse);
+
Style {
- color,
- bold,
- italic,
- underlined,
- strikethrough,
- obfuscated,
- ..Style::default()
+ color: j
+ .get("color")
+ .and_then(|v| v.as_str())
+ .and_then(TextColor::parse),
+ shadow_color: j
+ .get("shadow_color")
+ .and_then(|v| v.as_u64())
+ .map(|v| v as u32),
+ bold: j.get("bold").and_then(|v| v.as_bool()),
+ italic: j.get("italic").and_then(|v| v.as_bool()),
+ underlined: j.get("underlined").and_then(|v| v.as_bool()),
+ strikethrough: j.get("strikethrough").and_then(|v| v.as_bool()),
+ obfuscated: j.get("obfuscated").and_then(|v| v.as_bool()),
+ // TODO: impl deserialize functions for click_event and hover_event
+ click_event: Default::default(),
+ hover_event: Default::default(),
+ insertion: j
+ .get("insertion")
+ .and_then(|v| v.as_str())
+ .map(|s| s.to_string()),
+ font: j
+ .get("font")
+ .and_then(|v| v.as_str())
+ .map(|s| s.to_string()),
}
}
@@ -513,28 +496,6 @@ impl Style {
ansi_codes
}
- /// Apply another style to this one
- pub fn apply(&mut self, style: &Style) {
- if let Some(color) = &style.color {
- self.color = Some(color.clone());
- }
- if let Some(bold) = &style.bold {
- self.bold = Some(*bold);
- }
- if let Some(italic) = &style.italic {
- self.italic = Some(*italic);
- }
- if let Some(underlined) = &style.underlined {
- self.underlined = Some(*underlined);
- }
- if let Some(strikethrough) = &style.strikethrough {
- self.strikethrough = Some(*strikethrough);
- }
- if let Some(obfuscated) = &style.obfuscated {
- self.obfuscated = Some(*obfuscated);
- }
- }
-
/// Returns a new style that is a merge of self and other.
/// For any field that `other` does not specify (is None), self’s value is
/// used.
diff --git a/azalea-chat/src/text_component.rs b/azalea-chat/src/text_component.rs
index 962ec46e..0fa0cd6f 100644
--- a/azalea-chat/src/text_component.rs
+++ b/azalea-chat/src/text_component.rs
@@ -1,6 +1,6 @@
use std::fmt::{self, Display};
-use serde::{__private::ser::FlatMapSerializer, Serialize, Serializer, ser::SerializeMap};
+use serde::{Serialize, Serializer, ser::SerializeMap};
use crate::{
FormattedText,
@@ -25,7 +25,9 @@ impl Serialize for TextComponent {
let mut state = serializer.serialize_map(None)?;
state.serialize_entry("text", &self.text)?;
- Serialize::serialize(&self.base, FlatMapSerializer(&mut state))?;
+
+ self.base.serialize_map::<S>(&mut state)?;
+
if !self.base.siblings.is_empty() {
state.serialize_entry("extra", &self.base.siblings)?;
}
diff --git a/azalea-chat/src/translatable_component.rs b/azalea-chat/src/translatable_component.rs
index 28700366..b8e93245 100644
--- a/azalea-chat/src/translatable_component.rs
+++ b/azalea-chat/src/translatable_component.rs
@@ -1,6 +1,6 @@
use std::fmt::{self, Display};
-use serde::{__private::ser::FlatMapSerializer, Serialize, Serializer, ser::SerializeMap};
+use serde::Serialize;
#[cfg(feature = "simdnbt")]
use simdnbt::Serialize as _;
@@ -24,27 +24,18 @@ impl simdnbt::ToNbtTag for StringOrComponent {
}
/// A message whose content depends on the client's language.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct TranslatableComponent {
+ #[serde(flatten)]
pub base: BaseComponent,
+ #[serde(rename = "translate")]
pub key: String,
+ #[serde(skip_serializing_if = "Option::is_none")]
pub fallback: Option<String>,
+ #[serde(rename = "with")]
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()
- }
-}
-
#[cfg(feature = "simdnbt")]
fn serialize_args_as_nbt(args: &[StringOrComponent]) -> simdnbt::owned::NbtList {
// if it's all strings then make it a string list