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
protocol-generator

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

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

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

@@ -2,12 +2,15 @@ mod data;
use crate::data::input;
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::Bound;
use crate::data::output::{Bound, Packet, State};
use linked_hash_map::LinkedHashMap;
use serde::Serialize;
use serde_json::json;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use structopt::StructOpt;
@@ -31,10 +34,35 @@ pub fn main() {
let 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");
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> {
@@ -68,13 +96,81 @@ fn create_template_engine() -> Handlebars<'static> {
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)]
struct GenerateContext<'a> {
packet_enum_name: String,
packets: &'a Vec<output::Packet>,
}
pub fn generate_rust_file<W: Write>(
fn generate_rust_file<W: Write>(
protocol: &output::Protocol,
template_engine: &Handlebars,
mut writer: W,

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