Skip to main content

airi_codegen/
packets.rs

1use indexmap::IndexMap;
2use std::fs::File;
3
4use heck::ToShoutySnekCase;
5use proc_macro2::TokenStream;
6use quote::format_ident;
7use quote::quote;
8
9pub fn build() -> TokenStream {
10    let packets_file = File::open("airi-codegen/assets/packets.json").unwrap();
11    let packet_data: IndexMap<String, IndexMap<String, IndexMap<String, i32>>> =
12        serde_json::from_reader(packets_file).unwrap();
13
14    // packet -> (dir,state,id)
15    let mut seen_packets: IndexMap<String, (String, String, i32)> = IndexMap::new();
16
17    for (state, dirs) in packet_data {
18        for (dir, packets) in dirs {
19            for (mut packet, id) in packets {
20                packet = packet.strip_prefix("minecraft:").unwrap().to_owned();
21                insert_recurse(&mut seen_packets, packet, &dir, &state, id);
22            }
23        }
24    }
25
26    let mut packet_declarations = Vec::new();
27
28    for (packet, (_, _, id)) in seen_packets {
29        let var_name = format_ident!("{}", packet.replace('/', "_").TO_SHOUTY_SNEK_CASE());
30        packet_declarations.push(quote! { pub const #var_name: i32 = #id; });
31    }
32
33    quote! {
34        #(#packet_declarations)*
35    }
36}
37
38// this was so much more work than necessary omfg
39fn insert_recurse(
40    seen_packets: &mut IndexMap<String, (String, String, i32)>,
41    mut packet: String,
42    dir: &String,
43    state: &String,
44    id: i32,
45) {
46    // shift_remove is O(n) but maintains order
47    if let Some(other) = seen_packets.shift_remove(&packet) {
48        if &other.0 == dir {
49            packet.push('_');
50            insert_recurse(
51                seen_packets,
52                packet.clone() + &other.1,
53                &other.0,
54                &other.1,
55                other.2,
56            );
57            insert_recurse(seen_packets, packet.clone() + state, dir, state, id);
58        } else {
59            insert_recurse(
60                seen_packets,
61                other.0.clone() + "_" + &packet,
62                &other.0,
63                &other.1,
64                other.2,
65            );
66            insert_recurse(seen_packets, dir.clone() + "_" + &packet, dir, state, id);
67        }
68    } else {
69        seen_packets.insert(packet.clone(), (dir.clone(), state.clone(), id));
70    }
71}