use std::collections::HashMap;
use serde::Deserialize;
#[derive(Debug, Clone)]
pub struct Block {
pub(crate) name: String,
pub(crate) encoded: String,
pub(crate) archetype: BlockArchetype,
}
#[derive(Debug, PartialEq, Clone)]
pub enum BlockArchetype {
Normal,
Airy,
Watery,
Snowy,
}
impl Block {
pub fn name(&self) -> &str {
&self.name
}
pub fn snowy(&self) -> bool {
self.archetype == BlockArchetype::Snowy
}
pub fn encoded_description(&self) -> &str {
&self.encoded
}
}
#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
struct BlockRaw {
name: String,
#[serde(default)]
properties: HashMap<String, String>,
}
impl<'de> Deserialize<'de> for Block {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let raw: BlockRaw = Deserialize::deserialize(deserializer)?;
let snowy = raw.properties.get("snowy").map(String::as_str) == Some("true");
let mut id = raw.name.clone() + "|";
let mut sep = "";
let mut props = raw
.properties
.iter()
.filter(|(k, _)| *k != "waterlogged") .filter(|(k, _)| *k != "powered") .collect::<Vec<_>>();
props.sort_unstable();
for (k, v) in props {
id = id + sep + k + "=" + v;
sep = ",";
}
let arch = if snowy {
BlockArchetype::Snowy
} else if is_watery(&raw.name) {
BlockArchetype::Watery
} else if is_airy(&raw.name) {
BlockArchetype::Airy
} else {
BlockArchetype::Normal
};
Ok(Self {
name: raw.name,
archetype: arch,
encoded: id,
})
}
}
fn is_watery(block: &str) -> bool {
matches!(
block,
"minecraft:water"
| "minecraft:bubble_column"
| "minecraft:kelp"
| "minecraft:kelp_plant"
| "minecraft:sea_grass"
| "minecraft:tall_seagrass"
)
}
fn is_airy(block: &str) -> bool {
matches!(block, "minecraft:air" | "minecraft:cave_air")
}