From 6637b25e7784a71b2fb59f08191462a946205c4a Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Fri, 17 Jun 2022 19:18:36 -0400 Subject: [PATCH 01/14] Parses Types up to entityMetadataLoop --- src/api/mod.rs | 4 + src/api/protocol.rs | 17 ++ src/api/tests/mod.rs | 1 + src/api/tests/protocol.rs | 22 +++ src/data/mod.rs | 1 - src/models/mod.rs | 1 + src/models/protocol/mod.rs | 8 + src/models/protocol/types.rs | 360 +++++++++++++++++++++++++++++++++++ 8 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 src/api/protocol.rs create mode 100644 src/api/tests/protocol.rs create mode 100644 src/models/protocol/mod.rs create mode 100644 src/models/protocol/types.rs diff --git a/src/api/mod.rs b/src/api/mod.rs index 9d3ddcd..94ed6aa 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -23,6 +23,7 @@ mod items; mod loot; mod recipes; mod versions; +mod protocol; pub use biomes::*; pub use blocks::*; @@ -33,6 +34,7 @@ pub use items::*; pub use loot::*; pub use recipes::*; pub use versions::*; +use crate::api::protocol::Protocol; /// A type wrapping access to all the metadata /// about the selected minecraft version @@ -47,6 +49,7 @@ pub struct Api { pub foods: Foods, pub biomes: Biomes, pub entities: Entities, + pub protocols: Protocol, } impl Api { @@ -68,6 +71,7 @@ impl Api { foods: Foods::new(Arc::clone(&version)), biomes: Biomes::new(Arc::clone(&version)), entities: Entities::new(Arc::clone(&version)), + protocols: Protocol::new(Arc::clone(&version)), } } } diff --git a/src/api/protocol.rs b/src/api/protocol.rs new file mode 100644 index 0000000..60668bf --- /dev/null +++ b/src/api/protocol.rs @@ -0,0 +1,17 @@ +use std::sync::Arc; +use crate::data::{get_version_specific_file, PROTOCOL_FILE}; +use crate::{DataError, DataResult}; +use crate::models::version::Version; + +pub struct Protocol { + version: Arc, +} +impl Protocol{ + pub fn new(version: Arc) -> Self { + Self { version } + } + pub fn get_protocol(&self) -> DataResult { + let content = get_version_specific_file(&self.version, PROTOCOL_FILE)?; + serde_json::from_str(&content).map_err(DataError::from) + } +} \ No newline at end of file diff --git a/src/api/tests/mod.rs b/src/api/tests/mod.rs index e6b8478..3fa52ce 100644 --- a/src/api/tests/mod.rs +++ b/src/api/tests/mod.rs @@ -11,6 +11,7 @@ mod items; mod loot; mod recipes; mod versions; +mod protocol; fn get_api(version: Version) -> Api { Api::new(version) diff --git a/src/api/tests/protocol.rs b/src/api/tests/protocol.rs new file mode 100644 index 0000000..9aa8705 --- /dev/null +++ b/src/api/tests/protocol.rs @@ -0,0 +1,22 @@ +use std::sync::Arc; +use crate::Api; +use crate::api::protocol::Protocol; +use crate::api::tests::get_test_versions; +use crate::models::protocol::PacketDataType; + +#[test] +pub fn simple_test(){ + let versions = get_test_versions(); + for x in versions { + let protocol = Protocol::new(Arc::new(x)); + let protocol1 = protocol.get_protocol().unwrap(); + for protocol in protocol1.types.types { + match protocol { + PacketDataType::Other(other, data) => { + println!("{:?} data {:?}", other,data); + } + _ => {} + } + } + } +} \ No newline at end of file diff --git a/src/data/mod.rs b/src/data/mod.rs index b686921..1cee2a5 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -21,7 +21,6 @@ pub static ITEMS_FILE: &str = "items"; pub static LOGIN_PACKET_FILE: &str = "loginPacket"; #[allow(unused)] pub static MATERIALS_FILE: &str = "materials"; -#[allow(unused)] pub static PROTOCOL_FILE: &str = "protocol"; pub static RECIPES_FILE: &str = "recipes"; #[allow(unused)] diff --git a/src/models/mod.rs b/src/models/mod.rs index 5e61955..2e85b67 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -9,3 +9,4 @@ pub mod food; pub mod item; pub mod recipe; pub mod version; +pub mod protocol; diff --git a/src/models/protocol/mod.rs b/src/models/protocol/mod.rs new file mode 100644 index 0000000..5b6b9f6 --- /dev/null +++ b/src/models/protocol/mod.rs @@ -0,0 +1,8 @@ +pub mod types; +pub use types::{NativeType, PacketDataTypes, PacketDataType,BitField}; +use serde::Deserialize; +#[derive(Deserialize)] +pub struct Protocol { + pub types: PacketDataTypes, +} + diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs new file mode 100644 index 0000000..3151711 --- /dev/null +++ b/src/models/protocol/types.rs @@ -0,0 +1,360 @@ +use std::collections::HashMap; +use std::fmt::Formatter; +use serde::{Deserialize, Deserializer}; +use serde::de::Visitor; +use serde_json::Value; + +pub struct BitField { + name: String, + size: usize, + signed: bool, +} + +/// These data types should be available in every version. +/// However, they won't break anything if not present +/// This can also be known as the Native Types +pub enum NativeType { + /// Please read the following link for information on parsing https://wiki.vg/Protocol#VarInt_and_VarLong + VarInt, + PString { + count_type: Box + }, + Buffer { + count_type: Box, + }, + Bool, + U8, + U16, + U32, + U64, + I8, + I16, + I32, + I64, + F32, + F64, + Uuid, + // Optional + Option(Box), + EntityMetadataLoop { + end_val: i32, + metadata_type: Box, + }, + TopBitSetTerminatedArray(Box), + BitField(Vec), + // A set of Name and The Type + Container(Vec<(String, Box)>), + Switch { + compare_to: String, + fields: HashMap, + default: Option, + }, + Void, + Array { + count_type: Box, + array_type: Box, + }, + RestBuffer, + NBT, + OptionalNBT, +} + +impl NativeType { + pub fn contains_type(name: &str) -> bool { + match name { + "varint" => true, + "pstring" => true, + "buffer" => true, + "bool" => true, + "u8" => true, + "u16" => true, + "u32" => true, + "u64" => true, + "i8" => true, + "i16" => true, + "i32" => true, + "i64" => true, + "f32" => true, + "f64" => true, + "uuid" => true, + "option" => true, + "entitymetadataloop" => true, + "topbitsetterminatedarray" => true, + "bitfield" => true, + "container" => true, + "switch" => true, + "void" => true, + "array" => true, + "restbuffer" => true, + "nbt" => true, + "optionalnbt" => true, + _ => false, + } + } + pub fn new(name: &str, layout: Option) -> Option { + match name { + "varint" => Some(NativeType::VarInt), + "pstring" => { + if let Some(layout) = layout { + if let Some(value) = &layout.as_object().unwrap().get("countType") { + if let Some(count_type) = NativeType::new(value.as_str().unwrap(), None) { + Some(NativeType::PString { + count_type: Box::new(count_type), + }) + } else { + None + } + } else { + None + } + } else { + None + } + } + "buffer" => { + if let Some(layout) = layout { + if let Some(count_type) = NativeType::new(&layout["countType"].as_str().unwrap(), None) { + Some(NativeType::Buffer { + count_type: Box::new(count_type), + }) + } else { + None + } + } else { None } + } + "bool" => Some(NativeType::Bool), + "u8" => Some(NativeType::U8), + "u16" => Some(NativeType::U16), + "u32" => Some(NativeType::U32), + "u64" => Some(NativeType::U64), + "i8" => Some(NativeType::I8), + "i16" => Some(NativeType::I16), + "i32" => Some(NativeType::I32), + "i64" => Some(NativeType::I64), + "f32" => Some(NativeType::F32), + "f64" => Some(NativeType::F64), + "uuid" => Some(NativeType::Uuid), + "option" => { + if let Some(layout) = layout { + let option = layout.as_array().unwrap().get(1); + + if let Some(option_type) = option { + let key = option_type.as_str().unwrap(); + let value = PacketDataType::new(key, None).or(Self::new(key, None).and_then(|x| Some(PacketDataType::Native(x)))); + Some(NativeType::Option(Box::new(value.unwrap()))) + } else { + None + } + } else { + None + } + } + "entitymetadataloop" => { + if let Some(layout) = layout { + if let Some(end_val) = layout["endVal"].as_i64() { + let value1 = layout["type"].as_array().unwrap(); + if let Some(metadata_type) = NativeType::new(&value1.get(0).unwrap().to_string(), value1.get(1).cloned()) { + Some(NativeType::EntityMetadataLoop { + end_val: end_val as i32, + metadata_type: Box::new(metadata_type), + }) + } else { + None + } + } else { + None + } + } else { + None + } + } + "topbitsetterminatedarray" => { + if let Some(layout) = layout { + if let Some(count_type) = NativeType::new(&layout["countType"].as_str().unwrap(), None) { + Some(NativeType::TopBitSetTerminatedArray(Box::new(count_type))) + } else { + None + } + } else { + None + } + } + "bitfield" => { + if let Some(layout) = layout { + let bit_fields = layout.as_array().unwrap(); + let mut bit_fields_vec = Vec::new(); + for bit_field in bit_fields { + if let Some(name) = bit_field["name"].as_str() { + if let Some(size) = bit_field["size"].as_i64() { + if let Some(signed) = bit_field["signed"].as_bool() { + bit_fields_vec.push(BitField { + name: name.to_string(), + size: size as usize, + signed: signed, + }); + } + } + } + } + Some(NativeType::BitField(bit_fields_vec)) + } else { + None + } + } + "container" => { + if let Some(layout) = layout { + let containers = layout.as_array().unwrap(); + let mut containers_vec = Vec::new(); + for container in containers { + if let Some(name) = container["name"].as_str() { + if let Some(type_) = container["type"].as_str() { + containers_vec.push((name.to_string(), Box::new(PacketDataType::new(type_, None).or(Self::new(type_, None). + and_then(|x| Some(PacketDataType::Native(x)))).unwrap()))); + } + } + } + Some(NativeType::Container(containers_vec)) + } else { + None + } + } + "switch" => { + if let Some(layout) = layout { + if let Some(name) = layout["compareTo"].as_str() { + if let Some(fields) = layout["fields"].as_object() { + let fields = fields.iter().map(|(key, v)| { + (key.to_string(), v.to_string()) + }).collect(); + return Some(NativeType::Switch { + compare_to: name.to_string(), + fields: fields, + default: None, + }); + } + } + } + None + } + "void" => Some(NativeType::Void), + "array" => { + if let Some(layout) = layout { + let value = layout.as_object().unwrap(); + if let Some(count_type) = NativeType::new(&value.get("countType").unwrap().as_str().unwrap(), None) { + let type_ = value.get("type").unwrap(); + if let Some(type_) = &type_.as_str() { + return Some(NativeType::Array { + count_type: Box::new(count_type), + array_type: Box::new(PacketDataType::new(type_, None).or(Self::new(type_, None). + and_then(|x| Some(PacketDataType::Native(x)))).unwrap()), + }); + } else if let Some(array) = type_.as_array() { + let key = array.get(0).unwrap().as_str().unwrap(); + if let Some(inner_type) = PacketDataType::new(key, array.get(1).cloned()). + or(Self::new(key, array.get(1).cloned()).and_then(|x| Some(PacketDataType::Native(x)))) { + return Some(NativeType::Array { + count_type: Box::new(count_type), + array_type: Box::new(inner_type), + }); + }else{ + println!("Could not parse array type: {}", key); + } + + } + }else{ + return None; + } + } + return None; + } + + "restbuffer" => Some(NativeType::RestBuffer), + "nbt" => Some(NativeType::NBT), + "optionalnbt" => Some(NativeType::OptionalNBT), + _ => None, + } + } +} + +pub enum PacketDataType { + // Just a pure native type + Native(NativeType), + // It was marked as "native" however, this enum does not have it + UnknownNativeType(String), + // This type is built from a native type + Built(NativeType), + + Other(String, Value), +} + +impl PacketDataType { + pub fn new(key: &str, value: Option) -> Option { + if !NativeType::contains_type(&key) { + let value = value.unwrap_or_default(); + if value.is_string() { + Some(PacketDataType::UnknownNativeType(key.to_string())) + } else if let Some(array) = value.as_array() { + if let Some(name) = array.get(0) { + if let Some(name) = name.as_str() { + let option = value.get(1).cloned(); + let other_type = NativeType::new(&name, option.clone()); + if let Some(type_) = other_type { + Some(PacketDataType::Built(type_)) + } else { + Some(PacketDataType::Other(name.to_string(), option.unwrap_or_default())) + } + } else { + Some(PacketDataType::Other(key.to_string(), value)) + } + } else { + None + } + } else { + Some(PacketDataType::Other(key.to_string(), value)) + } + } else { + None + } + } +} + +pub struct PacketDataTypes { + pub types: Vec, +} + +use std::fmt; + +use serde::de::{self, SeqAccess, MapAccess}; + +impl<'de> Deserialize<'de> for PacketDataTypes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PacketDataTypesVisitor; + + impl<'de> Visitor<'de> for PacketDataTypesVisitor { + type Value = PacketDataTypes; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct PacketDataTypes") + } + + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + let mut types = Vec::new(); + while let Some(key) = map.next_key::()? { + let value = map.next_value::()?; + if let Some(ty) = PacketDataType::new(&key, Some(value)) { + types.push(ty); + } + } + Ok(PacketDataTypes { types }) + } + } + + deserializer.deserialize_map(PacketDataTypesVisitor) + } +} \ No newline at end of file From 1452ced77f01d47d65c2a55d3566279c35146063 Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Sat, 18 Jun 2022 09:05:20 -0400 Subject: [PATCH 02/14] Parses the Types Section of the protocol.json --- src/api/items.rs | 2 +- src/api/mod.rs | 4 +- src/api/protocol.rs | 8 +- src/api/tests/mod.rs | 2 +- src/api/tests/protocol.rs | 10 +- src/api/versions.rs | 2 +- src/data/mod.rs | 16 +- src/models/mod.rs | 2 +- src/models/protocol/mod.rs | 7 +- src/models/protocol/types.rs | 361 +++++++++++++++++------------------ 10 files changed, 203 insertions(+), 211 deletions(-) diff --git a/src/api/items.rs b/src/api/items.rs index 411df08..400f758 100644 --- a/src/api/items.rs +++ b/src/api/items.rs @@ -36,7 +36,7 @@ impl Items { Ok(self .items_array()? .into_iter() - .map(|i| (i.id.clone(), i)) + .map(|i| (i.id, i)) .collect()) } } diff --git a/src/api/mod.rs b/src/api/mod.rs index 94ed6aa..2ab9838 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -21,10 +21,11 @@ mod entities; mod foods; mod items; mod loot; +mod protocol; mod recipes; mod versions; -mod protocol; +use crate::api::protocol::Protocol; pub use biomes::*; pub use blocks::*; pub use enchantments::*; @@ -34,7 +35,6 @@ pub use items::*; pub use loot::*; pub use recipes::*; pub use versions::*; -use crate::api::protocol::Protocol; /// A type wrapping access to all the metadata /// about the selected minecraft version diff --git a/src/api/protocol.rs b/src/api/protocol.rs index 60668bf..1ccbd43 100644 --- a/src/api/protocol.rs +++ b/src/api/protocol.rs @@ -1,12 +1,12 @@ -use std::sync::Arc; use crate::data::{get_version_specific_file, PROTOCOL_FILE}; -use crate::{DataError, DataResult}; use crate::models::version::Version; +use crate::{DataError, DataResult}; +use std::sync::Arc; pub struct Protocol { version: Arc, } -impl Protocol{ +impl Protocol { pub fn new(version: Arc) -> Self { Self { version } } @@ -14,4 +14,4 @@ impl Protocol{ let content = get_version_specific_file(&self.version, PROTOCOL_FILE)?; serde_json::from_str(&content).map_err(DataError::from) } -} \ No newline at end of file +} diff --git a/src/api/tests/mod.rs b/src/api/tests/mod.rs index 3fa52ce..89437cc 100644 --- a/src/api/tests/mod.rs +++ b/src/api/tests/mod.rs @@ -9,9 +9,9 @@ mod entities; mod foods; mod items; mod loot; +mod protocol; mod recipes; mod versions; -mod protocol; fn get_api(version: Version) -> Api { Api::new(version) diff --git a/src/api/tests/protocol.rs b/src/api/tests/protocol.rs index 9aa8705..f6f09f8 100644 --- a/src/api/tests/protocol.rs +++ b/src/api/tests/protocol.rs @@ -1,11 +1,11 @@ -use std::sync::Arc; -use crate::Api; use crate::api::protocol::Protocol; use crate::api::tests::get_test_versions; use crate::models::protocol::PacketDataType; +use crate::Api; +use std::sync::Arc; #[test] -pub fn simple_test(){ +pub fn simple_test() { let versions = get_test_versions(); for x in versions { let protocol = Protocol::new(Arc::new(x)); @@ -13,10 +13,10 @@ pub fn simple_test(){ for protocol in protocol1.types.types { match protocol { PacketDataType::Other(other, data) => { - println!("{:?} data {:?}", other,data); + println!("{:?} data {:?}", other, data); } _ => {} } } } -} \ No newline at end of file +} diff --git a/src/api/versions.rs b/src/api/versions.rs index 516ce10..4a1fe57 100644 --- a/src/api/versions.rs +++ b/src/api/versions.rs @@ -29,7 +29,7 @@ pub fn latest_stable() -> DataResult { .into_iter() .filter_map(|v| { let version_string = v.clone(); - let mut parts = version_string.split("."); + let mut parts = version_string.split('.'); Some(( v, diff --git a/src/data/mod.rs b/src/data/mod.rs index 1cee2a5..014a878 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -39,9 +39,9 @@ pub static VERSIONS_FILE: &str = "versions"; pub fn get_common_file(filename: &str) -> DataResult { MINECRAFT_DATA .get_file(format!("pc/common/{}.json", filename)) - .ok_or(DataError::NotFoundError(filename.to_string()))? + .ok_or_else(||DataError::NotFoundError(filename.to_string()))? .contents_utf8() - .ok_or(DataError::InvalidEncodingError(filename.to_string())) + .ok_or_else(||DataError::InvalidEncodingError(filename.to_string())) .map(|d| d.to_string()) } @@ -50,12 +50,12 @@ pub fn get_version_specific_file(version: &Version, filename: &str) -> DataResul let path = get_path(version, filename)?; MINECRAFT_DATA .get_file(format!("{}/{}.json", path, filename)) - .ok_or(DataError::NotFoundError(format!( + .ok_or_else(||DataError::NotFoundError(format!( "{}/{}", version.minecraft_version, filename )))? .contents_utf8() - .ok_or(DataError::InvalidEncodingError(filename.to_string())) + .ok_or_else(||DataError::InvalidEncodingError(filename.to_string())) .map(|d| d.to_string()) } @@ -67,19 +67,19 @@ pub fn get_path(version: &Version, filename: &str) -> DataResult { PATHS .pc .get(&version.minecraft_version) - .ok_or(DataError::NotFoundError(version.minecraft_version.clone()))? + .ok_or_else(||DataError::NotFoundError(version.minecraft_version.clone()))? .get(filename) .cloned() - .ok_or(DataError::NotFoundError(filename.to_string())) + .ok_or_else(||DataError::NotFoundError(filename.to_string())) } /// Returns the parsed data paths fn get_datapaths() -> DataResult { let content = MINECRAFT_DATA .get_file("dataPaths.json") - .ok_or(DataError::NotFoundError("dataPaths.json".to_string()))? + .ok_or_else(||DataError::NotFoundError("dataPaths.json".to_string()))? .contents_utf8() - .ok_or(DataError::InvalidEncodingError( + .ok_or_else(||DataError::InvalidEncodingError( "dataPaths.json".to_string(), ))?; serde_json::from_str::(content).map_err(DataError::from) diff --git a/src/models/mod.rs b/src/models/mod.rs index 2e85b67..a5eed0f 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -7,6 +7,6 @@ pub mod entity; pub mod entity_loot; pub mod food; pub mod item; +pub mod protocol; pub mod recipe; pub mod version; -pub mod protocol; diff --git a/src/models/protocol/mod.rs b/src/models/protocol/mod.rs index 5b6b9f6..e69c813 100644 --- a/src/models/protocol/mod.rs +++ b/src/models/protocol/mod.rs @@ -1,8 +1,9 @@ pub mod types; -pub use types::{NativeType, PacketDataTypes, PacketDataType,BitField}; -use serde::Deserialize; + + +pub use types::{BitField, NativeType, PacketDataType, PacketDataTypes}; + #[derive(Deserialize)] pub struct Protocol { pub types: PacketDataTypes, } - diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index 3151711..faf4805 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -1,13 +1,14 @@ -use std::collections::HashMap; -use std::fmt::Formatter; -use serde::{Deserialize, Deserializer}; use serde::de::Visitor; +use serde::{Deserialize, Deserializer}; use serde_json::Value; +use std::borrow::{Cow}; +use std::collections::HashMap; +#[derive(Deserialize)] pub struct BitField { - name: String, - size: usize, - signed: bool, + pub name: String, + pub size: i64, + pub signed: bool, } /// These data types should be available in every version. @@ -17,7 +18,7 @@ pub enum NativeType { /// Please read the following link for information on parsing https://wiki.vg/Protocol#VarInt_and_VarLong VarInt, PString { - count_type: Box + count_type: Box, }, Buffer { count_type: Box, @@ -37,10 +38,10 @@ pub enum NativeType { // Optional Option(Box), EntityMetadataLoop { - end_val: i32, - metadata_type: Box, + end_val: i64, + metadata_type: Box, }, - TopBitSetTerminatedArray(Box), + TopBitSetTerminatedArray(Box), BitField(Vec), // A set of Name and The Type Container(Vec<(String, Box)>), @@ -61,66 +62,37 @@ pub enum NativeType { impl NativeType { pub fn contains_type(name: &str) -> bool { - match name { - "varint" => true, - "pstring" => true, - "buffer" => true, - "bool" => true, - "u8" => true, - "u16" => true, - "u32" => true, - "u64" => true, - "i8" => true, - "i16" => true, - "i32" => true, - "i64" => true, - "f32" => true, - "f64" => true, - "uuid" => true, - "option" => true, - "entitymetadataloop" => true, - "topbitsetterminatedarray" => true, - "bitfield" => true, - "container" => true, - "switch" => true, - "void" => true, - "array" => true, - "restbuffer" => true, - "nbt" => true, - "optionalnbt" => true, - _ => false, - } + matches!(name, "varint" | "pstring" | "buffer" | "bool" | "u8" | "u16" | "u32" | "u64" | "i8" | "i16" | "i32" | "i64" | "f32" | "f64" | "uuid" | "option" | "entityMetadataLoop" | "topbitsetterminatedarray" | "bitfield" | "container" | "switch" | "void" | "array" | "restbuffer" | "nbt" | "optionalnbt") } - pub fn new(name: &str, layout: Option) -> Option { + pub fn new(name: &str, layout: Cow<'_, Value>) -> Option { match name { "varint" => Some(NativeType::VarInt), "pstring" => { - if let Some(layout) = layout { - if let Some(value) = &layout.as_object().unwrap().get("countType") { - if let Some(count_type) = NativeType::new(value.as_str().unwrap(), None) { - Some(NativeType::PString { + if let Value::Object(mut obj) = layout.into_owned() { + if let Value::String(count_type) = obj.remove("countType").unwrap_or_default() { + if let Some(count_type) = + NativeType::new(&count_type, Cow::Owned(Value::Null)) { + return Some(NativeType::PString { count_type: Box::new(count_type), - }) - } else { - None + }); } - } else { - None } - } else { - None } + None } "buffer" => { - if let Some(layout) = layout { - if let Some(count_type) = NativeType::new(&layout["countType"].as_str().unwrap(), None) { - Some(NativeType::Buffer { - count_type: Box::new(count_type), - }) - } else { - None + if let Value::Object(mut obj) = layout.into_owned() { + if let Value::String(count_type) = obj.remove("countType").unwrap_or_default() { + if let Some(count_type) = + NativeType::new(&count_type, Cow::Owned(Value::Null)) + { + return Some(NativeType::PString { + count_type: Box::new(count_type), + }); + } } - } else { None } + } + None } "bool" => Some(NativeType::Bool), "u8" => Some(NativeType::U8), @@ -134,137 +106,115 @@ impl NativeType { "f32" => Some(NativeType::F32), "f64" => Some(NativeType::F64), "uuid" => Some(NativeType::Uuid), - "option" => { - if let Some(layout) = layout { - let option = layout.as_array().unwrap().get(1); - - if let Some(option_type) = option { - let key = option_type.as_str().unwrap(); - let value = PacketDataType::new(key, None).or(Self::new(key, None).and_then(|x| Some(PacketDataType::Native(x)))); - Some(NativeType::Option(Box::new(value.unwrap()))) - } else { - None + "option" => Some(NativeType::Option(build_inner_type(layout.into_owned()))), + "entityMetadataLoop" => { + match layout.into_owned() { + Value::Object(mut layout) => { + let end_val = layout + .remove("endVal") + .and_then(|v| v.as_i64()) + .unwrap_or_default(); + let inner_type = layout.remove("type").unwrap_or_default(); + let inner_type = build_inner_type(inner_type); + Some(NativeType::EntityMetadataLoop { + end_val, + metadata_type: inner_type, + }) } - } else { - None - } - } - "entitymetadataloop" => { - if let Some(layout) = layout { - if let Some(end_val) = layout["endVal"].as_i64() { - let value1 = layout["type"].as_array().unwrap(); - if let Some(metadata_type) = NativeType::new(&value1.get(0).unwrap().to_string(), value1.get(1).cloned()) { - Some(NativeType::EntityMetadataLoop { - end_val: end_val as i32, - metadata_type: Box::new(metadata_type), - }) - } else { - None - } - } else { - None - } - } else { - None + _ => None, } } "topbitsetterminatedarray" => { - if let Some(layout) = layout { - if let Some(count_type) = NativeType::new(&layout["countType"].as_str().unwrap(), None) { - Some(NativeType::TopBitSetTerminatedArray(Box::new(count_type))) - } else { - None - } - } else { - None + if let Value::Object(mut layout) = layout.into_owned() { + let inner_type = layout.remove("type").unwrap_or_default(); + let inner_type = build_inner_type(inner_type); + return Some(NativeType::TopBitSetTerminatedArray(inner_type)); } + None } "bitfield" => { - if let Some(layout) = layout { - let bit_fields = layout.as_array().unwrap(); - let mut bit_fields_vec = Vec::new(); - for bit_field in bit_fields { - if let Some(name) = bit_field["name"].as_str() { - if let Some(size) = bit_field["size"].as_i64() { - if let Some(signed) = bit_field["signed"].as_bool() { - bit_fields_vec.push(BitField { - name: name.to_string(), - size: size as usize, - signed: signed, - }); - } - } - } - } + if let Value::Array(bit_fields) = layout.into_owned() { + let bit_fields_vec = bit_fields + .into_iter() + .map(|v| serde_json::from_value(v).unwrap()) + .collect(); + Some(NativeType::BitField(bit_fields_vec)) } else { None } } "container" => { - if let Some(layout) = layout { - let containers = layout.as_array().unwrap(); - let mut containers_vec = Vec::new(); - for container in containers { - if let Some(name) = container["name"].as_str() { - if let Some(type_) = container["type"].as_str() { - containers_vec.push((name.to_string(), Box::new(PacketDataType::new(type_, None).or(Self::new(type_, None). - and_then(|x| Some(PacketDataType::Native(x)))).unwrap()))); + if let Value::Array(containers) = layout.into_owned() { + let containers_vec = containers + .into_iter() + .map(|v| { + if let Value::Object(mut obj) = v { + if let Some(name) = obj.remove("name") { + let name = name.to_string(); + let inner_type = obj.remove("type").unwrap_or_default(); + let inner_type = build_inner_type(inner_type); + (name, inner_type) + } else { + let inner_type = obj.remove("type").unwrap_or_default(); + let inner_type = build_inner_type(inner_type); + (String::new(), inner_type) + } + } else { + panic!("Container is not an object"); } - } - } + }) + .collect(); + Some(NativeType::Container(containers_vec)) } else { None } } + "switch" => { - if let Some(layout) = layout { - if let Some(name) = layout["compareTo"].as_str() { - if let Some(fields) = layout["fields"].as_object() { - let fields = fields.iter().map(|(key, v)| { - (key.to_string(), v.to_string()) - }).collect(); - return Some(NativeType::Switch { - compare_to: name.to_string(), - fields: fields, - default: None, - }); - } - } + if let Value::Object(mut layout) = layout.into_owned() { + return Some(NativeType::Switch { + compare_to: layout.remove("compareTo").unwrap().to_string(), + fields: layout + .remove("fields") + .and_then(|v| { + if let Value::Object(fields) = v { + Some( + fields + .into_iter() + .map(|(k, v)| (k, v.to_string())) + .collect(), + ) + } else { + None + } + }) + .unwrap_or_default(), + default: layout.remove("default").map(|v| v.to_string()), + }); } None } "void" => Some(NativeType::Void), "array" => { - if let Some(layout) = layout { - let value = layout.as_object().unwrap(); - if let Some(count_type) = NativeType::new(&value.get("countType").unwrap().as_str().unwrap(), None) { - let type_ = value.get("type").unwrap(); - if let Some(type_) = &type_.as_str() { - return Some(NativeType::Array { - count_type: Box::new(count_type), - array_type: Box::new(PacketDataType::new(type_, None).or(Self::new(type_, None). - and_then(|x| Some(PacketDataType::Native(x)))).unwrap()), - }); - } else if let Some(array) = type_.as_array() { - let key = array.get(0).unwrap().as_str().unwrap(); - if let Some(inner_type) = PacketDataType::new(key, array.get(1).cloned()). - or(Self::new(key, array.get(1).cloned()).and_then(|x| Some(PacketDataType::Native(x)))) { - return Some(NativeType::Array { - count_type: Box::new(count_type), - array_type: Box::new(inner_type), - }); - }else{ - println!("Could not parse array type: {}", key); - } - - } - }else{ - return None; + if let Value::Object(mut obj) = layout.into_owned() { + let value = NativeType::new( + obj.remove("countType") + .unwrap_or_default() + .as_str() + .unwrap(), + Cow::Owned(Value::Null), + ); + let inner_type = build_inner_type(obj.remove("type").unwrap_or_default()); + if let Some(v) = value { + return Some(NativeType::Array { + count_type: Box::new(v), + array_type: inner_type, + }); } } - return None; + None } "restbuffer" => Some(NativeType::RestBuffer), @@ -275,6 +225,48 @@ impl NativeType { } } +#[inline] +fn build_inner_type(value: Value) -> Box { + match value { + Value::String(simple_type) => { + return if let Some(simple_type) = NativeType::new(&simple_type, Cow::Owned(Value::Null)) + { + Box::new(PacketDataType::Native(simple_type)) + } else { + // Probably a reference to a built type + Box::new(PacketDataType::Other(simple_type, Value::Null)) + }; + } + Value::Array(mut array) => { + if array.len() != 2 { + return Box::new(PacketDataType::Other(String::new(), Value::Array(array))); + } + let inner_value = Cow::Owned(array.pop().unwrap_or_default()); + let key = array.pop().unwrap(); + if let Value::String(key) = &key { + let value = PacketDataType::new(key, Cow::clone(&inner_value)).or_else(|| { + let option = NativeType::new(key, inner_value.clone()); + option.map(PacketDataType::Native) + }); + if let Some(value) = value { + Box::new(value) + } else { + Box::new(PacketDataType::Other( + key.to_string(), + inner_value.into_owned(), + )) + } + } else { + Box::new(PacketDataType::Other( + key.to_string(), + inner_value.into_owned(), + )) + } + } + v => Box::new(PacketDataType::Other(String::new(), v)), + } +} + pub enum PacketDataType { // Just a pure native type Native(NativeType), @@ -287,29 +279,29 @@ pub enum PacketDataType { } impl PacketDataType { - pub fn new(key: &str, value: Option) -> Option { - if !NativeType::contains_type(&key) { - let value = value.unwrap_or_default(); - if value.is_string() { - Some(PacketDataType::UnknownNativeType(key.to_string())) - } else if let Some(array) = value.as_array() { - if let Some(name) = array.get(0) { - if let Some(name) = name.as_str() { - let option = value.get(1).cloned(); - let other_type = NativeType::new(&name, option.clone()); - if let Some(type_) = other_type { + pub fn new(key: &str, value: Cow<'_, Value>) -> Option { + if !NativeType::contains_type(key) { + match value.into_owned() { + Value::String(string) => Some(PacketDataType::UnknownNativeType(string)), + Value::Array(mut array) => { + if array.len() != 2 { + return Some(PacketDataType::Other(key.to_string(), Value::Array(array))); + } + + let inner_type_values = array.pop().unwrap_or_default(); + let inner_type_name = array.pop().unwrap(); + if let Value::String(inner_type_name) = inner_type_name { + return if let Some(type_) = + NativeType::new(&inner_type_name, Cow::Borrowed(&inner_type_values)) + { Some(PacketDataType::Built(type_)) } else { - Some(PacketDataType::Other(name.to_string(), option.unwrap_or_default())) - } - } else { - Some(PacketDataType::Other(key.to_string(), value)) + Some(PacketDataType::Other(inner_type_name, inner_type_values)) + }; } - } else { None } - } else { - Some(PacketDataType::Other(key.to_string(), value)) + _ => None, } } else { None @@ -323,7 +315,7 @@ pub struct PacketDataTypes { use std::fmt; -use serde::de::{self, SeqAccess, MapAccess}; +use serde::de::{MapAccess}; impl<'de> Deserialize<'de> for PacketDataTypes { fn deserialize(deserializer: D) -> Result @@ -339,7 +331,6 @@ impl<'de> Deserialize<'de> for PacketDataTypes { formatter.write_str("struct PacketDataTypes") } - fn visit_map(self, mut map: V) -> Result where V: MapAccess<'de>, @@ -347,7 +338,7 @@ impl<'de> Deserialize<'de> for PacketDataTypes { let mut types = Vec::new(); while let Some(key) = map.next_key::()? { let value = map.next_value::()?; - if let Some(ty) = PacketDataType::new(&key, Some(value)) { + if let Some(ty) = PacketDataType::new(&key, Cow::Owned(value)) { types.push(ty); } } @@ -357,4 +348,4 @@ impl<'de> Deserialize<'de> for PacketDataTypes { deserializer.deserialize_map(PacketDataTypesVisitor) } -} \ No newline at end of file +} From d76dc0d3445c7fe57e0d5df24c9b2c396d6599f1 Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Sat, 18 Jun 2022 10:36:52 -0400 Subject: [PATCH 03/14] Works. However, it is broken on the 21w07a,20w14a,20w13b --- src/api/tests/protocol.rs | 19 ++-- src/models/protocol/mod.rs | 136 ++++++++++++++++++++++++++- src/models/protocol/packet_mapper.rs | 84 +++++++++++++++++ src/models/protocol/types.rs | 7 +- 4 files changed, 232 insertions(+), 14 deletions(-) create mode 100644 src/models/protocol/packet_mapper.rs diff --git a/src/api/tests/protocol.rs b/src/api/tests/protocol.rs index f6f09f8..4b8fdb2 100644 --- a/src/api/tests/protocol.rs +++ b/src/api/tests/protocol.rs @@ -1,21 +1,22 @@ use crate::api::protocol::Protocol; use crate::api::tests::get_test_versions; use crate::models::protocol::PacketDataType; -use crate::Api; use std::sync::Arc; +use crate::DataResult; #[test] pub fn simple_test() { let versions = get_test_versions(); for x in versions { - let protocol = Protocol::new(Arc::new(x)); - let protocol1 = protocol.get_protocol().unwrap(); - for protocol in protocol1.types.types { - match protocol { - PacketDataType::Other(other, data) => { - println!("{:?} data {:?}", other, data); - } - _ => {} + let arc = Arc::new(x); + let protocol = Protocol::new(arc.clone()); + let protocol1 = protocol.get_protocol(); + match protocol1 { + Ok(_) => { + + } + Err(error) => { + println!("{:?} On Version {}", error, arc.minecraft_version); } } } diff --git a/src/models/protocol/mod.rs b/src/models/protocol/mod.rs index e69c813..cd0d608 100644 --- a/src/models/protocol/mod.rs +++ b/src/models/protocol/mod.rs @@ -1,9 +1,141 @@ pub mod types; +pub mod packet_mapper; - +use std::fmt; +use serde::{de, Deserialize, Deserializer}; +use serde::de::{MapAccess, Visitor}; +use serde_json::Value; +pub use packet_mapper::{PacketMapper, PacketSwitch, PacketMapperSwitch}; pub use types::{BitField, NativeType, PacketDataType, PacketDataTypes}; -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] pub struct Protocol { pub types: PacketDataTypes, + pub handshaking: PacketGrouping, + pub status: PacketGrouping, + pub login: PacketGrouping, + pub play: PacketGrouping, +} + +#[derive(Deserialize, Debug)] +pub struct PacketGrouping { + #[serde(rename = "toServer")] + pub to_server: PacketTypes, + #[serde(rename = "toClient")] + pub to_client: PacketTypes, +} + +#[derive(Debug)] +pub enum DataTypeReference { + Simple(String), + Complex { + name: String, + properties: Value, + }, +} + +#[derive(Debug)] +pub struct Packet { + pub name: String, + pub data: Vec<(String, DataTypeReference)>, +} + +#[derive(Debug)] +pub struct PacketTypes { + pub packet_mapper: PacketMapperSwitch, + pub types: Vec, +} + + +impl<'de> Deserialize<'de> for PacketTypes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PacketTypesVisitor; + + impl<'de> Visitor<'de> for PacketTypesVisitor { + type Value = PacketTypes; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Expected a map") + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + while let Some(key) = map.next_key::()? { + if key.eq("types") { + let mut packets = Vec::new(); + let mut packet_mapper = None; + let value = map.next_value::()?; + if let Value::Object(obj) = value { + for (key, value) in obj.into_iter() { + if key.eq("packet") { + if let Value::Array(mut array) = value { + let value = array.pop().ok_or_else(|| de::Error::missing_field("missing content"))?; + let value: PacketMapperSwitch = serde_json::from_value(value).map_err(de::Error::custom)?; + packet_mapper = Some(value); + } else { + return Err(de::Error::custom("Invalid Packet Mapper")); + } + } else if let Value::Array(mut array) = value { + let last = array.pop().ok_or_else(|| de::Error::missing_field("missing content"))?; + if let Value::Array(array) = last { + let mut packet_content = Vec::new(); + for value in array.into_iter() { + if let Value::Object(mut obj) = value { + let name = obj.remove("name"); + let name = if let Some(name) = name { + name.to_string() + }else{ + "anon".to_string() + }; + let value = obj.remove("type").ok_or_else(|| de::Error::custom(format!("Packet ID {} missing type", key)))?; + let value = match value { + Value::String(simple) => { + DataTypeReference::Simple(simple) + } + Value::Array(mut array) => { + let properties = array.pop().ok_or_else(|| de::Error::custom(format!("Packet ID {} missing properties", key)))?; + let name = array.pop().ok_or_else(|| de::Error::custom(format!("Packet ID {} missing name", key)))?.to_string(); + DataTypeReference::Complex { + name, + properties, + } + } + _ => return Err(de::Error::custom(format!("Invalid Packet Invalid Type {}", key))) + }; + packet_content.push((name, value)); + } else { + return Err(de::Error::custom(format!("Invalid Packet Expected Object {}", key))); + } + } + packets.push(Packet { + name: key, + data: packet_content, + }); + } else { + return Err(de::Error::custom(format!("Invalid Packet {}", key))); + } + } else { + return Err(de::Error::custom(format!("Invalid Packet Expected Array {}", key))); + } + } + } + + let packet_mapper = packet_mapper.ok_or_else(|| de::Error::missing_field("packet_mapper"))?; + return Ok(PacketTypes { + packet_mapper, + types: packets, + }); + } + } + Err(de::Error::custom("Expected a types")) + } + } + + deserializer.deserialize_map(PacketTypesVisitor) + } } diff --git a/src/models/protocol/packet_mapper.rs b/src/models/protocol/packet_mapper.rs new file mode 100644 index 0000000..27bda65 --- /dev/null +++ b/src/models/protocol/packet_mapper.rs @@ -0,0 +1,84 @@ +use std::collections::HashMap; +use std::fmt; + +use serde::de::{SeqAccess, Visitor}; +use serde::{de, Deserialize, Deserializer}; +use serde_json::Value; + +#[derive(Deserialize, Debug)] +pub struct PacketMapper { + /// A Type + #[serde(rename = "type")] + pub map_type: String, + pub mappings: HashMap, +} + +#[derive(Deserialize, Debug)] +pub struct PacketSwitch { + #[serde(rename = "compareTo")] + pub compare_to: String, + pub fields: HashMap, +} + +#[derive(Debug)] +pub struct PacketMapperSwitch { + pub mapper: PacketMapper, + pub switch: PacketSwitch, +} + + +impl<'de> Deserialize<'de> for PacketMapperSwitch { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PacketMapperSwitchVisitor; + + impl<'de> Visitor<'de> for PacketMapperSwitchVisitor { + type Value = PacketMapperSwitch; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Expected a sequence") + } + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut mapper = None; + let mut switch = None; + while let Some(value) = seq.next_element::()? { + if let Value::Object(mut value) = value { + let value = value.remove("type").ok_or_else(|| de::Error::missing_field("type"))?; + if let Value::Array(mut array) = value { + let value = array.pop().ok_or_else(|| de::Error::missing_field("missing content"))?; + let key = array.pop().ok_or_else(|| de::Error::missing_field("missing key"))?; + if let Value::String(key) = key { + if key.eq("mapper") { + let value: PacketMapper = serde_json::from_value(value).map_err(de::Error::custom)?; + mapper = Some(value); + } else if key.eq("switch") { + let value: PacketSwitch = serde_json::from_value(value).map_err(de::Error::custom)?; + switch = Some(value); + }else{ + return Err(de::Error::custom("unknown key")); + } + }else{ + return Err(de::Error::custom("unknown key")); + } + } else { + return Err(de::Error::custom("Expected an array")); + } + } + } + let map_type = mapper.ok_or_else(|| de::Error::missing_field("mapper"))?; + let switch = switch.ok_or_else(|| de::Error::missing_field("switch"))?; + Ok(PacketMapperSwitch { + mapper: map_type, + switch, + }) + } + } + + deserializer.deserialize_seq(PacketMapperSwitchVisitor) + } +} diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index faf4805..35539f3 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -4,7 +4,7 @@ use serde_json::Value; use std::borrow::{Cow}; use std::collections::HashMap; -#[derive(Deserialize)] +#[derive(Deserialize,Debug)] pub struct BitField { pub name: String, pub size: i64, @@ -14,6 +14,7 @@ pub struct BitField { /// These data types should be available in every version. /// However, they won't break anything if not present /// This can also be known as the Native Types +#[derive(Debug)] pub enum NativeType { /// Please read the following link for information on parsing https://wiki.vg/Protocol#VarInt_and_VarLong VarInt, @@ -266,7 +267,7 @@ fn build_inner_type(value: Value) -> Box { v => Box::new(PacketDataType::Other(String::new(), v)), } } - +#[derive(Debug)] pub enum PacketDataType { // Just a pure native type Native(NativeType), @@ -308,7 +309,7 @@ impl PacketDataType { } } } - +#[derive(Debug)] pub struct PacketDataTypes { pub types: Vec, } From d2e23ae118cbbf6274e39399b49ac5bfd3457470 Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Sun, 19 Jun 2022 20:58:23 -0400 Subject: [PATCH 04/14] Value::to_string on the String type added "" around the value. Also added a get_name value to the Native Type. --- src/models/protocol/types.rs | 62 ++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index 35539f3..098de22 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -4,7 +4,7 @@ use serde_json::Value; use std::borrow::{Cow}; use std::collections::HashMap; -#[derive(Deserialize,Debug)] +#[derive(Deserialize, Debug)] pub struct BitField { pub name: String, pub size: i64, @@ -152,7 +152,7 @@ impl NativeType { .map(|v| { if let Value::Object(mut obj) = v { if let Some(name) = obj.remove("name") { - let name = name.to_string(); + let name = name.as_str().unwrap().to_string(); let inner_type = obj.remove("type").unwrap_or_default(); let inner_type = build_inner_type(inner_type); (name, inner_type) @@ -176,7 +176,7 @@ impl NativeType { "switch" => { if let Value::Object(mut layout) = layout.into_owned() { return Some(NativeType::Switch { - compare_to: layout.remove("compareTo").unwrap().to_string(), + compare_to: layout.remove("compareTo").unwrap().as_str().unwrap_or_default().to_string(), fields: layout .remove("fields") .and_then(|v| { @@ -184,7 +184,7 @@ impl NativeType { Some( fields .into_iter() - .map(|(k, v)| (k, v.to_string())) + .map(|(k, v)| (k, v.as_str().unwrap_or_default().to_string())) .collect(), ) } else { @@ -192,7 +192,7 @@ impl NativeType { } }) .unwrap_or_default(), - default: layout.remove("default").map(|v| v.to_string()), + default: layout.remove("default").map(|v| v.as_str().unwrap_or_default().to_string()), }); } None @@ -224,6 +224,36 @@ impl NativeType { _ => None, } } + pub fn get_name(&self) -> &str { + match self { + NativeType::Bool => "bool", + NativeType::U8 => "u8", + NativeType::U16 => "u16", + NativeType::U32 => "u32", + NativeType::U64 => "u64", + NativeType::I8 => "i8", + NativeType::I16 => "i16", + NativeType::I32 => "i32", + NativeType::I64 => "i64", + NativeType::F32 => "f32", + NativeType::F64 => "f64", + NativeType::Uuid => "uuid", + NativeType::Option(_) => "option", + NativeType::EntityMetadataLoop { .. } => "entityMetadataLoop", + NativeType::TopBitSetTerminatedArray(_) => "topbitsetterminatedarray", + NativeType::BitField(_) => "bitfield", + NativeType::Container(_) => "container", + NativeType::Switch { .. } => "switch", + NativeType::Array { .. } => "array", + NativeType::Void => "void", + NativeType::RestBuffer => "restbuffer", + NativeType::NBT => "nbt", + NativeType::OptionalNBT => "optionalnbt", + NativeType::VarInt => { "varint" } + NativeType::PString { .. } => { "pstring" } + NativeType::Buffer { .. } => { "buffer" } + } + } } #[inline] @@ -253,13 +283,13 @@ fn build_inner_type(value: Value) -> Box { Box::new(value) } else { Box::new(PacketDataType::Other( - key.to_string(), + key.clone(), inner_value.into_owned(), )) } } else { Box::new(PacketDataType::Other( - key.to_string(), + key.as_str().unwrap_or_default().to_string(), inner_value.into_owned(), )) } @@ -267,6 +297,7 @@ fn build_inner_type(value: Value) -> Box { v => Box::new(PacketDataType::Other(String::new(), v)), } } + #[derive(Debug)] pub enum PacketDataType { // Just a pure native type @@ -274,7 +305,12 @@ pub enum PacketDataType { // It was marked as "native" however, this enum does not have it UnknownNativeType(String), // This type is built from a native type - Built(NativeType), + Built { + // The name of the built type + name: String, + // The value of the built type + value: NativeType, + }, Other(String, Value), } @@ -295,20 +331,26 @@ impl PacketDataType { return if let Some(type_) = NativeType::new(&inner_type_name, Cow::Borrowed(&inner_type_values)) { - Some(PacketDataType::Built(type_)) + Some(PacketDataType::Built { + name: key.to_string(), + value: type_, + }) } else { Some(PacketDataType::Other(inner_type_name, inner_type_values)) }; } None } - _ => None, + v => { + return Some(PacketDataType::Other(key.to_string(), v)); + } } } else { None } } } + #[derive(Debug)] pub struct PacketDataTypes { pub types: Vec, From 2777e30e10cd7e9e2f7d1f90da4785d3e09672c8 Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Sun, 19 Jun 2022 22:10:11 -0400 Subject: [PATCH 05/14] Improves NativeType::Switch --- src/api/tests/protocol.rs | 8 +++----- src/models/protocol/types.rs | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/api/tests/protocol.rs b/src/api/tests/protocol.rs index 4b8fdb2..235c46c 100644 --- a/src/api/tests/protocol.rs +++ b/src/api/tests/protocol.rs @@ -1,6 +1,6 @@ use crate::api::protocol::Protocol; use crate::api::tests::get_test_versions; -use crate::models::protocol::PacketDataType; +use crate::models::protocol::{NativeType, PacketDataType}; use std::sync::Arc; use crate::DataResult; @@ -12,12 +12,10 @@ pub fn simple_test() { let protocol = Protocol::new(arc.clone()); let protocol1 = protocol.get_protocol(); match protocol1 { - Ok(_) => { - - } + Ok(_) => {} Err(error) => { println!("{:?} On Version {}", error, arc.minecraft_version); } } } -} +} \ No newline at end of file diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index 098de22..9607956 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -11,6 +11,13 @@ pub struct BitField { pub signed: bool, } +#[derive(Debug)] +pub enum SwitchType { + Packet(String), + Type(Box), + Unknown(Value), +} + /// These data types should be available in every version. /// However, they won't break anything if not present /// This can also be known as the Native Types @@ -48,7 +55,7 @@ pub enum NativeType { Container(Vec<(String, Box)>), Switch { compare_to: String, - fields: HashMap, + fields: HashMap, default: Option, }, Void, @@ -184,7 +191,19 @@ impl NativeType { Some( fields .into_iter() - .map(|(k, v)| (k, v.as_str().unwrap_or_default().to_string())) + .map(|(k, v)| { + if let Value::String(value) = v { + if value.starts_with("packet") { + (k, SwitchType::Packet(value)) + } else { + (k, SwitchType::Type(build_inner_type(Value::String(value)))) + } + } else if let Value::Array(array) = v { + (k, SwitchType::Type(build_inner_type(Value::Array(array)))) + } else { + (k, SwitchType::Unknown(v)) + } + }) .collect(), ) } else { From 6bc99329839a7dd235b429b3f9fcae0a2e732b7c Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Mon, 20 Jun 2022 09:59:47 -0400 Subject: [PATCH 06/14] TypeName to handle Anonymous types! --- src/models/protocol/types.rs | 40 +++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index 9607956..8ccec6d 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -18,6 +18,35 @@ pub enum SwitchType { Unknown(Value), } +#[derive(Debug)] +pub enum TypeName { + Anonymous, + Named(String), +} + +impl Display for TypeName { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + TypeName::Anonymous => { + f.write_str("Anonymous") + } + TypeName::Named(name) => { + f.write_str(name.as_str()) + } + } + } +} + +impl PartialEq for TypeName { + fn eq(&self, other: &String) -> bool { + if let TypeName::Named(name) = self { + name == other + } else { + false + } + } +} + /// These data types should be available in every version. /// However, they won't break anything if not present /// This can also be known as the Native Types @@ -52,7 +81,7 @@ pub enum NativeType { TopBitSetTerminatedArray(Box), BitField(Vec), // A set of Name and The Type - Container(Vec<(String, Box)>), + Container(Vec<(TypeName, Box)>), Switch { compare_to: String, fields: HashMap, @@ -162,11 +191,11 @@ impl NativeType { let name = name.as_str().unwrap().to_string(); let inner_type = obj.remove("type").unwrap_or_default(); let inner_type = build_inner_type(inner_type); - (name, inner_type) + (TypeName::Named(name), inner_type) } else { let inner_type = obj.remove("type").unwrap_or_default(); let inner_type = build_inner_type(inner_type); - (String::new(), inner_type) + (TypeName::Anonymous, inner_type) } } else { panic!("Container is not an object"); @@ -326,7 +355,7 @@ pub enum PacketDataType { // This type is built from a native type Built { // The name of the built type - name: String, + name: TypeName, // The value of the built type value: NativeType, }, @@ -351,7 +380,7 @@ impl PacketDataType { NativeType::new(&inner_type_name, Cow::Borrowed(&inner_type_values)) { Some(PacketDataType::Built { - name: key.to_string(), + name: TypeName::Named(key.to_string()), value: type_, }) } else { @@ -376,6 +405,7 @@ pub struct PacketDataTypes { } use std::fmt; +use std::fmt::{Debug, Display, Formatter}; use serde::de::{MapAccess}; From 3b8bf2bc02bd2d107c93d3a7094e33bd8ac1efb4 Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Tue, 21 Jun 2022 15:59:51 -0400 Subject: [PATCH 07/14] Clippy Warning --- src/models/protocol/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index 8ccec6d..a6039f5 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -390,7 +390,7 @@ impl PacketDataType { None } v => { - return Some(PacketDataType::Other(key.to_string(), v)); + Some(PacketDataType::Other(key.to_string(), v)) } } } else { From d0f05cf14cae09cb03d7428b5148c705ca510962 Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Wed, 22 Jun 2022 14:34:06 -0400 Subject: [PATCH 08/14] Expanded the Packet Type API a bit more. Added some docs and errors on failure. --- src/api/protocol.rs | 5 + src/api/tests/protocol.rs | 7 +- src/models/protocol/types.rs | 511 +++++++++++++++++++++-------------- 3 files changed, 312 insertions(+), 211 deletions(-) diff --git a/src/api/protocol.rs b/src/api/protocol.rs index 1ccbd43..65358c6 100644 --- a/src/api/protocol.rs +++ b/src/api/protocol.rs @@ -3,9 +3,14 @@ use crate::models::version::Version; use crate::{DataError, DataResult}; use std::sync::Arc; + +/// Will not parse versions `21w07a`, `20w14a`, and `20w13b` +/// These snapshot versions have incompatible data types for the tags packet. + pub struct Protocol { version: Arc, } + impl Protocol { pub fn new(version: Arc) -> Self { Self { version } diff --git a/src/api/tests/protocol.rs b/src/api/tests/protocol.rs index 235c46c..f2fd1b0 100644 --- a/src/api/tests/protocol.rs +++ b/src/api/tests/protocol.rs @@ -3,18 +3,21 @@ use crate::api::tests::get_test_versions; use crate::models::protocol::{NativeType, PacketDataType}; use std::sync::Arc; use crate::DataResult; - +pub const VERSIONS_TO_SKIP: [&str; 3] = ["21w07a", "20w14a", "20w13b"]; #[test] pub fn simple_test() { let versions = get_test_versions(); for x in versions { + if VERSIONS_TO_SKIP.contains(&x.minecraft_version.as_str()) { + continue; + } let arc = Arc::new(x); let protocol = Protocol::new(arc.clone()); let protocol1 = protocol.get_protocol(); match protocol1 { Ok(_) => {} Err(error) => { - println!("{:?} On Version {}", error, arc.minecraft_version); + panic!("Minecraft Version {} could not be parsed into a Protocol object: {}", arc.minecraft_version, error); } } } diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index a6039f5..b9aebb1 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -1,38 +1,40 @@ use serde::de::Visitor; use serde::{Deserialize, Deserializer}; use serde_json::Value; -use std::borrow::{Cow}; +use std::borrow::Cow; use std::collections::HashMap; -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] pub struct BitField { pub name: String, pub size: i64, pub signed: bool, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum SwitchType { Packet(String), Type(Box), Unknown(Value), } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum TypeName { Anonymous, Named(String), } +impl From for TypeName { + fn from(value: String) -> Self { + Self::Named(value) + } +} + impl Display for TypeName { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - TypeName::Anonymous => { - f.write_str("Anonymous") - } - TypeName::Named(name) => { - f.write_str(name.as_str()) - } + TypeName::Anonymous => f.write_str("Anonymous"), + TypeName::Named(name) => f.write_str(name.as_str()), } } } @@ -50,7 +52,8 @@ impl PartialEq for TypeName { /// These data types should be available in every version. /// However, they won't break anything if not present /// This can also be known as the Native Types -#[derive(Debug)] +#[derive(Debug, Clone)] +#[non_exhaustive] pub enum NativeType { /// Please read the following link for information on parsing https://wiki.vg/Protocol#VarInt_and_VarLong VarInt, @@ -97,40 +100,77 @@ pub enum NativeType { OptionalNBT, } +impl Display for NativeType { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let value = match self { + NativeType::Bool => "bool", + NativeType::U8 => "u8", + NativeType::U16 => "u16", + NativeType::U32 => "u32", + NativeType::U64 => "u64", + NativeType::I8 => "i8", + NativeType::I16 => "i16", + NativeType::I32 => "i32", + NativeType::I64 => "i64", + NativeType::F32 => "f32", + NativeType::F64 => "f64", + NativeType::Uuid => "uuid", + NativeType::Option(_) => "option", + NativeType::EntityMetadataLoop { .. } => "entityMetadataLoop", + NativeType::TopBitSetTerminatedArray(_) => "topbitsetterminatedarray", + NativeType::BitField(_) => "bitfield", + NativeType::Container(_) => "container", + NativeType::Switch { .. } => "switch", + NativeType::Array { .. } => "array", + NativeType::Void => "void", + NativeType::RestBuffer => "restbuffer", + NativeType::NBT => "nbt", + NativeType::OptionalNBT => "optionalnbt", + NativeType::VarInt => "varint", + NativeType::PString { .. } => "pstring", + NativeType::Buffer { .. } => "buffer", + }; + write!(f, "{}", value) + } +} + impl NativeType { pub fn contains_type(name: &str) -> bool { - matches!(name, "varint" | "pstring" | "buffer" | "bool" | "u8" | "u16" | "u32" | "u64" | "i8" | "i16" | "i32" | "i64" | "f32" | "f64" | "uuid" | "option" | "entityMetadataLoop" | "topbitsetterminatedarray" | "bitfield" | "container" | "switch" | "void" | "array" | "restbuffer" | "nbt" | "optionalnbt") + matches!( + name, + "varint" + | "pstring" + | "buffer" + | "bool" + | "u8" + | "u16" + | "u32" + | "u64" + | "i8" + | "i16" + | "i32" + | "i64" + | "f32" + | "f64" + | "uuid" + | "option" + | "entityMetadataLoop" + | "topbitsetterminatedarray" + | "bitfield" + | "container" + | "switch" + | "void" + | "array" + | "restbuffer" + | "nbt" + | "optionalnbt" + ) } pub fn new(name: &str, layout: Cow<'_, Value>) -> Option { match name { "varint" => Some(NativeType::VarInt), - "pstring" => { - if let Value::Object(mut obj) = layout.into_owned() { - if let Value::String(count_type) = obj.remove("countType").unwrap_or_default() { - if let Some(count_type) = - NativeType::new(&count_type, Cow::Owned(Value::Null)) { - return Some(NativeType::PString { - count_type: Box::new(count_type), - }); - } - } - } - None - } - "buffer" => { - if let Value::Object(mut obj) = layout.into_owned() { - if let Value::String(count_type) = obj.remove("countType").unwrap_or_default() { - if let Some(count_type) = - NativeType::new(&count_type, Cow::Owned(Value::Null)) - { - return Some(NativeType::PString { - count_type: Box::new(count_type), - }); - } - } - } - None - } + "pstring" => Self::pstring(layout), + "buffer" => Self::generate_buffer(layout), "bool" => Some(NativeType::Bool), "u8" => Some(NativeType::U8), "u16" => Some(NativeType::U16), @@ -144,127 +184,14 @@ impl NativeType { "f64" => Some(NativeType::F64), "uuid" => Some(NativeType::Uuid), "option" => Some(NativeType::Option(build_inner_type(layout.into_owned()))), - "entityMetadataLoop" => { - match layout.into_owned() { - Value::Object(mut layout) => { - let end_val = layout - .remove("endVal") - .and_then(|v| v.as_i64()) - .unwrap_or_default(); - let inner_type = layout.remove("type").unwrap_or_default(); - let inner_type = build_inner_type(inner_type); - Some(NativeType::EntityMetadataLoop { - end_val, - metadata_type: inner_type, - }) - } - _ => None, - } - } - "topbitsetterminatedarray" => { - if let Value::Object(mut layout) = layout.into_owned() { - let inner_type = layout.remove("type").unwrap_or_default(); - let inner_type = build_inner_type(inner_type); - return Some(NativeType::TopBitSetTerminatedArray(inner_type)); - } - None - } - "bitfield" => { - if let Value::Array(bit_fields) = layout.into_owned() { - let bit_fields_vec = bit_fields - .into_iter() - .map(|v| serde_json::from_value(v).unwrap()) - .collect(); - - Some(NativeType::BitField(bit_fields_vec)) - } else { - None - } - } - "container" => { - if let Value::Array(containers) = layout.into_owned() { - let containers_vec = containers - .into_iter() - .map(|v| { - if let Value::Object(mut obj) = v { - if let Some(name) = obj.remove("name") { - let name = name.as_str().unwrap().to_string(); - let inner_type = obj.remove("type").unwrap_or_default(); - let inner_type = build_inner_type(inner_type); - (TypeName::Named(name), inner_type) - } else { - let inner_type = obj.remove("type").unwrap_or_default(); - let inner_type = build_inner_type(inner_type); - (TypeName::Anonymous, inner_type) - } - } else { - panic!("Container is not an object"); - } - }) - .collect(); - - Some(NativeType::Container(containers_vec)) - } else { - None - } - } + "entityMetadataLoop" => Self::entity_metadata_loop(layout), + "topbitsetterminatedarray" => Self::top_bitsetterminated_array(layout), + "bitfield" => Self::bitfield(layout), + "container" => Self::container(layout), - "switch" => { - if let Value::Object(mut layout) = layout.into_owned() { - return Some(NativeType::Switch { - compare_to: layout.remove("compareTo").unwrap().as_str().unwrap_or_default().to_string(), - fields: layout - .remove("fields") - .and_then(|v| { - if let Value::Object(fields) = v { - Some( - fields - .into_iter() - .map(|(k, v)| { - if let Value::String(value) = v { - if value.starts_with("packet") { - (k, SwitchType::Packet(value)) - } else { - (k, SwitchType::Type(build_inner_type(Value::String(value)))) - } - } else if let Value::Array(array) = v { - (k, SwitchType::Type(build_inner_type(Value::Array(array)))) - } else { - (k, SwitchType::Unknown(v)) - } - }) - .collect(), - ) - } else { - None - } - }) - .unwrap_or_default(), - default: layout.remove("default").map(|v| v.as_str().unwrap_or_default().to_string()), - }); - } - None - } + "switch" => Self::switch(layout), "void" => Some(NativeType::Void), - "array" => { - if let Value::Object(mut obj) = layout.into_owned() { - let value = NativeType::new( - obj.remove("countType") - .unwrap_or_default() - .as_str() - .unwrap(), - Cow::Owned(Value::Null), - ); - let inner_type = build_inner_type(obj.remove("type").unwrap_or_default()); - if let Some(v) = value { - return Some(NativeType::Array { - count_type: Box::new(v), - array_type: inner_type, - }); - } - } - None - } + "array" => Self::array(layout), "restbuffer" => Some(NativeType::RestBuffer), "nbt" => Some(NativeType::NBT), @@ -272,36 +199,174 @@ impl NativeType { _ => None, } } - pub fn get_name(&self) -> &str { - match self { - NativeType::Bool => "bool", - NativeType::U8 => "u8", - NativeType::U16 => "u16", - NativeType::U32 => "u32", - NativeType::U64 => "u64", - NativeType::I8 => "i8", - NativeType::I16 => "i16", - NativeType::I32 => "i32", - NativeType::I64 => "i64", - NativeType::F32 => "f32", - NativeType::F64 => "f64", - NativeType::Uuid => "uuid", - NativeType::Option(_) => "option", - NativeType::EntityMetadataLoop { .. } => "entityMetadataLoop", - NativeType::TopBitSetTerminatedArray(_) => "topbitsetterminatedarray", - NativeType::BitField(_) => "bitfield", - NativeType::Container(_) => "container", - NativeType::Switch { .. } => "switch", - NativeType::Array { .. } => "array", - NativeType::Void => "void", - NativeType::RestBuffer => "restbuffer", - NativeType::NBT => "nbt", - NativeType::OptionalNBT => "optionalnbt", - NativeType::VarInt => { "varint" } - NativeType::PString { .. } => { "pstring" } - NativeType::Buffer { .. } => { "buffer" } + + pub fn pstring(layout: Cow) -> Option { + if let Value::Object(mut obj) = layout.into_owned() { + if let Value::String(count_type) = obj.remove("countType").unwrap_or_default() { + if let Some(count_type) = NativeType::new(&count_type, Cow::Owned(Value::Null)) { + return Some(NativeType::PString { + count_type: Box::new(count_type), + }); + } + } + } + None + } + + fn top_bitsetterminated_array(layout: Cow) -> Option { + if let Value::Object(mut layout) = layout.into_owned() { + let inner_type = layout.remove("type").unwrap_or_default(); + let inner_type = build_inner_type(inner_type); + return Some(NativeType::TopBitSetTerminatedArray(inner_type)); + } + None + } + + pub fn bitfield(layout: Cow) -> Option { + if let Value::Array(bit_fields) = layout.into_owned() { + let bit_fields_vec = bit_fields + .into_iter() + .map(|v| serde_json::from_value(v).unwrap()) + .collect(); + + Some(NativeType::BitField(bit_fields_vec)) + } else { + None + } + } + + pub fn switch(layout: Cow) -> Option { + if let Value::Object(mut layout) = layout.into_owned() { + return Some(NativeType::Switch { + compare_to: layout + .remove("compareTo") + .unwrap() + .as_str() + .unwrap_or_default() + .to_string(), + fields: layout + .remove("fields") + .and_then(|v| { + if let Value::Object(fields) = v { + Some( + fields + .into_iter() + .map(|(k, v)| { + if let Value::String(value) = v { + if value.starts_with("packet") { + (k, SwitchType::Packet(value)) + } else { + ( + k, + SwitchType::Type(build_inner_type( + Value::String(value), + )), + ) + } + } else if let Value::Array(array) = v { + ( + k, + SwitchType::Type(build_inner_type(Value::Array( + array, + ))), + ) + } else { + (k, SwitchType::Unknown(v)) + } + }) + .collect(), + ) + } else { + None + } + }) + .unwrap_or_default(), + default: layout + .remove("default") + .map(|v| v.as_str().unwrap_or_default().to_string()), + }); + } + None + } + + pub fn array(layout: Cow) -> Option { + if let Value::Object(mut obj) = layout.into_owned() { + let value = NativeType::new( + obj.remove("countType") + .unwrap_or_default() + .as_str() + .unwrap(), + Cow::Owned(Value::Null), + ); + let inner_type = build_inner_type(obj.remove("type").unwrap_or_default()); + if let Some(v) = value { + return Some(NativeType::Array { + count_type: Box::new(v), + array_type: inner_type, + }); + } + } + None + } + + pub fn container(layout: Cow) -> Option { + if let Value::Array(containers) = layout.into_owned() { + let containers_vec = containers + .into_iter() + .map(|v| { + if let Value::Object(mut obj) = v { + if let Some(name) = obj.remove("name") { + let name = name.as_str().unwrap().to_string(); + let inner_type = obj.remove("type").unwrap_or_default(); + let inner_type = build_inner_type(inner_type); + (TypeName::Named(name), inner_type) + } else { + let inner_type = obj.remove("type").unwrap_or_default(); + let inner_type = build_inner_type(inner_type); + (TypeName::Anonymous, inner_type) + } + } else { + panic!("Container is not an object"); + } + }) + .collect(); + + Some(NativeType::Container(containers_vec)) + } else { + None } } + + pub fn entity_metadata_loop(layout: Cow) -> Option { + match layout.into_owned() { + Value::Object(mut layout) => { + let end_val = layout + .remove("endVal") + .and_then(|v| v.as_i64()) + .unwrap_or_default(); + let inner_type = layout.remove("type").unwrap_or_default(); + let inner_type = build_inner_type(inner_type); + Some(NativeType::EntityMetadataLoop { + end_val, + metadata_type: inner_type, + }) + } + _ => None, + } + } + + pub fn generate_buffer(layout: Cow) -> Option { + if let Value::Object(mut obj) = layout.into_owned() { + if let Value::String(count_type) = obj.remove("countType").unwrap_or_default() { + if let Some(count_type) = NativeType::new(&count_type, Cow::Owned(Value::Null)) { + return Some(NativeType::PString { + count_type: Box::new(count_type), + }); + } + } + } + None + } } #[inline] @@ -313,40 +378,49 @@ fn build_inner_type(value: Value) -> Box { Box::new(PacketDataType::Native(simple_type)) } else { // Probably a reference to a built type - Box::new(PacketDataType::Other(simple_type, Value::Null)) + Box::new(PacketDataType::Other { + name: Some(simple_type.into()), + value: Value::Null, + }) }; } Value::Array(mut array) => { if array.len() != 2 { - return Box::new(PacketDataType::Other(String::new(), Value::Array(array))); + return Box::new(PacketDataType::Other { + name: None, + value: Value::Array(array), + }); } let inner_value = Cow::Owned(array.pop().unwrap_or_default()); let key = array.pop().unwrap(); - if let Value::String(key) = &key { - let value = PacketDataType::new(key, Cow::clone(&inner_value)).or_else(|| { - let option = NativeType::new(key, inner_value.clone()); + if let Value::String(key) = key { + let value = PacketDataType::new(&key, Cow::clone(&inner_value)).or_else(|| { + let option = NativeType::new(&key, inner_value.clone()); option.map(PacketDataType::Native) }); if let Some(value) = value { Box::new(value) } else { - Box::new(PacketDataType::Other( - key.clone(), - inner_value.into_owned(), - )) + Box::new(PacketDataType::Other { + name: Some(key.into()), + value: inner_value.into_owned(), + }) } } else { - Box::new(PacketDataType::Other( - key.as_str().unwrap_or_default().to_string(), - inner_value.into_owned(), - )) + Box::new(PacketDataType::Other { + name: None, + value: inner_value.into_owned(), + }) } } - v => Box::new(PacketDataType::Other(String::new(), v)), + v => Box::new(PacketDataType::Other { + name: None, + value: v, + }), } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum PacketDataType { // Just a pure native type Native(NativeType), @@ -359,8 +433,20 @@ pub enum PacketDataType { // The value of the built type value: NativeType, }, + /// A Type that could not be built or parsed. This is a fallback for when we don't know what the type is + /// This type is usually a reference to a built type + Other { + // The name of the type if found + name: Option, + // The JSON value of the type + value: Value, + }, +} - Other(String, Value), +impl From for PacketDataType { + fn from(native: NativeType) -> Self { + PacketDataType::Native(native) + } } impl PacketDataType { @@ -370,7 +456,10 @@ impl PacketDataType { Value::String(string) => Some(PacketDataType::UnknownNativeType(string)), Value::Array(mut array) => { if array.len() != 2 { - return Some(PacketDataType::Other(key.to_string(), Value::Array(array))); + return Some(PacketDataType::Other { + name: None, + value: Value::Array(array), + }); } let inner_type_values = array.pop().unwrap_or_default(); @@ -384,14 +473,18 @@ impl PacketDataType { value: type_, }) } else { - Some(PacketDataType::Other(inner_type_name, inner_type_values)) + Some(PacketDataType::Other { + name: Some(inner_type_name.into()), + value: inner_type_values, + }) }; } None } - v => { - Some(PacketDataType::Other(key.to_string(), v)) - } + v => Some(PacketDataType::Other { + name: None, + value: v, + }), } } else { None @@ -407,7 +500,7 @@ pub struct PacketDataTypes { use std::fmt; use std::fmt::{Debug, Display, Formatter}; -use serde::de::{MapAccess}; +use serde::de::MapAccess; impl<'de> Deserialize<'de> for PacketDataTypes { fn deserialize(deserializer: D) -> Result @@ -419,7 +512,7 @@ impl<'de> Deserialize<'de> for PacketDataTypes { impl<'de> Visitor<'de> for PacketDataTypesVisitor { type Value = PacketDataTypes; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { formatter.write_str("struct PacketDataTypes") } From b7182cf818c49193c14246ba27a02c98ae85fd55 Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Wed, 22 Jun 2022 14:36:45 -0400 Subject: [PATCH 09/14] Rename some functions --- minecraft-data | 2 +- src/api/tests/protocol.rs | 5 +++-- src/models/protocol/types.rs | 32 ++++++++++++++++---------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/minecraft-data b/minecraft-data index 6428d49..153706b 160000 --- a/minecraft-data +++ b/minecraft-data @@ -1 +1 @@ -Subproject commit 6428d491a7e03fb3bfa2f75185cccc4f69fadec8 +Subproject commit 153706b6ffb2e56f51a1b91922dffd3350ddcb0e diff --git a/src/api/tests/protocol.rs b/src/api/tests/protocol.rs index f2fd1b0..73e562e 100644 --- a/src/api/tests/protocol.rs +++ b/src/api/tests/protocol.rs @@ -1,9 +1,10 @@ use crate::api::protocol::Protocol; use crate::api::tests::get_test_versions; -use crate::models::protocol::{NativeType, PacketDataType}; +use crate::models::protocol::{PacketDataType}; use std::sync::Arc; -use crate::DataResult; + pub const VERSIONS_TO_SKIP: [&str; 3] = ["21w07a", "20w14a", "20w13b"]; + #[test] pub fn simple_test() { let versions = get_test_versions(); diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index b9aebb1..b509d92 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -169,8 +169,8 @@ impl NativeType { pub fn new(name: &str, layout: Cow<'_, Value>) -> Option { match name { "varint" => Some(NativeType::VarInt), - "pstring" => Self::pstring(layout), - "buffer" => Self::generate_buffer(layout), + "pstring" => Self::new_pstring(layout), + "buffer" => Self::new_buffer(layout), "bool" => Some(NativeType::Bool), "u8" => Some(NativeType::U8), "u16" => Some(NativeType::U16), @@ -184,14 +184,14 @@ impl NativeType { "f64" => Some(NativeType::F64), "uuid" => Some(NativeType::Uuid), "option" => Some(NativeType::Option(build_inner_type(layout.into_owned()))), - "entityMetadataLoop" => Self::entity_metadata_loop(layout), - "topbitsetterminatedarray" => Self::top_bitsetterminated_array(layout), - "bitfield" => Self::bitfield(layout), - "container" => Self::container(layout), + "entityMetadataLoop" => Self::new_entity_metadata_loop(layout), + "topbitsetterminatedarray" => Self::new_top_bitsetterminated_array(layout), + "bitfield" => Self::new_bitfield(layout), + "container" => Self::new_container(layout), - "switch" => Self::switch(layout), + "switch" => Self::new_switch(layout), "void" => Some(NativeType::Void), - "array" => Self::array(layout), + "array" => Self::new_array(layout), "restbuffer" => Some(NativeType::RestBuffer), "nbt" => Some(NativeType::NBT), @@ -200,7 +200,7 @@ impl NativeType { } } - pub fn pstring(layout: Cow) -> Option { + pub fn new_pstring(layout: Cow) -> Option { if let Value::Object(mut obj) = layout.into_owned() { if let Value::String(count_type) = obj.remove("countType").unwrap_or_default() { if let Some(count_type) = NativeType::new(&count_type, Cow::Owned(Value::Null)) { @@ -213,7 +213,7 @@ impl NativeType { None } - fn top_bitsetterminated_array(layout: Cow) -> Option { + fn new_top_bitsetterminated_array(layout: Cow) -> Option { if let Value::Object(mut layout) = layout.into_owned() { let inner_type = layout.remove("type").unwrap_or_default(); let inner_type = build_inner_type(inner_type); @@ -222,7 +222,7 @@ impl NativeType { None } - pub fn bitfield(layout: Cow) -> Option { + pub fn new_bitfield(layout: Cow) -> Option { if let Value::Array(bit_fields) = layout.into_owned() { let bit_fields_vec = bit_fields .into_iter() @@ -235,7 +235,7 @@ impl NativeType { } } - pub fn switch(layout: Cow) -> Option { + pub fn new_switch(layout: Cow) -> Option { if let Value::Object(mut layout) = layout.into_owned() { return Some(NativeType::Switch { compare_to: layout @@ -289,7 +289,7 @@ impl NativeType { None } - pub fn array(layout: Cow) -> Option { + pub fn new_array(layout: Cow) -> Option { if let Value::Object(mut obj) = layout.into_owned() { let value = NativeType::new( obj.remove("countType") @@ -309,7 +309,7 @@ impl NativeType { None } - pub fn container(layout: Cow) -> Option { + pub fn new_container(layout: Cow) -> Option { if let Value::Array(containers) = layout.into_owned() { let containers_vec = containers .into_iter() @@ -337,7 +337,7 @@ impl NativeType { } } - pub fn entity_metadata_loop(layout: Cow) -> Option { + pub fn new_entity_metadata_loop(layout: Cow) -> Option { match layout.into_owned() { Value::Object(mut layout) => { let end_val = layout @@ -355,7 +355,7 @@ impl NativeType { } } - pub fn generate_buffer(layout: Cow) -> Option { + pub fn new_buffer(layout: Cow) -> Option { if let Value::Object(mut obj) = layout.into_owned() { if let Value::String(count_type) = obj.remove("countType").unwrap_or_default() { if let Some(count_type) = NativeType::new(&count_type, Cow::Owned(Value::Null)) { From adf1a3e4a8dcf7bb677fa1c16ae99347fe2ff4f2 Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Wed, 22 Jun 2022 21:02:54 -0400 Subject: [PATCH 10/14] Reassemble the array --- src/models/protocol/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index b509d92..a5c9500 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -409,7 +409,7 @@ fn build_inner_type(value: Value) -> Box { } else { Box::new(PacketDataType::Other { name: None, - value: inner_value.into_owned(), + value: Value::Array(vec![key, inner_value.into_owned()]), }) } } From 497552c730debbbcb92e09f017f2cec32b1d38b0 Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Wed, 22 Jun 2022 21:08:06 -0400 Subject: [PATCH 11/14] Missing Data --- src/models/protocol/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index a5c9500..ad6b040 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -457,7 +457,7 @@ impl PacketDataType { Value::Array(mut array) => { if array.len() != 2 { return Some(PacketDataType::Other { - name: None, + name: Some(key.to_string().into()), value: Value::Array(array), }); } @@ -482,7 +482,7 @@ impl PacketDataType { None } v => Some(PacketDataType::Other { - name: None, + name: Some(key.to_string().into()), value: v, }), } From 4d1353afd260f06d5845ac5a5469a0b0f99de63f Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Thu, 23 Jun 2022 07:33:30 -0400 Subject: [PATCH 12/14] Improving the packet mapping --- src/api/tests/protocol.rs | 2 ++ src/models/protocol/mod.rs | 38 +++++++++++++++++++++++----- src/models/protocol/packet_mapper.rs | 29 +++++++++++++++++---- src/models/protocol/types.rs | 5 +++- 4 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/api/tests/protocol.rs b/src/api/tests/protocol.rs index 73e562e..250bd54 100644 --- a/src/api/tests/protocol.rs +++ b/src/api/tests/protocol.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; +use std::convert::TryInto; use crate::api::protocol::Protocol; use crate::api::tests::get_test_versions; use crate::models::protocol::{PacketDataType}; diff --git a/src/models/protocol/mod.rs b/src/models/protocol/mod.rs index cd0d608..120af8d 100644 --- a/src/models/protocol/mod.rs +++ b/src/models/protocol/mod.rs @@ -1,6 +1,7 @@ pub mod types; pub mod packet_mapper; +use std::borrow::Cow; use std::fmt; use serde::{de, Deserialize, Deserializer}; use serde::de::{MapAccess, Visitor}; @@ -8,7 +9,7 @@ use serde_json::Value; pub use packet_mapper::{PacketMapper, PacketSwitch, PacketMapperSwitch}; pub use types::{BitField, NativeType, PacketDataType, PacketDataTypes}; -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] pub struct Protocol { pub types: PacketDataTypes, pub handshaking: PacketGrouping, @@ -17,7 +18,7 @@ pub struct Protocol { pub play: PacketGrouping, } -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] pub struct PacketGrouping { #[serde(rename = "toServer")] pub to_server: PacketTypes, @@ -25,7 +26,7 @@ pub struct PacketGrouping { pub to_client: PacketTypes, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum DataTypeReference { Simple(String), Complex { @@ -34,13 +35,38 @@ pub enum DataTypeReference { }, } -#[derive(Debug)] +impl Into for DataTypeReference { + fn into(self) -> PacketDataType { + let (name, properties) = match self { + DataTypeReference::Simple(simple) => { + (simple, Value::Null) + } + DataTypeReference::Complex { name, properties } => { + (name, properties) + } + }; + + PacketDataType::new(name.as_str(), Cow::Borrowed(&properties)). + or_else(|| { + let option = NativeType::new(name.as_str(), Cow::Borrowed(&properties)); + option.map(PacketDataType::Native) + }) + .unwrap_or_else(|| { + PacketDataType::Other { + name: Some(name.into()), + value: properties, + } + }) + } +} + +#[derive(Debug, Clone)] pub struct Packet { pub name: String, pub data: Vec<(String, DataTypeReference)>, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PacketTypes { pub packet_mapper: PacketMapperSwitch, pub types: Vec, @@ -89,7 +115,7 @@ impl<'de> Deserialize<'de> for PacketTypes { let name = obj.remove("name"); let name = if let Some(name) = name { name.to_string() - }else{ + } else { "anon".to_string() }; let value = obj.remove("type").ok_or_else(|| de::Error::custom(format!("Packet ID {} missing type", key)))?; diff --git a/src/models/protocol/packet_mapper.rs b/src/models/protocol/packet_mapper.rs index 27bda65..0649fe6 100644 --- a/src/models/protocol/packet_mapper.rs +++ b/src/models/protocol/packet_mapper.rs @@ -1,26 +1,45 @@ use std::collections::HashMap; +use std::convert::TryInto; use std::fmt; +use std::iter::Map; +use std::num::ParseIntError; use serde::de::{SeqAccess, Visitor}; use serde::{de, Deserialize, Deserializer}; use serde_json::Value; -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] pub struct PacketMapper { /// A Type #[serde(rename = "type")] pub map_type: String, + /// The first Value is a Hex value of the packet id. That is a string in the JSON. You can convert the map with the `i32::from_str_radix` (The ids do start with 0x) function. You can also just do try_into::() on the PacketMapper + /// The second Value is the name of the packet pub mappings: HashMap, } -#[derive(Deserialize, Debug)] +impl TryInto> for PacketMapper { + type Error = ParseIntError; + + fn try_into(self) -> Result, Self::Error> { + let mut map = HashMap::with_capacity(self.mappings.len()); + for (key, value) in self.mappings.into_iter() { + let key = i32::from_str_radix(key.trim_start_matches("0x"), 16)?; + map.insert(key, value); + } + Ok(map) + } +} + +#[derive(Deserialize, Debug, Clone)] pub struct PacketSwitch { #[serde(rename = "compareTo")] pub compare_to: String, + /// First value is the name of the packet. Second is the name of the JSON object for the packet. pub fields: HashMap, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PacketMapperSwitch { pub mapper: PacketMapper, pub switch: PacketSwitch, @@ -59,10 +78,10 @@ impl<'de> Deserialize<'de> for PacketMapperSwitch { } else if key.eq("switch") { let value: PacketSwitch = serde_json::from_value(value).map_err(de::Error::custom)?; switch = Some(value); - }else{ + } else { return Err(de::Error::custom("unknown key")); } - }else{ + } else { return Err(de::Error::custom("unknown key")); } } else { diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index ad6b040..8914128 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -435,6 +435,9 @@ pub enum PacketDataType { }, /// A Type that could not be built or parsed. This is a fallback for when we don't know what the type is /// This type is usually a reference to a built type + /// + /// If this is a reference you you will want to push any data within Value to the reference. + /// For example the Packet type references another type called "PacketData" that has a variable within it for the compareTo value. You will want to take the value from the Value and push it to the PacketData type. Other { // The name of the type if found name: Option, @@ -492,7 +495,7 @@ impl PacketDataType { } } -#[derive(Debug)] +#[derive(Debug,Clone)] pub struct PacketDataTypes { pub types: Vec, } From 9d03b8ae51e2ed8a33002795aab59d912b8335a0 Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Thu, 23 Jun 2022 08:26:01 -0400 Subject: [PATCH 13/14] Different way of parsing packets --- src/api/tests/protocol.rs | 6 ++++- src/models/protocol/mod.rs | 44 ++++++------------------------------ src/models/protocol/types.rs | 18 +++++++-------- 3 files changed, 20 insertions(+), 48 deletions(-) diff --git a/src/api/tests/protocol.rs b/src/api/tests/protocol.rs index 250bd54..6ab309f 100644 --- a/src/api/tests/protocol.rs +++ b/src/api/tests/protocol.rs @@ -18,7 +18,11 @@ pub fn simple_test() { let protocol = Protocol::new(arc.clone()); let protocol1 = protocol.get_protocol(); match protocol1 { - Ok(_) => {} + Ok(data) => { + for x in data.play.to_server.types { + println!("{:#?}", x); + } + } Err(error) => { panic!("Minecraft Version {} could not be parsed into a Protocol object: {}", arc.minecraft_version, error); } diff --git a/src/models/protocol/mod.rs b/src/models/protocol/mod.rs index 120af8d..8f8e508 100644 --- a/src/models/protocol/mod.rs +++ b/src/models/protocol/mod.rs @@ -63,7 +63,7 @@ impl Into for DataTypeReference { #[derive(Debug, Clone)] pub struct Packet { pub name: String, - pub data: Vec<(String, DataTypeReference)>, + pub data: PacketDataType, } #[derive(Debug, Clone)] @@ -106,45 +106,15 @@ impl<'de> Deserialize<'de> for PacketTypes { } else { return Err(de::Error::custom("Invalid Packet Mapper")); } - } else if let Value::Array(mut array) = value { - let last = array.pop().ok_or_else(|| de::Error::missing_field("missing content"))?; - if let Value::Array(array) = last { - let mut packet_content = Vec::new(); - for value in array.into_iter() { - if let Value::Object(mut obj) = value { - let name = obj.remove("name"); - let name = if let Some(name) = name { - name.to_string() - } else { - "anon".to_string() - }; - let value = obj.remove("type").ok_or_else(|| de::Error::custom(format!("Packet ID {} missing type", key)))?; - let value = match value { - Value::String(simple) => { - DataTypeReference::Simple(simple) - } - Value::Array(mut array) => { - let properties = array.pop().ok_or_else(|| de::Error::custom(format!("Packet ID {} missing properties", key)))?; - let name = array.pop().ok_or_else(|| de::Error::custom(format!("Packet ID {} missing name", key)))?.to_string(); - DataTypeReference::Complex { - name, - properties, - } - } - _ => return Err(de::Error::custom(format!("Invalid Packet Invalid Type {}", key))) - }; - packet_content.push((name, value)); - } else { - return Err(de::Error::custom(format!("Invalid Packet Expected Object {}", key))); - } - } + } else if let Value::Array( array) = value { + let value1 = Value::Array(vec![Value::String(key.clone()), Value::Array(array)]); + println!("{:#?}", value1); + let inner_type = types::build_inner_type(value1); packets.push(Packet { name: key, - data: packet_content, + data: *inner_type, }); - } else { - return Err(de::Error::custom(format!("Invalid Packet {}", key))); - } + } else { return Err(de::Error::custom(format!("Invalid Packet Expected Array {}", key))); } diff --git a/src/models/protocol/types.rs b/src/models/protocol/types.rs index 8914128..86214f7 100644 --- a/src/models/protocol/types.rs +++ b/src/models/protocol/types.rs @@ -295,16 +295,14 @@ impl NativeType { obj.remove("countType") .unwrap_or_default() .as_str() - .unwrap(), + .unwrap_or_default(), Cow::Owned(Value::Null), - ); + ).unwrap_or(NativeType::VarInt); let inner_type = build_inner_type(obj.remove("type").unwrap_or_default()); - if let Some(v) = value { - return Some(NativeType::Array { - count_type: Box::new(v), - array_type: inner_type, - }); - } + return Some(NativeType::Array { + count_type: Box::new(value), + array_type: inner_type, + }); } None } @@ -370,7 +368,7 @@ impl NativeType { } #[inline] -fn build_inner_type(value: Value) -> Box { +pub(crate) fn build_inner_type(value: Value) -> Box { match value { Value::String(simple_type) => { return if let Some(simple_type) = NativeType::new(&simple_type, Cow::Owned(Value::Null)) @@ -495,7 +493,7 @@ impl PacketDataType { } } -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub struct PacketDataTypes { pub types: Vec, } From 89002a908fe56ca6e7bb394ed49c1c955d4a403a Mon Sep 17 00:00:00 2001 From: Wyatt Herkamp Date: Thu, 23 Jun 2022 08:35:34 -0400 Subject: [PATCH 14/14] Remove Debug Messages --- src/api/tests/protocol.rs | 4 +--- src/models/protocol/mod.rs | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/api/tests/protocol.rs b/src/api/tests/protocol.rs index 6ab309f..7eda49c 100644 --- a/src/api/tests/protocol.rs +++ b/src/api/tests/protocol.rs @@ -19,9 +19,7 @@ pub fn simple_test() { let protocol1 = protocol.get_protocol(); match protocol1 { Ok(data) => { - for x in data.play.to_server.types { - println!("{:#?}", x); - } + } Err(error) => { panic!("Minecraft Version {} could not be parsed into a Protocol object: {}", arc.minecraft_version, error); diff --git a/src/models/protocol/mod.rs b/src/models/protocol/mod.rs index 8f8e508..8eab803 100644 --- a/src/models/protocol/mod.rs +++ b/src/models/protocol/mod.rs @@ -108,7 +108,6 @@ impl<'de> Deserialize<'de> for PacketTypes { } } else if let Value::Array( array) = value { let value1 = Value::Array(vec![Value::String(key.clone()), Value::Array(array)]); - println!("{:#?}", value1); let inner_type = types::build_inner_type(value1); packets.push(Packet { name: key,