Developer Documentation

Build on top of ItemsCore

ItemsCore ships a public Java API and an addon system. Read and give out custom items from your own plugin, or register an addon that extends the in-game editor with your own categories, methods, attributes, listeners and actions.

Java 8+Spigot / PaperMaven or Gradlev5.0

Introduction

There are two ways to build on ItemsCore, and you can use either or both:

  • The API - call into ItemsCore from your plugin to look up a custom item by name, give it to a player, read the custom name off an ItemStack, or ask a player for typed input.
  • Addons - register a PluginAddon that adds your own categories, methods, attributes, listeners and actions to the editor, and lets you modify items as they are created.

The video below walks through building a complete addon from scratch. The pages after it document each piece on its own.

Project setup

Drop ItemsCore.jar into a libs/ folder in your project and add it as a system-scoped dependency:

xml
<!-- pom.xml -->
<dependency>
<groupId>me.TastyCake</groupId>
<artifactId>ItemsCore</artifactId>
<version>1.0</version>
<systemPath>${project.basedir}/libs/ItemsCore.jar</systemPath>
<scope>system</scope>
</dependency>
Copy

Depend on ItemsCore in your plugin.yml so it always loads first:

yaml
# plugin.yml
depend: [ItemsCore]
Copy

If you add custom methods, compile your addon classes with the -parameters flag and a Java 8+ target. That keeps the real argument names so they show up correctly in the editor instead of arg0, arg1:

xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
Copy

The API

Grab the API instance once ItemsCore is enabled:

java
ItemsCoreAPI api = ItemsCore.getItemsCoreAPI();
Copy
MethodReturnsWhat it does
getItemByName(String)ItemFinds one of your custom items by its name, or null if none matches.
giveItem(Entity, Item)voidGives a player the custom item (ignored for non-players).
getItemName(ItemStack)StringReads the internal ItemsCore name stored on an item stack.
tryGetItemFromPlayerHand(Entity)ItemReturns the custom item the player is holding, or null if it is not one.
isUsingVault()booleanWhether the Vault economy hook is active.
getInput()PlayerInputThe helper used to ask a player for typed chat input.
java
Item sword = api.getItemByName("magic_sword");
if (sword != null) {
api.giveItem(player, sword);
}
Item held = api.tryGetItemFromPlayerHand(player);
if (held != null) {
player.sendMessage("You are holding " + api.getItemName(held));
}
Copy

Addons

An addon is a PluginAddon you register with the AddonProvider. It can add editor categories and methods, attributes, listeners and actions, and modify items as they are built.

Get the provider and register your addon, usually in your plugin's onEnable:

java
AddonProvider provider = AddonProvider.get();
provider.addAddon(
new PluginAddon("YourPluginName", XMaterial.WRITABLE_BOOK.get())
// .addon(...) add a methods category
// .attribute(...) add a toggle/value attribute
// .listener(...) listen to item events
// .action(...) add a custom action block
// .onItemCreate(...) modify the built ItemStack
);
Copy
!The plugin name must match your plugin exactly - check it with /plugins in game. The material is the icon shown for your addon in the editor; the no-argument new PluginAddon(name) defaults to a firework star.

You can look an addon up again later with provider.getAddonByName("YourPluginName").

Custom methods

An Addon<T> exposes a class whose public methods become a new category in the editor. The first argument is the identifier players call it by; the second builds the object per player.

java
AddonProvider provider = AddonProvider.get();
provider.addAddon(
new PluginAddon("YourPluginName")
.addon(new Addon<>("myCategory", (Player player) -> new MyMethods()))
);
Copy

The class holding your methods:

java
public class MyMethods {
public void greet(Player player) {
player.sendMessage("Hello from my addon!");
}
public int doubled(int value) {
return value * 2;
}
}
Copy
!Every method you want available in the editor must be public.

Inside an item action the methods are then called on the identifier, for example myCategory.greet(player) or myCategory.doubled(5).

Attributes

An attribute is a per-item value (often a boolean toggle) shown in the editor that your plugin can read back. It takes a name, a GUI material, a default value, an update callback, and lore lines.

java
provider.addAddon(
new PluginAddon("PowerScrolls", XMaterial.WRITABLE_BOOK.get())
.attribute(new AddonAttribute<>(
"Is a scroll", // attribute name
XMaterial.WRITTEN_BOOK.get(), // GUI material
false, // default value
(player, gui, editor, callback) -> {
Boolean current = (Boolean) editor
.getAttributeSerializableByName("PowerScrolls_Is a scroll")
.getValue();
callback.result(!current); // store the new value
editor.createAddonGui(provider.getAddonByName("PowerScrolls"))
.openInventory(player); // reopen the addon GUI
},
"&7If true, the item will be used to upgrade",
"&7other items and add abilities to them.",
"",
"&aClick to toggle"
))
);
Copy
iThe stored key is %AddonName%_%AttributeName% - here PowerScrolls_Is a scroll. Read it back anywhere with editor.getAttributeSerializableByName(key).getValue().

Listeners

Implement ItemsCoreListener to react to item events. Return an ItemEventResult(boolean cancel, BukkitRunnable runnable) - set cancel to true to stop the item's ability from running. Leave the runnable null for now.

java
provider.addAddon(
new PluginAddon("PowerScrolls", XMaterial.WRITABLE_BOOK.get())
.listener(new MyListener())
);
public class MyListener implements ItemsCoreListener {
@Override
public ItemEventResult itemEvent(Player player, Item item, String action, Event event) {
// your logic here
// return true to cancel the item's ability
return new ItemEventResult(false, null);
}
}
Copy

Actions

An AddonAction is a custom action block players can place on an item. You trigger it from your own code and pass in custom variables that become available inside the action's script.

java
AddonAction action = new AddonAction(
"TestAction", // action name
Material.REDSTONE, // GUI material
new String[] { "&7This is a test" } // lore
);
provider.addAddon(
new PluginAddon("PluginName", XMaterial.WRITABLE_BOOK.get())
.action(action)
);
// run it for an item that has this action attached
action.call(player, itemStack, new HashMap<String, Object>() {{
put("exampleVariable", player.getDisplayName());
}});
Copy
iEach key in the map becomes a variable available inside that action's script - here exampleVariable.

Modify item creation

onItemCreate lets you transform the ItemStack as it is built from an Item. Every addon runs in a chain - you receive the most recent stack and return your modified one, and later addons may still change it after you.

java
provider.addAddon(
new PluginAddon("PluginName", XMaterial.WRITABLE_BOOK.get())
.onItemCreate(new ItemCreationRunnable() {
@Override
public ItemStack onCreate(Item used, ItemStack created) {
// inspect "used", modify and return "created"
return created;
}
})
);
Copy

Annotate the runnable with @AddonModifier to set a priority. The chain runs from highest to lowest, so a higher priority gets the final say:

java
.onItemCreate(new @AddonModifier(priority = AddonPriority.LOW) ItemCreationRunnable() {
@Override
public ItemStack onCreate(Item used, ItemStack created) {
return created;
}
})
Copy
iPriorities, highest first: MONITOR, HIGHEST, HIGH, NORMAL, LOW, LOWEST. The default is NORMAL.

Hooks

!Hooks are mostly superseded by addons now, but they still work for quick plugin-to-plugin calls from item code.

A hook is like a plugin dependency you can reach from item code. Put the other plugin's jar in the hooks folder inside the ItemsCore plugin folder, then register it once with core.setHook:

java
// core.setHook(accessName, jarName, groupId, artifactId)
// accessName - how you reference it from item code (e.g. "bla")
// jarName - the file name you put in the hooks folder
// groupId - the plugin's Maven groupId
// artifactId - the plugin's Maven artifactId
core.setHook("bla", "OtherPlugin", "com.example", "otherplugin");
Copy

Call a method on the hook by its access name with runMethod:

java
// bla.runMethod(methodName, Class<?>[] argTypes, Object... values)
// build the argument types with core.getClassByName(...)
bla.runMethod("test", new Class[]{ core.getClassByName("String") }, "hello");
Copy