API
Reading the skin catalogue, a player's wardrobe, and the skins written onto armor.
ArmorSkinService is what another plugin reads and drives ExyliaArmorSkin through: the catalogue,
the wardrobe a player chooses in, and the skins written onto armor itself.
ExyliaAPI.get(ArmorSkinService.class).ifPresent(skins -> {
skins.select(player, ArmorPiece.HELMET, "sakura");
skins.skinItem("sakura").ifPresent(item -> player.getInventory().addItem(item));
});The artifact, the repository and the plugin.yml line are the same for every Exylia plugin and live
on the public API page.
Everything is addressed by skin id, matched without regard to case. An id the catalogue does not
declare is not an error — a reload can remove one while a crate still hands it out — so lookups
answer empty and writes answer false.
The catalogue
| Method | What it does |
|---|---|
skins() | Every skin the server declares, in the order a menu draws them. A snapshot: fine for building a shop, wasteful in a loop. |
skin(String skinId) | One skin as an Optional<ArmorSkin>. Empty when the catalogue declares no such id. |
exists(String skinId) | Whether the catalogue declares that id. |
Permissions
| Method | What it does |
|---|---|
canUse(Player, String skinId) | Whether they may wear the skin on at least one piece. |
canUse(Player, String skinId, ArmorPiece) | Whether they may wear it on that one piece. |
Both answer by the server's own rule, which includes the setting that turns permissions off entirely — a shop asking gets the same answer the wardrobe would give, not a raw permission check. The per-piece form is separate because a rank can be sold one slot at a time: a player given the helmet node wears the skin on their head and nowhere else.
The wardrobe
| Method | What it does |
|---|---|
mode() | Where the skins this server draws come from, as a SkinMode. |
selected(UUID player, ArmorPiece) | The skin id chosen for that slot, as an Optional<String>. Empty when they chose none, the wardrobe is off, or their wardrobe is still being read. |
select(Player, ArmorPiece, String skinId) | Sets the choice for that slot. true when it was stored. |
clear(Player, ArmorPiece) | Takes the chosen skin off one slot. true when something was there to remove. |
clearAll(Player) | Takes every chosen skin off. true when something was there to remove. |
selected is a choice, not a result: it stays set while the slot is empty, and the skin appears
again the moment the player equips armor that fits.
select is a set rather than a toggle — running it twice leaves the skin on. In this plugin it is
gated by permission: the wardrobe offers one write, that write enforces the server's rule, and a
player who may not wear the skin is refused. That is the opposite of ExyliaArmorTrims and
ExyliaArrows, where the owner's own setting says selection is never limited by a node. Ask
canUse(Player, String, ArmorPiece) first if you want to know why before asking.
Skins on items
| Method | What it does |
|---|---|
skinOf(ItemStack armor) | The skin id written onto that armor, as an Optional<String>. Empty when it carries none. |
apply(ItemStack armor, String skinId) | Writes a skin onto the armor in place, keeping everything else it had. true when written. |
strip(ItemStack armor) | Takes the skin off and gives nothing back. true when a skin was there. |
skinItem(String skinId) | A skin item ready to be given out, as an Optional<ItemStack>. Empty when the catalogue declares no such skin. |
isSkinItem(ItemStack) | Whether an item is one of this plugin's skin items. |
Ask isSkinItem before a container, a shop or a trade treats a stack as ordinary loot: a skin item
is drawn as whatever suits it and is not the material it looks like.
Redrawing
| Method | What it does |
|---|---|
refresh(Player) | Recomputes what the player looks like and re-sends it to everyone who can see them. |
Only needed after something the service does not know about changed — a permission granted at runtime, an item swapped by another plugin. Every write above already redraws.
Types
ArmorSkin — id, name (colour codes still in it), permission (the node granting the skin
on every piece it fits) and pieces. supports(ArmorPiece) answers whether the skin fits a slot.
What the skin looks like is deliberately absent: that is the plugin's own drawing code, and
skinItem already covers what a third party needs.
ArmorPiece — HELMET, CHESTPLATE, LEGGINGS, BOOTS. slot() gives the Bukkit
EquipmentSlot, so a caller reading an inventory does not keep a switch of its own in step.
SkinMode — where a drawn skin comes from: ITEM (only what a skin item wrote onto the armor),
WARDROBE (only what the wearer chose; skin items do nothing) or BOTH. usesItems() and
usesWardrobe() answer without a switch. Worth asking before writing anything: the half a server
does not use answers false or empty rather than throwing, so an integration written for both runs
on either.
Everything returning a value reads the plugin's cache and is safe from a menu redraw or a placeholder. Everything that changes a wardrobe writes to the database and redraws the player for everyone watching — call those on the main thread, and no more often than a player could.
What it does not expose
No events: ExyliaArmorSkin publishes none. Menu openers, the wardrobe's own editor flow, animation definitions and raw configuration rows are left out on purpose — a public contract cannot be broken later, so it carries what an integration needs and nothing that only made sense inside one version.
If something you need is genuinely missing, ask on Discord.
Something missing on this page? Tell us on Discord