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}