Using MMOItems API you may register custom stats as complex as abilities or item restrictions. The first thing you will need to do is define a class which extends `DoubleStat` which is an abstract class with many functions, we will go over what each does, but first let's deal with the ItemStat constructor you need to call.
```super("GEM_SOCKETS", new ItemStack(Material.EMERALD), "Gem Sockets", new String[] { "The amount of gem", "sockets your weapon has." }, new String[] { "piercing", "slashing", "blunt", "offhand", "range", "tool", "armor", "accessory" });```
The string id corresponds to your internal stat ID. You may only use upper case letters and _ dashes. This stat is used to calculate player stats in MMOLib, used to saved stat data in MMOItems config files, literally anywhere in the plugin. Do never change it once your stat is setup otherwise you might "lose" precious created item data.
The ItemStack parameter corresponds to the icon your stat has in the item edition GUI. `name` corresponds to your stat name, it's also used to display your stat in the edition GUI. This piece of string cannot be seen by normal players. `lore` is your stat description (edition GUI).
`types` is the list of the item types which are supported by your item stat.\
`new String[] { "!armor", "!gem_stone", "all" }` would ban armors and gem stones from using your stat. Using `!<type_name>` you can ban a specific item type. Make sure you put type restrictions at the beginning of the string array. Using `all` you can make the stat compatible with any item type. Make sure you use `all` after type restrictions.
`materials` are the item materials supported. This is specific to some stats like `Dye Color` or `Shield Pattern` which depend on the ItemMeta instance and which are type-specific. If the given array is empty, the stat is obviously available for any type by default.
## Methods to override
This is the class for numeric stats.
```
@Override
public StatData whenInitialized(Object object) {
return new DoubleData(object);
}
@Override
public RandomStatData whenInitializedGeneration(Object object) {
if (object instanceof Number)
return new NumericStatFormula(Double.valueOf(object.toString()), 0, 0, 0);
if (object instanceof ConfigurationSection)
return new NumericStatFormula((ConfigurationSection) object);
throw new IllegalArgumentException("Must specify a number or a config section");
}
@Override
public void whenApplied(MMOItemBuilder item, StatData data) {
double value = ((DoubleData) data).generateNewValue();
lore.add(ChatColor.YELLOW + AltChar.listDash + " Left click to change this value.");
lore.add(ChatColor.YELLOW + AltChar.listDash + " Right click to remove this value.");
}
```
### whenInitialized(Object)
`whenInitialized(Object)` is called when MMOItems is requesting to read stat data from the config file. `obj` could be anything, it's the object obtained using `ConfigurationSection#get(#yourStatPath#)`. Here, users can either use a double to have a set stat value, or a config section and in that case MMOItems reads a numeric stat formula from that config section.
This method must return a class which extends the `StatData` interface. It's a **purely cosmetic** interface because it has no function to override but I might need to add some functions to it in a later update. **You can see a StatData class example under the _Mergeable Stats_ section**.
### whenInitializedGeneration(Object)
`whenInitializedGeneration(Object)` is almost the same thing, except that should return a `RandomStatData` instance. The `RandomStatData` interface is used to store data about stat data from an item generation template. For further info, see the RandomStatData paragraph below.
### whenApplied(MMOItemBuilder, StatData)
This function is used by MMOItems when generating an `ItemStack` instance based on a list of `StatData` instances. You can access the item meta, item lore using the `MMOItemBuilder` instance. You will need to cast the `StatData` instance given as input to whatever your stat is compatible with. MMOItems only gives you as input what you gave it as output in the `whenInitialized(Generation)` methods.
Used to do stuff when a player just inputs some message in the chat. You can request for a player chat input using the following method:
```new StatEdition(inv, this, objectArray).enable("Write in the chat the numeric value you want.", "Or write [MIN-VALUE]=[MAX-VALUE] to make the stat random.");```
That function would typically be called when the player clicks the stat icon in the edition GUI. The `objectArray` parameter in the `StatEdition` class constructor can be replaced by **any object at all**, it's a way for more complex stats like elements or abilities what the player is editing (is it the ability casting mode, what ability, etc??). That array is kept intact and given as input in the `whenInput` method.
It's a really old method which will be updated soon. It's the function used to display the current item stat data in the edition GUI. It is still using config sections as input, it will be soon replaced by StatDatas for cleaner functionality.
## RandomStatDatas
They are the equivalent of StatData's but with a random factor needed for random item generation. A good example is the NumericStatFormula which is used for any numeric stats.
```
public class NumericStatFormula implements RandomStatData {
private final double base, scale, spread, maxSpread;
private static final Random random = new Random();
public static final NumericStatFormula ZERO = new NumericStatFormula(0, 0, 0, 0);
public NumericStatFormula(Object object) {
Validate.notNull(object, "Config must not be null");
public StatData randomize(GeneratedItemBuilder builder) {
return new DoubleData(calculate(builder.getLevel()));
}
}
```
The `randomize` function is the key here. This takes as input a GeneratedItemBuilder which contains info about the item level, tier etc. and outputs a randomized `RandomStatData`, i.e a `StatData` instance which will be later used to build the item!
The `GeneratedItemBuilder` class can be seen as the equivalent of the `MMOItemBuilder` for random stat generation. When a random item is being generated from an item template, MMOItems first creates a `GeneratedItemBuilder`, rolls the item modifiers and gather the randomized `StatData` when generates the item using a `MMOItemBuilder`.
## Mergeable stats
Mergeable stats are stats which can be stacked with each others, for instance when a player tries to apply a gem stone onto another item, where MMOItems needs to "merge" the two stat datas together. A good example is the `DoubleData` class.
```
public class DoubleData implements StatData, Mergeable {
private static final Random random = new Random();
private double min, max;
public DoubleData(Object object) {
if (object instanceof Number) {
min = Double.valueOf(object.toString());
return;
}
if (object instanceof String) {
String[] split = ((String) object).split("\\=");
Validate.isTrue(split.length == 2, "Must specify a valid range");
min = Double.parseDouble(split[0]);
max = Double.parseDouble(split[1]);
return;
}
throw new IllegalArgumentException("Must specify a range or a number");
Validate.isTrue(data instanceof DoubleData, "Cannot merge two different stat data types");
min += ((DoubleData) data).min;
// TODO if hasMax()
}
}
```
Simple enough: MMOItems just adds the two values together. A little specification here: the `min` and `max` options are used to have a stat range but whenever that `StatData` is loaded from an NBTItem using `whenLoading(MMOItem mmoitem, NBTItem)`, only the `min` variable is used because a generated item does not have stat ranges anymore, they have already been rolled on item generation.