Inventory, menus, and crafting
Inventory is split into storage and interaction. Containers own stacks; slots adapt container indices to menu rules; menus coordinate cursor actions and route them to slots. This lets a chest, furnace, workbench, and player inventory share click behavior while keeping their layouts and constraints separate.
Ownership map
Section titled “Ownership map”| Type | Responsibility |
|---|---|
IItemContainer |
Read, write, and remove stacks by slot index. |
SimpleContainer |
Fixed-size in-memory stack storage with change notifications. |
Slot |
Connect a container index to menu position and allow place/take policy overrides. |
AbstractContainerMenu |
Shared cursor, click, split, merge, swap, quick-move, and outside-drop behavior. |
| Concrete menus | Define slot order, positions, and transfer ranges for one screen or workstation. |
CraftingGrid and IRecipe |
Hold a recipe input matrix and match/assemble recipe results. |
Click and transfer flow
Section titled “Click and transfer flow”A UI click should enter through the active menu, not mutate a container from presentation code. The menu interprets the slot index and button, then uses Slot.MayPlace, MayPickup, and stack operations to apply the action. Shift-click delegates to the concrete menu’s quick-move ranges. Outside-click sends dropped stacks to the supplied world callback. A menu broadcasts changes after the operation so the view can refresh.
The container remains the source of truth for its slots. When implementing a new screen, define the container and slot policy first, then slot order and screen positions, then quick-transfer direction and result-slot behavior. Test both directions of each transfer path because slot ranges are easy to reverse.
Crafting
Section titled “Crafting”CraftingGrid supports arbitrary width and height, including the player’s 2×2 and the workbench’s 3×3 matrices. ShapedRecipe scans valid offsets and mirrored patterns. ShapelessRecipe matches each occupied input against a remaining ingredient list, so duplicate ingredients are accounted for individually. RecipeRegistry.FindMatchingRecipe returns the first registered match; Assemble returns a fresh copy of the result.
The result slot is special: taking a result must consume the inputs according to its recipe/workstation rules, not behave like an ordinary storage slot. Follow ResultSlot and the concrete menu when changing consumption, container remainders, or shift-crafting.
Recipe data
Section titled “Recipe data”RecipeLoader reads JSON definitions from assets/data/minecraft/recipe/. The data covers shaped and shapeless crafting, cooking, stonecutting, and smithing transforms. Ingredients can name an item, refer to a tag with #, or provide a list of alternatives. For example:
{ "type": "minecraft:crafting_shaped", "key": { "#": "minecraft:stick", "X": "#minecraft:stone_tool_materials" }, "pattern": ["XXX", " # ", " # "], "result": { "id": "minecraft:stone_pickaxe" }}The loader feeds the existing recipe registries; matching and result consumption remain runtime responsibilities. Unsupported or unresolved definitions are reported and skipped, and hand-registered recipes still provide coverage for special cases. When adding a recipe, confirm its type is supported, ensure referenced tags are loaded, and inspect the target workstation’s result-slot behavior.
Where to trace a change
Section titled “Where to trace a change”- Shared clicks:
src/Inventory/AbstractContainerMenu.cs - Slot constraints and placement:
src/Inventory/Slot.csand concrete slot subclasses - Workbench layout:
src/Inventory/CraftingMenu.cs - Recipe matching and registration:
src/Crafting/IRecipe.cs,ShapedRecipe.cs,ShapelessRecipe.cs,RecipeRegistry.cs - Storage widgets:
src/Inventory/*Menu.csand the owning block entity/container
A UI can present menu state, but it should not become the rule owner for recipe matching, stack compatibility, or transfer policy.
Known boundaries
Section titled “Known boundaries”Recipe definitions are JSON-backed for the supported recipe types, with hand-registered fallbacks for special cases. This is not a general-purpose data-pack reload system. Menu implementations exist for many workstation types, but their feature completeness varies. Inspect each concrete menu before assuming every interaction is implemented.