diff --git a/protocol-generator/src/data/input.rs b/protocol-generator/src/data/input.rs index 68ca055..b7a2c30 100644 --- a/protocol-generator/src/data/input.rs +++ b/protocol-generator/src/data/input.rs @@ -1,7 +1,5 @@ use linked_hash_map::LinkedHashMap; use serde::Deserialize; -use serde::Serialize; -use std::collections::HashMap; #[derive(Debug, Deserialize)] pub struct Protocol { @@ -24,7 +22,7 @@ pub struct ProtocolData { pub types: LinkedHashMap>, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, PartialEq, Eq)] #[serde(untagged)] pub enum Data { Type(String), @@ -39,7 +37,7 @@ pub enum Data { Bitfield(Vec), } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, PartialEq, Eq)] #[serde(untagged)] pub enum Container { Value { @@ -50,11 +48,11 @@ pub enum Container { List { name: Option, #[serde(rename = "type")] - data: Vec, + data_vec: Vec, }, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, PartialEq, Eq)] #[serde(untagged)] pub enum Switch { Empty { @@ -73,7 +71,7 @@ pub enum Switch { }, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, PartialEq, Eq)] #[serde(untagged)] pub enum List { Empty { @@ -94,7 +92,7 @@ pub enum List { }, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, PartialEq, Eq)] pub struct BitField { name: String, size: usize, diff --git a/protocol-generator/src/main.rs b/protocol-generator/src/main.rs index e1fb3f6..c09e7be 100644 --- a/protocol-generator/src/main.rs +++ b/protocol-generator/src/main.rs @@ -2,12 +2,10 @@ mod data; use crate::data::input; use handlebars::*; -use heck::{CamelCase, KebabCase, MixedCase, SnakeCase, TitleCase}; +use heck::{CamelCase, SnakeCase}; use crate::data::input::{Container, Data, ProtocolData, ProtocolState}; use crate::data::output; -use crate::data::output::{Bound, Packet, State}; -use linked_hash_map::LinkedHashMap; use serde::Serialize; use serde_json::json; use std::collections::HashMap; @@ -39,25 +37,28 @@ pub fn main() { let protocols = vec![ ( - transform_protocol_state(State::Handshake, &protocol_input.handshaking), - State::Handshake, + transform_protocol_state(output::State::Handshake, &protocol_input.handshaking), + output::State::Handshake, ), ( - transform_protocol_state(State::Status, &protocol_input.status), - State::Status, + transform_protocol_state(output::State::Status, &protocol_input.status), + output::State::Status, ), ( - transform_protocol_state(State::Login, &protocol_input.login), - State::Login, - ), - ( - transform_protocol_state(State::Game, &protocol_input.game), - State::Game, + transform_protocol_state(output::State::Login, &protocol_input.login), + output::State::Login, ), + // ( + // transform_protocol_state(State::Game, &protocol_input.game), + // State::Game, + // ), ]; for (protocol, state) in protocols { - let file_name = format!("{}.rs", state.to_string().to_lowercase()); + let file_name = format!( + "protocol/src/packet/{}.rs", + state.to_string().to_lowercase() + ); let file = File::create(file_name).expect("Failed to create file"); generate_rust_file(&protocol, &template_engine, &file) @@ -96,9 +97,14 @@ fn create_template_engine() -> Handlebars<'static> { template_engine } -fn transform_protocol_state(state: State, protocol_state: &ProtocolState) -> output::Protocol { - let server_bound_packets = transform_protocol_data(&protocol_state.to_server); - let client_bound_packets = transform_protocol_data(&protocol_state.to_client); +fn transform_protocol_state( + state: output::State, + protocol_state: &ProtocolState, +) -> output::Protocol { + let server_bound_packets = + transform_protocol_data(&protocol_state.to_server, output::Bound::Server); + let client_bound_packets = + transform_protocol_data(&protocol_state.to_client, output::Bound::Client); output::Protocol { state, @@ -107,38 +113,14 @@ fn transform_protocol_state(state: State, protocol_state: &ProtocolState) -> out } } -fn transform_protocol_data(protocol_data: &ProtocolData) -> Vec { +fn transform_protocol_data( + protocol_data: &ProtocolData, + bound: output::Bound, +) -> Vec { + let packet_ids = get_packet_ids(protocol_data); let mut packets = vec![]; - let reversed_packet_ids = protocol_data - .types - .get("packet") - .and_then(|d| d.get(1)) - .and_then(|d| match d { - Data::Container(data) => data.get(0), - _ => None, - }) - .and_then(|c| match c { - Container::List { data, .. } => data.get(1), - _ => None, - }) - .and_then(|d| match d { - Data::Mapper { mappings, .. } => Some(mappings), - _ => None, - }) - .expect("Failed to get packet ids"); - - let packet_ids: HashMap = reversed_packet_ids - .into_iter() - .map(|(k, v)| { - ( - v.clone(), - u8::from_str_radix(k.trim_start_matches("0x"), 16).expect("Invalid packet id"), - ) - }) - .collect(); - - for (unformatted_name, data) in protocol_data.types.iter() { + for (unformatted_name, data_vec) in protocol_data.types.iter() { if !unformatted_name.starts_with("packet_") || unformatted_name == "packet_legacy_server_list_ping" { @@ -150,13 +132,34 @@ fn transform_protocol_data(protocol_data: &ProtocolData) -> Vec { let id = *packet_ids .get(no_prefix_name) .expect("Failed to get packet id"); - let name = no_prefix_name.to_camel_case(); + let name = rename_packet(&no_prefix_name.to_camel_case(), &bound); - let packet = Packet { - id, - name, - fields: vec![], - }; + let mut fields = vec![]; + + for data in data_vec { + if let Data::Container(container_vec) = data { + for container in container_vec { + match container { + Container::Value { name, data } => { + if let Some(field) = transform_field(name, data) { + fields.push(field); + } + } + Container::List { name, data_vec } => { + if let Some(name) = name { + for data in data_vec { + if let Some(field) = transform_field(name, data) { + fields.push(field); + } + } + } + } + } + } + } + } + + let packet = output::Packet { id, name, fields }; packets.push(packet); } @@ -164,6 +167,95 @@ fn transform_protocol_data(protocol_data: &ProtocolData) -> Vec { packets } +fn get_packet_ids(protocol_data: &ProtocolData) -> HashMap { + let reversed_packet_ids = protocol_data + .types + .get("packet") + .and_then(|d| d.get(1)) + .and_then(|d| match d { + Data::Container(data) => data.get(0), + _ => None, + }) + .and_then(|c| match c { + Container::List { data_vec, .. } => data_vec.get(1), + _ => None, + }) + .and_then(|d| match d { + Data::Mapper { mappings, .. } => Some(mappings), + _ => None, + }) + .expect("Failed to get packet ids"); + + reversed_packet_ids + .into_iter() + .map(|(k, v)| { + ( + v.clone(), + u8::from_str_radix(k.trim_start_matches("0x"), 16).expect("Invalid packet id"), + ) + }) + .collect() +} + +fn transform_field(unformatted_field_name: &str, data: &Data) -> Option { + match data { + Data::Type(str_type) => match transform_data_type(str_type) { + Some(data_type) => Some(output::Field { + name: format_field_name(unformatted_field_name), + data_type, + }), + None => None, + }, + _ => None, + } +} + +fn format_field_name(unformatted_field_name: &str) -> String { + if unformatted_field_name == "Type" { + String::from("type_") + } else { + unformatted_field_name.to_snake_case() + } +} + +fn transform_data_type(str_type: &str) -> Option { + match str_type { + "bool" => Some(output::DataType::Boolean), + "i8" => Some(output::DataType::Byte), + "i16" => Some(output::DataType::Short), + "i32" => Some(output::DataType::Int { var_int: false }), + "i64" => Some(output::DataType::Long { var_long: false }), + "u8" => Some(output::DataType::UnsignedByte), + "u16" => Some(output::DataType::UnsignedShort), + "f32" => Some(output::DataType::Float), + "f64" => Some(output::DataType::Double), + "varint" => Some(output::DataType::Int { var_int: true }), + "varlong" => Some(output::DataType::Long { var_long: true }), + "string" => Some(output::DataType::String { max_length: 0 }), + "nbt" | "optionalNbt" => Some(output::DataType::CompoundTag), + "UUID" => Some(output::DataType::Uuid { hyphenated: false }), + "buffer" => Some(output::DataType::ByteArray { rest: false }), + "restBuffer" => Some(output::DataType::ByteArray { rest: true }), + _ => { + println!("{}", str_type); + None + } + } +} + +fn rename_packet(name: &str, bound: &output::Bound) -> String { + match (name, bound) { + ("EncryptionBegin", output::Bound::Server) => "EncryptionResponse", + ("EncryptionBegin", output::Bound::Client) => "EncryptionRequest", + ("PingStart", output::Bound::Server) => "StatusRequest", + ("Ping", output::Bound::Server) => "PingRequest", + ("ServerInfo", output::Bound::Client) => "StatusResponse", + ("Ping", output::Bound::Client) => "PingResponse", + _ => name, + } + .to_owned() +} + #[derive(Serialize)] struct GenerateContext<'a> { packet_enum_name: String, @@ -176,12 +268,12 @@ fn generate_rust_file( mut writer: W, ) -> Result<(), TemplateRenderError> { let server_bound_ctx = GenerateContext { - packet_enum_name: format!("{}{}BoundPacket", &protocol.state, Bound::Server), + packet_enum_name: format!("{}{}BoundPacket", &protocol.state, output::Bound::Server), packets: &protocol.server_bound_packets, }; let client_bound_ctx = GenerateContext { - packet_enum_name: format!("{}{}BoundPacket", &protocol.state, Bound::Client), + packet_enum_name: format!("{}{}BoundPacket", &protocol.state, output::Bound::Client), packets: &protocol.client_bound_packets, }; diff --git a/protocol/src/packet/handshake.rs b/protocol/src/packet/handshake.rs new file mode 100644 index 0000000..77d3687 --- /dev/null +++ b/protocol/src/packet/handshake.rs @@ -0,0 +1,52 @@ +use crate::DecodeError; +use crate::Decoder; +use minecraft_protocol_derive::Packet; +use std::io::Read; + +pub enum HandshakeServerBoundPacket { + SetProtocol(SetProtocol), +} + +impl HandshakeServerBoundPacket { + pub fn get_type_id(&self) -> u8 { + match self { + Self::SetProtocol(_) => 0x00, + } + } + + pub fn decode(type_id: u8, reader: &mut R) -> Result { + match type_id { + 0x00 => { + let set_protocol = SetProtocol::decode(reader)?; + + Ok(Self::SetProtocol(set_protocol)) + } + _ => Err(DecodeError::UnknownPacketType { type_id }), + } + } + + pub fn set_protocol( + protocol_version: i32, + server_host: String, + server_port: u16, + next_state: i32, + ) -> Self { + let set_protocol = SetProtocol { + protocol_version, + server_host, + server_port, + next_state, + }; + + Self::SetProtocol(set_protocol) + } +} +#[derive(Packet, Debug)] +pub struct SetProtocol { + #[packet(with = "var_int")] + pub protocol_version: i32, + pub server_host: String, + pub server_port: u16, + #[packet(with = "var_int")] + pub next_state: i32, +} diff --git a/protocol/src/packet/login.rs b/protocol/src/packet/login.rs index c70f8e4..00c489e 100644 --- a/protocol/src/packet/login.rs +++ b/protocol/src/packet/login.rs @@ -1,31 +1,21 @@ -use crate::data::chat::Message; use crate::DecodeError; use crate::Decoder; use std::io::Read; -use uuid::Uuid; - use minecraft_protocol_derive::Packet; + pub enum LoginServerBoundPacket { LoginStart(LoginStart), EncryptionResponse(EncryptionResponse), - LoginPluginResponse(LoginPluginResponse), -} - -pub enum LoginClientBoundPacket { - LoginDisconnect(LoginDisconnect), - EncryptionRequest(EncryptionRequest), - LoginSuccess(LoginSuccess), - SetCompression(SetCompression), - LoginPluginRequest(LoginPluginRequest), + LoginPluginResponse(LoginPluginResponse) } impl LoginServerBoundPacket { pub fn get_type_id(&self) -> u8 { match self { - LoginServerBoundPacket::LoginStart(_) => 0x00, - LoginServerBoundPacket::EncryptionResponse(_) => 0x01, - LoginServerBoundPacket::LoginPluginResponse(_) => 0x02, + Self::LoginStart(_) => 0x00, + Self::EncryptionResponse(_) => 0x01, + Self::LoginPluginResponse(_) => 0x02 } } @@ -34,119 +24,185 @@ impl LoginServerBoundPacket { 0x00 => { let login_start = LoginStart::decode(reader)?; - Ok(LoginServerBoundPacket::LoginStart(login_start)) + Ok(Self::LoginStart(login_start)) } 0x01 => { let encryption_response = EncryptionResponse::decode(reader)?; - Ok(LoginServerBoundPacket::EncryptionResponse( - encryption_response, - )) + Ok(Self::EncryptionResponse(encryption_response)) } 0x02 => { let login_plugin_response = LoginPluginResponse::decode(reader)?; - Ok(LoginServerBoundPacket::LoginPluginResponse( - login_plugin_response, - )) + Ok(Self::LoginPluginResponse(login_plugin_response)) } - _ => Err(DecodeError::UnknownPacketType { type_id }), + _ => Err(DecodeError::UnknownPacketType { type_id }) } } + + pub fn login_start(username: String) -> Self { + let login_start = LoginStart { + username + }; + + Self::LoginStart(login_start) + } + + pub fn encryption_response(shared_secret: Vec, verify_token: Vec) -> Self { + let encryption_response = EncryptionResponse { + shared_secret, + verify_token + }; + + Self::EncryptionResponse(encryption_response) + } + + pub fn login_plugin_response(message_id: i32, data: Vec) -> Self { + let login_plugin_response = LoginPluginResponse { + message_id, + data + }; + + Self::LoginPluginResponse(login_plugin_response) + } +} +pub enum LoginClientBoundPacket { + Disconnect(Disconnect), + EncryptionRequest(EncryptionRequest), + Success(Success), + Compress(Compress), + LoginPluginRequest(LoginPluginRequest) } impl LoginClientBoundPacket { pub fn get_type_id(&self) -> u8 { match self { - LoginClientBoundPacket::LoginDisconnect(_) => 0x00, - LoginClientBoundPacket::EncryptionRequest(_) => 0x01, - LoginClientBoundPacket::LoginSuccess(_) => 0x02, - LoginClientBoundPacket::SetCompression(_) => 0x03, - LoginClientBoundPacket::LoginPluginRequest(_) => 0x04, + Self::Disconnect(_) => 0x00, + Self::EncryptionRequest(_) => 0x01, + Self::Success(_) => 0x02, + Self::Compress(_) => 0x03, + Self::LoginPluginRequest(_) => 0x04 } } pub fn decode(type_id: u8, reader: &mut R) -> Result { match type_id { 0x00 => { - let login_disconnect = LoginDisconnect::decode(reader)?; + let disconnect = Disconnect::decode(reader)?; - Ok(LoginClientBoundPacket::LoginDisconnect(login_disconnect)) + Ok(Self::Disconnect(disconnect)) } 0x01 => { let encryption_request = EncryptionRequest::decode(reader)?; - Ok(LoginClientBoundPacket::EncryptionRequest( - encryption_request, - )) + Ok(Self::EncryptionRequest(encryption_request)) } 0x02 => { - let login_success = LoginSuccess::decode(reader)?; + let success = Success::decode(reader)?; - Ok(LoginClientBoundPacket::LoginSuccess(login_success)) + Ok(Self::Success(success)) } 0x03 => { - let set_compression = SetCompression::decode(reader)?; + let compress = Compress::decode(reader)?; - Ok(LoginClientBoundPacket::SetCompression(set_compression)) + Ok(Self::Compress(compress)) } 0x04 => { let login_plugin_request = LoginPluginRequest::decode(reader)?; - Ok(LoginClientBoundPacket::LoginPluginRequest( - login_plugin_request, - )) + Ok(Self::LoginPluginRequest(login_plugin_request)) } - _ => Err(DecodeError::UnknownPacketType { type_id }), + _ => Err(DecodeError::UnknownPacketType { type_id }) } } -} + pub fn disconnect(reason: String) -> Self { + let disconnect = Disconnect { + reason + }; + + Self::Disconnect(disconnect) + } + + pub fn encryption_request(server_id: String, public_key: Vec, verify_token: Vec) -> Self { + let encryption_request = EncryptionRequest { + server_id, + public_key, + verify_token + }; + + Self::EncryptionRequest(encryption_request) + } + + pub fn success(uuid: String, username: String) -> Self { + let success = Success { + uuid, + username + }; + + Self::Success(success) + } + + pub fn compress(threshold: i32) -> Self { + let compress = Compress { + threshold + }; + + Self::Compress(compress) + } + + pub fn login_plugin_request(message_id: i32, channel: String, data: Vec) -> Self { + let login_plugin_request = LoginPluginRequest { + message_id, + channel, + data + }; + + Self::LoginPluginRequest(login_plugin_request) + } +} #[derive(Packet, Debug)] pub struct LoginStart { - pub name: String, + pub username: String } #[derive(Packet, Debug)] pub struct EncryptionResponse { pub shared_secret: Vec, - pub verify_token: Vec, + pub verify_token: Vec } #[derive(Packet, Debug)] pub struct LoginPluginResponse { #[packet(with = "var_int")] pub message_id: i32, - pub successful: bool, #[packet(with = "rest")] - pub data: Vec, + pub data: Vec } + #[derive(Packet, Debug)] -pub struct LoginDisconnect { - pub reason: Message, +pub struct Disconnect { + pub reason: String } #[derive(Packet, Debug)] pub struct EncryptionRequest { - #[packet(max_length = 20)] pub server_id: String, pub public_key: Vec, - pub verify_token: Vec, + pub verify_token: Vec } #[derive(Packet, Debug)] -pub struct LoginSuccess { - #[packet(with = "uuid_hyp_str")] - pub uuid: Uuid, - #[packet(max_length = 16)] - pub username: String, +pub struct Success { + pub uuid: String, + pub username: String } #[derive(Packet, Debug)] -pub struct SetCompression { +pub struct Compress { #[packet(with = "var_int")] - pub threshold: i32, + pub threshold: i32 } #[derive(Packet, Debug)] @@ -155,5 +211,6 @@ pub struct LoginPluginRequest { pub message_id: i32, pub channel: String, #[packet(with = "rest")] - pub data: Vec, + pub data: Vec } + diff --git a/protocol/src/packet/mod.rs b/protocol/src/packet/mod.rs index 986f00e..29a91c1 100644 --- a/protocol/src/packet/mod.rs +++ b/protocol/src/packet/mod.rs @@ -1,3 +1,4 @@ pub mod game; +pub mod handshake; pub mod login; pub mod status; diff --git a/protocol/src/packet/status.rs b/protocol/src/packet/status.rs index a801f2f..a754a9c 100644 --- a/protocol/src/packet/status.rs +++ b/protocol/src/packet/status.rs @@ -1,60 +1,106 @@ -use crate::data::status::ServerStatus; use crate::DecodeError; use crate::Decoder; -use minecraft_protocol_derive::Packet; use std::io::Read; +use minecraft_protocol_derive::Packet; + pub enum StatusServerBoundPacket { StatusRequest, - PingRequest(PingRequest), -} - -pub enum StatusClientBoundPacket { - StatusResponse(StatusResponse), - PingResponse(PingResponse), + PingRequest(PingRequest) } impl StatusServerBoundPacket { pub fn get_type_id(&self) -> u8 { match self { - StatusServerBoundPacket::StatusRequest => 0x00, - StatusServerBoundPacket::PingRequest(_) => 0x01, + Self::StatusRequest => 0x00, + Self::PingRequest(_) => 0x01 } } pub fn decode(type_id: u8, reader: &mut R) -> Result { match type_id { - 0x00 => Ok(StatusServerBoundPacket::StatusRequest), + 0x00 => { + Ok(Self::StatusRequest) + } 0x01 => { let ping_request = PingRequest::decode(reader)?; - Ok(StatusServerBoundPacket::PingRequest(ping_request)) + Ok(Self::PingRequest(ping_request)) } - _ => Err(DecodeError::UnknownPacketType { type_id }), + _ => Err(DecodeError::UnknownPacketType { type_id }) } } + + pub fn status_request() -> Self { + Self::StatusRequest + } + + pub fn ping_request(time: i64) -> Self { + let ping_request = PingRequest { + time + }; + + Self::PingRequest(ping_request) + } +} +pub enum StatusClientBoundPacket { + StatusResponse(StatusResponse), + PingResponse(PingResponse) } impl StatusClientBoundPacket { pub fn get_type_id(&self) -> u8 { match self { - StatusClientBoundPacket::StatusResponse(_) => 0x00, - StatusClientBoundPacket::PingResponse(_) => 0x01, + Self::StatusResponse(_) => 0x00, + Self::PingResponse(_) => 0x01 } } -} + pub fn decode(type_id: u8, reader: &mut R) -> Result { + match type_id { + 0x00 => { + let status_response = StatusResponse::decode(reader)?; + + Ok(Self::StatusResponse(status_response)) + } + 0x01 => { + let ping_response = PingResponse::decode(reader)?; + + Ok(Self::PingResponse(ping_response)) + } + _ => Err(DecodeError::UnknownPacketType { type_id }) + } + } + + pub fn status_response(response: String) -> Self { + let status_response = StatusResponse { + response + }; + + Self::StatusResponse(status_response) + } + + pub fn ping_response(time: i64) -> Self { + let ping_response = PingResponse { + time + }; + + Self::PingResponse(ping_response) + } +} #[derive(Packet, Debug)] pub struct PingRequest { - pub time: u64, + pub time: i64 +} + + +#[derive(Packet, Debug)] +pub struct StatusResponse { + pub response: String } #[derive(Packet, Debug)] pub struct PingResponse { - pub time: u64, + pub time: i64 } -#[derive(Packet, Debug)] -pub struct StatusResponse { - pub server_status: ServerStatus, -}