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