Inventory Library

| GitHub |

This library is a lightweight framework that can be used to create inventory menus. The largest consideration of the library is to provide an interface around Sponge’s Inventory API where developers can easily create inventory views without having to work through the complexity of the process alone. It is not intended that this is to be an all-encompassing library; rather the goal is to keep things lightweight, simple, and account for the majority of common use cases.

The Inventory Library was one of the initial libraries in TeslaLibs and was improved in PR #5 by Simon_Flash.

Element

An Element [link] is an individual component of a GUI that contains an item and click action. Creating an Element can be done quite simply:

ItemStack item = ItemStack.of(ItemTypes.BLAZE_POWDER, 1);
Consumer<Action.Click> action = action -> action.getPlayer().sendMessage(Text.of("Elements are awesome!"));

Element element = Element.of(item, action);

Note that because Elements are immutable, the item is stored as an ItemStackSnapshot and modifying the ItemStack will not have any effect on it’s state. An Element with no item or action can be retrieved using Element.EMPTY, which can be used to ‘reset’ a slot and is non-operational.

Layout

Before we can talk about Views, we need to start with a way to define where an Element is positioned in an inventory. To do this, we use the Layout [link] class to design where Elements go in the final view. Let’s take a look at a simple Layout with only a couple elements.

Element stone = Element.of(ItemStack.of(ItemTypes.STONE, 1));
Element dirt = Element.of(ItemStack.of(ItemTypes.DIRT, 2));
Element grass = Element.of(ItemStack.of(ItemTypes.GRASS, 3));

Layout layout = Layout.builder()
        .set(stone, 0)
        .set(dirt, 1, 9)
        .set(grass, 2, 10, 18)
        .build();

Result

The Layout.Builder class also has a number of different utility methods for common design patterns. Many of these make use of the layout’s dimension (defaults to a 6 by 9 double chest), which can be changed using the dimension method. Here’s a simple example using some of the available methods.

Layout layout = Layout.builder()
        .dimension(InventoryDimension.of(9, 3))
        .border(stone)
        .center(grass)
        .fill(dirt)
        .build();

Result

View

At long last, we’ve made it! The View [link] class is the heart of the library and manages the inventory, delegates click events to the appropriate element, and handles a variety of other actions. Once created, a View may be shared between players and any changes (such as through View#update) will be displayed automatically. To create a View, you’ll need an InventoryArchetype, your PluginContainer, and a Layout.

InventoryArchetype archetype;
PluginContainer container;
Layout layout;

View view = View.of(archetype, container).define(layout);

The View.Builder class contains additional methods to further customize your view by setting properties for the inventory or an action to fire when the view closes - just be careful if you’re canceling the close event to ensure the player doesn’t get trapped!

View view = View.builder()
        .archetype(archetype)
        .property(InventoryTitle.of(Text.of("Title")))
        .onClose(action -> action.getPlayer().sendMessage(Text.of("Goodbye!")))
        .build(container);

Page

At times, you’ll come across cases where you need to add a variable number of Elements into a View to be displayed. This can be pretty straightforward for small numbers, but it quickly becomes a hassle if you need more than one view to do so. To handle this, the Page [link] class can be used to paginate a list of Elements and handle all of the page controls for you.

Trying to do this in a customizable way isn’t easy, but the Page class does it’s best by working off of a Layout template using Element placeholders. To create our template, we’ll need to use the static Elements to define where we want our navigation icons to go.

Layout layout = Layout.builder()
        .set(Element.empty(), 45, 46, 52, 53)
        .set(Page.FIRST, 47)
        .set(Page.PREVIOUS, 48)
        .set(Page.CURRENT, 49)
        .set(Page.NEXT, 50)
        .set(Page.LAST, 51)
        .build();

Page page = Page.builder().layout(layout).build(container);

The key thing to note here is how we’re adding the static elements for the different page positions. The way this works is a bit of a mess, but all you need to know is that they’ll be replaced with an Element displaying the page number that will have the appropriate click action when the page is defined. With the Page build, we can define it using a List<Element> as follows.

List<Element> elements = IntStream.rangeClosed(1, 64)
        .mapToObj(i -> Element.of(ItemStack.of(ItemTypes.SLIME_BALL, i)))
        .collect(Collectors.toList());

page.define(elements);

Page 1 Page 2

Category: Developer Tools

Published on Mar 18, 2018

views

stars

watchers

total downloads

Promoted Versions

Members