A number of advanced blocks use "containers" - these are blocks that can store items, including
- Chests (permanent storage)
- Furnaces (permanent storage)
- Crafting table (temporary storage only)
The logic for containers can be quite confusing until you understand how they are structured.
Key points
- A Container is used to bundle together different “Slots” into a single location. Each Slot contains an ItemStack. The Container may also contain other information, eg progress bar time. For example, the FurnaceContainer collates information from the FurnaceTileEntity and the PlayerInventory. It provides a consecutive list of Slots numbered from 0 .. N-1, where (eg) 0..35 might come from the player inventory, and 36 - 44 might come from the TileEntity. It also tracks the smelting progress as an int.
- Containers don’t permanently store information. They are created, exist for a short time, then disappear. Any items permanently stored in the “container” are actually stored elsewhere (usually – in the TileEntity).
- Two Containers are created, one on the server and one on the client. Vanilla will keep the slots in synch for you automatically, but extra information (eg progress bar information) you will need to synchronise yourself.
- These two containers are created in two different ways:
- The server Container is constructed by a NamedContainerProvider::createMenu(), which is usually a TileEntity that implements the interface. The NCP gives the container a link to its “permanent storage” inventory of items, which allows the container to alter the permanently stored items in the TileEntity. In vanilla, this link is via the IInventory interface.
- The client Container is constructed (in response to a packet from the server) by using the registered ContainerType::create() method, which gives the container a link to an empty/temporary inventory instead of to a TileEntity’s “permanent storage”.
- In addition to the client container, the client also has a ContainerScreen, which is the visual representation of the container. It specifies the layout of the GUI, retrieves items and other data (eg progress bars) for display, and interacts with the user. The basic element of the Screen is a number of "Slots" where items can be placed, you can add other graphic elements as desired. The Screen only ever exists on the client, and is created by the registered IScreenFactory for that ContainerType.
- PlayerEntity::openContainer instead of NetworkHooks::openGUI
You can use the Vanilla methods if you prefer to do so, although the Forge methods are slightly more convenient / flexible.
It is not essential to use TileEntities as the NamedContainerProvider. Blocks without TileEntities (eg CraftingTableBlock), an Entity (similar to the player's inventory), or even an Itemstack (eg using Capability) can be used instead.
Screen representation of a Container |
Information flow involved with Containers |
Creation/initialisation sequence for Containers |
Thanks for your great job. Can I translate you articles to Chinese?
ReplyDeleteYes, just give me credit for the original link :)
ReplyDeleteThis explanation was so incredible!
ReplyDeleteI made entity with inventory in 1.7.10,I am trying to do the same for 1.14.4. Is there any examples already that I can spy to learn how to do and how it works?
Thank you
Really a great job you're doing here m8...well done
ReplyDeleteI have a question about containers. I want to create a mod which contains a pistol, a pistol clip and bullets. The bullets should be placed in the pistol clip, just by dropping the bullets on the pistol clip (no need for GUI). Same thing goes for the pistol. The user should be able to drop a single clip on to the pistol to load it. The bullet will be the projectile, but what about the clip and pistol? Should I build them as TileEnties?
Where can I find more detailed information about the vanilla classes to find out which events are supported by these vanilla classes (for item hovering, dragging, dropping etc)?