Skip to main content

cobble/
pack_format.rs

1use serde::{Serialize, Serializer};
2
3pub const COBBLE_VERSION: &str = match option_env!("COBBLE_LANG_VERSION") {
4    Some(version) => version,
5    None => env!("CARGO_PKG_VERSION"),
6};
7pub const SUPPORTED_MINECRAFT_VERSION: &str = "26.1.2";
8pub const SUPPORTED_PACK_FORMAT: PackFormat = PackFormat::Decimal(101, 1);
9
10/// Pack format representation that supports both integer and decimal formats
11/// Minecraft 1.21.9+ introduced decimal pack formats (e.g., 88.0).
12#[derive(Debug, Clone, Copy, PartialEq)]
13pub enum PackFormat {
14    /// Integer format used by older Minecraft releases (e.g., 18, 48, 88).
15    Integer(u8),
16    /// Decimal format used by newer Minecraft releases (e.g., 88.0, 101.1).
17    /// Represented as (major, minor) where format is "major.minor"
18    Decimal(u8, u8),
19}
20
21impl PackFormat {
22    /// Create from an integer
23    pub fn from_int(value: u8) -> Self {
24        PackFormat::Integer(value)
25    }
26
27    /// Create from a string like "101" or "101.1"
28    pub fn parse_format(s: &str) -> Result<Self, String> {
29        if let Some(dot_pos) = s.find('.') {
30            // Decimal format
31            let major = s[..dot_pos]
32                .parse::<u8>()
33                .map_err(|_| format!("Invalid pack format: {}", s))?;
34            let minor = s[dot_pos + 1..]
35                .parse::<u8>()
36                .map_err(|_| format!("Invalid pack format: {}", s))?;
37            Ok(PackFormat::Decimal(major, minor))
38        } else {
39            // Integer format
40            let value = s
41                .parse::<u8>()
42                .map_err(|_| format!("Invalid pack format: {}", s))?;
43            Ok(PackFormat::Integer(value))
44        }
45    }
46
47    /// Convert to JSON value (integer or decimal number)
48    pub fn to_json_value(&self) -> serde_json::Value {
49        match self {
50            PackFormat::Integer(v) => serde_json::Value::Number((*v).into()),
51            PackFormat::Decimal(major, minor) => {
52                // Return as JSON number (float), not string
53                let value_str = format!("{}.{}", major, minor);
54                let value: f64 = value_str.parse().unwrap();
55                serde_json::json!(value)
56            }
57        }
58    }
59
60    /// Get the major version number
61    pub fn major(&self) -> u8 {
62        match self {
63            PackFormat::Integer(v) => *v,
64            PackFormat::Decimal(major, _) => *major,
65        }
66    }
67
68    /// Whether this pack format is supported by this Cobble release.
69    pub fn is_supported(self) -> bool {
70        self == SUPPORTED_PACK_FORMAT
71    }
72}
73
74impl Default for PackFormat {
75    fn default() -> Self {
76        // Default to pack format 101.1 (Minecraft Java Edition 26.1.2)
77        SUPPORTED_PACK_FORMAT
78    }
79}
80
81impl std::fmt::Display for PackFormat {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        match self {
84            PackFormat::Integer(v) => write!(f, "{}", v),
85            PackFormat::Decimal(major, minor) => write!(f, "{}.{}", major, minor),
86        }
87    }
88}
89
90impl Serialize for PackFormat {
91    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
92    where
93        S: Serializer,
94    {
95        match self {
96            PackFormat::Integer(v) => serializer.serialize_u8(*v),
97            PackFormat::Decimal(major, minor) => {
98                // Serialize as JSON number (float), not string
99                // Example: Decimal(101, 1) -> 101.1 (number), not "101.1" (string)
100                let value_str = format!("{}.{}", major, minor);
101                let value: f64 = value_str.parse().unwrap();
102                serializer.serialize_f64(value)
103            }
104        }
105    }
106}