WIP input parse

This commit is contained in:
Vladislavs Golubs
2021-02-06 18:59:51 +03:00
parent 3189f0c0d9
commit 3229d02418
5 changed files with 174 additions and 61 deletions

@@ -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"

@@ -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);
}
}

@@ -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> {