Skip to main content

yog_registry/
equipment.rs

1//! Tools and armor: their items, and the materials they're made of (the game's built in).
2
3use yog_ids::tool_kind::{AXE, HOE, PICKAXE, SHOVEL, SWORD};
4
5/// An item as a tool or weapon.
6#[derive(yog_data::Schema, Debug, Clone, PartialEq)]
7pub struct ToolItem {
8    /// `pickaxe`, `axe`, `shovel`, `hoe`, `sword`, or the mineable tag of
9    /// a mod's kind of tool (`mymod:mineable/hammer`).
10    pub kind: String,
11    /// Its [`ToolMaterial`]'s id (`minecraft:iron`, `mymod:mythril`).
12    pub material: String,
13    /// Attack damage on top of the material's; none: the game's tool's
14    /// ([`ToolMaterial::game_tool`]), as the running version has it.
15    pub attack_damage: Option<f32>,
16    /// Attack speed change; none: the game's tool's.
17    pub attack_speed: Option<f32>,
18}
19
20/// The game's kinds of tool that mine.
21pub const DIGGERS: [&str; 4] = [PICKAXE, AXE, SHOVEL, HOE];
22/// The game's kinds of tool: its diggers and the sword.
23pub const TOOL_KINDS: [&str; 5] = [PICKAXE, AXE, SHOVEL, HOE, SWORD];
24
25/// A mod's material takes its tools' attack from the game's tools of this
26/// one; a mod's kind of tool, from the game's of this kind.
27pub const REFERENCE_MATERIAL: &str = yog_ids::id!(yog_ids::ns::MINECRAFT, "iron");
28pub const REFERENCE_KIND: &str = PICKAXE;
29
30/// The game's tool a tool takes its attack from when it gives none: its
31/// item id, and the attack damage its material adds (what the kind adds is
32/// the rest).
33#[derive(yog_data::Schema, Debug, Clone, PartialEq)]
34pub struct GameTool {
35    pub item: String,
36    pub material_damage: f32,
37}
38
39/// Where a piece of armor, or something else worn, is worn.
40#[derive(yog_data::Schema, Debug, Clone, Copy, PartialEq, Eq)]
41pub enum ArmorSlot {
42    Head,
43    Chest,
44    Legs,
45    Feet,
46}
47
48/// An item as a piece of armor.
49#[derive(yog_data::Schema, Debug, Clone, PartialEq)]
50pub struct ArmorPiece {
51    pub slot: ArmorSlot,
52    /// Its [`ArmorMaterial`]'s id.
53    pub material: String,
54}
55
56/// What tools are made of. The game's are built in
57/// ([`ToolMaterial::built_ins`]); a mod declares its own in a `.ydef`
58/// (`kind: "tool_material"`) or registers one
59/// (`Registry::register_tool_material`).
60#[derive(yog_data::Schema, Debug, Clone, PartialEq)]
61pub struct ToolMaterial {
62    pub id: String,
63    /// Uses before it breaks.
64    pub durability: u32,
65    /// How fast it mines (wood 2 … netherite 9, gold 12).
66    pub speed: f32,
67    /// Attack damage it adds (wood 0 … netherite 4).
68    pub attack_damage: f32,
69    pub enchantability: u32,
70    /// Its level on the tool ladder (`minecraft:iron`, `mymod:mythril`).
71    pub level: String,
72    /// What repairs it: an item id or `#tag`.
73    pub repair: String,
74    /// Minecraft 1.20's level number of `level` (wood 0 … netherite 4).
75    #[data(default)]
76    pub level_index: u32,
77    /// Minecraft 1.21's tag of the blocks a tool of it can't mine for
78    /// drops (`minecraft:incorrect_for_iron_tool`).
79    #[data(default)]
80    pub incorrect: String,
81    /// What the game's tools of it are named by (`wooden_`: `minecraft:wooden_axe`);
82    /// empty for a mod's own.
83    #[data(default)]
84    pub game_tools: String,
85}
86
87/// Defense points per armor piece.
88#[derive(yog_data::Schema, Debug, Clone, Copy, PartialEq)]
89pub struct ArmorDefense {
90    pub head: u32,
91    pub chest: u32,
92    pub legs: u32,
93    pub feet: u32,
94}
95
96/// What armor is made of. The game's are built in
97/// ([`ArmorMaterial::built_ins`]); a mod declares its own in a `.ydef`
98/// (`kind: "armor_material"`) or registers one.
99#[derive(yog_data::Schema, Debug, Clone, PartialEq)]
100pub struct ArmorMaterial {
101    pub id: String,
102    /// Multiplies each piece's base durability (helmet 11, chestplate 16,
103    /// leggings 15, boots 13).
104    pub durability: u32,
105    pub defense: ArmorDefense,
106    pub enchantability: u32,
107    /// The sound event of putting it on.
108    pub equip_sound: String,
109    #[data(default)]
110    pub toughness: f32,
111    #[data(default)]
112    pub knockback_resistance: f32,
113    /// What repairs it: an item id or `#tag`.
114    pub repair: String,
115    /// Its look on a player: `<ns>:<name>` is
116    /// `<ns>:textures/models/armor/<name>_layer_1.png` (and `_layer_2`).
117    pub texture: String,
118}
119
120static BUILT_IN_TOOL_MATERIALS: yog_sync::LazyLock<Vec<ToolMaterial>> =
121    yog_sync::LazyLock::new(|| {
122        yog_data::built_in::<Vec<ToolMaterial>>(
123            "yog-registry's built-in tool materials",
124            include_str!("../assets/tool_materials.ydata"),
125        )
126    });
127
128static BUILT_IN_ARMOR_MATERIALS: yog_sync::LazyLock<Vec<ArmorMaterial>> =
129    yog_sync::LazyLock::new(|| {
130        yog_data::built_in::<Vec<ArmorMaterial>>(
131            "yog-registry's built-in armor materials",
132            include_str!("../assets/armor_materials.ydata"),
133        )
134    });
135
136/// One of `list` by short name or id (`iron` = `minecraft:iron`).
137pub(crate) fn built_in<'a, T>(list: &'a [T], id: impl Fn(&T) -> &str, name: &str) -> Option<&'a T> {
138    let name = yog_ids::qualify(name);
139    list.iter().find(|x| id(x) == name)
140}
141
142impl ToolMaterial {
143    /// The game's materials: wood, stone, iron, diamond, gold, netherite.
144    pub fn built_ins() -> &'static [ToolMaterial] {
145        &BUILT_IN_TOOL_MATERIALS
146    }
147
148    /// One of the game's, by short name or id.
149    pub fn built_in(name: &str) -> Option<&'static ToolMaterial> {
150        built_in(Self::built_ins(), |m| &m.id, name)
151    }
152
153    /// `id` with `like`'s level (one of the game's: `iron`), durability,
154    /// speed, damage, enchantability and repair — change what differs.
155    pub fn like(id: impl Into<String>, like: &str) -> Option<Self> {
156        let mut m = Self::built_in(like)?.clone();
157        m.id = id.into();
158        Some(m)
159    }
160
161    /// The game's tool of `kind` (a mod's kind: [`REFERENCE_KIND`]) made of
162    /// this material, or — a mod's — of [`REFERENCE_MATERIAL`].
163    pub fn game_tool(&self, kind: &str) -> Option<GameTool> {
164        let made = if self.game_tools.is_empty() {
165            Self::built_in(REFERENCE_MATERIAL)?
166        } else {
167            Self::built_ins()
168                .iter()
169                .find(|m| m.game_tools == self.game_tools)?
170        };
171        let kind = if TOOL_KINDS.contains(&kind) {
172            kind
173        } else {
174            REFERENCE_KIND
175        };
176        Some(GameTool {
177            item: yog_ids::qualify(&format!("{}{kind}", made.game_tools)),
178            material_damage: made.attack_damage,
179        })
180    }
181}
182
183impl ArmorMaterial {
184    /// The game's materials: leather, chainmail, iron, gold, diamond, turtle, netherite.
185    pub fn built_ins() -> &'static [ArmorMaterial] {
186        &BUILT_IN_ARMOR_MATERIALS
187    }
188
189    /// One of the game's, by short name or id.
190    pub fn built_in(name: &str) -> Option<&'static ArmorMaterial> {
191        built_in(Self::built_ins(), |m| &m.id, name)
192    }
193}