Skip to main content

steel_core/inventory/menu/
kind.rs

1//! Per-menu behavior hooks.
2
3use steel_registry::item_stack::ItemStack;
4use steel_utils::ErasedType;
5
6use crate::inventory::menu::behavior::MenuBehavior;
7use crate::{inventory::lock::ContainerLockGuard, player::Player};
8
9use crate::inventory::click::{Click, ClickOutcome, QuickCraft};
10
11/// Per-menu behavior that isn't shared: recompute-on-change, validity, close
12/// cleanup, and the optional shift-click override.
13///
14/// Menu transitions requested while a hook owns mutable access to the current
15/// menu are applied after that hook returns.
16///
17/// Concrete implementations must claim a unique
18/// [`steel_utils::DowncastTypeKey`] through [`steel_utils::DowncastType`].
19pub trait MenuKind: ErasedType + Send + Sync {
20    /// Recompute recipe-driven slots after a click touched a real slot.
21    fn slots_changed(
22        &mut self,
23        _behavior: &mut MenuBehavior,
24        _guard: &mut ContainerLockGuard,
25        _player: &Player,
26    ) {
27    }
28
29    /// Extra cleanup on close beyond [`Menu::removed`].
30    fn removed(&mut self, _behavior: &mut MenuBehavior, _player: &Player) {}
31
32    /// Applies a rename from the client (anvil-style text input) and recomputes
33    /// any result. No-op for kinds without a rename input.
34    fn on_rename(&mut self, _behavior: &mut MenuBehavior, _name: String, _player: &Player) {}
35
36    /// Runs after initial contents are built but before they're sent, so
37    /// anything populated here appears in the first render.
38    fn on_open(
39        &mut self,
40        _behavior: &mut MenuBehavior,
41        _guard: &mut ContainerLockGuard,
42        _player: &Player,
43    ) {
44    }
45
46    /// Runs once per tick per viewer while open, before changes are synced.
47    fn on_tick(
48        &mut self,
49        _behavior: &mut MenuBehavior,
50        _guard: &mut ContainerLockGuard,
51        _player: &Player,
52    ) {
53    }
54
55    /// Runs for every non-drag click before default handling. Return
56    /// [`ClickOutcome::Consume`] to treat the slot as a button, or
57    /// [`ClickOutcome::Fallthrough`] for default handling.
58    fn on_slot_clicked(
59        &mut self,
60        _behavior: &mut MenuBehavior,
61        _guard: &mut ContainerLockGuard,
62        _click: Click,
63        _player: &Player,
64    ) -> ClickOutcome {
65        ClickOutcome::Fallthrough
66    }
67
68    /// Runs for each drag phase before default handling. Return
69    /// [`ClickOutcome::Consume`] to cancel the drag.
70    fn on_drag(
71        &mut self,
72        _behavior: &mut MenuBehavior,
73        _guard: &mut ContainerLockGuard,
74        _action: QuickCraft,
75        _player: &Player,
76    ) -> ClickOutcome {
77        ClickOutcome::Fallthrough
78    }
79
80    /// Returns true if a drag may distribute items into `slot_index`.
81    fn can_drag_to(&self, _slot_index: usize) -> bool {
82        true
83    }
84
85    /// Returns true if this menu is still valid for the player.
86    fn still_valid(&self, _behavior: &MenuBehavior, _player: &Player) -> bool {
87        true
88    }
89
90    /// Returns true if an item may be taken from `slot_index` during pickup-all.
91    fn can_take_item_for_pick_all(&self, _carried: &ItemStack, _slot_index: usize) -> bool {
92        true
93    }
94
95    /// Shift-click override. Return `Some` to fully handle the quick-move, or
96    /// `None` to fall back to the route table.
97    fn quick_move(
98        &mut self,
99        _behavior: &mut MenuBehavior,
100        _guard: &mut ContainerLockGuard,
101        _slot_index: usize,
102        _player: &Player,
103    ) -> Option<ItemStack> {
104        None
105    }
106}