diff options
author | regenerativep <regeneralp@gmail.com> | 2021-06-29 15:25:22 -0400 |
---|---|---|
committer | regenerativep <regeneralp@gmail.com> | 2021-06-29 15:25:22 -0400 |
commit | 5e58c8153235a4bd93486c1196b2883280c2424e (patch) | |
tree | 53795b1edc3757e3199de12035547e4a64ae950f /src | |
parent | 57a8c1b7c5e9bcc3d92c75732c29ba7300f40753 (diff) | |
download | mcproto-rs-5e58c8153235a4bd93486c1196b2883280c2424e.tar.gz mcproto-rs-5e58c8153235a4bd93486c1196b2883280c2424e.tar.bz2 mcproto-rs-5e58c8153235a4bd93486c1196b2883280c2424e.zip |
possible chat fix, jigsaw/creative swap
Diffstat (limited to 'src')
-rw-r--r-- | src/chat.rs | 385 | ||||
-rw-r--r-- | src/v1_16_3.rs | 4 |
2 files changed, 248 insertions, 141 deletions
diff --git a/src/chat.rs b/src/chat.rs index 59b9097..fbce103 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1,9 +1,16 @@ -use alloc::{vec::Vec, string::{String, ToString}, collections::{BTreeMap}, boxed::Box, borrow::ToOwned, fmt, format}; -use serde::{Serialize, Deserialize, Deserializer, de, Serializer}; -use serde::de::{Visitor, Error, IntoDeserializer, MapAccess}; +use crate::{DeserializeResult, SerializeResult}; +use alloc::{ + borrow::ToOwned, + boxed::Box, + collections::BTreeMap, + fmt, format, + string::{String, ToString}, + vec::Vec, +}; +use serde::de::{Error, IntoDeserializer, MapAccess, Visitor}; use serde::ser::SerializeMap; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde_json::Value; -use crate::{SerializeResult, DeserializeResult}; pub type BoxedChat = Box<Chat>; @@ -51,7 +58,7 @@ impl Chat { match self { Text(body) => Some(body.to_traditional()), - _ => None + _ => None, } } } @@ -75,7 +82,6 @@ struct TraditionalParser { } impl TraditionalParser { - fn new(source: &str, translate_colorcodes: bool) -> Self { Self { source: source.chars().collect(), @@ -101,7 +107,7 @@ impl TraditionalParser { } else if let Some(next) = self.consume_char() { self.push_next(next) } else { - return self.finalize() + return self.finalize(); } } } @@ -145,8 +151,8 @@ impl TraditionalParser { hover_event: None, click_event: None, insertion: None, - extra: Vec::default() - } + extra: Vec::default(), + }, }; self.text.clear(); self.done.push(current); @@ -165,14 +171,17 @@ impl TraditionalParser { } fn has_text(&self) -> bool { - return !self.text.is_empty() + return !self.text.is_empty(); } fn is_on_formatter(&self) -> bool { - self.source.get(self.at).map(move |c| { - let c = *c; - c == SECTION_SYMBOL || (self.translate_colorcodes && c == '&') - }).unwrap_or(false) + self.source + .get(self.at) + .map(move |c| { + let c = *c; + c == SECTION_SYMBOL || (self.translate_colorcodes && c == '&') + }) + .unwrap_or(false) } fn consume_char(&mut self) -> Option<char> { @@ -214,8 +223,10 @@ impl TraditionalParser { if n_components > 0 { top_level.base.extra.extend( - self.done.into_iter() - .map(move |component| Chat::Text(component).boxed())); + self.done + .into_iter() + .map(move |component| Chat::Text(component).boxed()), + ); } Chat::Text(top_level) @@ -276,14 +287,13 @@ fn should_skip_flag_field(flag: &bool) -> bool { } impl BaseComponent { - fn has_same_style_as(&self, other: &Self) -> bool { - other.bold == self.bold && - other.italic == self.italic && - other.underlined == self.underlined && - other.strikethrough == self.strikethrough && - other.obfuscated == self.obfuscated && - other.color.eq(&self.color) + other.bold == self.bold + && other.italic == self.italic + && other.underlined == self.underlined + && other.strikethrough == self.strikethrough + && other.obfuscated == self.obfuscated + && other.color.eq(&self.color) } } @@ -299,7 +309,11 @@ impl Into<BaseComponent> for JsonComponentBase { insertion: self.insertion, click_event: self.click_event, hover_event: self.hover_event, - extra: self.extra.into_iter().map(move |elem| elem.boxed()).collect(), + extra: self + .extra + .into_iter() + .map(move |elem| elem.boxed()) + .collect(), } } } @@ -321,7 +335,7 @@ struct JsonComponentBase { pub extra: Vec<Chat>, #[serde(flatten)] - _additional: BTreeMap<String, serde_json::Value> + _additional: BTreeMap<String, serde_json::Value>, } impl Default for BaseComponent { @@ -372,7 +386,7 @@ impl TextComponent { Some(child_fmts) => { last_had_formatters = true; buf.extend(child_fmts.chars()) - }, + } None => { last_had_formatters = false; } @@ -438,7 +452,7 @@ pub struct KeybindComponent { #[serde(flatten)] #[serde(skip_deserializing)] - pub base: BaseComponent + pub base: BaseComponent, } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] pub struct ScoreComponent { @@ -446,7 +460,7 @@ pub struct ScoreComponent { #[serde(flatten)] #[serde(skip_deserializing)] - pub base: BaseComponent + pub base: BaseComponent, } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] @@ -463,23 +477,27 @@ pub enum ChatClickEvent { OpenUrl(String), RunCommand(String), SuggestCommand(String), - ChangePage(i32) + ChangePage(i32), } impl Serialize for ChatClickEvent { - fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where - S: Serializer + fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> + where + S: Serializer, { let mut m = serializer.serialize_map(Some(2))?; use ChatClickEvent::*; - m.serialize_entry("action", match self { - OpenUrl(_) => "open_url", - RunCommand(_) => "run_command", - SuggestCommand(_) => "suggest_command", - ChangePage(_) => "change_page", - })?; + m.serialize_entry( + "action", + match self { + OpenUrl(_) => "open_url", + RunCommand(_) => "run_command", + SuggestCommand(_) => "suggest_command", + ChangePage(_) => "change_page", + }, + )?; m.serialize_key("value")?; @@ -495,8 +513,9 @@ impl Serialize for ChatClickEvent { } impl<'de> Deserialize<'de> for ChatClickEvent { - fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> where - D: Deserializer<'de> + fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> + where + D: Deserializer<'de>, { struct V; @@ -507,8 +526,9 @@ impl<'de> Deserialize<'de> for ChatClickEvent { write!(f, "an event object for ChatClickEvent") } - fn visit_map<A>(self, mut map: A) -> Result<Self::Value, <A as MapAccess<'de>>::Error> where - A: MapAccess<'de> + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, <A as MapAccess<'de>>::Error> + where + A: MapAccess<'de>, { let (action, value) = read_event(&mut map)?; @@ -516,21 +536,36 @@ impl<'de> Deserialize<'de> for ChatClickEvent { match action { "open_url" => match value.as_str() { Some(url) => Ok(OpenUrl(url.to_owned())), - None => Err(A::Error::custom(format!("open_url requires string body, got {}", value))) + None => Err(A::Error::custom(format!( + "open_url requires string body, got {}", + value + ))), }, "run_command" => match value.as_str() { Some(cmd) => Ok(RunCommand(cmd.to_owned())), - None => Err(A::Error::custom(format!("run_command requires string body, got {}", value))) + None => Err(A::Error::custom(format!( + "run_command requires string body, got {}", + value + ))), }, "suggest_command" => match value.as_str() { Some(cmd) => Ok(SuggestCommand(cmd.to_owned())), - None => Err(A::Error::custom(format!("suggest_command requires string body, got {}", value))) + None => Err(A::Error::custom(format!( + "suggest_command requires string body, got {}", + value + ))), }, "change_page" => match value.as_i64() { Some(v) => Ok(ChangePage(v as i32)), - None => Err(A::Error::custom(format!("change_page requires integer body, got {}", value))) + None => Err(A::Error::custom(format!( + "change_page requires integer body, got {}", + value + ))), }, - other => Err(A::Error::custom(format!("invalid click action kind {}", other))) + other => Err(A::Error::custom(format!( + "invalid click action kind {}", + other + ))), } } } @@ -543,22 +578,26 @@ impl<'de> Deserialize<'de> for ChatClickEvent { pub enum ChatHoverEvent { ShowText(BoxedChat), ShowItem(Value), - ShowEntity(Value) + ShowEntity(Value), } impl Serialize for ChatHoverEvent { - fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where - S: Serializer + fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> + where + S: Serializer, { let mut m = serializer.serialize_map(Some(2))?; use ChatHoverEvent::*; - m.serialize_entry("action", match self { - ShowText(_) => "show_text", - ShowItem(_) => "show_item", - ShowEntity(_) => "show_entity", - })?; + m.serialize_entry( + "action", + match self { + ShowText(_) => "show_text", + ShowItem(_) => "show_item", + ShowEntity(_) => "show_entity", + }, + )?; m.serialize_key("value")?; @@ -573,8 +612,9 @@ impl Serialize for ChatHoverEvent { } impl<'de> Deserialize<'de> for ChatHoverEvent { - fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> where - D: Deserializer<'de> + fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> + where + D: Deserializer<'de>, { struct V; @@ -586,8 +626,9 @@ impl<'de> Deserialize<'de> for ChatHoverEvent { } //noinspection ALL - fn visit_map<A>(self, mut map: A) -> Result<Self::Value, <A as MapAccess<'de>>::Error> where - A: MapAccess<'de> + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, <A as MapAccess<'de>>::Error> + where + A: MapAccess<'de>, { let (action, value) = read_event(&mut map)?; @@ -595,12 +636,20 @@ impl<'de> Deserialize<'de> for ChatHoverEvent { match action { "show_text" => Ok(ShowText( Chat::deserialize(value.into_deserializer()) - .map_err(move |err| A::Error::custom( - format!("error deserializing text to show {:?}", err)))? - .boxed())), + .map_err(move |err| { + A::Error::custom(format!( + "error deserializing text to show {:?}", + err + )) + })? + .boxed(), + )), "show_item" => Ok(ShowItem(value)), "show_entity" => Ok(ShowEntity(value)), - other => Err(A::Error::custom(format!("invalid hover action kind {}", other))) + other => Err(A::Error::custom(format!( + "invalid hover action kind {}", + other + ))), } } } @@ -726,15 +775,18 @@ impl fmt::Display for ColorCode { } impl Serialize for ColorCode { - fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where - S: Serializer { + fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> + where + S: Serializer, + { serializer.serialize_str(self.name()) } } impl<'de> Deserialize<'de> for ColorCode { - fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> where - D: Deserializer<'de> + fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> + where + D: Deserializer<'de>, { struct V; @@ -745,7 +797,8 @@ impl<'de> Deserialize<'de> for ColorCode { write!(fmt, "a string representing a color code") } - fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where E: de::Error, { if let Some(code) = ColorCode::from_name(v) { @@ -827,10 +880,10 @@ impl fmt::Display for Formatter { } } - impl<'de> Deserialize<'de> for Chat { - fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> where - D: Deserializer<'de> + fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> + where + D: Deserializer<'de>, { struct V; @@ -838,30 +891,49 @@ impl<'de> Deserialize<'de> for Chat { type Value = Chat; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "any primitive or a JSON object specifying the component") + write!( + formatter, + "any primitive or a JSON object specifying the component" + ) } - fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E> where E: de::Error { + fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E> + where + E: de::Error, + { self.visit_string(value.to_string()) } - fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> where E: de::Error { + fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> + where + E: de::Error, + { self.visit_string(value.to_string()) } - fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> where E: de::Error { + fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> + where + E: de::Error, + { self.visit_string(value.to_string()) } - fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: de::Error { + fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> + where + E: de::Error, + { Ok(Chat::Text(TextComponent { base: BaseComponent::default(), text: value.to_owned(), })) } - fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error> where M: de::MapAccess<'de> { - let mut base: JsonComponentBase = de::Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?; + fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error> + where + M: de::MapAccess<'de>, + { + let mut base: JsonComponentBase = + de::Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?; let additional = &mut base._additional; // string component @@ -873,7 +945,10 @@ impl<'de> Deserialize<'de> for Chat { base: base.into(), })) } else { - Err(M::Error::custom(format!("have text but it's not a string - {:?}", raw_text))) + Err(M::Error::custom(format!( + "have text but it's not a string - {:?}", + raw_text + ))) }; } @@ -890,36 +965,45 @@ impl<'de> Deserialize<'de> for Chat { format!("unable to parse one of the translation with entries :: {}", err)))? .boxed()); } - Ok(Chat::Translation(TranslationComponent{ + Ok(Chat::Translation(TranslationComponent { base: base.into(), translate: translate.to_owned(), with: withs_out, })) } else { - Err(M::Error::custom(format!("have with but it's not an array - {:?}", raw_with))) + Err(M::Error::custom(format!( + "have with but it's not an array - {:?}", + raw_with + ))) } } else { - Ok(Chat::Translation(TranslationComponent{ + Ok(Chat::Translation(TranslationComponent { base: base.into(), translate: translate.to_owned(), with: Vec::default(), })) } } else { - Err(M::Error::custom(format!("have translate but it's not a string - {:?}", raw_translate))) - } + Err(M::Error::custom(format!( + "have translate but it's not a string - {:?}", + raw_translate + ))) + }; } // keybind if let Some(raw_keybind) = additional.remove("keybind") { return if let Some(keybind) = raw_keybind.as_str() { - Ok(Chat::Keybind(KeybindComponent{ + Ok(Chat::Keybind(KeybindComponent { keybind: keybind.to_owned(), - base: base.into() + base: base.into(), })) } else { - Err(M::Error::custom(format!("have keybind but it's not a string! {:?}", raw_keybind))) - } + Err(M::Error::custom(format!( + "have keybind but it's not a string! {:?}", + raw_keybind + ))) + }; } // score @@ -928,7 +1012,7 @@ impl<'de> Deserialize<'de> for Chat { .map_err(move |err| M::Error::custom( format!("failed to deserialize scoreboard objective for score chat component :: {:?}", err)))?; - return Ok(Chat::Score(ScoreComponent{ + return Ok(Chat::Score(ScoreComponent { score, base: base.into(), })); @@ -936,7 +1020,9 @@ impl<'de> Deserialize<'de> for Chat { // selector (SKIP) - Err(M::Error::custom("not able to parse chat component, not a valid chat component kind")) + Err(M::Error::custom( + "not able to parse chat component, not a valid chat component kind", + )) } } @@ -945,8 +1031,9 @@ impl<'de> Deserialize<'de> for Chat { } impl Serialize for Chat { - fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where - S: Serializer + fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> + where + S: Serializer, { use Chat::*; @@ -954,7 +1041,7 @@ impl Serialize for Chat { Text(body) => body.serialize(serializer), Translation(body) => body.serialize(serializer), Keybind(body) => body.serialize(serializer), - Score(body) => body.serialize(serializer) + Score(body) => body.serialize(serializer), } } } @@ -962,8 +1049,12 @@ impl Serialize for Chat { impl super::Serialize for Chat { fn mc_serialize<S: super::Serializer>(&self, to: &mut S) -> SerializeResult { serde_json::to_string(self) - .map_err(move |err| super::SerializeErr::FailedJsonEncode( - format!("error while encoding chat :: {:?} -> {:?}", self, err)))? + .map_err(move |err| { + super::SerializeErr::FailedJsonEncode(format!( + "error while encoding chat :: {:?} -> {:?}", + self, err + )) + })? .mc_serialize(to) } } @@ -971,10 +1062,12 @@ impl super::Serialize for Chat { impl super::Deserialize for Chat { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { String::mc_deserialize(data)?.try_map(move |raw| { - serde_json::from_str(raw.as_str()).map_err(move |err| + serde_json::from_str(raw.as_str()).map_err(move |err| { super::DeserializeErr::FailedJsonDeserialize(format!( - "failed to deserialize chat from JSON '{}' :: {:?}", raw, err - ))) + "failed to deserialize chat from JSON '{}' :: {:?}", + raw, err + )) + }) }) } } @@ -990,10 +1083,9 @@ impl TestRandom for Chat { } } -fn read_event<'de, A>( - access: &mut A, -) -> Result<(&'de str, Value), <A as MapAccess<'de>>::Error> - where A: MapAccess<'de> +fn read_event<'de, A>(access: &mut A) -> Result<(&'de str, Value), <A as MapAccess<'de>>::Error> +where + A: MapAccess<'de>, { let mut action: Option<&str> = None; let mut value: Option<Value> = None; @@ -1005,15 +1097,18 @@ fn read_event<'de, A>( if action.is_none() { return Err(A::Error::custom("none for value key=action")); } - }, - "value" => { + } + "value" | "content" => { value = access.next_value()?; if value.is_none() { return Err(A::Error::custom("none for value key=value")); } - }, + } other => { - return Err(A::Error::custom(format!("unexpected key in event {}", other))); + return Err(A::Error::custom(format!( + "unexpected key in event {}", + other + ))); } } } else { @@ -1032,40 +1127,52 @@ pub mod tests { #[test] fn test_from_traditional_simple() { let out = Chat::from_traditional("&cthis &cis red, and &rthis is &e&lyellow", true); - assert_eq!(out, Chat::Text(TextComponent{ - text: String::default(), - base: { - let mut b = BaseComponent::default(); - b.extra = alloc::vec!( - Chat::Text(TextComponent{ - text: "this is red, and ".to_owned(), - base: { - let mut b = BaseComponent::default(); - b.color = Some(ColorCode::Red); - b - }, - }).boxed(), - Chat::Text(TextComponent{ - text: "this is ".to_owned(), - base: BaseComponent::default(), - }).boxed(), - Chat::Text(TextComponent{ - text: "yellow".to_owned(), - base: { - let mut b = BaseComponent::default(); - b.color = Some(ColorCode::Yellow); - b.bold = true; - b - } - }).boxed() - ); - b - } - })); + assert_eq!( + out, + Chat::Text(TextComponent { + text: String::default(), + base: { + let mut b = BaseComponent::default(); + b.extra = alloc::vec!( + Chat::Text(TextComponent { + text: "this is red, and ".to_owned(), + base: { + let mut b = BaseComponent::default(); + b.color = Some(ColorCode::Red); + b + }, + }) + .boxed(), + Chat::Text(TextComponent { + text: "this is ".to_owned(), + base: BaseComponent::default(), + }) + .boxed(), + Chat::Text(TextComponent { + text: "yellow".to_owned(), + base: { + let mut b = BaseComponent::default(); + b.color = Some(ColorCode::Yellow); + b.bold = true; + b + } + }) + .boxed() + ); + b + } + }) + ); let traditional = out.to_traditional().expect("is text"); - assert_eq!(traditional.as_str(), "§cthis is red, and §rthis is §e§lyellow"); - #[cfg(feature="std")] - println!("{}", serde_json::to_string_pretty(&out).expect("should serialize fine")); + assert_eq!( + traditional.as_str(), + "§cthis is red, and §rthis is §e§lyellow" + ); + #[cfg(feature = "std")] + println!( + "{}", + serde_json::to_string_pretty(&out).expect("should serialize fine") + ); } -}
\ No newline at end of file +} diff --git a/src/v1_16_3.rs b/src/v1_16_3.rs index b9743d4..4c7bce5 100644 --- a/src/v1_16_3.rs +++ b/src/v1_16_3.rs @@ -673,13 +673,13 @@ define_protocol!(753, Packet753, RawPacket753, RawPacket753Body, Packet753Kind = command: String, track_output: bool }, - PlayUpdateJigsawBlock, 0x28, Play, ServerBound => PlayUpdateJigsawBlockSpec { + PlayUpdateJigsawBlock, 0x29, Play, ServerBound => PlayUpdateJigsawBlockSpec { location: IntPosition, attachment_type: String, target_pool: String, final_state: String }, - PlayCreativeInventoryAction, 0x29, Play, ServerBound => PlayCreativeInventoryActionSpec { + PlayCreativeInventoryAction, 0x28, Play, ServerBound => PlayCreativeInventoryActionSpec { slot: i16, clicked_item: Slot }, |