WIP input parse
This commit is contained in:
@@ -10,7 +10,7 @@ repository = "https://github.com/eihwaz/minecraft-protocol"
|
|||||||
keywords = ["minecraft", "cli", "protocol", "packet", "io"]
|
keywords = ["minecraft", "cli", "protocol", "packet", "io"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.3"
|
structopt = "0.3"
|
||||||
serde = "1.0.120"
|
serde = "1.0.120"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
handlebars = "3.5.2"
|
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;
|
mod data;
|
||||||
|
|
||||||
use crate::data::*;
|
use crate::data::input;
|
||||||
use handlebars::*;
|
use handlebars::*;
|
||||||
use heck::SnakeCase;
|
use heck::SnakeCase;
|
||||||
|
|
||||||
|
use crate::data::output;
|
||||||
|
use crate::data::output::Bound;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
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() {
|
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();
|
let mut template_engine = Handlebars::new();
|
||||||
|
|
||||||
template_engine.register_helper("snake_case", Box::new(format_snake_case));
|
template_engine.register_helper("snake_case", Box::new(format_snake_case));
|
||||||
@@ -36,73 +65,17 @@ pub fn main() {
|
|||||||
)
|
)
|
||||||
.expect("Failed to register template");
|
.expect("Failed to register template");
|
||||||
|
|
||||||
let protocol = Protocol::new(
|
template_engine
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct GenerateContext<'a> {
|
struct GenerateContext<'a> {
|
||||||
packet_enum_name: String,
|
packet_enum_name: String,
|
||||||
packets: &'a Vec<Packet>,
|
packets: &'a Vec<output::Packet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_rust_file<W: Write>(
|
pub fn generate_rust_file<W: Write>(
|
||||||
protocol: &Protocol,
|
protocol: &output::Protocol,
|
||||||
template_engine: &Handlebars,
|
template_engine: &Handlebars,
|
||||||
mut writer: W,
|
mut writer: W,
|
||||||
) -> Result<(), TemplateRenderError> {
|
) -> Result<(), TemplateRenderError> {
|
||||||
|
Reference in New Issue
Block a user