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