Fix packet ids
This commit is contained in:
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}}
|
Reference in New Issue
Block a user