Fix packet ids

This commit is contained in:
Vladislavs Golubs
2021-02-07 02:20:12 +03:00
parent ab4d40e482
commit d589bd7956
5 changed files with 130 additions and 29 deletions

View File

@@ -15,3 +15,4 @@ serde = "1.0.120"
serde_json = "1.0" serde_json = "1.0"
handlebars = "3.5.2" handlebars = "3.5.2"
heck = "0.3.2" heck = "0.3.2"
linked-hash-map = { version = "0.5.4", features = ["serde_impl"] }

View File

@@ -1,37 +1,38 @@
use linked_hash_map::LinkedHashMap;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct Protocol { pub struct Protocol {
handshaking: ProtocolState, pub handshaking: ProtocolState,
status: ProtocolState, pub status: ProtocolState,
login: ProtocolState, pub login: ProtocolState,
#[serde(rename = "play")] #[serde(rename = "play")]
game: ProtocolState, pub game: ProtocolState,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ProtocolState { pub struct ProtocolState {
to_client: ProtocolData, pub to_client: ProtocolData,
to_server: ProtocolData, pub to_server: ProtocolData,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct ProtocolData { pub struct ProtocolData {
types: HashMap<String, Vec<Data>>, pub types: LinkedHashMap<String, Vec<Data>>,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
enum Data { pub enum Data {
Type(String), Type(String),
Container(Vec<Container>), Container(Vec<Container>),
Mapper { Mapper {
#[serde(rename = "type")] #[serde(rename = "type")]
mappings_type: String, mappings_type: String,
mappings: HashMap<String, String>, mappings: LinkedHashMap<String, String>,
}, },
Switch(Switch), Switch(Switch),
List(Box<List>), List(Box<List>),
@@ -40,13 +41,13 @@ enum Data {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
enum Container { pub enum Container {
Value { Value {
name: String, name: String,
#[serde(rename = "type")] #[serde(rename = "type")]
data: Data, data: Data,
}, },
Array { List {
name: Option<String>, name: Option<String>,
#[serde(rename = "type")] #[serde(rename = "type")]
data: Vec<Data>, data: Vec<Data>,
@@ -55,7 +56,7 @@ enum Container {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
enum Switch { pub enum Switch {
Empty { Empty {
#[serde(rename = "compareTo")] #[serde(rename = "compareTo")]
compare_to: String, compare_to: String,
@@ -63,18 +64,18 @@ enum Switch {
Value { Value {
#[serde(rename = "compareTo")] #[serde(rename = "compareTo")]
compare_to: String, compare_to: String,
fields: HashMap<String, Data>, fields: LinkedHashMap<String, Data>,
}, },
List { List {
#[serde(rename = "compareTo")] #[serde(rename = "compareTo")]
compare_to: String, compare_to: String,
fields: HashMap<String, Vec<Data>>, fields: LinkedHashMap<String, Vec<Data>>,
}, },
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
enum List { pub enum List {
Empty { Empty {
#[serde(rename = "countType")] #[serde(rename = "countType")]
count_type: String, count_type: String,
@@ -85,7 +86,7 @@ enum List {
#[serde(rename = "type")] #[serde(rename = "type")]
list_type: Data, list_type: Data,
}, },
Array { List {
#[serde(rename = "countType")] #[serde(rename = "countType")]
count_type: String, count_type: String,
#[serde(rename = "type")] #[serde(rename = "type")]
@@ -94,7 +95,7 @@ enum List {
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct BitField { pub struct BitField {
name: String, name: String,
size: usize, size: usize,
signed: bool, signed: bool,

View File

@@ -52,13 +52,15 @@ impl Display for Bound {
#[derive(Serialize)] #[derive(Serialize)]
pub struct Packet { pub struct Packet {
pub id: u8,
pub name: String, pub name: String,
pub fields: Vec<Field>, pub fields: Vec<Field>,
} }
impl Packet { impl Packet {
pub fn new(name: impl ToString, fields: Vec<Field>) -> Packet { pub fn new(id: u8, name: impl ToString, fields: Vec<Field>) -> Packet {
Packet { Packet {
id,
name: name.to_string(), name: name.to_string(),
fields, fields,
} }

View File

@@ -2,12 +2,15 @@ mod data;
use crate::data::input; use crate::data::input;
use handlebars::*; use handlebars::*;
use heck::SnakeCase; use heck::{CamelCase, KebabCase, MixedCase, SnakeCase, TitleCase};
use crate::data::input::{Container, Data, ProtocolData, ProtocolState};
use crate::data::output; use crate::data::output;
use crate::data::output::Bound; use crate::data::output::{Bound, Packet, State};
use linked_hash_map::LinkedHashMap;
use serde::Serialize; use serde::Serialize;
use serde_json::json; use serde_json::json;
use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use structopt::StructOpt; use structopt::StructOpt;
@@ -31,10 +34,35 @@ pub fn main() {
let protocol_data_file = let protocol_data_file =
File::open(protocol_data_file_name).expect("Failed to open protocol data file"); File::open(protocol_data_file_name).expect("Failed to open protocol data file");
let protocol_data: input::Protocol = let protocol_input: input::Protocol =
serde_json::from_reader(protocol_data_file).expect("Failed to parse protocol data"); serde_json::from_reader(protocol_data_file).expect("Failed to parse protocol data");
println!("{:#?}", protocol_data) let protocols = vec![
(
transform_protocol_state(State::Handshake, &protocol_input.handshaking),
State::Handshake,
),
(
transform_protocol_state(State::Status, &protocol_input.status),
State::Status,
),
(
transform_protocol_state(State::Login, &protocol_input.login),
State::Login,
),
(
transform_protocol_state(State::Game, &protocol_input.game),
State::Game,
),
];
for (protocol, state) in protocols {
let file_name = format!("{}.rs", state.to_string().to_lowercase());
let file = File::create(file_name).expect("Failed to create file");
generate_rust_file(&protocol, &template_engine, &file)
.expect("Failed to generate rust file");
}
} }
fn create_template_engine() -> Handlebars<'static> { fn create_template_engine() -> Handlebars<'static> {
@@ -68,13 +96,81 @@ fn create_template_engine() -> Handlebars<'static> {
template_engine template_engine
} }
fn transform_protocol_state(state: State, protocol_state: &ProtocolState) -> output::Protocol {
let server_bound_packets = transform_protocol_data(&protocol_state.to_server);
let client_bound_packets = transform_protocol_data(&protocol_state.to_client);
output::Protocol {
state,
server_bound_packets,
client_bound_packets,
}
}
fn transform_protocol_data(protocol_data: &ProtocolData) -> Vec<Packet> {
let mut packets = vec![];
let reversed_packet_ids = protocol_data
.types
.get("packet")
.and_then(|d| d.get(1))
.and_then(|d| match d {
Data::Container(data) => data.get(0),
_ => None,
})
.and_then(|c| match c {
Container::List { data, .. } => data.get(1),
_ => None,
})
.and_then(|d| match d {
Data::Mapper { mappings, .. } => Some(mappings),
_ => None,
})
.expect("Failed to get packet ids");
let packet_ids: HashMap<String, u8> = reversed_packet_ids
.into_iter()
.map(|(k, v)| {
(
v.clone(),
u8::from_str_radix(k.trim_start_matches("0x"), 16).expect("Invalid packet id"),
)
})
.collect();
for (unformatted_name, data) in protocol_data.types.iter() {
if !unformatted_name.starts_with("packet_")
|| unformatted_name == "packet_legacy_server_list_ping"
{
continue;
}
let no_prefix_name = unformatted_name.trim_start_matches("packet_");
let id = *packet_ids
.get(no_prefix_name)
.expect("Failed to get packet id");
let name = no_prefix_name.to_camel_case();
let packet = Packet {
id,
name,
fields: vec![],
};
packets.push(packet);
}
packets
}
#[derive(Serialize)] #[derive(Serialize)]
struct GenerateContext<'a> { struct GenerateContext<'a> {
packet_enum_name: String, packet_enum_name: String,
packets: &'a Vec<output::Packet>, packets: &'a Vec<output::Packet>,
} }
pub fn generate_rust_file<W: Write>( fn generate_rust_file<W: Write>(
protocol: &output::Protocol, protocol: &output::Protocol,
template_engine: &Handlebars, template_engine: &Handlebars,
mut writer: W, mut writer: W,

View File

@@ -1,15 +1,15 @@
{{~#if packets}}
pub enum {{protocol_enum_name}} { pub enum {{packet_enum_name}} {
{{~#each packets as |p|}} {{~#each packets as |p|}}
{{p.name}}{{#if p.fields}}({{p.name}}){{/if}}{{#unless @last}},{{/unless}} {{p.name}}{{#if p.fields}}({{p.name}}){{/if}}{{#unless @last}},{{/unless}}
{{~/each}} {{~/each}}
} }
impl {{protocol_enum_name}} { impl {{packet_enum_name}} {
pub fn get_type_id(&self) -> u8 { pub fn get_type_id(&self) -> u8 {
match self { match self {
{{~#each packets as |p|}} {{~#each packets as |p|}}
Self::{{p.name}}{{#if p.fields}}(_){{/if}} => {{packet_id @index}}{{#unless @last}},{{/unless}} Self::{{p.name}}{{#if p.fields}}(_){{/if}} => {{packet_id p.id}}{{#unless @last}},{{/unless}}
{{~/each}} {{~/each}}
} }
} }
@@ -17,7 +17,7 @@ impl {{protocol_enum_name}} {
pub fn decode<R: Read>(type_id: u8, reader: &mut R) -> Result<Self, DecodeError> { pub fn decode<R: Read>(type_id: u8, reader: &mut R) -> Result<Self, DecodeError> {
match type_id { match type_id {
{{~#each packets as |p|}} {{~#each packets as |p|}}
{{@index}} => { {{packet_id p.id}} => {
{{~#if p.fields}} {{~#if p.fields}}
let {{snake_case p.name}} = {{p.name}}::decode(reader)?; let {{snake_case p.name}} = {{p.name}}::decode(reader)?;
@@ -48,3 +48,4 @@ impl {{protocol_enum_name}} {
} }
{{/each~}} {{/each~}}
} }
{{~/if}}