Class MenuSwitch
java.lang.Object
com.trevlar.slotkit.api.menu.MenuSwitch
Switching a player between menus while one menu, the one they opened in the world,
waits open behind the others. For tabs on a container screen: a player at a chest
flips to their inventory, a shulker box, their ender chest, and back, and the chest
stays open in the world the whole time (its lid up, no close sound), while every
other menu really closes when they leave it (the inventory's crafting grid hands its
items back).
// Server, from a tab click:
MenuSwitch.open(player, boxProvider); // the chest waits behind, the box opens
MenuSwitch.openInventory(player); // the box closes, the inventory opens
MenuSwitch.back(player); // the inventory closes, the chest comes back
// Common init: hear when the waiting menu closes on its own.
MenuSwitch.onSetAsideClosed((player, menu, why) -> ...);
The menu set aside
The first switch away from a menu the player opened some other way (a chest they clicked, anyplayer.openMenu that isn't this class's) sets it aside instead
of closing it: no removed(), no close packet, so the block's opener count
holds. Menus opened through open(ServerPlayer, MenuProvider) are the tabs: switching away from one
closes it normally. The inventory is never set aside, so a switch that starts at
the inventory screen sets nothing aside, and back(ServerPlayer) has nothing to return to.
Only a menu opened through openMenu, or a mount's inventory (a horse's, a
llama's, a nautilus's), can be set aside: back sends the packet that opened it
again. Any other closes normally. A trading screen comes back with its trades (the
selected one may reset); its trader stays locked to the player while it waits.
While it waits, the set-aside menu's stillValid is checked every tick,
and it closes properly (removed(), so the lid shuts) when that fails, the
player dies or changes dimension, the menu in front closes (Escape on any screen),
a menu opens some other way, or the player leaves. onSetAsideClosed(MenuSwitch.SetAsideClosed) hears
each of these. It gets no sync while it waits; back resyncs it whole.
The cursor
The stack on the cursor moves across every switch, to the next menu, instead of going back to the inventory.Clicks in flight
A click the client sent before it heard of a switch is addressed to the menu it left, and vanilla drops it. Until the client's first click on the new menu, such a click on one of the player's inventory slots (any slot whose container the new menu also shows) lands on that same slot in the new menu: a pickup, a put-down, a number key, a middle click or a drop key, or a click outside the screen. A click on the old menu's own slots, a shift-click, a double-click collect and a drag are still dropped, since what they would do depends on the menu they were aimed at.The client
open and back send only vanilla packets, so they work for a player
without SlotKit. openInventory(ServerPlayer) needs SlotKit on the client (vanilla has no
packet that opens the inventory) and returns false without it. With SlotKit
on the client, the screen the player is on stays up until the next menu's contents
arrive, so a switch never shows an empty screen for a frame.
Server thread only. Since 2.1.0.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enumWhy the set-aside menu closed.static interfaceHears the set-aside menu close on its own. -
Method Summary
Modifier and TypeMethodDescriptionstatic booleanback(net.minecraft.server.level.ServerPlayer player) Closes the menu in front normally and reopens the set-aside one as itself: its container id, type and title, then all its contents.static net.minecraft.network.protocol.game.ServerboundContainerClickPacketclickArrived(net.minecraft.server.level.ServerPlayer player, net.minecraft.network.protocol.game.ServerboundContainerClickPacket click) A click from the player's client, on the server thread before vanilla handles it: the same click on the menu in front when it was aimed at the menu just switched away from (see "Clicks in flight" in the class doc), otherwiseclickitself.static voidfrontClosed(net.minecraft.server.level.ServerPlayer player) The menu in front closed: unless that was a switch, the set-aside one closes too.static intheldId(net.minecraft.server.level.ServerPlayer player) The container id the player's next menu must not take while one is set aside, or -1.static voidleft(net.minecraft.server.level.ServerPlayer player) The player is leaving the server.static voidmenuOpened(net.minecraft.server.level.ServerPlayer player, net.minecraft.network.chat.Component title) openMenuopened the player's new menu undertitle.static voidmenuOpening(net.minecraft.world.inventory.AbstractContainerMenu menu) openMenumademenu, just before its first sync: anopen(ServerPlayer, MenuProvider)gets its cursor stack.static voidmountOpened(net.minecraft.server.level.ServerPlayer player, int inventoryColumns, int mountId) A mount's inventory opened for the player (openHorseInventory,openNautilusInventory), which skipsopenMenu.static voidoffersSent(net.minecraft.server.level.ServerPlayer player, int containerId, int traderLevel) The player's trading menucontainerIdwas sent its offers attraderLevel.static voidonSetAsideClosed(MenuSwitch.SetAsideClosed listener) Adds a listener for the set-aside menu closing on its own.static OptionalIntopen(net.minecraft.server.level.ServerPlayer player, net.minecraft.world.MenuProvider next) Opensnextforplayer.static booleanopenInventory(net.minecraft.server.level.ServerPlayer player) Opens the player's own inventory screen, asopen(ServerPlayer, MenuProvider)does a menu: the menu in front is set aside or closes, and the cursor stack moves over.static voidremoved(net.minecraft.server.level.ServerPlayer player) The player's entity is leaving its level: a dimension change, a respawn (which replaces the entity), the End's exit, or leaving the server.static Optional<net.minecraft.world.inventory.AbstractContainerMenu> setAside(net.minecraft.server.level.ServerPlayer player) The menuplayerhas set aside, if any.static voidtick(net.minecraft.server.level.ServerPlayer player) Each player tick: the set-aside menu still has to be valid.
-
Method Details
-
open
public static OptionalInt open(net.minecraft.server.level.ServerPlayer player, net.minecraft.world.MenuProvider next) Opensnextforplayer. The menu in front is set aside if it can be (see the class doc) and nothing is set aside yet, and otherwise closes normally. The cursor stack moves tonext.- Returns:
- the new menu's container id, or empty when
nextmade no menu. Then the player goes back to the set-aside menu, or with none, the screen closes and the cursor stack returns to the inventory.
-
openInventory
public static boolean openInventory(net.minecraft.server.level.ServerPlayer player) Opens the player's own inventory screen, asopen(ServerPlayer, MenuProvider)does a menu: the menu in front is set aside or closes, and the cursor stack moves over.- Returns:
false, and nothing changes, when the player's client has no SlotKit
-
back
public static boolean back(net.minecraft.server.level.ServerPlayer player) Closes the menu in front normally and reopens the set-aside one as itself: its container id, type and title, then all its contents. The cursor stack moves over.- Returns:
falsewhen nothing is set aside
-
setAside
public static Optional<net.minecraft.world.inventory.AbstractContainerMenu> setAside(net.minecraft.server.level.ServerPlayer player) The menuplayerhas set aside, if any. -
mountOpened
@Internal public static void mountOpened(net.minecraft.server.level.ServerPlayer player, int inventoryColumns, int mountId) A mount's inventory opened for the player (openHorseInventory,openNautilusInventory), which skipsopenMenu. -
offersSent
@Internal public static void offersSent(net.minecraft.server.level.ServerPlayer player, int containerId, int traderLevel) The player's trading menucontainerIdwas sent its offers attraderLevel. -
frontClosed
@Internal public static void frontClosed(net.minecraft.server.level.ServerPlayer player) The menu in front closed: unless that was a switch, the set-aside one closes too. -
tick
@Internal public static void tick(net.minecraft.server.level.ServerPlayer player) Each player tick: the set-aside menu still has to be valid. -
left
@Internal public static void left(net.minecraft.server.level.ServerPlayer player) The player is leaving the server. -
removed
@Internal public static void removed(net.minecraft.server.level.ServerPlayer player) The player's entity is leaving its level: a dimension change, a respawn (which replaces the entity), the End's exit, or leaving the server. A respawned or departed entity never ticks again, so its set-aside menu closes now or never (a crafting grid's items would be lost), and this class lets go of it. Each map entry's menu holds its player, so a weak key alone never frees it. -
clickArrived
@Internal public static net.minecraft.network.protocol.game.ServerboundContainerClickPacket clickArrived(net.minecraft.server.level.ServerPlayer player, net.minecraft.network.protocol.game.ServerboundContainerClickPacket click) A click from the player's client, on the server thread before vanilla handles it: the same click on the menu in front when it was aimed at the menu just switched away from (see "Clicks in flight" in the class doc), otherwiseclickitself. -
heldId
@Internal public static int heldId(net.minecraft.server.level.ServerPlayer player) The container id the player's next menu must not take while one is set aside, or -1.
-