Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in
M mmoitems
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 47
    • Issues 47
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Operations
    • Operations
    • Incidents
    • Environments
  • Packages & Registries
    • Packages & Registries
    • Package Registry
  • Analytics
    • Analytics
    • CI/CD
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Administrator
  • mmoitems
  • Wiki
  • Stat API

Stat API · Changes

Page history
Updated Stat API (markdown) authored May 09, 2020 by Indyuce's avatar Indyuce
Hide whitespace changes
Inline Side-by-side
Showing with 280 additions and 1 deletion
+280 -1
  • Stat-API.md Stat-API.md +280 -1
  • No files found.
Stat-API.md
View page @ 841964c9
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. 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" });``` ## ItemStat constructor
\ No newline at end of file ```public ItemStat(String id, ItemStack item, String name, String[] lore, String[] types, Material... materials)```
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();
item.addItemTag(new ItemTag(getNBTPath(), value));
item.getLore().insert(getPath(), format(value, "#", new StatFormat("##").format(value)));
}
@Override
public boolean whenClicked(EditionInventory inv, InventoryClickEvent event) {
if (event.getAction() == InventoryAction.PICKUP_HALF) {
ConfigFile config = inv.getItemType().getConfigFile();
config.getConfig().set(inv.getItemId() + "." + getPath(), null);
inv.registerItemEdition(config);
inv.open();
inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + "Successfully removed " + getName() + ChatColor.GRAY + ".");
return true;
}
new StatEdition(inv, this).enable("Write in the chat the numeric value you want.",
"Or write [MIN-VALUE]=[MAX-VALUE] to make the stat random.");
return true;
}
@Override
public boolean whenInput(EditionInventory inv, ConfigFile config, String message, Object... info) {
String[] split = message.split("\\=");
double value = 0;
double value1 = 0;
try {
value = Double.parseDouble(split[0]);
} catch (Exception e1) {
inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + ChatColor.RED + split[0] + " is not a valid number.");
return false;
}
// second value
if (split.length > 1)
try {
value1 = Double.parseDouble(split[1]);
} catch (Exception e1) {
inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + ChatColor.RED + split[1] + " is not a valid number.");
return false;
}
// STRING if length == 2
// DOUBLE if length == 1
config.getConfig().set(inv.getItemId() + "." + getPath(), split.length > 1 ? value + "=" + value1 : value);
if (value == 0 && value1 == 0)
config.getConfig().set(inv.getItemId() + "." + getPath(), null);
inv.registerItemEdition(config);
inv.open();
inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + getName() + " successfully changed to "
+ (value1 != 0 ? "{between " + value + " and " + value1 + "}" : "" + value) + ".");
return true;
}
@Override
public void whenLoaded(MMOItem mmoitem, NBTItem item) {
if (item.hasTag(getNBTPath()))
mmoitem.setData(this, new DoubleData(item.getDouble(getNBTPath())));
}
@Override
public void whenDisplayed(List<String> lore, FileConfiguration config, String id) {
lore.add("");
String[] split = config.contains(id + "." + getPath()) ? config.getString(id + "." + getPath()).split("\\=") : new String[] { "0" };
String format = split.length > 1 ? tryParse(split[0]) + " -> " + tryParse(split[1]) : "" + config.getDouble(id + "." + getPath());
lore.add(ChatColor.GRAY + "Current Value: " + ChatColor.GREEN + format);
lore.add("");
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.
### whenClicked(EditionInventory, InventoryClickEvent)
This is the function used to do stuff when a player just clicked the stat icon in the item edition GUI.
### whenInput(EditionInventory, ConfigFile config, String message, Object...)
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.
### whenLoaded(MMOItem, NBTItem)
Used to load stat data from a random ItemStack.
### whenDisplayed(List<String>, ConfigurationSection, String)
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");
if (object instanceof Number) {
base = Double.valueOf(object.toString());
scale = 0;
spread = 0;
maxSpread = 0;
return;
}
if (object instanceof ConfigurationSection) {
ConfigurationSection config = (ConfigurationSection) object;
base = config.getDouble("base");
scale = config.getDouble("scale");
spread = config.getDouble("spread");
maxSpread = config.getDouble("max-spread");
Validate.isTrue(spread >= 0, "Spread must be positive");
Validate.isTrue(maxSpread >= 0, "Max spread must be positive");
return;
}
throw new IllegalArgumentException("Must specify a config section or a number");
}
/*
* used as a StatData class to generate a DoubleData instance!
*/
public NumericStatFormula(double base, double scale, double spread, double maxSpread) {
this.base = base;
this.scale = scale;
this.spread = spread;
this.maxSpread = maxSpread;
}
public double getBase() {
return base;
}
public double getScale() {
return scale;
}
public double calculate(double x) {
// calculate linear value
double linear = base + scale * x;
// apply gaussian distribution to add +- maxSpread%
// spread represents the standard deviation in % of the calculated
// linear value
double gaussian = linear * (1 + Math.min(Math.max(random.nextGaussian() * spread, -maxSpread), maxSpread));
return gaussian;
}
@Override
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");
}
public DoubleData(double min, double max) {
this.min = min;
this.max = max;
}
public boolean hasMax() {
return max > min && max != 0;
}
public double getMin() {
return min;
}
public double getMax() {
return max;
}
public void setMax(double value) {
max = value;
}
public void setMin(double value) {
min = value;
}
public void add(double value) {
min = min + value;
}
public void addRelative(double value) {
min *= 1 + value;
}
public double generateNewValue() {
return hasMax() ? min + random.nextDouble() * (max - min) : min;
}
@Override
public void merge(StatData data) {
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.
\ No newline at end of file
Clone repository

  • Home
  • Installation Guide
  • Commands

General

  • Item Types
  • Item Stats & Options
  • Item Creation

Features

  • Mitigation
  • Elemental Damage
  • Item Identification
  • Item Tiers
  • Gem Stones
  • Custom Durability
  • Item Sets
  • Item Upgrading
  • Soulbound

Crafting Stations

  • Crafting Stations
  • Upgrading Recipes
  • Recipe Conditions
  • Recipe Ingredients
  • Recipe Triggers

Custom Blocks

  • Custom Blocks
  • World Gen Templates

Item Management

  • Item Updater
  • Item Drop Tables

Item Generator

  • General
  • Item Templates
  • Item Modifiers
  • Complex Stats

Abilities

  • Abilities
  • Ability List

Compatibility & API

  • Supported Plugins
  • Custom Item Textures
  • Main API Features