Skip to main content

yog_registry/
tool_levels.rs

1//! The game's tool ladder as data (`assets/tool_levels.ydata`): its levels
2//! bottom to top, and the block tags that make a block need each level on
3//! every loader and version.
4
5use std::sync::LazyLock;
6
7/// A block tag, and where it applies: `<loader|any>/<version>`, or
8/// everywhere when empty.
9#[derive(yog_data::Schema, Debug, Clone, PartialEq)]
10pub struct LevelTag {
11    pub tag: String,
12    #[data(default)]
13    pub when: String,
14}
15
16/// One of the game's tool levels.
17#[derive(yog_data::Schema, Debug, Clone, PartialEq)]
18pub struct ToolLevel {
19    /// `minecraft:stone`.
20    pub id: String,
21    /// 1.21's tag of blocks a tool of this level can't mine for drops.
22    pub incorrect: String,
23    /// What makes a block need this level.
24    pub needs: Vec<LevelTag>,
25}
26
27/// What a block needing a level above the game's top one gets.
28#[derive(yog_data::Schema, Debug, Clone, PartialEq)]
29pub struct AboveTop {
30    pub needs: Vec<LevelTag>,
31    /// What doesn't hold everywhere, for the build to warn about.
32    pub caveat: String,
33}
34
35/// The game's tool ladder.
36#[derive(yog_data::Schema, Debug, Clone, PartialEq)]
37pub struct ToolLadder {
38    /// Its id: `@ladder:minecraft:tool`.
39    pub ladder: String,
40    /// Where the game has [`ToolLevel::incorrect`] tags: `any/1.21`.
41    pub incorrect_when: String,
42    /// Bottom to top.
43    pub levels: Vec<ToolLevel>,
44    pub above: AboveTop,
45}
46
47static TOOL_LADDER: LazyLock<ToolLadder> = LazyLock::new(|| {
48    yog_data::from_text::<ToolLadder>(include_str!("../assets/tool_levels.ydata"))
49        .unwrap_or_else(|e| panic!("yog-registry's tool levels: {e}"))
50        .value
51});
52
53impl ToolLadder {
54    /// The game's.
55    pub fn game() -> &'static ToolLadder {
56        &TOOL_LADDER
57    }
58
59    /// One of its levels by short name or id (`iron` = `minecraft:iron`).
60    pub fn level(&self, name: &str) -> Option<&ToolLevel> {
61        let id = yog_ids::qualify(name);
62        self.levels.iter().find(|l| l.id == id)
63    }
64
65    /// Its levels' ids, bottom to top.
66    pub fn ids(&self) -> impl Iterator<Item = &str> {
67        self.levels.iter().map(|l| l.id.as_str())
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn the_game_ladder_reads() {
77        let l = ToolLadder::game();
78        assert_eq!(l.ids().collect::<Vec<_>>(), ["minecraft:wood", "minecraft:stone", "minecraft:iron", "minecraft:diamond", "minecraft:netherite"]);
79        assert_eq!(l.level("iron").unwrap().needs[0].tag, "minecraft:needs_iron_tool");
80        assert!(l.above.needs.iter().any(|t| t.when == "fabric/1.20"));
81    }
82}