Skip to main content

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}