diff --git a/protocol-generator/src/frontend.rs b/protocol-generator/src/frontend.rs index dda1d30..49ce8f1 100644 --- a/protocol-generator/src/frontend.rs +++ b/protocol-generator/src/frontend.rs @@ -1,7 +1,11 @@ +use crate::frontend; +use handlebars::{Handlebars, TemplateRenderError}; use serde::Serialize; +use serde_json::json; use std::collections::HashSet; use std::fmt; use std::fmt::Display; +use std::io::Write; #[derive(Debug, Copy, Clone)] pub enum State { @@ -172,3 +176,48 @@ impl Protocol { .collect() } } + +#[derive(Serialize)] +struct GenerateContext<'a> { + packet_enum_name: String, + packets: &'a Vec, +} + +pub fn generate_rust_file( + protocol: &frontend::Protocol, + template_engine: &Handlebars, + mut writer: W, +) -> Result<(), TemplateRenderError> { + let server_bound_ctx = GenerateContext { + packet_enum_name: format!("{}{}BoundPacket", &protocol.state, frontend::Bound::Server), + packets: &protocol.server_bound_packets, + }; + + let client_bound_ctx = GenerateContext { + packet_enum_name: format!("{}{}BoundPacket", &protocol.state, frontend::Bound::Client), + packets: &protocol.client_bound_packets, + }; + + let mut imports = vec![ + "crate::DecodeError", + "crate::Decoder", + "std::io::Read", + "minecraft_protocol_derive::Packet", + ]; + + imports.extend(protocol.data_type_imports().iter()); + + template_engine.render_to_write( + "packet_imports", + &json!({ "imports": imports }), + &mut writer, + )?; + + template_engine.render_to_write("packet_enum", &server_bound_ctx, &mut writer)?; + template_engine.render_to_write("packet_enum", &client_bound_ctx, &mut writer)?; + + template_engine.render_to_write("packet_structs", &server_bound_ctx, &mut writer)?; + template_engine.render_to_write("packet_structs", &client_bound_ctx, &mut writer)?; + + Ok(()) +} diff --git a/protocol-generator/src/main.rs b/protocol-generator/src/main.rs index ffbd346..cd6f1cc 100644 --- a/protocol-generator/src/main.rs +++ b/protocol-generator/src/main.rs @@ -1,18 +1,13 @@ use std::fs::File; -use std::io::Write; use crate::mappings::CodeMappings; -use crate::transformer::transform_protocol; -use handlebars::*; -use heck::SnakeCase; -use serde::Serialize; -use serde_json::json; use structopt::StructOpt; pub mod backend; pub mod frontend; pub mod mappings; -pub mod transformer; +pub mod templates; +pub mod transformers; #[derive(StructOpt)] #[structopt(name = "protocol-generator")] @@ -23,7 +18,7 @@ struct Opt { pub fn main() { let opt: Opt = Opt::from_args(); - let template_engine = create_template_engine(); + let template_engine = templates::create_template_engine(); let protocol_data_file_name = format!( "protocol-generator/minecraft-data/data/pc/{}/protocol.json", @@ -40,7 +35,7 @@ pub fn main() { let protocols = vec![ ( - transform_protocol( + transformers::transform_protocol( &mappings, frontend::State::Handshake, &protocol_input.handshaking, @@ -48,15 +43,27 @@ pub fn main() { frontend::State::Handshake, ), ( - transform_protocol(&mappings, frontend::State::Status, &protocol_input.status), + transformers::transform_protocol( + &mappings, + frontend::State::Status, + &protocol_input.status, + ), frontend::State::Status, ), ( - transform_protocol(&mappings, frontend::State::Login, &protocol_input.login), + transformers::transform_protocol( + &mappings, + frontend::State::Login, + &protocol_input.login, + ), frontend::State::Login, ), ( - transform_protocol(&mappings, frontend::State::Game, &protocol_input.game), + transformers::transform_protocol( + &mappings, + frontend::State::Game, + &protocol_input.game, + ), frontend::State::Game, ), ]; @@ -68,123 +75,7 @@ pub fn main() { ); let file = File::create(file_name).expect("Failed to create file"); - generate_rust_file(&protocol, &template_engine, &file) + frontend::generate_rust_file(&protocol, &template_engine, &file) .expect("Failed to generate rust file"); } } - -fn create_template_engine() -> Handlebars<'static> { - let mut template_engine = Handlebars::new(); - - template_engine.register_helper("snake_case", Box::new(format_snake_case)); - template_engine.register_helper("packet_id", Box::new(format_packet_id)); - template_engine.register_escape_fn(|s| s.to_owned()); - - template_engine - .register_template_file( - "packet_imports", - "protocol-generator/templates/packet_imports.hbs", - ) - .expect("Failed to register template"); - - template_engine - .register_template_file( - "packet_enum", - "protocol-generator/templates/packet_enum.hbs", - ) - .expect("Failed to register template"); - - template_engine - .register_template_file( - "packet_structs", - "protocol-generator/templates/packet_structs.hbs", - ) - .expect("Failed to register template"); - - template_engine -} - -#[derive(Serialize)] -struct GenerateContext<'a> { - packet_enum_name: String, - packets: &'a Vec, -} - -fn generate_rust_file( - protocol: &frontend::Protocol, - template_engine: &Handlebars, - mut writer: W, -) -> Result<(), TemplateRenderError> { - let server_bound_ctx = GenerateContext { - packet_enum_name: format!("{}{}BoundPacket", &protocol.state, frontend::Bound::Server), - packets: &protocol.server_bound_packets, - }; - - let client_bound_ctx = GenerateContext { - packet_enum_name: format!("{}{}BoundPacket", &protocol.state, frontend::Bound::Client), - packets: &protocol.client_bound_packets, - }; - - let mut imports = vec![ - "crate::DecodeError", - "crate::Decoder", - "std::io::Read", - "minecraft_protocol_derive::Packet", - ]; - - imports.extend(protocol.data_type_imports().iter()); - - template_engine.render_to_write( - "packet_imports", - &json!({ "imports": imports }), - &mut writer, - )?; - - template_engine.render_to_write("packet_enum", &server_bound_ctx, &mut writer)?; - template_engine.render_to_write("packet_enum", &client_bound_ctx, &mut writer)?; - - template_engine.render_to_write("packet_structs", &server_bound_ctx, &mut writer)?; - template_engine.render_to_write("packet_structs", &client_bound_ctx, &mut writer)?; - - Ok(()) -} - -fn format_snake_case( - h: &Helper, - _: &Handlebars, - _: &Context, - _: &mut RenderContext, - out: &mut dyn Output, -) -> Result<(), RenderError> { - let str = h - .param(0) - .and_then(|v| v.value().as_str()) - .ok_or(RenderError::new( - "Param 0 with str type is required for snake case helper.", - ))? as &str; - - let snake_case_str = str.to_snake_case(); - - out.write(snake_case_str.as_ref())?; - Ok(()) -} - -fn format_packet_id( - h: &Helper, - _: &Handlebars, - _: &Context, - _: &mut RenderContext, - out: &mut dyn Output, -) -> Result<(), RenderError> { - let id = h - .param(0) - .and_then(|v| v.value().as_u64()) - .ok_or(RenderError::new( - "Param 0 with u64 type is required for packet id helper.", - ))? as u64; - - let packet_id_str = format!("{:#04X}", id); - - out.write(packet_id_str.as_ref())?; - Ok(()) -} diff --git a/protocol-generator/src/templates.rs b/protocol-generator/src/templates.rs new file mode 100644 index 0000000..2bc1993 --- /dev/null +++ b/protocol-generator/src/templates.rs @@ -0,0 +1,73 @@ +use handlebars::{Context, Handlebars, Helper, Output, RenderContext, RenderError}; +use heck::SnakeCase; + +pub fn create_template_engine() -> Handlebars<'static> { + let mut template_engine = Handlebars::new(); + + template_engine.register_helper("snake_case", Box::new(format_snake_case)); + template_engine.register_helper("packet_id", Box::new(format_packet_id)); + template_engine.register_escape_fn(|s| s.to_owned()); + + template_engine + .register_template_file( + "packet_imports", + "protocol-generator/templates/packet_imports.hbs", + ) + .expect("Failed to register template"); + + template_engine + .register_template_file( + "packet_enum", + "protocol-generator/templates/packet_enum.hbs", + ) + .expect("Failed to register template"); + + template_engine + .register_template_file( + "packet_structs", + "protocol-generator/templates/packet_structs.hbs", + ) + .expect("Failed to register template"); + + template_engine +} + +fn format_snake_case( + h: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> Result<(), RenderError> { + let str = h + .param(0) + .and_then(|v| v.value().as_str()) + .ok_or(RenderError::new( + "Param 0 with str type is required for snake case helper.", + ))? as &str; + + let snake_case_str = str.to_snake_case(); + + out.write(snake_case_str.as_ref())?; + Ok(()) +} + +fn format_packet_id( + h: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> Result<(), RenderError> { + let id = h + .param(0) + .and_then(|v| v.value().as_u64()) + .ok_or(RenderError::new( + "Param 0 with u64 type is required for packet id helper.", + ))? as u64; + + let packet_id_str = format!("{:#04X}", id); + + out.write(packet_id_str.as_ref())?; + Ok(()) +} diff --git a/protocol-generator/src/transformer.rs b/protocol-generator/src/transformers.rs similarity index 100% rename from protocol-generator/src/transformer.rs rename to protocol-generator/src/transformers.rs