Pumpkin/pumpkin-codegen/src/statistic.rs
Alexander Medvedev 23e7992b2d Port to 26.2
2026-06-20 20:07:31 +02:00

115 lines
3.6 KiB
Rust

use heck::ToPascalCase;
use indexmap::IndexMap;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use serde::Deserialize;
#[derive(Deserialize)]
struct CustomStatisticEntry {
id: i32,
}
#[derive(Deserialize)]
struct StatisticData {
id: i32,
registry: String,
entries: IndexMap<String, CustomStatisticEntry>,
}
pub fn build() -> TokenStream {
let stats_json =
std::fs::read_to_string("../assets/stats.json").expect("Failed to read stats.json");
let stats_data: IndexMap<String, StatisticData> =
serde_json::from_str(&stats_json).expect("Failed to parse stats.json");
let mut category_variants = Vec::new();
let mut category_from_id_arms = Vec::new();
let mut category_from_name_arms = Vec::new();
let mut custom_stat_variants = Vec::new();
let mut custom_stat_from_id_arms = Vec::new();
for (category_name, data) in &stats_data {
let category_ident = format_ident!(
"{}",
category_name.replace("minecraft:", "").to_pascal_case()
);
let category_id = data.id;
category_variants.push(quote! { #category_ident = #category_id });
category_from_id_arms.push(quote! { #category_id => Some(Self::#category_ident) });
let category_name_stripped = category_name.replace("minecraft:", "");
category_from_name_arms
.push(quote! { #category_name_stripped => Some(Self::#category_ident) });
if category_name == "minecraft:custom" {
for (stat_name, entry) in &data.entries {
let stat_ident =
format_ident!("{}", stat_name.replace("minecraft:", "").to_pascal_case());
let stat_id = entry.id;
custom_stat_variants.push(quote! { #stat_ident = #stat_id });
custom_stat_from_id_arms.push(quote! { #stat_id => Some(Self::#stat_ident) });
}
}
}
quote! {
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(i32)]
pub enum StatisticCategory {
#(#category_variants,)*
}
impl StatisticCategory {
#[must_use]
pub const fn from_i32(id: i32) -> Option<Self> {
match id {
#(#category_from_id_arms,)*
_ => None,
}
}
#[must_use]
pub fn from_registry_key(name: &str) -> Option<Self> {
let name = name.strip_prefix("minecraft:").unwrap_or(name);
match name {
#(#category_from_name_arms,)*
_ => None,
}
}
}
impl TryFrom<i32> for StatisticCategory {
type Error = ();
fn try_from(value: i32) -> Result<Self, Self::Error> {
Self::from_i32(value).ok_or(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(i32)]
pub enum CustomStatistic {
#(#custom_stat_variants,)*
}
impl CustomStatistic {
#[must_use]
pub const fn from_i32(id: i32) -> Option<Self> {
match id {
#(#custom_stat_from_id_arms,)*
_ => None,
}
}
}
impl TryFrom<i32> for CustomStatistic {
type Error = ();
fn try_from(value: i32) -> Result<Self, Self::Error> {
Self::from_i32(value).ok_or(())
}
}
}
}