From 5e68e0f8cd619176e5d7f4a5b042ac899b3b4fc9 Mon Sep 17 00:00:00 2001 From: C191239 Date: Fri, 6 Oct 2023 20:09:40 +0800 Subject: [PATCH] Partial HoverEvent Co-authored-by: Yjn024 --- core/src/text/mod.rs | 117 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 18 deletions(-) diff --git a/core/src/text/mod.rs b/core/src/text/mod.rs index d572176b..ffcfa113 100644 --- a/core/src/text/mod.rs +++ b/core/src/text/mod.rs @@ -1,13 +1,17 @@ use std::{ any::TypeId, + borrow::Cow, collections::{hash_map::DefaultHasher, HashMap}, fmt::{Debug, Display}, hash::{Hash, Hasher}, }; +use anyhow::anyhow; use once_cell::sync::Lazy; +use parking_lot::RwLock; +use serde::{Deserialize, Serialize}; -use anyhow::anyhow; +use rimecraft_event::Event; ///TODO: Implement net.minecraft.text.Text pub trait Text { @@ -45,9 +49,14 @@ impl Style { }; } +/// Represents an RGB color of a [`Text`]. +/// +/// # MCJE Reference +/// +/// This type represents `net.minecraft.text.TextColor` (yarn). #[derive(Debug, Hash)] pub struct Color { - ///24-bit color. + /// 24-bit color. rgb: u32, name: Option, } @@ -56,19 +65,14 @@ impl Color { const RGB_PREFIX: &str = "#"; pub fn try_parse(name: String) -> anyhow::Result { - if name.starts_with(Self::RGB_PREFIX) { - let i: u32 = str::parse(&name[1..])?; - Ok(Self::from_rgb(i)) + if let Some(value) = name.strip_prefix(Self::RGB_PREFIX) { + Ok(Self::from_rgb(value.parse()?)) } else { let f = crate::util::formatting::Formatting::try_from_name(&name)?; - - let cv: u32 = match f.color_value() { - Some(x) => x, - None => return Err(anyhow!("No valid color value!")), - }; - Ok(Self { - rgb: cv, + rgb: f + .color_value() + .ok_or_else(|| anyhow::anyhow!("no valid color value"))?, name: Some(String::from(f.name())), }) } @@ -209,12 +213,12 @@ impl ClickEventAction { pub struct HoverEvent { contents: (Box, TypeId), - action: HoverEventAction, + action: &'static HoverEventAction, hash: u64, } impl HoverEvent { - pub fn new(action: HoverEventAction, contents: T) -> Self + pub fn new(action: &'static HoverEventAction, contents: T) -> Self where T: Debug + Hash + Send + Sync + 'static, { @@ -233,7 +237,6 @@ impl HoverEvent { &self.action } - #[inline] pub fn value(&self) -> Option<&T> { if TypeId::of::() == self.contents.1 { Some(unsafe { &*(&*self.contents.0 as *const (dyn Debug + Send + Sync) as *const T) }) @@ -242,7 +245,6 @@ impl HoverEvent { } } - #[inline] pub fn value_mut(&mut self) -> Option<&mut T> { if TypeId::of::() == self.contents.1 { Some(unsafe { @@ -254,7 +256,17 @@ impl HoverEvent { } } +impl Serialize for HoverEvent { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + todo!() + } +} + impl Hash for HoverEvent { + #[inline] fn hash(&self, state: &mut H) { state.write_u64(self.hash); self.action.hash(state); @@ -262,6 +274,7 @@ impl Hash for HoverEvent { } impl Debug for HoverEvent { + #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, @@ -273,11 +286,51 @@ impl Debug for HoverEvent { #[derive(PartialEq, Eq, Clone, Hash)] pub struct HoverEventAction { - name: String, + name: Cow<'static, str>, parsable: bool, } +/// An event to process actions on initialize. +static HE_ACTIONS: RwLock)>> = + RwLock::new(Event::new(|listeners| { + Box::new(move |actions| { + for listener in listeners { + listener(actions) + } + }) + })); + +static HE_MAPPING: Lazy> = Lazy::new(|| { + HE_ACTIONS.write().register(Box::new(|v| { + let mut vec = vec![ + HoverEventAction::SHOW_TEXT, + HoverEventAction::SHOW_ITEM, + HoverEventAction::SHOW_ENTITY, + ]; + v.append(&mut vec); + })); + + let mut vec = Vec::new(); + HE_ACTIONS.read().invoker()(&mut vec); + vec.into_iter().map(|v| (v.name().to_owned(), v)).collect() +}); + impl HoverEventAction { + pub const SHOW_TEXT: Self = Self { + name: Cow::Borrowed("show_text"), + parsable: true, + }; + + pub const SHOW_ITEM: Self = Self { + name: Cow::Borrowed("show_item"), + parsable: true, + }; + + pub const SHOW_ENTITY: Self = Self { + name: Cow::Borrowed("show_entity"), + parsable: true, + }; + #[inline] pub fn name(&self) -> &str { &self.name @@ -287,11 +340,39 @@ impl HoverEventAction { pub fn is_parsable(&self) -> bool { self.parsable } + + pub fn from_name(name: &str) -> Option<&'static Self> { + HE_MAPPING.get(name) + } } impl Debug for HoverEventAction { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "", self.name) + write!(f, "", self.name) + } +} + +impl Serialize for HoverEventAction { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.name().serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for &'static HoverEventAction { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + static VARIANTS: Lazy> = + Lazy::new(|| HE_MAPPING.iter().map(|v| v.0.as_str()).collect()); + let value = String::deserialize(deserializer)?; + + use serde::de::Error; + HoverEventAction::from_name(&value) + .ok_or_else(|| D::Error::unknown_variant(&value, &VARIANTS)) } }