1#![allow(clippy::type_complexity)]
9
10use std::sync::OnceLock;
11
12use ussr_nbt::owned::Nbt;
13
14include!(concat!(env!("OUT_DIR"), "/registries.rs"));
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum Version {
19 V26_1_2,
20}
21
22impl Version {
23 fn id(self) -> &'static str {
24 match self {
25 Version::V26_1_2 => "26.1.2",
26 }
27 }
28}
29
30pub fn registry(
33 version: Version,
34 registry_id: &str,
35) -> Option<&'static [(&'static str, &'static [u8])]> {
36 let (_, registries) = REGISTRIES.iter().find(|(v, _)| *v == version.id())?;
37 let (_, entries) = registries.iter().find(|(id, _)| *id == registry_id)?;
38 Some(*entries)
39}
40
41pub fn registry_index(version: Version, registry_id: &str, entry_id: &str) -> Option<i32> {
46 let entries = registry(version, registry_id)?;
47 entries
48 .iter()
49 .position(|(id, _)| *id == entry_id)
50 .map(|i| i as i32)
51}
52
53pub fn registries(
55 version: Version,
56) -> &'static [(&'static str, &'static [(&'static str, &'static [u8])])] {
57 REGISTRIES
58 .iter()
59 .find(|(v, _)| *v == version.id())
60 .map(|(_, regs)| *regs)
61 .unwrap_or(&[])
62}
63
64pub fn tags(
67 version: Version,
68 registry_id: &str,
69) -> &'static [(&'static str, &'static [&'static str])] {
70 TAGS.iter()
71 .find(|(v, _)| *v == version.id())
72 .and_then(|(_, regs)| regs.iter().find(|(id, _)| *id == registry_id))
73 .map(|(_, t)| *t)
74 .unwrap_or(&[])
75}
76
77pub fn tagged_registries(
79 version: Version,
80) -> &'static [(
81 &'static str,
82 &'static [(&'static str, &'static [&'static str])],
83)] {
84 TAGS.iter()
85 .find(|(v, _)| *v == version.id())
86 .map(|(_, regs)| *regs)
87 .unwrap_or(&[])
88}
89
90pub fn entry_nbt(version: Version, registry_id: &str, entry_id: &str) -> Option<&'static Nbt> {
93 let entries = registry(version, registry_id)?;
94 let (_, bytes) = entries.iter().find(|(id, _)| *id == entry_id)?;
95 Some(parse_cached(bytes))
96}
97
98fn parse_cached(bytes: &'static [u8]) -> &'static Nbt {
99 use std::collections::HashMap;
100 use std::sync::Mutex;
101
102 static CACHE: OnceLock<Mutex<HashMap<usize, &'static Nbt>>> = OnceLock::new();
103 let cache = CACHE.get_or_init(|| Mutex::new(HashMap::new()));
104 let key = bytes.as_ptr() as usize;
105
106 {
107 let guard = cache.lock().unwrap();
108 if let Some(nbt) = guard.get(&key) {
109 return nbt;
110 }
111 }
112
113 let mut cursor = bytes;
114 let parsed = Nbt::read(&mut cursor).expect("embedded NBT parse failed");
115 let leaked: &'static Nbt = Box::leak(Box::new(parsed));
116
117 let mut guard = cache.lock().unwrap();
118 guard.entry(key).or_insert(leaked)
119}