Only this pageAll pages
Powered by GitBook
1 of 16

CraftVentory

Loading...

get started

Loading...

Loading...

Loading...

Loading...

Loading...

Advanced concepts

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Initialize the library

This page describes how to initialize the library.

To use the library and create custom inventories, it first must be initialized by defining a set of reusable Java objects. This is done by using the CraftVentoryLibrary class that provides several methods to use the default behaviors implemented in the library.

Create an InventoryService

An InventoryService is a class with two purposes:

  • Register, store and retrieve inventory providers

  • Store information about players with an opened inventory and manage inventories' life cycle

An instance of this class with the default behavior provided by the library can be created by using the following code:

InventoryService service = CraftVentoryLibrary.createInventoryService(Plugin plugin);

Note: We recommand to store this object as an instance variable in the main class of your plugin (eq. the class that extends JavaPlugin).

Create an InventoryConfigDAO

An InventoryConfigDAO is a class used to load an inventory from a configuration file. By default, the library provides an instance of this class to load inventories from YAML files. The following code uses the library built-in methods to create a new instance of InventoryConfigDAO:

// Factory used to load item click actions.
ClickActionLoaderFactory<ConfigurationSection> factory =
        FastInventoryLibrary.createDefaultClickActionLoaderFactory();

InventoryConfigDAO dao = FastInventoryLibrary.createDefaultConfigDAO(factory);

Note: ClickActionLoaderFactory is a class that is used to load item actions from the configuration file.

Example

Here is a complete example:

public class CraftVentoryPlugin extends JavaPlugin {

    private InventoryService inventoryService;

    @Override
    public void onEnable() {
        this.inventoryService = CraftVentoryLibrary.createInventoryService(this);
        this.loadInventoryProviders();
    }

    private void loadInventoryProviders() {

        ClickActionLoaderFactory<ConfigurationSection> factory =
                FastInventoryLibrary.createDefaultClickActionLoaderFactory();

        InventoryConfigDAO dao = FastInventoryLibrary.createDefaultConfigDAO(factory);

        // Register inventory providers here.
    }
}

Open a inventory

This page describes how to open an inventory to a player.

Retrieve the InventoryViewer

An InventoryViewer is an encapsulation of a player and its associated inventories, which are handled in the an InventoryViewManager. This class provides methods for opening / closing inventories and to navigate through the player's inventory history.

An InventoryViewer is created automatically for each player joining the server and then stored in an InventoryService. The viewer associated to a player can be retrieved as in the following code:

InventoryService inventoryService = ... ;
Player player = ... ;

// Retrieve the InventoryViewer instance associated to a player.
InventoryViewer viewer = inventoryService.getInventoryViewer(player);

Retrieve the InventoryProvider

An InventoryProvider is responsible for providing an inventory. All the providers are stored in an InventoryService and can be retrieved as in the following code:

InventoryService inventoryService = ... ;

// Retrieve the provider for an inventory.
Optional<InventoryProvider> optional = inventoryService.getProvider("inventory-id");

Example

The following code shows how you can open an inventory to a player.

InventoryService inventoryService = ... ;
Player player = ... ;

InventoryViewer viewer = inventoryService.getInventoryViewer(player);

inventoryService.getProvider("inventory-id").ifPresent(provider -> {
    CraftVentory inventory = provider.createInventory(this.service, player);
    viewer.getViewManager().openView(inventory);
});

The open() and close() methods available in the CraftVentory interface should never be used to open or close an inventory. You must use the methods from the InventoryViewManager interface instead.

Welcome

Welcome to the CraftVentory wiki.

What is CraftVentory?

CraftVentory is a Java / Spigot library that facilitates the development of Minecraft inventories. It enables developers to define fully configurable inventories in configuration files and provide them with Java code in their plugins.

This library was developed to facilitate the development of in-game inventories. Indeed, making them fully configurable is an important feature for server administrators but this process is very tedious without an appropriate tool. CraftVentory solves this problem by providing a lot of built-in features to help developers implement fully customizable inventories very easily.

Features

CraftVentory comes with the following features:

  • Fully customizable inventories / items / paginations from configuration files (YAML support).

  • Fully customizable actions when clicking on items like sending messages / sounds, executing commands, inventory navigation, etc.

  • Paginations to paginate a large list of results in an inventory.

  • Placeholders to display custom values in texts (inventory title, item name / lore, etc.).

  • Inventory history to enable players to easily navigate between inventories (home, backward, forward).

  • I18n support.

  • Enhancements to dynamically modify inventory properties with Java code.

  • Hooks to execute custom Java code for an inventory when specific events happen.

Setup

To use CraftVentory, you can directly include the JAR file as a dependency of your plugin. This JAR file can be downloaded on the Releases page of the GitHub repository of the project.

The library can also be included in your project by using a dependency manager like Maven or Gradle.

<repository>
    <id>jitpack.io</id>
    <url>https://jitpack.io</url>
</repository>

<dependency>
    <groupId>com.github.Syr0ws</groupId>
    <artifactId>CraftVentory</artifactId>
    <version>{VERSION}</version>
    <scope>compile</scope>
</dependency>
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}

dependencies {
    implementation 'com.github.Syr0ws:CraftVentory:{VERSION}'
}

After being added as a dependency, you must initialize the library by following this tutorial.

Useful links

  • GitHub

  • Spigot

  • Discord

Example

Configuration :

id: "warp-inventory"

type: "CHEST_9x6"

title: "&6Warps"

pattern:
  - "OOOOOOOOO"
  - "OYYWWWYYO"
  - "OY1W2W3YO"
  - "OYW4W5WYO"
  - "OYYWWWYYO"
  - "OOOOOOOOC"

content:
  orange-stained-glass:
    item:
      type: ORANGE_STAINED_GLASS_PANE
      name: " "
    symbol: "O"
  yellow-stained-glass:
    item:
      type: YELLOW_STAINED_GLASS_PANE
      name: " "
    symbol: "Y"
  white-stained-glass:
    item:
      type: WHITE_STAINED_GLASS_PANE
      name: " "
    symbol: "W"
  warp-world:
    item:
      type: GRASS_BLOCK
      name: "&aOverworld"
      lore:
        - ""
        - "&fClick to be teleported to the overworld."
    symbol: "1"
    actions:
      close:
        type: "CLOSE"
      player-command:
        type: "PLAYER_COMMAND"
        command: "warp overworld"
  warp-nether:
    item:
      type: NETHERRACK
      name: "&cNether"
      lore:
        - ""
        - "&fClick to be teleported to the nether."
    symbol: "2"
    actions:
      close:
        type: "CLOSE"
      player-command:
        type: "PLAYER_COMMAND"
        command: "warp nether"
  warp-end:
    item:
      type: END_STONE
      name: "&5End"
      lore:
        - ""
        - "&fClick to be teleported to the End."
    symbol: "3"
    actions:
      close:
        type: "CLOSE"
      player-command:
        type: "PLAYER_COMMAND"
        command: "warp end"
  warp-mining:
    item:
      type: "IRON_ORE"
      name: "&7Mining"
      lore:
        - ""
        - "&fClick to be teleported to the mining world."
    symbol: "4"
    actions:
      close:
        type: "CLOSE"
      player-command:
        type: "PLAYER_COMMAND"
        command: "warp mining"
  warp-enchant:
    item:
      type: ENCHANTING_TABLE
      name: "&5Enchantment"
      lore:
        - ""
        - "&fClick to be teleported to the enchantment room."
    symbol: "5"
    actions:
      close:
        type: "CLOSE"
      player-command:
        type: "PLAYER_COMMAND"
        command: "warp enchant"
  close:
    item:
      type: BARRIER
      name: "&cClose"
    symbol: "C"
    actions:
      close:
        type: "CLOSE"

Inventory configuration

This page describes how to configure an inventory in YAML.

CraftVentory enables developers to create fully customizable inventories from configuration files. YAML is the default file format supported by the library for this purpose.

How to configure an inventory?

Each inventory must be defined in a separate configuration file. It is represented by a set of properties which are listed below:

Id

# An id that uniquely identify the inventory.
id: "inventory-id"

Type

# The type of view that will be used for the inventory.
# Available types:
# - CHEST_9x1 (1 row)
# - CHEST_9x2 (2 rows)
# - CHEST_9x3 (3 rows)
# - CHEST_9x4 (4 rows)
# - CHEST_9x5 (5 rows)
# - CHEST_9x6 (6 rows)
# - DROPPER
# - HOPPER
type: "CHEST_9x6"

Title

# The title of the inventory.
# The following placeholders are available by default:
# - %player_name% : The name of the player who is viewing the inventory.
# - %inventory_type% : The name of the inventory type.
# - %inventory_size% : The number of slots of the inventory.
title: "title"

Pattern

# The pattern of the inventory used to set items.
# A pattern must have the exact same number of rows and columns than the inventory.
# Items are represented by their associated symbol in the pattern.
# The symbol '&' must be used to represent an empty slot.
pattern:
  - "&&&&&&&&&"
  - "&1111111&"
  - "&1111111&"
  - "&1111111&"
  - "&P&&&&&N&"
  - "&&&&&&&&C"

Content

# The content of the inventory.
# You can add as many items as you want.
content:
  # Each item is described by a section.
  close:
    # The item to display.
    # You can use the default YAML representation supported by Bukkit to define an ItemStack
    # or the custom one provided by the library.
    item:
      type: BARRIER
    # Symbol used in the pattern to place the item in the inventory.
    # You must ensure that two items do not have the same symbol.
    symbol: "C"
    # Actions executed when a player clicks on the item.
    actions:
      # Each action is described by a section.
      close:
        # The type of the action.
        type: "CLOSE"

Paginations

# Paginations used in the inventory.
# An inventory can contain several paginations.
paginations:
  # Each pagination is described by a section.
  pagination-1:
    # The internal id of the pagination.
    # It must be unique for the inventory, as an inventory can contain several paginations.
    id: "pagination-1"
    # The symbol used in the pattern to place the pagination items in the inventory.
    symbol: "1"
    # The item used to represent each value of the pagination.
    # The Bukkit ItemStack representation must be used.
    pagination-item:
      item:
        type: DIAMOND
    # Item to open the previous page.
    # It is configured like items in the 'content' section.
    previous-page-item:
      item:
        type: ARROW
        # The following placeholders are available by default and can be used in name and lore:
        # %previous_page%: Previous page number.
        # %current_page%: Current page number.
        # %total_pages%: Total number of pages.
        name: "Page %previous_page%"
      symbol: "P"
    # Item to open the next page.
    # It is configured like items in the 'content' section.
    next-page-item:
      item:
        type: ARROW
        # The following placeholders are available by default and can be used in name and lore:
        # %next_page%: Next page number.
        # %current_page%: Current page number.
        # %total_pages%: Total number of pages.
        name: "Page %next_page%"
      symbol: "N"

Item configuration

An inventory is composed of a set of items. CraftVentory supports two ways to configure items in configuration files:

  • Using the default Bukkit YAML representation that supports complex ItemStack configurations

  • Using the custom representation that only supports simple item configurations

Custom item configuration

An item is represented by a set of required properties. All these properties are listed below, with comments on what is configurable and supported.

# Item configuration section.
item:
  # Type of the item. All the types can be found in the following link:
  # https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html
  type: DIAMOND
  # Display name of the item.
  # Color codes using the character '&' and hexadecimal colors prefixed by '#' are supported
  name: ""
  # Lore of the item.
  # Color codes using the character '&' and hexadecimal colors prefixed by '#' are supported
  lore:
  - "line 1"
  - "line 2"
  - "line 3"
  # Set true if you want a glow effect on the item or else set false.
  enchant: true

Pagination

This page describes how to register paginations in an inventory provider.

Pagination is the fact of splitting a list of values into pages. This is very useful when you want to display a large list of values in a container with a restricted size.

In CraftVentory, you can paginate a list of Java objects and convert each item to an InventoryItem to be displayed in an inventory.

Pagination configuration

To learn how to configure a pagination in an inventory configuration file, please refer to the Paginations configuration section.

Create a pagination provider

Like inventories, paginations are configurable. As a pagination relies on a list of Java object, there must be a link between its configuration and this list.

Let's say we want to paginate the following list of integers:

List<Integer> values = new ArrayList<>();

for(int i = 0; i < 50; i++) {
    values.add(i);
}

To paginate this list, you must create a pagination provider to let the library understand what data is paginated. This can be done by redefining the addProviders(ProviderManager manager) method from the InventoryDescriptor interface:

public class CustomInventoryDescriptor implements InventoryDescriptor {

    ...

    @Override
    public void addProviders(ProviderManager manager) {

        List<Integer> values = new ArrayList<>();

        for(int i = 0; i < 50; i++) {
            values.add(i);
        }
        
        manager.addProvider(new PaginationProvider<>("pagination-1", Integer.class, inventory -> values));
    }
    
    ...
} 

The PaginationProvider class takes the following paramaters in its constructors:

  • paginationId: The id of the pagination. It must be the same as the one defined in the configuration file of the inventory.

  • dataType: The data type that will be paginated. In the example, it is an Integer but it must be any Java class type.

  • supplier: A function that retrieves and returns the list of values to paginate. Here, we simply use the variable values defined above but we can imagine that the list comes from another class.

An inventory can contain several paginations. Each pagination must have its own pagination provider.

Example

Configuration :

id: "custom-inventory"

type: "CHEST_9x6"

title: "&6Custom title"

pattern:
  - "&&&&&&&&&"
  - "&1111111&"
  - "&1111111&"
  - "&1111111&"
  - "&P&&&&&N&"
  - "&&&&&&&&C"

content:
  close:
    item:
      type: BARRIER
    symbol: "C"
    actions:
      close:
        type: "CLOSE"

paginations:
  pagination-1:
    id: "pagination-1"
    symbol: "1"
    pagination-item:
      item:
        type: DIAMOND
        name: "Item n°%pagination_item_number%"
    previous-page-item:
      item:
        type: ARROW
        name: "Page %previous_page%"
      symbol: "P"
    next-page-item:
      item:
        type: ARROW
        name: "Page %next_page%"
      symbol: "N"

Declare an inventory

This page describes how to declare and register an inventory in Java.

In CraftVentory, an inventory is declared using the InventoryDescriptor interface. This interface is then mapped into an InventoryProvider which is a bridge between an InventoryConfig and an in-game inventory.

Create an InventoryDescriptor

Using the InventoryDescriptor interface, you can declare some properties of your inventory: the configuration file to load, the inventory id, its hooks, paginations and enhancements. The following code shows a basic implementation of this interface:

The interface also contains default methods you can redefine to register pagination providers, hooks and enhancements. These methods are not shown in the example above.

As these methods are not necessary for each inventory, the choice was make to declare them as default empty methods in the InventoryDescriptor interface. Thus, when using them, you don't need to make a call using the super keyword.

Create an InventoryProvider

An InventoryProvider encapsulates an InventoryDescriptor to create and provide an inventory. To be reused, inventory providers are registered in an InventoryService. The following code illustrates how to create and register a provider using a descriptor:

Advanced concepts

Paginations

The page describes how to create a new pagination to paginate a large list of results in the inventory.

Placeholders

The page describes how to create a new placeholder to be able to display custom values.

Enhancements

The page describes how you can enhance some inventory properties manually using Java code.

Hooks

The page describes how you can execute Java code when events happen for an inventory.

public class CustomInventoryDescriptor implements InventoryDescriptor {

    public static final String INVENTORY_ID = "custom-inventory";
    private static final String INVENTORY_CONFIG_PATH = "menus/waypoint-icons-menu.yml";

    private final Plugin plugin;
    private final InventoryConfigDAO inventoryConfigDAO;

    public CustomInventoryDescriptor(Plugin plugin, InventoryConfigDAO inventoryConfigDAO) {
        this.plugin = plugin;
        this.inventoryConfigDAO = inventoryConfigDAO;
    }

    @Override
    public String getInventoryResourceFile() {
        // Path to the configuration file of the inventory in the plugin's resources.
        return INVENTORY_CONFIG_PATH;
    }

    @Override
    public Path getInventoryConfigFile() {
        // Path to the inventory configuration file in the plugin's folder.
        return Paths.get(this.plugin.getDataFolder() + File.separator + INVENTORY_CONFIG_PATH);
    }

    @Override
    public String getInventoryId() {
        // This id must be unique. t is also recommended to only use the 
        // following characters: A-Z, a-z, 0-9, -, _.
        return INVENTORY_ID;
    }

    @Override
    public InventoryConfigDAO getInventoryConfigDAO() {
        return this.inventoryConfigDAO;
    }
}
public class CraftVentoryPlugin extends JavaPlugin {

    private InventoryService inventoryService;

    @Override
    public void onEnable() {
        this.inventoryService = CraftVentoryLibrary.createInventoryService(this);
        this.loadInventoryProviders();
    }

    private void loadInventoryProviders() {

        ClickActionLoaderFactory<ConfigurationSection> factory =
                FastInventoryLibrary.createDefaultClickActionLoaderFactory();

        InventoryConfigDAO dao = FastInventoryLibrary.createDefaultConfigDAO(factory);

        // Register inventory providers here.
        this.inventoryService.createProvider(new CustomInventoryDescriptor(this, dao));
    }
}
Pagination
Placeholders
Enhancements
Hooks

I18n

This page describes how to support text internationalization (i18n).

The I18n interface was developed as a bridge between CraftVentory and any internationalization library. It consists in a single method whose goal is to retrieve a text using a key and the player who requests it.

public interface I18n {

    String getText(Player player, String key);
}

To support text internationalization, the first step is to create a class that implements this interface and that does the mapping with an internationalization library. Then, the created class can be used in inventory descriptors by redefining the getI18n() method and everything should be automatically translated.

CraftVentory is not an internationalization library. It only provides a bridge to be mapped with one.

Hooks

This page describes how to create and register hooks.

A hook is a set of instructions to be executed when an inventory event is performed for a specific inventory.

How to create a hook?

Hooks are represented by the generic Hook functional interface. The following code illustrates how to create a hook.

Hook<FastInventoryBeforeOpenEvent> hook = event -> {
    System.out.println("Hook called before opening the inventory");
};

Hooks can be applied on the following events:

  • FastInventoryBeforeOpenEvent: Called before opening an inventory.

  • FastInventoryAfterOpenEvent: Called after an inventory has been opened.

  • FastInventoryClickEvent: Called when a player clicks on an item.

  • FastInventoryCloseEvent: Called when an inventory is closed.

Register a hook

Hooks are registered specifically for an inventory in its inventory descriptor by redefining the addHooks(HookManager manager) method.

The HookManager interface provides the addHook(hookId, eventClass, hook) method to register a new hook.

public class CustomInventoryDescriptor implements InventoryDescriptor {
    
    ...
    
    @Override
    public void addHooks(HookManager manager) {

        manager.addHook("before-open", FastInventoryBeforeOpenEvent.class, event -> {
            System.out.println("Hook called before opening the inventory.");
        });

        manager.addHook("after-open", FastInventoryAfterOpenEvent.class, event -> {
            System.out.println("Hook called after the inventory has been opened.");
        });

        manager.addHook("close", FastInventoryCloseEvent.class, event -> {
            System.out.println("Hook called when the inventory is closed.");
        });

        manager.addHook("click", FastInventoryClickEvent.class, event -> {
            System.out.println("Hook called when the inventory viewer clicks on an item in the inventory.");
        });
    }
    
    ...

}

Additional information

In CraftVentory, we do not rely on Bukkit events. Indeed, we prefer using hooks which are registered and executed specifically for an inventory instead of events which are executed for all inventories.

Context

The page describes the context concept implemented in the library.

What is a context?

In the library, a Context is a class that store values identified by keys which may differ depending on where the context is created and used. It is used in value providers and placeholders.

Common values

By default, several values may be added by the library and present in a context. The CommonContextKeyEnum is an enumeration that defines the keys of these common values.

These keys are described in the following table:

Key
Type
Type of context
Description

VIEWER

Player

Everywhere

The player who is viewing the inventory

INVENTORY

FastInventory

Everywhere

The inventory viewed

SLOT

Integer

Item

The slot of the item

PAGINATION_ID

String

Pagination

The id of the pagination

PAGINATION_ITEM

Depends on what is paginated

Pagination item

The current pagination item

Some keys are not available depending on where the context is declared and used. You must always check that the key is present before retrieving its associated value.

Placeholders

This page describes how to create and register custom placeholders.

A placeholder is used to display a value in a text. The library provides default placeholders but also enables developers to create their own placeholders to display their custom values in texts.

Create a placeholder

A placeholder is defined by creating a class that implements the Placeholder interface. The following code represents a placeholder for the player's ping:

public class PlayerPingPlaceholder implements Placeholder {

    @Override
    public String getName() {
        return "%player_ping%";
    }

    @Override
    public String getValue(Context context) {
        InventoryViewer viewer = context.getData(CommonContextKey.VIEWER.name(), InventoryViewer.class);
        Player player = viewer.getPlayer();
        return Integer.toString(player.getPing());
    }

    @Override
    public boolean accept(Context context) {
        return context.hasData(CommonContextKey.VIEWER.name());
    }
}

When using the Placeholder interface, several methods must be implemented:

Method name
Description

String getName()

Returns the name of the placeholder. It is recommended to use the format %placeholder_name%.

String getValue(Context context)

Returns the value the placeholder for the provided context.

boolean accept(Context context)

Check that the placeholder can be applied using the provided context.

Note: Some of these methods relies on a Context that is explained in the Context page.

Register a placeholder

To be used in an inventory, a placeholder must be registered in its InventoryDescriptor. This can be done by redefining the addPlaceholders(PlaceholderManager manager) method. The following code registers the placeholder created in the previous step of this tutorial:

public class CustomInventoryDescriptor implements InventoryDescriptor {  

    ... 

    @Override
    public void addPlaceholders(PlaceholderManager manager) {
        manager.addPlaceholder(new PlayerPingPlaceholder());
    }

    ...
}

Placeholders for pagination items

The library enables developers to paginate items in an inventory and it is then a common use case to need to display some values of what is paginated. This can be done using placeholders.

The process is nearly the same as the previous example. However, the only difference is that, as inventories may contain several paginations, you must ensure that the placeholder is only applied on items of the targeted pagination.

This is done by taking the pagination id as parameter in the class constructor and comparing it in the accept(Context context) method. The following code gives an example for a pagination that paginates a list of Integer:

public class PaginationItemNumberPlaceholder implements Placeholder {
    
    private final String paginationId;
    
    public PaginationItemNumberPlaceholder(String paginationId) {
        this.paginationId = paginationId;
    }
    
    @Override
    public String getName() {
        return "%pagination_item_number%";
    }

    @Override
    public String getValue(Context context) {
    
        // Using the key PAGINATION_ITEM to retrieve the value of the current item in the pagination.
        // The variable type depends on the data type paginated.
        Integer number = context.getData(CommonContextKey.PAGINATION_ITEM.name(), Integer.class);
        
        return Integer.toString(number);
    }

    @Override
    public boolean accept(Context context) {
        
        // Checking that the pagination id has been provided.
        if(!context.hasData(CommonContextKey.PAGINATION_ID.name())) {
            return false;
        }
        
        // Retrieving the pagination id.
        String paginationId = context.getData(CommonContextKey.PAGINATION_ID.name(), String.class);
        
        // Comparing ids and checking that there is a pagination item in the context.
        return paginationId.equals(this.paginationId) && context.hasData(CommonContextKey.PAGINATION_ITEM.name());
    }
}

Enhancements

This page describes the enhancement concept to customize inventories programmatically.

How does CraftVentory work?

To understand the enhancement concept and why it was implemented in CraftVentory, you first need to have a brief overview on how the library works. CraftVentory is built on three modules:

  • Configuration: Responsible for loading an inventory from a configuration file and store this configuration as a set of Java objects.

  • Transform: Bridge between the Configuration module and the Inventory module which is responsible for dynamically converting the configuration to a working inventory.

  • Inventory: The working inventory that can be opened and viewed by players in-game, with events and actions.

The image below illustrates the links between all of these modules:

The enhancement concept

During the Transformation process, each inventory property is converted by a specific provider which is responsible to do the transformation. This enables to customize the behavior dependently of the transformed property.

The enhancement step takes place during the Transformation process and is executed by a provider on the property it handles. It allows to add custom Java code to customize and enhance properties programatically before they are provided and without changing the original configuration.

Enhancements work with two specific objects:

  • Context: Class that contains additional data that may be useful for the enhancement. See for more information.

  • DTO (Data Transfer Object): Class that contains the inventory properties currently transformed. It provides getters and setters to modify some of these properties.

Create an enhancement

To create a new enhancement, you first need to know the name and the class of the DTO it will manipulate. Below is the list of all the available DTO:

Name
Class

Enhancements are defined using the generic Enhancement class. The following code gives an example of enhancement for pagination items.

Register an enhancement

Enhancements are registered specifically for an inventory in its inventory descriptor and are then provided to its provider.

The following code registers the enhancement created in the section above by redefining the addEnhancements(EnhancementManager manager) method of the InventoryDescriptor interface:

In this code, you must provide as first argument the name of the DTO used. This name can be found in the table defined in a previous section of this page.

Result:

Custom item actions

This page describes how to develop custom item actions.

CraftVentory comes with a set of predefined item actions. However, to meet your needs, you may want to create new item actions. This page explains step by step how this can be achieved.

Create the action

The first step consists in creating the action itself. This is done by creating a new class that implements the interface ClickAction. In the following example, we are implementing an action which executes a command when a player clicks on an item.

When implementing the ClickAction interface, two methods must be defined:

  • execute(FastInventoryClickEvent event): Method executed when a player clicks on an item which has our action.

  • getName(): Returns the name of the action. This name must identify uniquely the action and it is encouraged to use a globally visible constant to store it.

Create the action loader

Like inventories and items, actions can be configured in configuration files. Thus, it is necessary to tell the library how to load each action.

This is done by creating a class that implements the ClickActionLoader<T> interface. Here, we only want to load our action from YAML files so the generic parameter will be a ConfigurationSection.

When implementing the ClickActionLoader<T> interface, two methods must be defined:

  • load(ConfigurationSection section): Method executed to load the action. When an error occurs, this method should throw an InventoryConfigException.

  • getName(): Returns the name of the action. This name must be the same as the one defined in the class that implements the ClickAction interface.

Register the action loader

The last step consists in registering our action loader in a factory to tell the library to use it. If you are using the default ClickActionLoaderFactory provided by the library, this can be done with the following code:

public class CommandAction implements ClickAction {

    public static final String ACTION_NAME = "EXECUTE_COMMAND";

    private final String command;

    public CommandAction(String command) {

        if(command == null || command.isEmpty()) {
            throw new IllegalArgumentException("command cannot null or empty");
        }

        this.command = command;
    }

    @Override
    public void execute(FastInventoryClickEvent event) {
        Player player = event.getPlayer();
        player.performCommand(this.command);
    }

    @Override
    public String getName() {
        return ACTION_NAME;
    }
}
public class CommandActionLoader implements ClickActionLoader<ConfigurationSection> {

    private static final String COMMAND_KEY = "command";

    @Override
    public ClickAction load(ConfigurationSection section) throws InventoryConfigException {

        if(!section.isString(COMMAND_KEY)) {
            throw new InventoryConfigException(String.format("Property '%s' not found or not a string at '%s'", COMMAND_KEY, section.getCurrentPath()));
        }

        String command = section.getString(COMMAND_KEY);

        if(command.startsWith("/")) {
            command = command.substring(1);
        }

        return new CommandAction(command);
    }

    @Override
    public String getName() {
        return CommandAction.ACTION_NAME;
    }
}
ClickActionLoaderFactory<ConfigurationSection> factory = FastInventoryLibrary.createDefaultClickActionLoaderFactory();
factory.addLoader(new CommandActionLoader());

TITLE

TitleDto

INVENTORY_TYPE

InventoryTypeDto

INVENTORY_ITEM

InventoryItemDto

PAGINATION

PaginationDto

PAGINATION_ITEM

PaginationItemDto

PAGINATION_PREVIOUS_PAGE_ITEM

PaginationPageItemDto

PAGINATION_NEXT_PAGE_ITEM

PaginationPageItemDto

Enhancement<PaginationItemDto> enhancement = new Enhancement<>() {

    @Override
    public void enhance(PaginationItemDto dto, Context context) {
        
        // We only want to enhance the pagination with id 'pagination-1'.
        if(!dto.getPaginationId().equals("pagination-1")) {
            return;
        }
        
        // Enhancing the pagination item. If the slot is even, then setting a diamond.
        // If it is odd, setting an emerald.
        Integer slot = context.getData(CommonContextKey.SLOT.name(), Integer.class);
        Material material = slot % 2 == 0 ? Material.DIAMOND : Material.EMERALD;
        
        dto.getItem().setType(material);
    }

    @Override
    public Class<PaginationItemDto> getDTOClass() {
        // The class of the DTO the enhancement manipulates.
        return PaginationItemDto.class;
    }

    @Override
    public String getId() {
        // The unique id of the enhancement.
        return "pagination-1-item-enhancement";
    }
};
public class CustomInventoryDescriptor implements InventoryDescriptor {

    ...

    @Override
    public void addEnhancements(EnhancementManager manager) {
    
        Enhancement<PaginationItemDto> enhancement = new Enhancement<>() {

            @Override
            public void enhance(PaginationItemDto dto, Context context) {

                if(!dto.getPaginationId().equals("pagination-1")) {
                    return;
                }

                Integer slot = context.getData(CommonContextKey.SLOT.name(), Integer.class);
                Material material = slot % 2 == 0 ? Material.DIAMOND : Material.EMERALD;

                dto.getItem().setType(material);
            }

            @Override
            public Class<PaginationItemDto> getDTOClass() {
                return PaginationItemDto.class;
            }

            @Override
            public String getId() {
                return UUID.randomUUID().toString();
            }
        };
        
        manager.addEnhancement(DtoNameEnum.PAGINATION_ITEM.name(), enhancement);
    }

    ...

}
this page

Data storage

This page illustrates how data can be stored and shared between inventories.

The InventoryStorage interface enables to store additional data related to an inventory. CraftVentory provides two types of storage for these additional data : local storage and shared storage.

Local storage

Local storage is a type of storage specific to a single inventory. That means that all stored data is accessible only for the inventory that holds them.

This type of storage is accessible through the CraftVentory#getLocalStorage() method.

Shared storage

Shared storage is a type of storage shared between all the inventories in the player's inventory history. That means that stored data is accessible to all the inventories in the history.

This type of storage is accessible through the InventoryViewManager#getSharedStorage() method.

When the player's inventory history is reset, the shared storage is reset too.

Item actions

This page describes how to configure item actions.

What is an action?

In CraftVentory, an item action is a behavior executed when a player clicks on an item. An item may have as many actions as you want.

Item actions are fully configurable and each action has its own set of customizable properties. In the inventory configuration, each action is declared in a subsection of the actions section of an item.

# Global item section.
# You can use the name your want, but explicit names are encouraged.
close:
  # Item configuration section.
  # See the 'Item configuration' chapter of this tutorial.
  item:
    type: BARRIER
  # Symbol of the item to place it in the inventory.
  symbol: "C"
  # Set of actions executed when a player clicks on the item.
  actions:
    # Action configuration section.
    # You can use the name your want, but explicit names are encouraged.
    close:
      # Action type.
      # It is required to identify and load the corresponding action.
      type: "CLOSE"
      # Additionnal properties may be listed below depending on the action.

Available actions

In the list below, you can find all the actions provided by default by the library.

Close

Close the opened inventory.

close:
  # Action type.
  type: "CLOSE"

Message

Send a message to the inventory viewer.

message:
  # Action type.
  type: "MESSAGE"
  # List of messages to send.
  # Features supported:
  # - Placeholders
  # - Color codes prefixed by the character '&' (ex: &e)
  # - Hexadecimal color codes prefixed by the character '#' (ex: #FFFFFF)
  messages: 
    - "message 1"
    - "message 2"
    - "message 3"

Broadcast

Broadcast a message in the chat.

# Broadcast messages in the chat.
broadcast:
  # Action type.
  type: "BROADCAST"
  # List of messages to broadcast.
  # Features supported:
  # - Placeholders
  # - Color codes prefixed by the character '&' (ex: &e)
  # - Hexadecimal color codes prefixed by the character '#' (ex: #FFFFFF)
  messages:
    - "message 1"
    - "message 2"
    - "message 3"

Player command

Make the inventory viewer execute a list of commands.

player-command:
  # Action type.
  type: "PLAYER_COMMAND"
  # List of commands to execute without slash.
  # Supported placeholders:
  # - %player_name%: Name of the player who executes the action.
  # - %player_uuid%: UUID of the player who executes the action.
  commands: 
    - "command_1"
    - "command 2 arg1"
    - "command 3 arg1 arg2 arg3"

Console command

When performed, this action makes the server execute a command.

console-command:
  # Action type.
  type: "CONSOLE_COMMAND"
  # List of commands to execute without slash.
  # Supported placeholders:
  # - %player_name%: Name of the player who executes the action.
  # - %player_uuid%: UUID of the player who executes the action.
  commands: 
    - "command_1"
    - "command 2 arg1"
    - "command 3 arg1 arg2 arg3"

Sound

Play a sound to the inventory viewer.

sound:
  # Action type.
  type: "SOUND"
  # Sound name to play.
  sound: "<name>"
  # How far the sound can be heard.
  volume: <float>
  # How fast the sound is played.
  pitch: <float>

Update content

Trigger an update of the content of an opened inventory.

update-content:
  # Action type.
  type: "UPDATE_CONTENT"

Update paginations

Trigger an update of the paginations in an opened inventory.

update-paginations:
  # Action type.
  type: "UPDATE_PAGINATIONS"
  # The ids of the paginations to update.
  pagination-ids:
    - <pagination-id-1>
    - <pagination-id-2>
    - <pagination-id-3>

Open inventory

Open a new inventory.

open-inventory:
  # Action type.
  type: "OPEN_INVENTORY"
  # The id of the inventory to open.
  inventory-id: "<id>"
  # If true, a new history will be created for the inventory.
  # If false, the inventory will be appended at the end of it. 
  new-history: <true|false>

Home

Open the root inventory in the viewer's history.

home:
  # Action type.
  type: "HOME"

Backward

Open a previously opened inventory in the history which is before the current one in the history.

backward:
  # Action type.
  type: "BACKWARD"
  # This property is optional. When set, the action opens the previously opened inventory before the current
  # one which has the specified id. When not set, the inventory just before the current one in the history is opened.
  inventory-id: ""

Forward

Open a previously opened inventory in the history which is after the current one in the history.

forward:
  # The action type.
  type: "FORWARD"
  # This property is optional. When set, the action opens the previously opened inventory after the current
  # one which has the specified id. When not set, the inventory just after the current one in the history is opened.
  inventory-id: ""

Click type

CraftVentory enables to configure the type of click a user must do to execute an action by adding the click-types property.

# List of click types to execute the action.
# Allowed click types:
# - LEFT: Left click
# - RIGHT: Right click
# - MIDDLE: Middle click
# - ALL: All clicks
# You can use a combination of the above values.
# When this property is note set, the ALL value is used by default.
click-types:
  - "LEFT"
  - "RIGHT"

Example:

actions:  
  message-left:
    type: "MESSAGE"
    click-types:
      - "LEFT"
    messages: 
      - "left click"
      
  message-right:
    type: "MESSAGE"
    click-types:
      - "RIGHT"
    messages: 
      - "right click"
  
  message-middle:
    type: "MESSAGE"
    click-types:
      - "MIDDLE"
    messages: 
      - "middle click"
      
  message-all:
    type: "MESSAGE"
    messages: 
      - "message sent for each click"