#![allow(clippy::type_complexity)]
use std::sync::OnceLock;
use ussr_nbt::owned::Nbt;
include!(concat!(env!("OUT_DIR"), "/registries.rs"));
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Version {
V26_1_2,
}
impl Version {
fn id(self) -> &'static str {
match self {
Version::V26_1_2 => "26.1.2",
}
}
}
pub fn registry(
version: Version,
registry_id: &str,
) -> Option<&'static [(&'static str, &'static [u8])]> {
let (_, registries) = REGISTRIES.iter().find(|(v, _)| *v == version.id())?;
let (_, entries) = registries.iter().find(|(id, _)| *id == registry_id)?;
Some(*entries)
}
pub fn registry_index(version: Version, registry_id: &str, entry_id: &str) -> Option<i32> {
let entries = registry(version, registry_id)?;
entries
.iter()
.position(|(id, _)| *id == entry_id)
.map(|i| i as i32)
}
pub fn registries(
version: Version,
) -> &'static [(&'static str, &'static [(&'static str, &'static [u8])])] {
REGISTRIES
.iter()
.find(|(v, _)| *v == version.id())
.map(|(_, regs)| *regs)
.unwrap_or(&[])
}
pub fn tags(
version: Version,
registry_id: &str,
) -> &'static [(&'static str, &'static [&'static str])] {
TAGS.iter()
.find(|(v, _)| *v == version.id())
.and_then(|(_, regs)| regs.iter().find(|(id, _)| *id == registry_id))
.map(|(_, t)| *t)
.unwrap_or(&[])
}
pub fn tagged_registries(
version: Version,
) -> &'static [(
&'static str,
&'static [(&'static str, &'static [&'static str])],
)] {
TAGS.iter()
.find(|(v, _)| *v == version.id())
.map(|(_, regs)| *regs)
.unwrap_or(&[])
}
pub fn entry_nbt(version: Version, registry_id: &str, entry_id: &str) -> Option<&'static Nbt> {
let entries = registry(version, registry_id)?;
let (_, bytes) = entries.iter().find(|(id, _)| *id == entry_id)?;
Some(parse_cached(bytes))
}
fn parse_cached(bytes: &'static [u8]) -> &'static Nbt {
use std::collections::HashMap;
use std::sync::Mutex;
static CACHE: OnceLock<Mutex<HashMap<usize, &'static Nbt>>> = OnceLock::new();
let cache = CACHE.get_or_init(|| Mutex::new(HashMap::new()));
let key = bytes.as_ptr() as usize;
{
let guard = cache.lock().unwrap();
if let Some(nbt) = guard.get(&key) {
return nbt;
}
}
let mut cursor = bytes;
let parsed = Nbt::read(&mut cursor).expect("embedded NBT parse failed");
let leaked: &'static Nbt = Box::leak(Box::new(parsed));
let mut guard = cache.lock().unwrap();
guard.entry(key).or_insert(leaked)
}