use std::fmt::{Formatter, Write}; use std::ops::{Deref, DerefMut}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::de::{EnumAccess, Error, MapAccess, SeqAccess, Visitor}; use lixcraft_derive::Wrapper; #[derive(Copy, Clone, Debug, PartialEq, Eq, Wrapper)] pub struct VarInt(pub i32); impl From for usize { fn from(v: VarInt) -> Self { v.0 as usize } } impl From for VarInt { fn from(v: usize) -> Self { VarInt(v as i32) } } impl Serialize for VarInt { fn serialize(&self, serializer: S) -> Result where S: Serializer { let mut v = self.0 as u32; let mut result = Vec::with_capacity(5); loop { if v & 0x80 == 0 { result.push(v as u8); return serializer.serialize_bytes(&result); } result.push((v as u8 & 0x7f) | 0x80); v >>= 7; } } } impl<'de> Deserialize<'de> for VarInt { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { let mut num_read = 0; let mut result = 0; loop { let read = (&mut *deserializer).deserialize_u8(VarIntVisitor{})?; let value = i32::from(read & 0b0111_1111); result |= value.overflowing_shl(7 * num_read).0; num_read += 1; if num_read > 5 { return Err(D::Error::custom("VarInt too large")); } if read & 0b1000_0000 == 0 { break; } } Ok(VarInt(result)) } } #[derive(Debug)] pub enum NextState { Status, Login } impl Serialize for NextState { fn serialize(&self, serializer: S) -> Result where S: Serializer { VarInt::from(match self { NextState::Status => 1, NextState::Login => 2 }).serialize(serializer) } } impl<'de> Deserialize<'de> for NextState { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { match VarInt::deserialize(deserializer)? { VarInt(1) => Ok(NextState::Status), VarInt(2) => Ok(NextState::Login), _ => Err(D::Error::custom("Invalid NextState")) } } } #[derive(Debug, Serialize, Deserialize)] pub struct StatusResponseVersion { pub name: String, pub protocol: i32 } #[derive(Debug, Serialize, Deserialize)] pub struct StatusResponseSample { pub name: String, pub id: String } #[derive(Debug, Serialize, Deserialize)] pub struct StatusResponsePlayers { pub max: i32, pub online: i32, pub sample: Vec } #[derive(Debug, Serialize, Deserialize)] pub struct StatusResponseDescription { pub text: String } #[derive(Debug)] pub struct StatusResponse { pub version: StatusResponseVersion, pub players: StatusResponsePlayers, pub description: StatusResponseDescription, //#[serde(skip_serializing_if = "Option::is_none")] pub favicon: Option } impl Serialize for StatusResponse { fn serialize(&self, serializer: S) -> Result where S: Serializer { serializer.serialize_str(&match serde_json::to_string(self) { Ok(v) => v, Err(_) => return Err(serde::ser::Error::custom("Could not serialize status response")) }) } } impl<'de> Deserialize<'de> for StatusResponse { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { match String::deserialize(deserializer) { Ok(json) => match serde_json::from_str(&json) { Ok(v) => Ok(v), Err(_) => Err(D::Error::custom("Could not parse json status response")) }, Err(err) => Err(err) } } } #[derive(Debug, Serialize, Deserialize)] //TODO: Serialize, Deserialize pub enum Font { Uniform, //minecraft:uniform Alt, //minecraft:alt Default //minecraft:default } #[derive(Debug, Serialize, Deserialize)] pub enum ClickEventAction { open_url, run_command, suggest_command, change_page, copy_to_clipboard } #[derive(Debug, Serialize, Deserialize)] pub struct ClickEvent { action: ClickEventAction, value: String } #[derive(Debug, Serialize, Deserialize)] pub enum HoverEventAction { show_text, show_item, show_entity } #[derive(Debug, Serialize, Deserialize)] pub struct HoverEvent { action: HoverEventAction, value: String //or Chat (Recursion!) } #[derive(Debug, Serialize, Deserialize)] pub struct SharedChat { //#[serde(skip_serializing_if = "Option::is_none")] bold: bool, //#[serde(skip_serializing_if = "Option::is_none")] italic: bool, //#[serde(skip_serializing_if = "Option::is_none")] underlined: bool, //#[serde(skip_serializing_if = "Option::is_none")] strikethrough: bool, //#[serde(skip_serializing_if = "Option::is_none")] obfuscated: bool, //#[serde(skip_serializing_if = "Option::is_none")] font: Font, //#[serde(skip_serializing_if = "Option::is_none")] color: String, //TODO Color code, format code or hex code //#[serde(skip_serializing_if = "Option::is_none")] insertion: String, //#[serde(skip_serializing_if = "Option::is_none")] clickEvent: ClickEvent, //#[serde(skip_serializing_if = "Option::is_none")] hoverEvent: HoverEvent, //#[serde(skip_serializing_if = "Option::is_none")] extra: Vec } #[derive(Debug, Serialize, Deserialize)] pub struct Score { name: String, //Or UUID objective: String, value: String } #[derive(Debug, Serialize, Deserialize)] //TODO: Serialize, Deserialize pub enum Chat { StringComponent { #[serde(flatten)] options: SharedChat, text: String }, TranslationComponent { #[serde(flatten)] options: SharedChat, translate: String //TODO Special strings }, KeybindComponent { #[serde(flatten)] options: SharedChat, keybind: String }, ScoreComponent { #[serde(flatten)] options: SharedChat, score: Score }, SelectorComponent { #[serde(flatten)] options: SharedChat, selector: String //TODO ominous } }