Skip to main content

voidmc_data/
lib.rs

1//! Vanilla Minecraft registry data, generated at build time from JSON assets
2//! shipped under `assets/<version>/`.
3//!
4//! Each entry is stored as a serialized NBT compound. Use [`registry`] or
5//! [`entry_nbt`] to access them; NBT parsing is lazy.
6//!
7//! Asset extraction is a separate, manual step — see `scripts/extract.sh`.
8#![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/// A supported Minecraft version.
17#[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
30/// Returns the raw `(entry_id, nbt_bytes)` slice for `(version, registry_id)`,
31/// or `None` if the registry is not shipped for this version.
32pub 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
41/// Returns the index of `entry_id` within `registry_id` for `version`, which
42/// is the numeric ID the client uses on the wire (e.g. in chunk biome
43/// palettes, dimension types in the Login packet). Returns `None` if the
44/// registry or entry isn't shipped.
45pub 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
53/// Returns every registry shipped for `version`.
54pub 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
64/// Returns `[(tag_id, [entry_id, ...]), ...]` for `(version, registry_id)`.
65/// All `#tag` references are pre-resolved to direct entry IDs at build time.
66pub 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
77/// Returns every tagged registry shipped for `version`.
78pub 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
90/// Lazily parses a single entry's NBT. Each call after the first returns a
91/// cached reference.
92pub 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}