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 yog_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, Default)]
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, Default)]
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::built_in::<ToolLadder>(
49        "yog-registry's tool levels",
50        include_str!("../assets/tool_levels.ydata"),
51    )
52});
53
54impl ToolLadder {
55    /// The game's.
56    pub fn game() -> &'static ToolLadder {
57        &TOOL_LADDER
58    }
59
60    /// One of its levels by short name or id (`iron` = `minecraft:iron`).
61    pub fn level(&self, name: &str) -> Option<&ToolLevel> {
62        let id = yog_ids::qualify(name);
63        self.levels.iter().find(|l| l.id == id)
64    }
65
66    /// Its levels' ids, bottom to top.
67    pub fn ids(&self) -> impl Iterator<Item = &str> {
68        self.levels.iter().map(|l| l.id.as_str())
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn the_game_ladder_reads() {
78        let l = ToolLadder::game();
79        assert_eq!(
80            l.ids().collect::<Vec<_>>(),
81            [
82                "minecraft:wood",
83                "minecraft:stone",
84                "minecraft:iron",
85                "minecraft:diamond",
86                "minecraft:netherite"
87            ]
88        );
89        assert_eq!(
90            l.level("iron").unwrap().needs[0].tag,
91            "minecraft:needs_iron_tool"
92        );
93        assert!(l.above.needs.iter().any(|t| t.when == "fabric/1.20"));
94    }
95}