2022-03-02 21:58:17 +01:00
|
|
|
use std::fmt::{Formatter, Write};
|
2022-03-01 20:45:10 +01:00
|
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
2022-03-02 21:58:17 +01:00
|
|
|
use serde::de::{EnumAccess, Error, MapAccess, SeqAccess, Visitor};
|
2022-03-01 20:45:10 +01:00
|
|
|
use lixcraft_derive::Wrapper;
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Wrapper)]
|
|
|
|
pub struct VarInt(pub i32);
|
|
|
|
|
|
|
|
impl From<VarInt> for usize {
|
|
|
|
fn from(v: VarInt) -> Self {
|
|
|
|
v.0 as usize
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<usize> for VarInt {
|
|
|
|
fn from(v: usize) -> Self {
|
|
|
|
VarInt(v as i32)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serialize for VarInt {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
|
|
|
let mut v = self.0 as u32;
|
2022-03-02 21:58:17 +01:00
|
|
|
let mut result = Vec::with_capacity(5);
|
2022-03-01 20:45:10 +01:00
|
|
|
loop {
|
|
|
|
if v & 0x80 == 0 {
|
2022-03-02 21:58:17 +01:00
|
|
|
result.push(v as u8);
|
|
|
|
return serializer.serialize_bytes(&result);
|
2022-03-01 20:45:10 +01:00
|
|
|
}
|
|
|
|
|
2022-03-02 21:58:17 +01:00
|
|
|
result.push((v as u8 & 0x7f) | 0x80);
|
2022-03-01 20:45:10 +01:00
|
|
|
v >>= 7;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'de> Deserialize<'de> for VarInt {
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
|
|
|
let mut num_read = 0;
|
|
|
|
let mut result = 0;
|
|
|
|
loop {
|
2022-03-02 21:58:17 +01:00
|
|
|
let read = (&mut *deserializer).deserialize_u8(VarIntVisitor{})?;
|
2022-03-01 20:45:10 +01:00
|
|
|
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
|
|
|
VarInt::from(match self {
|
|
|
|
NextState::Status => 1,
|
|
|
|
NextState::Login => 2
|
|
|
|
}).serialize(serializer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'de> Deserialize<'de> for NextState {
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 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 {
|
2022-03-02 21:58:17 +01:00
|
|
|
pub name: String,
|
|
|
|
pub protocol: i32
|
2022-03-01 20:45:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
pub struct StatusResponseSample {
|
2022-03-02 21:58:17 +01:00
|
|
|
pub name: String,
|
|
|
|
pub id: String
|
2022-03-01 20:45:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
pub struct StatusResponsePlayers {
|
2022-03-02 21:58:17 +01:00
|
|
|
pub max: i32,
|
|
|
|
pub online: i32,
|
|
|
|
pub sample: Vec<StatusResponseSample>
|
2022-03-01 20:45:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
pub struct StatusResponseDescription {
|
2022-03-02 21:58:17 +01:00
|
|
|
pub text: String
|
2022-03-01 20:45:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct StatusResponse {
|
2022-03-02 21:58:17 +01:00
|
|
|
pub version: StatusResponseVersion,
|
|
|
|
pub players: StatusResponsePlayers,
|
|
|
|
pub description: StatusResponseDescription,
|
2022-03-01 20:45:10 +01:00
|
|
|
//#[serde(skip_serializing_if = "Option::is_none")]
|
2022-03-02 21:58:17 +01:00
|
|
|
pub favicon: Option<String>
|
2022-03-01 20:45:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Serialize for StatusResponse {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 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<D>(deserializer: D) -> Result<Self, D::Error> 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)
|
|
|
|
}
|
|
|
|
}
|
2022-03-02 21:58:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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<Chat>
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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
|
|
|
|
}
|
2022-03-01 20:45:10 +01:00
|
|
|
}
|