Pumpkin/pumpkin-data/build/packet.rs
Alexander Medvedev b0ab5006ca chore: remove unused deps
also apply some clippy lints in some places
2026-02-09 00:07:39 +01:00

115 lines
3.6 KiB
Rust

use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use serde::Deserialize;
use std::{collections::BTreeMap, fs};
#[derive(Deserialize)]
pub struct Packets {
version: u32,
serverbound: BTreeMap<String, BTreeMap<String, i32>>,
clientbound: BTreeMap<String, BTreeMap<String, i32>>,
}
pub fn build() -> TokenStream {
println!("cargo:rerun-if-changed=../assets/packet/1_21_7_packets.json");
println!("cargo:rerun-if-changed=../assets/packet/1_21_11_packets.json");
// 2. Parse the protocol files
let packets_7: Packets = serde_json::from_str(
&fs::read_to_string("../assets/packet/1_21_7_packets.json").expect("1.21.7 file missing"),
)
.unwrap();
let packets_11: Packets = serde_json::from_str(
&fs::read_to_string("../assets/packet/1_21_11_packets.json").expect("1.21.11 file missing"),
)
.unwrap();
let latest_version = packets_11.version;
// 3. Generate mapped constants for both directions
let serverbound_consts = generate_mapped_consts(&packets_11, &packets_7, true);
let clientbound_consts = generate_mapped_consts(&packets_11, &packets_7, false);
quote!(
use pumpkin_util::version::MinecraftVersion;
pub const CURRENT_MC_PROTOCOL: u32 = #latest_version;
pub struct PacketId {
pub latest_id: i32,
pub v1_21_7_id: i32,
}
impl PacketId {
/// Converts the latest packet ID to the ID used in the requested version.
/// Returns -1 if the packet does not exist in that version.
pub fn to_id(&self, version: MinecraftVersion) -> i32 {
match version {
MinecraftVersion::V_1_21_11 => self.latest_id,
MinecraftVersion::V_1_21_7 => self.v1_21_7_id,
// Default to latest for unrecognized/unmapped versions
_ => self.latest_id,
}
}
}
impl PartialEq<i32> for PacketId {
fn eq(&self, other: &i32) -> bool {
self.latest_id == *other
}
}
impl PartialEq<PacketId> for i32 {
fn eq(&self, other: &PacketId) -> bool {
*self == other.latest_id
}
}
// We place the constants directly into these modules
pub mod serverbound {
#serverbound_consts
}
pub mod clientbound {
#clientbound_consts
}
)
}
fn generate_mapped_consts(latest: &Packets, v7: &Packets, is_serverbound: bool) -> TokenStream {
let mut output = TokenStream::new();
let latest_phases = if is_serverbound {
&latest.serverbound
} else {
&latest.clientbound
};
let v7_phases = if is_serverbound {
&v7.serverbound
} else {
&v7.clientbound
};
for (phase, packets) in latest_phases {
for (name, id_11) in packets {
let sanitized = name.replace(['/', '-'], "_").to_uppercase();
let const_name = format_ident!("{}_{}", phase.to_uppercase(), sanitized);
// Check if the packet exists in 1.21.7 to get the alternate ID
let id_7 = v7_phases
.get(phase)
.and_then(|p| p.get(name))
.copied()
.unwrap_or(-1);
// Since serverbound/clientbound are modules, we reference the PacketId in the parent scope
output.extend(quote! {
pub const #const_name: super::PacketId = super::PacketId {
latest_id: #id_11,
v1_21_7_id: #id_7,
};
});
}
}
output
}