Язык

SlotKit

SlotKit

Modrinth

A Fabric library for finding and acting on the slots in any menu, and for building real slots that persist and sync.

1.7k загрузок обновлено 1h ago
последняя v2.3.0+26.3 Modrinth
Fabric 1.21.11 – 26.3 LibraryUtility

SlotKit

SlotKit is a slot library for Fabric mods, built on MenuKit. A mod uses it to find and act on the slots in any menu, vanilla or modded, or to build real slots and custom menus that persist and sync. I built it for my own mods and opened it up so other modders can use it too.

If you're a player and another mod asked for SlotKit, install it alongside that mod and you're done.

SlotKit was called MenuKit: Containers. Mods built for Containers need an update, and the upgrading guide has the steps. MenuKit: Containers 6.2.0 is still in this project's version list.

Features

SlotKit has two tiers. A mod needs SlotKit on the other side only for the second.

| Tier | Needs SlotKit on | Adds |
| --- | --- | --- |
| Client | The client only. It works on any server, vanilla included. | Slot groups and categories in every menu, slot operations, vetoes and gates, and panels placed on a slot or a slot group |
| Client and server | Both sides | Created slots, custom container menus, storage attachments, per-slot state, and items found inside shulker boxes and bundles |

  • Every slot group, vanilla or created, is published under a category any mod can read, with or without a menu open.
  • Each thing that can be done to a slot is named as an operation. Vanilla has eleven, one per gesture, and a mod can add its own. A slot's own setting is checked first, then its group's, then its category's, and a locking mod can veto any operation.
  • A MenuKit panel can be placed around a slot group, or at an offset from one slot, so it shows on every screen with that group or slot. That includes the survival inventory, every chest, and every other container.
  • Every rule about a slot (a veto, a category rule, a gate, a slot-state channel) is declared for survival, creative, or both, and holds in creative too. A panel can take a different place in each mode.
  • A player inventory slot has one address, the same on every screen and for every player, so a rule can name it at startup.
  • Each container on a menu stays its own container. A menu's shift-click never lands in another mod's slots by accident, and a mod can show any container's slots in its own panel by the group's id.
  • The server can add slot groups to the menu a player has open and remove them again, for something the player opens while a screen is up, like a shulker box opened from a chest's screen.
  • A panel can sit on every shown group of a category, so a chest and each shulker box or ender chest opened beside it get a panel of their own.
  • A player at a chest can switch to their inventory, a shulker box, or their ender chest and back, and the chest stays open in the world the whole time.
  • Slots in a MenuKit scroll area clip to it, so a long grid of slots can scroll.
  • Created slots are UI components. A pocket, an extra equipment slot, or a satchel is each a real Slot, synced by vanilla's protocol. A mod registers its slot groups once and places them in its own MenuKit panels, next to its buttons and labels, on every screen it chooses.
  • The server can open, close, and resize a slot group for each player, and a mod can decide where a shift-click goes.
  • A slot's contents can be shown to other players, for gear drawn on the player model.
  • A mod can find and use items anywhere a player carries them: the inventory, the ender chest, and shulker boxes and bundles nested to any depth. The chest a player has open can be searched too. A change writes back through every container, and a menu can stay open on a nested item, like a bundle inside a shulker box. A mod's own carried slots, such as a pocket or a carried ender chest, can be searched as well.
  • An item can carry a state of the mod's own, saved with it or not, and a slot can draw the item differently while that state or a client-side check holds: an animation, another stack in its place, or a mark under or over it.
  • A mod can take a plain double-click on a slot for its own action, the same gesture in every mod that uses it.
  • Custom container menus are built from MenuKit panels.
  • Created slots behave like vanilla ones in creative and survival, on death, and with Curse of Binding and Mending.
  • Per-slot state can be attached to any slot, either private to each player or shared by everyone viewing it. The server checks every write a client sends. The state is stored on the slot's owner (a player, block, entity, or item), where /data get can read it.
  • Each side checks which mods the other has before the world loads. A server refuses only players missing a mod that builds slots, and names the mods to install, with links. Everyone else joins.
  • Worlds and player files saved with MenuKit: Containers load with no conversion, and shulker boxes keep their contents and slot state.

Example

A panel above the player inventory, registered once from the client entry point. It uses the client tier, so it works on any server.

Panel panel = Panel.builder("mymod:toolbar")
        .style(PanelStyle.NONE)
        .elements(toolbarButtons)
        .in(ModeScope.BOTH, SlotPlacement.group(SlotGroupCategory.PLAYER_INVENTORY,
                PanelPosition.region(OutsideRegion.TOP_ALIGN_RIGHT)))
        .visibleWhen(() -> config.toolbar)
        .build();
new AnchorPanelAdapter(panel);

Nine synced pocket slots on every container screen, registered once from the common entry point. These need SlotKit on both sides.

public static final PlayerStorageAttachment<NonNullList<ItemStack>> POCKETS =
        StorageAttachment.playerAttached("mymod", "pockets", 9);
POCKET_SLOTS = ParityGroup.register("mymod:pockets",
        SlotSpec.at("pockets", SlotGroupCategory.PLAYER_INVENTORY).count(9)
                .storage(player -> POCKETS.bind(player)));

The slots go in a panel of the mod's own, built from the client entry point.

// Client initializer: your panel, the slots under a button.
Panel pockets = Panel.builder("mymod:pockets")
        .add(Button.builder().label(Component.literal("Sort")).size(60, 14).build())
        .add(SlotFlowElement.builder().addGroup(POCKET_SLOTS).at(0, 18).build())
        .style(PanelStyle.RAISED)
        .in(ModeScope.BOTH, Placement.screen(PanelPosition.region(OutsideRegion.LEFT_ALIGN_TOP).priority(20)))
        .build()
        .visibleWhen(() -> ClientSlots.isShown(POCKET_SLOTS.id()));
new ScreenPanelAdapter(pockets).onMatching(ScreenMatcher.all());

Getting started

Minecraft 26.3 is unobfuscated, so SlotKit goes on the plain implementation configuration, beside MenuKit.

repositories {
    maven { url 'https://api.modrinth.com/maven' }
}
dependencies {
    implementation 'maven.modrinth:menukit:7.5.0+26.3'
    implementation 'maven.modrinth:xQUBXV8I:2.3.0+26.3'   // SlotKit
}

xQUBXV8I is SlotKit's Modrinth project id. It points to the project no matter what the slug is.

Declare both in fabric.mod.json, each against its own version, with both bounds (why). Separate the bounds with a space, since Fabric doesn't read a comma there.

"depends": { "menukit": ">=7.5.0 <8.0.0", "slotkit": ">=2.3.0 <3.0.0" }

Players install SlotKit as its own mod, next to the mods that use it. List it as a required dependency on the mod's Modrinth page so it's installed with them.

Requirements

  • MenuKit 7.5.0 or newer, below 8.0.0. SlotKit builds its panels and slot drawing on MenuKit.
  • Fabric API

Compatibility

Minecraft 26.3 with Fabric. Install SlotKit on the client. A server needs it only when a mod that adds slots, such as Hotbar Pockets or Simple Elytra Slot, is installed there too. That mod lists SlotKit as a required dependency, so SlotKit comes along with it. That's why Modrinth lists SlotKit as client-side, even though it ends up on plenty of servers. SlotKit replaces MenuKit: Containers, so the two can't be installed together, and it can't be installed with Inventory Max either.

Used by

How to use

This guide follows the order a mod usually meets SlotKit, from finding slots on the client to building slots that need both sides. Each part links to the full developer docs. Concepts defines every term, and Recipes has a worked example for each common task.

The public API

The API is every type in a package named api, which is com.trevlar.slotkit.api.*. The version contract covers those. Every other package is internal and can change in any release, a patch included. A task that seems to need an internal type is a gap in the API, so open an issue for it. Versioning has what each part of a version number promises.

Declare which sides need SlotKit

A mod states in its fabric.mod.json whether it needs SlotKit on both sides.

"custom": { "slotkit": { "bothSides": "required" } }
  • required is for a mod that builds slots or custom menus. A server with the mod admits only clients that have SlotKit and the mod.
  • preferred is for a mod that works on one side and does more with both, such as shared slot state. Nobody is refused for it.
  • A mod with no slotkit block only finds and acts on slots. It works on any server and never causes a refusal.

Any other value throws when the mod loads. Declaring sides covers the handshake and every message a refused player sees.

Choose a mode scope

Every declaration about a slot names the game mode it's for: ModeScope.SURVIVAL, CREATIVE, or BOTH, MenuKit's ModeScope. SlotKit reads the acting player's mode on each check, so a lock declared for BOTH holds on both of creative's tabs. The forms without a scope still work, mean BOTH, and are deprecated. See Mode scope.

Find slot groups

A slot group category is a name for a group of slots, such as PLAYER_INVENTORY, PLAYER_HOTBAR, CHEST_STORAGE, or FURNACE_INPUT. SlotGroupCategories.all() lists every category with no menu open, SlotGroupCategories.of(menu) lists the categories on a menu with their slots, and SlotGroupCategories.categoriesBySlot(menu) gives the category of each slot. SlotGroups lists individual groups, which can tell one mod's pockets apart from the main inventory when both declare PLAYER_INVENTORY. This is client tier. Slot group category has the full rules for naming and minting categories.

Place a panel on a slot or a slot group

A slot anchor is a MenuKit anchor whose box is one slot's frame or one slot group's box on the open screen. SlotPlacement.group(group, position) places a panel around a slot group, as in the first example above, and SlotPlacement.slot(address, dx, dy) places it at an offset from one slot. The panel takes one placement per mode with Panel.Builder.in(scope, placement) and is registered with MenuKit's AnchorPanelAdapter. A panel shows only where its slot or group is on the open menu, so a placement for creative and another for survival put the same slot in two places with no mode check of the mod's own. This is client tier. See Slot anchors and Put a slot in another place in creative.

Allow, gate, and veto operations

An operation is something done to a slot. Vanilla's eleven are CLICK_TAKE, CLICK_PUT, SHIFT_CLICK_OUT, SHIFT_CLICK_IN, COLLECT, DRAG_FILL, HOTBAR_SWAP, OFFHAND_SWAP, DROP, DROP_STACK, and INVENTORY_INSERT, and every one is on by default.

  • What a slot allows is decided by a cascade. A per-slot declaration wins over the slot's group, the group wins over its category, and the category wins over the key's default. SlotOperations.inherent(scope, category, operation, value) sets the category level.
  • SlotOperations.veto(scope, rule) registers a rule that can only say no, for a mod that is not the slot's author, such as a lock.
  • SlotOperations.allows(menu, slot, player, operation) is the one check, and it passes when the cascade allows the operation and no veto refuses it.
  • A gate sets what a slot accepts and releases, and how many of an item it holds. It is set with SlotSpec.gate(...) or Window.slot(scope, address).gate(...). Address.playerInventory(n) names a player inventory slot at startup, the same address on every screen.
  • A mod adds its own operation by declaring a BehaviorKey, publishing it with SlotOperations.define, and shipping a name and description in its lang file.

Operation and Gate cover roles, AppliesTo, and click tagging with SlotOperations.as. See also Block operations on a locked slot and Add an operation of your own.

Build created slots

A created slot is a real Slot a mod adds to a menu. ParityGroup.register(owner, spec) registers a group of them once, in common code, on the player's inventory menu and every container menu, as in the second example above. SlotKit builds no panel for it. The mod shows the group in its own MenuKit panel with SlotFlowElement, which lays the slots out in rows, or SlotElement, which places one slot. The contents persist through a StorageAttachment on the slot's owner, built with StorageAttachment.playerAttached(namespace, key, size) for a player or EphemeralStorage.of(size) for one menu session.

  • The owner id's namespace is the mod's id. register throws at startup when it isn't, or when the mod doesn't declare required. The message names the group and the line to add.
  • SlotSpec.shiftClickIn(true) makes a group a shift-click target, and SlotSpec.emptyIcon(...) draws an outline in its empty slots.
  • SlotSpec.activeCount(start) lets the server set how many of the group's slots are live for each player, and QuickMoveRoutes decides where a shift-click goes.
  • StorageAttachment.playerAttachedVisible(...) also sends the contents to other players' clients, for gear drawn on the player.
  • A SlotPlacement places the panel on a slot group or a slot, such as above the offhand.

This needs SlotKit on both sides. See Parity group, Storage, and Put a slot above the offhand.

Find items inside shulker boxes and bundles

ItemSources walks the items a player carries, in the inventory, the ender chest, and shulker boxes and bundles to any depth, nearest first. An ItemScope says which of those to search. On the server, take and walk remove or change an item and write the change back through every container. find lists matches on either side with an ItemPath for each, so a client can choose an item and the server can act on it with at. The same calls also take a Container the caller supplies, such as the chest a player has open. It resolves only against the container the mod passes in, so on the server pass the one behind the player's menu, never one the client names. To keep a menu open on a nested item, such as a bundle inside a shulker box in a chest, bind it with ItemSources.live(container, path). The LiveItem takes any number of writes, sends each one back up the chain, and goes stale when the item moves or something else changes it, so the menu's stillValid returns !live.isStale(). See Item sources and Find and use items inside shulker boxes and bundles.

Since 2.2.0, ItemSources.pathOf(player, slot) names the item in a main inventory slot, an ender chest slot, or a carried attachment's slot, with the same answer on the client and the server. On the client an ender chest's own menu shows a stand-in container, so its slots name nothing there. A player attachment declared playerAttached(...).carried() holds the player's own things, a scope with carried(true) walks it, and containerOf(player, path) returns its contents. Every binding of a player, block, or entity attachment shares one list of stacks, so a stack is the same object wherever it's read. See Item sources.

Give an item a state, and change how it draws

An ItemState is a value that rides on an item, through shulker boxes and back, synced to every client with the stack. ItemState.Saved.YES saves it with the item, and Saved.NO drops it at a relog or restart. The server sets it with set and clear. Only a mod that declares bothSides: required can declare a state. SlotLooks changes how a slot draws an item while an ItemState holds or a SlotLooks.When check answers yes on the client: animate plays an animation, swapWhen draws another stack in its place, and under and over draw a mark through MenuKit's slot decorations. Declare looks from the client initializer. See Item state and slot looks and Show an item as open.

Take a double-click on a slot

SlotDoubleClick gives a plain left double-click on a slot to a mod's action. Both clicks land within one second with the cursor on the same pixel, and only the real mouse counts, so a sort mod's simulated clicks never pair. The first click stays vanilla's and lifts the stack, which is drawn back in its slot while the pair is pending. The second, which vanilla would take as gather all, goes to the first registration that accepted the slot. See Double-click and Open an item on a double-click.

Show a container by its group's id

SlotGroupElement.of(id) shows one slot group in rows, found by its SlotGroupId on whatever menu is open. SlotGroupElement.of(SlotGroupId.category(SlotGroupCategory.CHEST_STORAGE)) shows a single chest, a double chest, or a barrel with no menu-type indices, and another mod's created group is named by its saved form with no compile dependency on that mod. The element shows only while the group's slots do. Showing a group in another panel moves its slots on the screen only. Each container stays its own, and a menu's own shift-click stops before every slot SlotKit added. See Slot group element and Separate containers.

Add slot groups to an open menu

An OnDemandGroup is registered once in common code, like a ParityGroup, but it's on no menu until the server adds it. BOX.add(player, storage) puts an instance's slots on the menu the player has open, the client's included, and instance.remove() takes them away. Each instance is its own slot group, with an id like mymod:box:slots#0, and declarations on the kind reach every instance. A removed instance's slots stay on the menu, inert, until the next instance of its kind takes them, so no other slot's index moves while the menu is open. add returns null for a client without SlotKit and the kind's mod. This needs SlotKit on both sides. The class Javadoc covers gates, quick-move routes, and active counts per instance.

Put a panel on every group of a category

SlotPlacement.group(category, position) reaches only a category's vanilla group. CategoryPanels.declare(category, on -> panel) puts one panel on each group of the category shown on the open menu, created groups and on-demand instances included, so a chest and the shulker box and ender chest a mod opens beside it each get their own Sort button. on.group() names the group a panel sits on. Read it when acting on a click, since a tab switch can change it. Declare at init, up to CategoryPanels.MAX_SHOWN panels per category. SlotGroupCategory.BUNDLE_STORAGE is the category for an opened bundle, so other mods treat any mod's bundle the same way. This is client tier.

Switch between menus

MenuSwitch moves a player between menus while the one they opened in the world waits behind the others. From a tab click on the server, MenuSwitch.open(player, provider) opens a menu with the chest set aside (its lid stays up, with no close sound), openInventory(player) opens the inventory, and back(player) returns to the chest. Menus opened through open close normally when the player leaves them, so the crafting grid hands its items back. The stack on the cursor moves with every switch. The set-aside menu closes properly when its stillValid fails, the player dies, changes dimension, or leaves, or the menu in front closes, and onSetAsideClosed hears each of these. open and back send only vanilla packets. openInventory needs SlotKit on the client and returns false without it. Server thread only.

Scroll slots in a scroll area

A SlotElement inside a MenuKit ScrollContainer scrolls and clips like any other element. A slot across the edge of the scroll area draws, hovers, and takes clicks only where it shows. A mod that uses SlotElement needs no extra code for this.

Open a custom menu

CustomMenu.define(id, ...) builds a container menu with its own slots, laid out with MenuKit panels. The server decides which panels are shown, a player can toggle only a panel declared toggleable(), and a client can open the menu only while its validWhen holds. The same definition check as ParityGroup applies. See Open a custom menu with its own slots.

Attach state to a slot

SlotState.register(scope, id, codec, streamCodec, defaultValue, visibility, canWrite) creates a channel that stores one typed value per slot, separate from the slot's item. PRIVATE stores one value per viewer, and SHARED stores one value for everyone. A slot is named by an Address, which resolves after a menu reopens and on both sides. The server checks every write a client sends, and a SHARED channel refuses every client unless its canWrite rule allows them. See Slot state channel and Attach a flag to a slot.

Ask what the other side runs

Presence reports what the other side had when the player joined. On the client, Presence.serverHasSlotKit(), serverHas(modId), and serverHasChannel(channelId) answer about the server. On the server, Presence.clientHasSlotKit(player) and clientHas(player, modId) answer about a player. See Presence.

Know the limits

Limits lists what SlotKit doesn't do and the open gaps in this release, such as created slots in overlay panels.

Upgrade

Upgrading moves a mod from SlotKit 2.1 to 2.2, from 2.0 to 2.1, and from 1.x to 2.0, with a before and after for each change, and from MenuKit: Containers or MenuKit 6's slot code, with an import map and the two renames.

License

MIT.

Версии

Release
2.3.0+26.3
fabric · 26.3 · 1h ago
## 2.3.0 #### Added - `SlotOperations.PutVeto`, registered with `vetoPut`: a veto handed the stack about to land, so a rule can refuse a put by item ("only…
10
Release
2.2.0+26.3
fabric · 26.3 · 4d ago
## 2.2.0 #### Added - `ItemSources.pathOf(player, slot)` names the item in an inventory slot, an ender chest slot, or a carried attachment's slot, with the…
181
Release
2.1.0+26.3
fabric · 26.3 · 8d ago
## 2.1.0 Rules about slots now hold in creative, and a mod says which game mode each one is for. Panels can sit on a single slot, and each container on a menu…
222
Release
2.0.0+26.3
fabric · 26.3 · 11d ago
## 2.0.0 Mods now place SlotKit's slots in their own MenuKit panels, and can reach items inside shulker boxes and bundles. Mods built on 1.x need an update,…
286
Release
1.1.1+26.3
fabric · 26.3 · 16d ago
## 1.1.1 Fixes for slots in MenuKit scroll areas. Nothing changes for mods built on 1.1.0. Requires MenuKit 7.2.0 or newer. ### Changed - Slots clip to the…
202
Release
1.1.0+26.3
fabric · 26.3 · 18d ago
## 1.1.0 Additions for mods that build slots. Nothing in 1.0.0 changes. Needs MenuKit 7.1.0 or newer. ### Added -…
79
Release
1.0.0+26.3
fabric · 26.3 · 20d ago
## 1.0.0 SlotKit is MenuKit: Containers renamed, plus the slot code MenuKit 6 carried. It has its own version number and needs MenuKit 7.0.0 or newer, below…
98
Release
6.2.0+26.3
fabric · 26.3 · 21d ago
## 6.2.0 Released alongside MenuKit 6.2.0, and requires it. That MenuKit release docks tooltips at the bottom or top of the screen under…
57
Release
6.1.1+26.3
fabric · 26.3 · 21d ago
Now runs on Minecraft 26.3.
26
Release
6.1.0+26.2
fabric · 26.2 · 21d ago
## 6.1.0 Released alongside MenuKit 6.1.0, and requires it. That MenuKit release draws each element to suit the kind of screen it is on, and adds text…
60
Release
6.0.0+26.2
fabric · 26.2 · 1mo ago
## 6.0.0 One of everything. Requires MenuKit 6.0.0. Breaking: every mod that uses Containers migrates. The README's "To 6.0.0" section lists the changes most…
65
Release
5.1.0+26.2
fabric · 26.2 · 1mo ago
5.1.0: Created slots follow MenuKit's slot operations. Requires MenuKit 5.1.0. This release adds API and breaks nothing. Shift-clicking into or out of a…
23

Комментарии 0

Пока нет комментариев. Будь первым, кто поделится мнением.

FAQ

Как установить SlotKit?

Скачайте файл под свою версию Minecraft и загрузчик с этой страницы, затем положите .jar в папку mods (или plugins) и запустите игру.

SlotKit бесплатный?

SlotKit можно скачать бесплатно на Modgrid — мы ведём прямо к официальному источнику, без paywall и лишних установщиков.

Какие версии Minecraft поддерживает SlotKit?

Работает с Fabric. Поддерживаются версии 1.21.11–26.3. Список поддерживаемых версий и загрузчиков — в блоке загрузки на этой странице.