SkillAgentSearch skills...

Canvas

Canvas is a java library built for Bukkit to manage custom inventory based menus

Install / Use

/learn @IPVP-MC/Canvas
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

canvas Build Status

A highly advanced and effective inventory management library for Bukkit plugins. The primary goal of canvas is to enable creation of elegant inventory systems without the quirks of existing libraries.

Feature Overview

Using canvas

canvas is integrated into plugins through the use of Maven.

Requirements

Then use the following command to install canvas to your local maven repository

git clone https://github.com/IPVP-MC/canvas.git
cd canvas/
mvn clean install

You will now be able to add canvas as a dependency in your pom.xml files with the following

<dependency>
    <groupId>org.ipvp</groupId>
    <artifactId>canvas</artifactId>
    <version>1.7.0-SNAPSHOT</version>
    <scope>compile</scope>
</dependency>

Note: You will need to use the Maven shade plugin in order to package your final .jar file. Add the following to your maven plugins section:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.4</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>   

see here for additional documentation on the shade plugin.

Once the dependency is registered, the only thing left to do is to register the MenuFunctionListener with the Bukkit event dispatcher.

Bukkit.getPluginManager().registerEvents(new MenuFunctionListener(), plugin);

Features

Menus

Out of the box, canvas supports the following inventory types as menus:

  • Chest menus
  • Hopper menus
  • Box menus (ie. 3x3 inventories such as workbench, dispenser, dropper)
    • Note: Due to an error in internal Minecraft code, shift clicking is disabled in Hopper and Box menus.

The above menus can be created by using the Builder pattern available in their respective classes. Creating a standard ChestMenu with 4 rows would look as such:

public Menu createMenu() {
    return ChestMenu.builder(4)
            .title("Menu")
            .build();
}

Displaying the menu to a player is made simple with Menu#open(Player)

public void displayMenu(Player player) {
    Menu menu = createMenu();
    menu.open(player);
}

Simple yet effective, our result looks like this:

Close handlers

Functionality when a Menu is closed can be added to Menus through the Menu.CloseHandler interface. The interface is meant to be used as a functional interface, and functionality is added elegantly with Java 8 lambda expressions.

Let's say we want to send the player some messages when they leave the inventory:

public void addCloseHandler(Menu menu) {
    menu.setCloseHandler((player, menu1) -> {
            player.sendMessage("You just closed the menu...");
            player.sendMessage("See you next time!");
    });
}

Redrawing

When switching between different Menus for players, by default the cursor will reset to the middle of the screen. This behavior can be changed to preserve cursor location at the cost of not being able to update Menu titles by enabling the redraw property of a Menu. When building a Menu via MenuBuilder, passing a value of true to MenuBuilder#redraw(boolean) enabled this functionality.

Note: If switching to a menu that has different dimensions, the redraw flag will be ignored and a new Inventory will be opened for the player, resetting their cursor.

Pagination

Creating connected pages of Menus to display a catalog of items is made easy with the PaginatedMenuBuilder class. The utility is able to be configured to set the proper previous and next page icons, and any necessary functions for items that are added.

In the basic example below, we create a simple menu displaying various static items.

Menu.Builder pageTemplate = ChestMenu.builder(3).title("Items").redraw(true);
Mask itemSlots = BinaryMask.builder(pageTemplate.getDimensions())
        .pattern("011111110").build();
List<Menu> pages = PaginatedMenuBuilder.builder(pageTemplate)
        .slots(itemSlots)
        .nextButton(new ItemStack(Material.ARROW))
        .nextButtonEmpty(new ItemStack(Material.ARROW)) // Icon when no next page available
        .nextButtonSlot(23)
        .previousButton(new ItemStack(Material.ARROW))
        .previousButtonEmpty(new ItemStack(Material.ARROW)) // Icon when no previous page available
        .previousButtonSlot(21)
        .addItem(new ItemStack(Material.DIRT))
        .addItem(new ItemStack(Material.GRASS))
        .addItem(new ItemStack(Material.COBBLESTONE))
        .addItem(new ItemStack(Material.STONE))
        // ...
        .build();

Per-player items and click handlers are supported for added items as well, via the PaginatedMenuBuilder.addItem(ItemStackTemplate) or PaginatedMenuBuilder.addItem(SlotSettings) methods.

If additional modifications need to be made to any newly created page that the builder doesn't support, adding functionality to modify a freshly created page is available by adding a Consumer<Menu> with the PaginatedMenuBuilder.newMenuModifier(Consumer<Menu>) method.

Slots

A Slot is exactly what you'd expect it to be, however canvas allows incredible customization of what they can do. Menus grant access to their slots through the Menu#getSlot(int) method.

There are 3 major pieces to Slot functionality:

Additionally, Slots grant the ability to render non-static items within their parent Menu via ItemStackTemplate (see below).

ClickOptions

Click options are the primary method of controlling what actions and click types can be performed on the raw item contents of the holding inventory. Two basic sets are provided with the library, which are ClickOptions.ALLOW_ALL and ClickOptions.DENY_ALL. By default, slots carry the DENY_ALL trait, denying all pickup and dropping off of items in the respective inventory. These behaviors are easily modified with the Slot#setClickOptions(ClickOptions) method.

Creation of custom options is done through the ClickOptions.Builder class. In the following example, we show you how to only allow dropping off of items into a specific slot, but not picking it up.

public void addClickOptions(Slot slot) {
    ClickOptions options = ClickOptions.builder()
            .allow(ClickType.LEFT, ClickType.RIGHT)
            .allow(InventoryAction.PLACE_ALL, InventoryAction.PLACE_ONE, InventoryAction.PLACE_SOME)
            .build();
    slot.setClickOptions(options);
}

ClickInformation

ClickInformation is a class constructed to provide the ClickHandler of a Slot with all available information about a click performed on the Slot. Also available is the possibility to change the resulting outcome of the click (whether interaction in the raw inventory occurs).

ClickHandler

Click handlers are where most of the logic of a slot will occur. As a slot is clicked, the click handler (if present) is triggered with information about who clicked as well as the click performed. The handler of a slot will always be triggered, regardless of whether or not the options of a slot forbid interaction with it. Keep in mind that the result of the click will be set by the options before the handler is triggered and as such the ClickInformation will represent this result.

Adding a handler is made simple with Slot#setClickHandler(ClickHandler):

public void addClickHandler(Slot slot) {
    slot.setClickHandler((player, info) -> {
        player.sendMessage("You clicked the slot at index " + info.getClickedSlot().getIndex());
        // Additional functionality goes here
    });
}

Templates

Item templates are used to render non-static items on a per-player basis. In certain situations, users of canvas may require a Menu to be updated because state has changed. For example, if an icon in a Menu displays the level of a player and the player has levelled up then the icon must be redrawn to reflect the changes. Item templates allow this functionality to happen without requiring a completely new Menu for each player.

Item templates are assigned to slots via the Slot#setItemTemplate(ItemStackTemplate) method. Alternatively,
Slot#setItem(ItemStack) can be used to set a static item that will render the same for every player.

Using the scenario above, where a player may be lev

Related Skills

View on GitHub
GitHub Stars156
CategoryDevelopment
Updated11d ago
Forks25

Languages

Java

Security Score

95/100

Audited on Mar 27, 2026

No findings