basalt_api/components/crafting.rs
1//! Crafting grid component for player crafting state.
2
3use basalt_types::Slot;
4
5use crate::components::Component;
6
7/// Tracks the contents of a player's crafting grid.
8///
9/// Used for both the 2x2 inventory crafting grid and the 3x3 crafting
10/// table grid. The `grid_size` field determines which slots are active:
11/// for a 2x2 grid, only `slots[0..4]` are used; for a 3x3 grid, all
12/// nine slots are active.
13///
14/// The `output` slot holds the result computed by the recipe matching
15/// system. It is read-only from the player's perspective — the server
16/// sets it when the grid contents change.
17#[derive(Debug, Clone)]
18pub struct CraftingGrid {
19 /// The 9 crafting input slots. For a 2x2 grid, only indices 0-3
20 /// are used; indices 4-8 remain empty.
21 pub slots: [Slot; 9],
22 /// Grid dimension: 2 for the player inventory grid, 3 for a
23 /// crafting table.
24 pub grid_size: u8,
25 /// The crafting output slot, set by the recipe matching system.
26 pub output: Slot,
27}
28
29impl CraftingGrid {
30 /// Creates an empty 2x2 crafting grid with no items.
31 ///
32 /// All nine slot positions are initialized to empty, and the output
33 /// slot is empty. This is the default state for a player who has
34 /// not interacted with any crafting interface.
35 pub fn empty() -> Self {
36 Self {
37 slots: std::array::from_fn(|_| Slot::empty()),
38 grid_size: 2,
39 output: Slot::empty(),
40 }
41 }
42
43 /// Clears all input slots and the output slot.
44 ///
45 /// The grid size is preserved — a 3x3 grid remains 3x3 after
46 /// clearing. This is used when a player closes a crafting table
47 /// window (items are returned to inventory, grid is reset).
48 pub fn clear(&mut self) {
49 for slot in &mut self.slots {
50 *slot = Slot::empty();
51 }
52 self.output = Slot::empty();
53 }
54}
55
56impl Component for CraftingGrid {}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn empty_returns_grid_size_two() {
64 let grid = CraftingGrid::empty();
65 assert_eq!(grid.grid_size, 2);
66 }
67
68 #[test]
69 fn empty_has_all_empty_slots() {
70 let grid = CraftingGrid::empty();
71 for slot in &grid.slots {
72 assert!(slot.is_empty());
73 }
74 assert!(grid.output.is_empty());
75 }
76
77 #[test]
78 fn clear_resets_slots_but_keeps_grid_size() {
79 let mut grid = CraftingGrid::empty();
80 grid.grid_size = 3;
81 grid.slots[0] = Slot::new(1, 1);
82 grid.slots[4] = Slot::new(2, 5);
83 grid.output = Slot::new(3, 1);
84
85 grid.clear();
86
87 assert_eq!(grid.grid_size, 3);
88 for slot in &grid.slots {
89 assert!(slot.is_empty());
90 }
91 assert!(grid.output.is_empty());
92 }
93}