WIP input parse
This commit is contained in:
protocol-generator
@@ -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"
|
||||
|
138
protocol-generator/src/data/input.rs
Normal file
138
protocol-generator/src/data/input.rs
Normal file
@@ -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<String, Vec<Container>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Container {
|
||||
Type(String),
|
||||
Data(Vec<ContainerData>),
|
||||
}
|
||||
|
||||
#[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<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct Switch {
|
||||
#[serde(rename = "compareTo")]
|
||||
compare_to: String,
|
||||
fields: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
}
|
2
protocol-generator/src/data/mod.rs
Normal file
2
protocol-generator/src/data/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod input;
|
||||
pub mod output;
|
@@ -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<Packet>,
|
||||
packets: &'a Vec<output::Packet>,
|
||||
}
|
||||
|
||||
pub fn generate_rust_file<W: Write>(
|
||||
protocol: &Protocol,
|
||||
protocol: &output::Protocol,
|
||||
template_engine: &Handlebars,
|
||||
mut writer: W,
|
||||
) -> Result<(), TemplateRenderError> {
|
||||
|
Reference in New Issue
Block a user