diff --git a/Cargo.lock b/Cargo.lock index 940c901..1efae70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1745,10 +1745,14 @@ version = "0.1.0" dependencies = [ "byteorder", "crc32fast", + "prettyplease", "prost", "prost-build", "quote", + "serde", + "serde_json", "shorekeeper-protocol-derive", + "syn", "thiserror", ] diff --git a/shorekeeper-protocol/Cargo.toml b/shorekeeper-protocol/Cargo.toml index 43854dc..2d43db2 100644 --- a/shorekeeper-protocol/Cargo.toml +++ b/shorekeeper-protocol/Cargo.toml @@ -8,8 +8,12 @@ byteorder.workspace = true crc32fast.workspace = true thiserror.workspace = true prost.workspace = true +serde.workspace = true +serde_json.workspace = true shorekeeper-protocol-derive.workspace = true [build-dependencies] prost-build.workspace = true quote = "1.0.35" +syn = "2.0.76" +prettyplease = "0.2.22" diff --git a/shorekeeper-protocol/build.rs b/shorekeeper-protocol/build.rs index 14e3a4f..f423e99 100644 --- a/shorekeeper-protocol/build.rs +++ b/shorekeeper-protocol/build.rs @@ -3,8 +3,9 @@ use std::{ io::{self, BufRead}, path::Path, }; +use std::io::Write; -use quote::quote; +use quote::{format_ident, quote}; const CODEGEN_OUT_DIR: &str = "generated/"; @@ -26,9 +27,11 @@ pub fn main() { prost_build::Config::new() .out_dir(CODEGEN_OUT_DIR) .type_attribute(".", "#[derive(shorekeeper_protocol_derive::MessageID)]") + .type_attribute(".", "#[derive(serde::Serialize,serde::Deserialize)]") .compile_protos(&[proto_file], &["shorekeeper"]) .unwrap(); + impl_dumper(Path::new("generated/shorekeeper.rs")).unwrap(); impl_message_id(Path::new("generated/shorekeeper.rs")).unwrap(); } @@ -92,10 +95,11 @@ pub fn impl_proto_config(csv_path: &Path, codegen_path: &Path) -> io::Result<()> } } } - } - .to_string(); + }; - fs::write(codegen_path, generated_code.as_bytes())?; + let syntax_tree = syn::parse2(generated_code).unwrap(); + let formatted = prettyplease::unparse(&syntax_tree); + fs::write(codegen_path, formatted.as_bytes())?; Ok(()) } @@ -126,3 +130,54 @@ fn make_message_id_attr(line: &str) -> Option { let id = line.trim_start().split(' ').nth(2)?.parse::().ok()?; Some(format!("#[message_id({id})]")) } + +pub fn impl_dumper(codegen_path: &Path) -> io::Result<()> { + let file = fs::File::open(codegen_path)?; + let reader = io::BufReader::new(file); + let mut match_arms = quote! {}; + + let mut id = None; + for line in reader.lines() { + let line = line?; + + if line.contains("MessageId:") { + id = Some( + line.trim_start().split(' ').nth(2).unwrap().parse::().ok().unwrap() + ); + } else if line.contains("pub struct") { + if let Some(id) = id.take() { + let name = format_ident!( + "{}", line.trim_start().split(' ').nth(2).unwrap().to_string() + ); + match_arms = quote! { + #match_arms + #id => serde_json::to_string(&#name::decode(data).unwrap()), + }; + } + } + } + + let generated_code = quote! { + pub mod proto_dumper { + use prost::Message; + use crate::*; + use crate::ai::*; + use crate::combat_message::*; + use crate::debug::*; + use crate::summon::*; + + pub fn get_debug_info(id: u16, data: &[u8]) -> String { + match id { + #match_arms + _ => Ok("".to_string()), + }.unwrap() + } + } + }; + + let syntax_tree = syn::parse2(generated_code).unwrap(); + let formatted = prettyplease::unparse(&syntax_tree); + let mut file = fs::OpenOptions::new().append(true).open(codegen_path)?; + file.write(formatted.as_bytes())?; + Ok(()) +} \ No newline at end of file