diff --git a/protocol-generator/Cargo.toml b/protocol-generator/Cargo.toml index a4fd963..b8c85ae 100644 --- a/protocol-generator/Cargo.toml +++ b/protocol-generator/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/eihwaz/minecraft-protocol" keywords = ["minecraft", "cli", "protocol", "packet", "io"] [dependencies] -clap = "2.33.3" +structopt = "0.3" serde = "1.0.120" serde_json = "1.0" handlebars = "3.5.2" diff --git a/protocol-generator/src/data/input.rs b/protocol-generator/src/data/input.rs new file mode 100644 index 0000000..bd6b091 --- /dev/null +++ b/protocol-generator/src/data/input.rs @@ -0,0 +1,138 @@ +use serde::Deserialize; +use serde::Serialize; +use std::collections::HashMap; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Protocol { + handshaking: ProtocolState, + status: ProtocolState, + login: ProtocolState, + #[serde(rename = "play")] + game: ProtocolState, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ProtocolState { + to_client: ProtocolTypes, + to_server: ProtocolTypes, +} + +#[derive(Debug, Serialize, Deserialize)] +struct ProtocolTypes { + types: HashMap>, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +enum Container { + Type(String), + Data(Vec), +} + +#[derive(Debug, Serialize, Deserialize)] +struct ContainerData { + name: String, + #[serde(rename = "type")] + container_type: ContainerDataType, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +enum ContainerDataType { + Type(String), + Mapper(String, Mappings), + Switch(String, Switch), +} + +#[derive(Debug, Serialize, Deserialize)] +struct Mappings { + #[serde(rename = "type")] + mappings_type: String, + mappings: HashMap, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Switch { + #[serde(rename = "compareTo")] + compare_to: String, + fields: HashMap, +} + +#[cfg(test)] +mod tests { + use crate::data::input::*; + use std::collections::HashMap; + + #[test] + fn test_to_json() { + let mut types = HashMap::new(); + + let data = vec![ + ContainerData { + name: "protocolVersion".to_string(), + container_type: ContainerDataType::Type("varint".to_string()), + }, + ContainerData { + name: "serverHost".to_string(), + container_type: ContainerDataType::Type("string".to_string()), + }, + ContainerData { + name: "serverPort".to_string(), + container_type: ContainerDataType::Type("u16".to_string()), + }, + ContainerData { + name: "nextState".to_string(), + container_type: ContainerDataType::Type("varint".to_string()), + }, + ]; + + types.insert( + "packet_set_protocol".to_owned(), + vec![ + Container::Type("container".to_owned()), + Container::Data(data), + ], + ); + + let mut mappings = HashMap::new(); + mappings.insert("0x00".to_owned(), "set_protocol".to_owned()); + mappings.insert("0xfe".to_owned(), "legacy_server_list_ping".to_owned()); + + let data2 = vec![ContainerData { + name: "name".to_string(), + container_type: ContainerDataType::Mapper( + "mapper".to_owned(), + Mappings { + mappings_type: "varint".to_string(), + mappings, + }, + ), + }]; + + // _type: ContainerDataType::Mapper(vec![ + // Mapper::Type("mapper".to_owned()), + // Mapper::Data("varint".to_owned(), mappings), + // ]), + + types.insert( + "packet".to_owned(), + vec![ + Container::Type("container".to_owned()), + Container::Data(data2), + ], + ); + + // let protocol = Protocol { + // handshaking: ProtocolState { + // to_server: ProtocolTypes { types }, + // }, + // }; + // + // let j = serde_json::to_string(&protocol).unwrap(); + // + // println!("{}", j); + // + // assert_eq!("", j); + } +} diff --git a/protocol-generator/src/data/mod.rs b/protocol-generator/src/data/mod.rs new file mode 100644 index 0000000..7d1a548 --- /dev/null +++ b/protocol-generator/src/data/mod.rs @@ -0,0 +1,2 @@ +pub mod input; +pub mod output; diff --git a/protocol-generator/src/data.rs b/protocol-generator/src/data/output.rs similarity index 100% rename from protocol-generator/src/data.rs rename to protocol-generator/src/data/output.rs diff --git a/protocol-generator/src/main.rs b/protocol-generator/src/main.rs index 5fa6f51..187011d 100644 --- a/protocol-generator/src/main.rs +++ b/protocol-generator/src/main.rs @@ -1,14 +1,43 @@ mod data; -use crate::data::*; +use crate::data::input; use handlebars::*; use heck::SnakeCase; + +use crate::data::output; +use crate::data::output::Bound; use serde::Serialize; use serde_json::json; use std::fs::File; use std::io::Write; +use structopt::StructOpt; + +#[derive(StructOpt)] +#[structopt(name = "protocol-generator")] +struct Opt { + #[structopt(short, long, default_value = "1.14.4")] + protocol_version: String, +} pub fn main() { + let opt: Opt = Opt::from_args(); + let template_engine = create_template_engine(); + + let protocol_data_file_name = format!( + "protocol-generator/minecraft-data/data/pc/{}/protocol.json", + opt.protocol_version + ); + + let protocol_data_file = + File::open(protocol_data_file_name).expect("Failed to open protocol data file"); + + let protocol_data: input::Protocol = + serde_json::from_reader(protocol_data_file).expect("Failed to parse protocol data"); + + println!("{:#?}", protocol_data) +} + +fn create_template_engine() -> Handlebars<'static> { let mut template_engine = Handlebars::new(); template_engine.register_helper("snake_case", Box::new(format_snake_case)); @@ -36,73 +65,17 @@ pub fn main() { ) .expect("Failed to register template"); - let protocol = Protocol::new( - State::Login, - vec![ - Packet::new( - "LoginStart", - vec![Field::new("name", DataType::String { max_length: 256 })], - ), - Packet::new( - "EncryptionResponse", - vec![ - Field::new("shared_secret", DataType::ByteArray { rest: true }), - Field::new("verify_token", DataType::ByteArray { rest: true }), - ], - ), - Packet::new( - "LoginPluginResponse", - vec![ - Field::new("message_id", DataType::Int { var_int: true }), - Field::new("successful", DataType::Boolean), - Field::new("data", DataType::ByteArray { rest: true }), - ], - ), - ], - vec![ - Packet::new( - "LoginDisconnect", - vec![ - Field::new("hyphenated", DataType::Uuid { hyphenated: true }), - Field::new("default", DataType::Uuid { hyphenated: false }), - ], - ), - Packet::new( - "EncryptionRequest", - vec![Field::new( - "game_mode", - DataType::RefType { - ref_name: "GameMode".to_string(), - }, - )], - ), - Packet::new( - "LoginSuccess", - vec![Field::new( - "server_status", - DataType::RefType { - ref_name: "ServerStatus".to_string(), - }, - )], - ), - Packet::new("SetCompression", vec![]), - Packet::new("LoginPluginRequest", vec![]), - ], - ); - - let file = File::create("login.rs").expect("Failed to create file"); - - generate_rust_file(&protocol, &template_engine, &file).expect("Failed to generate rust file"); + template_engine } #[derive(Serialize)] struct GenerateContext<'a> { packet_enum_name: String, - packets: &'a Vec, + packets: &'a Vec, } pub fn generate_rust_file( - protocol: &Protocol, + protocol: &output::Protocol, template_engine: &Handlebars, mut writer: W, ) -> Result<(), TemplateRenderError> {