diff options
| author | mat <git@matdoes.dev> | 2025-09-26 06:16:33 +0800 |
|---|---|---|
| committer | mat <git@matdoes.dev> | 2025-09-25 19:20:09 -0300 |
| commit | 730297cf561d42fd9132eb201d1aec0d3d7c7e00 (patch) | |
| tree | d26f63b8a4553cc1b07c41a5b1a06aba773e60c4 /azalea-chat/src | |
| parent | 8927a0fe65f5f89b4459956f19989f27f1e0981c (diff) | |
| download | azalea-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.rs | 30 | ||||
| -rw-r--r-- | azalea-chat/src/click_event.rs | 47 | ||||
| -rw-r--r-- | azalea-chat/src/hover_event.rs | 28 | ||||
| -rw-r--r-- | azalea-chat/src/style.rs | 237 | ||||
| -rw-r--r-- | azalea-chat/src/text_component.rs | 6 | ||||
| -rw-r--r-- | azalea-chat/src/translatable_component.rs | 21 |
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 |
