diff options
| author | EightFactorial <murphkev000@gmail.com> | 2022-12-03 17:08:05 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-03 19:08:05 -0600 |
| commit | 3b93fc641250c4d01ab7f0764b7d5faec2f8ae5b (patch) | |
| tree | 727b94c9f90bba59f8571ecebeab1a33e0f4af07 /azalea-chat/src | |
| parent | 661c3622bebc111a1523bc80792dc90d9d571b24 (diff) | |
| download | azalea-drasl-3b93fc641250c4d01ab7f0764b7d5faec2f8ae5b.tar.xz | |
Serialize Component (#47)
* Serializing ClientboundStatusResponsePacket
Enable serialization of ClientboundStatusResponsePacket
* Update clientbound_status_response_packet.rs
Add options previewsChat and enforcesSecureChat
* Serialize Style and TextColor
* Serialize BaseComponent
* Serialize TextComponent
* Fix Style
* Serialize Component
* Fix multiple formats per message, fix reset tag
* Fix Style, again
* Use FlatMapSerializer
* Forgot italics
* Count struct fields, reorganize logic
* Serialize TranslatableComponent
* Rewrite TextComponent Serializer
* Fix using TextColor::Parse
* Code Cleanup
* Add default attribute, just in case
* Clippy
* use serde derive feature + preferred formatting choices
Co-authored-by: BuildTools <unconfigured@null.spigotmc.org>
Co-authored-by: mat <github@matdoes.dev>
Diffstat (limited to 'azalea-chat/src')
| -rwxr-xr-x | azalea-chat/src/base_component.rs | 5 | ||||
| -rwxr-xr-x | azalea-chat/src/component.rs | 14 | ||||
| -rwxr-xr-x | azalea-chat/src/style.rs | 68 | ||||
| -rwxr-xr-x | azalea-chat/src/text_component.rs | 19 | ||||
| -rwxr-xr-x | azalea-chat/src/translatable_component.rs | 17 |
5 files changed, 110 insertions, 13 deletions
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 { |
