Configuring content
Everything StarEnchants reads lives under plugins/StarEnchants/ as plain YAML. Edit a file and run
/se reload, or manage it all from the in-game GUIs. This section walks through the whole layout and
then takes each content type — enchants, sets, crystals, items — field by field.
The data folder
config.yml global toggles · combat caps · souls · crystals · heroic · lore · integrations · reload
content/ the content library
├─ tiers.yml rarity tiers (color · weight · glint)
├─ enchants/ one file per enchant
├─ crystals/ one file per socketable crystal
├─ sets/ one file per armor set
├─ masks/ one file per wearable mask (helmet-slot cosmetic with a bonus)
├─ pets/ one file per levelling companion head
├─ use-items/ one file per right-click use-item
└─ reforges/ one file per weapon reforge (shipped in the signature pack)
items/ one file per physical item — books · scrolls · dust · soul gem · orb · nametag · …
menus/ in-game GUI layout overrides
packs/ config-pack snapshots (/se pack) — your exports, plus the two packs the jar ships
lang.yml every player-facing message & GUI string
:::tip Keys are path-derived
An enchant at content/enchants/lifesteal.yml has the key lifesteal. Organize files into
subfolders freely — the key is just the path under content/. The file path is the identity, so
moving or renaming a file changes its key.
:::
The rest of this section:
- config.yml — the cross-cutting knobs.
- An annotated enchant — every field of a real enchant, explained.
- Defining a set — pieces, completion, the matched weapon.
- Defining a crystal — a levelless socket bonus.
- Defining a use-item — a right-click item that is the ability.
- Defining a mask — a worn head with a bonus.
- Defining a pet — a levelling companion with level brackets.
- Defining a reforge — a weapon's shift-right-click active.
- Customizing items — the physical item files.
- Reloading —
/se reload [--dry-run].
For the exhaustive catalog of effect/trigger/selector/condition tokens, see the DSL reference.
config.yml — the cross-cutting knobs
config.yml holds the settings that aren't a single item's look and aren't player-facing text: the
master feature switches, combat caps, and tuning for souls/crystals/heroic/slots/lore/integrations.
Most values are re-read live on the next use, so a /se reload re-tunes them without a restart (the
exceptions — integration discovery, the auto-reload interval, the command trigger, the two engine
sweep intervals, and the slots/souls/scrolls listeners — are armed once at boot and noted below).
# StarEnchants — master config (docs/v3-directives.md §L).
#
# This file holds the CROSS-CUTTING knobs: ceilings and switches that are not a single item's "physical
# likeness" (those live in items/*.yml) and not player-facing text (that lives in lang.yml). Edit here, then
# run /se reload — the master config, items/, menus/, lang.yml and content/ all reload together in one
# transaction. Most values below are re-read live on the next use, so a reload re-tunes them without a restart
# (the exceptions — integration discovery and the auto-reload interval — are armed once at boot and noted).
#
# Colours: every coloured string here and in items/, menus/, lang.yml and content/ accepts legacy &-codes AND
# {#RRGGBB} hex tokens ("{#FF5733}&lBold" composes as usual). Hex renders true on every modern server; the
# 1.8.9 build degrades each hex to the nearest classic colour. A malformed token stays literal text.
# Per-feature master switches. Each turns a whole subsystem on/off. enchants/sets/crystals/heroic drop that
# source when a player's worn state is resolved (their combat + trigger effects go inert; re-read live, so a
# /se reload takes effect at once). slots/souls/scrolls gate their apply/interaction listeners at boot, so a
# change to those three takes effect on the next server start (like the integration toggles below).
features:
enchants: true # enchant effects fire in combat / on triggers
sets: true # armour-set bonuses (and the held-weapon set bonus) apply
crystals: true # crystal effects fire
heroic: true # heroic percents feed the additive damage fold
slots: true # the slot-expander orb can be applied to gear
souls: true # the soul gem system (deposit on kill, soul mode, gem inventory)
scrolls: true # scroll-family interactions (black/randomizer/transmog/holy/nametag/godly transmog)
use-items: true # right-click use-items fire their abilities (§3.6); false leaves a held use-item inert
bless: true # register /bless, the player-facing debuff cleanse
# Combat caps (cross-cutting). The additive damage fold (ADR-0012) sums every source's outgoing% and
# reduction%; these ceil those sums. A negative value = no cap; outgoing defaults to +500% so a pre-charged
# combo streak cannot one-shot. pvp/pve gate whether StarEnchants combat effects apply at all in that context.
# All read live on /se reload.
combat:
max-bonus-damage: 5.0 # ceiling on summed outgoing-damage fraction (5.0 = at most +500%); <0 = uncapped
max-bonus-reduction: -1.0 # ceiling on summed damage-reduction fraction (e.g. 0.8 = at most 80%); <0 = uncapped
pvp: true # apply combat effects in player-vs-player hits
pve: true # apply combat effects in player-vs-environment hits
# Mining rewards (cross-cutting). Read live on /se reload.
mining:
# Suppress the MINE trigger on a block a player placed since the last server start, so a place/break loop
# cannot farm MINE rewards (XP, money, auto-smelt, teleport-drops). This suppresses the WHOLE MINE dispatch on
# a placed block — QoL MINE effects are gated too (vanilla-consistent, mcMMO-precedented). Placement memory is
# boot-lifetime only: a restart forgets prior placements. false = reward every break (the old behaviour).
placed-block-guard: true
# Vanilla-station guards on plugin SET gear. Read live on /se reload. Set pieces and set weapons carry their whole
# plugin identity (set key, custom enchants, crystals, heroic) in item NBT, which vanilla stations copy wholesale —
# so an unguarded station would bolt off-design stats onto gear the pack balanced as diamond. Each guard denies one
# station on set gear; false = restore that station's vanilla behaviour. A bare anvil RENAME of set gear always
# works (it adds no stats). Grindstone/smithing exist only on modern servers (1.14/1.16+); on 1.8.9 only the anvil.
stations:
anvil-guard: true # deny anvil combine/repair on set gear (adding Mending etc. / cheap repair); rename stays allowed
grindstone-guard: true # deny grindstone disenchant/merge on set gear (cashing minted vanilla enchants for XP)
smithing-guard: true # deny the smithing-table netherite upgrade on set gear
# Player feedback (chat style). prefix is prepended to every message the plugin sends through its message
# facade (chat feedback only — never item names/lore). feedback toggles the keyed gameplay-feedback channel
# (e.g. menu confirmations); false = a quieter server (admin command echoes still print). Read live on reload.
messages:
prefix: "" # e.g. "&8[&dSE&8] " — prepended to plugin chat messages
feedback: true # send keyed gameplay-feedback messages to players
# Global enchant message-on-activate (§L). When an enchant fires, the holder ("BY you") and the other combat
# party ("ON you") can each get a chat line; each side is toggled separately. Tokens: {ENCHANT} = display name,
# {TIER_COLOR} = the tier's & colour, {VICTIM} = the BY-side target's name, {ATTACKER} = the ON-side source's
# name. Off by default — a content pack opts in (and drops any per-enchant self-announce MESSAGE effect). A
# non-combat activation (no other party) sends nothing.
message-on-activate:
by-enabled: false # message YOU when your enchant fires (names the victim)
by-template: "{TIER_COLOR}&l** {ENCHANT} &r&7[&f{VICTIM}&7] {TIER_COLOR}&l**"
on-enabled: false # message the other party when an enchant fires on them (names the attacker)
on-template: "{TIER_COLOR}&l** {ENCHANT} &7FROM &r&7[&c{ATTACKER}&7] {TIER_COLOR}&l **"
uppercase: false # render the {ENCHANT} name in UPPERCASE
# Universal armour-set equip/unequip feedback (§6.6). ONE config for ALL sets (not per-set): equipping a
# completed set plays equip-sound + equip-particle at the player, removing it plays unequip-sound +
# unequip-particle — independent of whether the set has an announce message. Sounds use our unified
# { sound: NAME, volume: V, pitch: P } bracket form (a LIST, played together); particles our
# { particle: NAME, count: N, color: { r, g, b }, spread: S, y-offset: Y } form. With use-set-color on, the
# dust cloud is tinted to each set's own & colour (read from its display name), overriding any configured
# color; turn it off to use a fixed color. message-uppercase auto-capitalises the set equip/remove message.
sets:
message-uppercase: false # auto-capitalise the set equip/remove message (colour codes preserved)
use-set-color: true # tint the EQUIP dust to the set's own & colour (the unequip dust stays as configured)
equip-sound:
- { sound: BLOCK_BEACON_POWER_SELECT, volume: 0.4, pitch: 2 }
- { sound: BLOCK_BONE_BLOCK_BREAK, volume: 1, pitch: 1 }
- { sound: ITEM_ARMOR_EQUIP_COPPER, volume: 0.4, pitch: 1 }
unequip-sound:
- { sound: BLOCK_GLASS_BREAK, volume: 0.25, pitch: 0.8 }
- { sound: BLOCK_CHAIN_STEP, volume: 0.6, pitch: 1.0 }
- { sound: BLOCK_COPPER_GOLEM_STATUE_BREAK, volume: 1, pitch: 1 }
- { sound: ITEM_LLAMA_CARPET_UNEQUIP, volume: 0.4, pitch: 2 }
# The EQUIP cloud is tinted per set (use-set-color); the UNEQUIP cloud stays gray (&7) for every set.
equip-particle: { particle: REDSTONE, count: 20, spread: 1.25, y-offset: 1.0 }
unequip-particle: { particle: REDSTONE, count: 20, color: { r: 170, g: 170, b: 170 }, spread: 1.25, y-offset: 1.0 }
# Enchant books (§I). The book likeness (name/lore/material/destroy-on-fail) lives in items/enchant-book.yml;
# its {DESCRIPTION} wraps at the universal lore.item-wrap. Only this global success ceiling is cross-cutting.
books:
# Global maximum success rate (%) a book may reach via RANDOMISED minting (unopened book / randomizer
# scroll), the black scroll's conversion roll, or Magic Dust. A dust that would push a book past this snaps
# to it. 100 = no practical cap. Does NOT touch guaranteed books (/se book, the admin browser) or an
# explicit /se give book <success>, which are admin overrides.
max-success: 100
# Universal enchant-book apply feedback. When a book is applied to gear, a SUCCESSFUL apply plays the success
# cue and a FAILED one (whether the gear shattered, was protected by a white scroll, or survived unharmed) plays
# the fail cue. `sound` is our unified { sound: NAME, volume: V, pitch: P } bracket form (a bare string plays at
# 1.0/1.0); `particles` is a list of particle tokens spawned at the applier (alias-resolved, degrade on 1.8.9).
# Leave a sound blank / particles empty for silence. Read live on /se reload.
apply-cues:
success:
sound: { sound: ENTITY_PLAYER_LEVELUP, volume: 0.7, pitch: 1.4 }
particles:
- HAPPY_VILLAGER
fail:
sound: { sound: ENTITY_ITEM_BREAK, volume: 1.0, pitch: 1.0 }
particles:
- SMOKE_NORMAL
# Enchant slots (§H). The hard cap on TOTAL slots (base + purchased) lives in the expander's own config
# (items/slots.yml -> hard-cap), per §H; only the base every item starts with is cross-cutting.
slots:
base: 9
# The gear lore line shown once a slot-expander orb has ADDED slots (rendered below the enchant/set lines,
# above the white-scroll/holy/trak lines). {TOTAL} = base + added slots; {ADDED} = the orb-granted slots.
lore-line: "&a&l{TOTAL} Enchantment Slots &r&7(Orb [&a+{ADDED}&7])"
# Souls (§D). The full soul economy — per-kill amount, per-mob overrides, colour tiers, sounds, particles,
# messages — is the gem's likeness in items/soul-gem.yml. Only the master deposit switch lives here.
souls:
# Whether souls deposit into a carried gem on ANY kill. false disables the deposit-on-kill mechanic entirely
# (the give/combine/split commands and soul-cost spending still work).
deposit-on-any-kill: true
# Crystals (§E, ADR-0034). Per-item crystal slots are a SEPARATE ledger from enchant slots; the crystal ITEM's
# likeness (material/name/lore) lives in items/crystal.yml. Applying a crystal always succeeds (no roll).
crystals:
# Crystal slots (entries) every item has by default.
slots: 1
# The "global max multi-crystal count": how many crystals may merge into ONE multi-crystal (and thus into one
# gear entry). 2 = a crystal may hold at most two combined effects.
max-merge: 2
# Pets (ADR-0052 / ADR-0059). The universal knobs for every pet: leveling economy, the level-up cue, the
# income ceiling, and the universal messages. A hotbar pet gains exp-per-mob-kill per mob kill and
# exp-per-xp-point × the XP gained on every vanilla XP pickup; an ACTIVE pet also gains a random
# [exp-per-level/8, exp-per-level/5] exp (min 1) on each successful right-click. Any pet sitting in the
# player's main inventory passively earns passive-levels-per-hour of ONLINE time (fractions carried exactly
# on the item, so moving a pet never loses progress); a PASSIVE-type pet held in the HOTBAR earns
# passive-hotbar-levels-per-hour instead. Every exp-per-level exp is one level, capped at max-level (accrual
# parks there). Pet Food's +levels lives on ITS likeness (items/pet-food.yml). level-up-sound /
# level-up-particle play for the holder whenever a pet gains a level from ANY source — once per gain event,
# so a +10 food plays one cue; blank the sound ("") / empty the particle ({ }) to silence it.
# max-percent-money-cap ceilings ONE Fish-pet interest deposit (<= 0 = uncapped). The message templates
# carry {COLOR} (the pet's own colour), {NAME} (uppercased in activate/end when uppercase is on) and
# {TIME_FORMATTED}; an empty template is silent. All read live on /se reload.
pets:
max-level: 100
exp-per-level: 100
exp-per-mob-kill: 5
exp-per-xp-point: 1.0
passive-levels-per-hour: 0.5 # every pet in the main inventory, per hour of ONLINE time
passive-hotbar-levels-per-hour: 1.0 # a PASSIVE-type pet held in the hotbar earns this instead
level-up-sound: { sound: entity.player.levelup, volume: 0.8, pitch: 1.5 }
level-up-particle: { particle: HAPPY_VILLAGER, count: 12, spread: 0.4, y-offset: 1.0 }
max-percent-money-cap: 1000000
message-on-activate: "&{COLOR}&l** PET ABILITY: &f&l&n{NAME}&r &{COLOR}&l**"
message-on-end: "&{COLOR}&l** PET ABILITY: &r&c&l&nENDED&r &{COLOR}&l**"
# Sent to the holder when an armed CHANCE-gated pet effect lands on a hit (the Anubis scroll strip) —
# it replaces the enchant proc line there, which cannot name a pet. Empty = silent.
message-on-effect: "&{COLOR}&l** {NAME} PET EFFECT **"
message-on-cooldown: "&c&l(!) {NAME}&r&c&l is on cooldown for another &f&n{TIME_FORMATTED}&r&c&l!"
message-on-fail: "&c&l(!) You cannot use {NAME}&r&c&l right now!"
uppercase: true
# Masks (ADR-0053 §8). The /near immunity (the Hacker mask) is an OWNED interception: no plugin can filter
# another plugin's proximity scan, so NearGuard listens for these command names, cancels them, and answers with
# its OWN proximity listing (scanning near-radius blocks) that omits near-warded players. near-commands lists the
# command names it intercepts (no leading slash) — while ANY name is configured, this owned listing REPLACES the
# external plugin's /near output format (a documented, opt-out divergence). Set near-commands: [] to disable the
# interception entirely and restore the external plugin's own /near (the Hacker hiding then no longer works).
# On Folia, a cross-region player's location is a region-guarded read: unreadable = omitted from the listing.
# /invsee needs no such knob — its InventoryOpenEvent cancel is plugin-agnostic. All read live on /se reload.
masks:
near-commands: ["near"] # command names NearGuard intercepts (no leading slash); [] disables the interception
near-radius: 200 # radius in blocks the owned /near listing scans
# How many masks may FOLD into one multi-mask (ADR-0074), and so onto one helmet: drag a mask onto another to
# combine them — every folded mask's abilities resolve as if it alone were worn, and the worn illusion shows the
# first one's face. 1 disables folding entirely. The crystals.max-merge knob's twin.
max-merge: 2
# Weapon Reforges (ADR-0070). A reforge drag-applies onto a WEAPON (one socket per weapon — the ONLY knob
# here decides what counts as a weapon) and its signature ability fires on SHIFT + Right Click while that
# weapon is held. The reforge ITEM's likeness lives in items/reforge.yml; each reforge's identity + ability
# in content/reforges/<key>.yml. Removal is the Item Extractor (items/crystal.yml `extractor:`). weapon-groups
# takes ItemGroups tokens (SWORD, AXE, TRIDENT, MACE, or the WEAPON composite); a token's materials that don't
# exist on this server version are simply skipped. Read live on /se reload.
reforges:
weapon-groups: [SWORD, AXE]
# The universal reforge chat lines — the pets convention 1:1 (ADR-0052 shape): activated on a successful
# SHIFT+right-click, ENDED when a timed window (Berry Overdrive, The Ace) closes, plus the on-cooldown /
# fail lines. Tokens: {COLOR} the reforge's colour, {NAME} its display (uppercased on activate/end when
# `uppercase` is on), {TIME_FORMATTED} the remaining cooldown. Empty = silent.
message-on-activate: "&{COLOR}&l** REFORGE ABILITY: &f&l&n{NAME}&r &{COLOR}&l**"
message-on-end: "&{COLOR}&l** REFORGE ABILITY: &r&c&l&nENDED&r &{COLOR}&l**"
message-on-cooldown: "&c&l(!) {NAME}&r&c&l is on cooldown for another &f&n{TIME_FORMATTED}&r&c&l!"
message-on-fail: "&c&l(!) You cannot use {NAME}&r&c&l right now!"
uppercase: true
# Heroic (§F / ADR-0037). The granted percents, success range and material-upgrade map are the upgrade's
# likeness in items/heroic.yml. A heroic piece's percents feed the SAME additive damage fold every enchant
# uses (ADR-0012) — a weapon adds its outgoing%, armour its reduction% — so there is no cross-cutting knob.
# Lore render style (§L). Legacy '&' colour codes. Re-read on every lore render, so a reload restyles live.
lore:
enchant-color: "&7" # an enchant's display name
level-color: "&f" # the level numeral; leave BLANK ("") to make the level use the enchant's tier colour
crystal-color: "&b" # a crystal line
roman: true # levels as Roman numerals (Venom III) vs Arabic (Venom 3)
unknown-label: "&8Unknown Enchant" # shown for a stored key no longer in the catalog
# THE single universal lore-wrap width (VISIBLE chars; colour codes don't count). EVERYTHING that auto-wraps
# uses it: scrolls, the orb, dust, the soul gem, the trak gems, the enchant book's {DESCRIPTION}, AND the
# armour-set piece lore. Authors write one long line and it word-wraps to this width (explicit line breaks
# stay hard breaks). 0 = off. Tune this one number to change wrapping everywhere.
item-wrap: 40
# Integration discovery (§N). Toggles read ONCE at boot (un-discovering a provider mid-run is not clean), so a
# change here takes effect on the next server start. Named integrations (worldguard, vault, mental, …) read
# from the 'named' map below; an unlisted name is enabled. e.g. `named: {mental: false}` stops StarEnchants
# coordinating KNOCKBACK_CONTROL with the Mental knockback plugin. `named: {mental-combo-sync: false}` keeps
# that knockback coordination but turns off combo-DoT parking (SE damage-over-time ticks banking while Mental
# holds an active combo on the victim and joining the combo's own hits — ADR-0069); `mental: false` disables
# BOTH Mental integrations.
integrations:
protection: true # discover ProtectionProviders for the region/build gate
economy: true # discover an EconomyProvider for the money effects
named: {}
# Reload behaviour (§L).
reload:
re-resolve-players: true # re-resolve every online player's worn state after a content swap
auto-seconds: 0 # auto-/se-reload interval in seconds (0 = off; armed once at boot)
# /bless — ONE application of the same cleanse the Clarity set's Bless passive runs on a timer (and the Cow
# Pet on right-click): removes harmful potion effects and puts out fire. A PERMANENT debuff the player
# carries by choice (a helmet granting mining fatigue) is never stripped, and a FREEZE is not broken —
# that is confinement, not a debuff. Buffs are never touched.
# Gated on starenchants.bless (default true); starenchants.bless.bypass skips both knobs below.
# Both are read live on /se reload.
bless:
cooldown-seconds: 60 # seconds between one player's blesses (0 = no cooldown); survives a relog
cost: 0.0 # charged per bless via the economy bridge (0 = free). With a cost set but no economy
# provider installed the command refuses rather than running free.
# Command trigger (§B). The COMMAND trigger fires a player's worn COMMAND-trigger enchants when they run a
# configured command. Registered ONCE at boot (a command name cannot be re-bound mid-run cleanly), so a
# change here takes effect on the next server start, not a /se reload.
command-trigger:
enabled: true # register the command at boot
name: cast # the command players run (no leading slash): /cast
description: "Trigger your COMMAND enchantments." # shown in tab/help listings
# Engine runtime. Combat-integrity per-player state — ability cooldowns and victim-applied teleport-block /
# suppression windows — is RETAINED across a relog (against the monotonic game tick), so a quick
# disconnect+reconnect can no longer skip a long cooldown (e.g. Phoenix) or shed a landed debuff. An offline
# player's entries are only read again on rejoin; this periodic sweep evicts already-elapsed ones to bound
# memory for players who never return. Armed once at boot (restart to re-tune), so NOT a /se reload knob.
engine:
offline-state-sweep-ticks: 6000 # sweep interval in ticks (6000 = 5 min); <= 0 disables the periodic sweep
# Temp cosmetic blocks (magma floors, footprint trails) revert on a timer; on Folia a chunk unload can drop that
# timer and strand the block. Chunk-load re-arms the revert; this sweep also force-reverts any loaded-chunk tile
# whose timer was dropped. Armed once at boot (restart to re-tune).
temp-block-sweep-ticks: 600 # sweep interval in ticks (600 = 30s); <= 0 disables the periodic sweep
:::warning Boot-time vs. live
integrations, reload.auto-seconds, command-trigger, engine.offline-state-sweep-ticks,
engine.temp-block-sweep-ticks, and the slots/souls/scrolls feature switches are armed once at
server start. Changing those takes effect on the next restart, not on /se reload. Everything else
re-reads live.
:::
Sections worth a closer look
Most of the file is self-explanatory from its comments. These few are worth calling out:
stations— vanilla-station guards on plugin set gear. Set pieces and set weapons carry their whole plugin identity in item NBT, which vanilla stations copy wholesale, so an unguarded station would bolt off-design stats onto gear the pack balanced as diamond.anvil-guarddenies anvil combine/repair (a bare rename always stays allowed — it adds no stats),grindstone-guarddenies disenchant/merge, andsmithing-guarddenies the netherite upgrade. Set any tofalseto restore that one station's vanilla behaviour. Grindstone and smithing exist only on modern servers; on 1.8.9 only the anvil guard is meaningful.mining.placed-block-guard— suppresses the wholeMINEdispatch on a block a player placed since the last server start, so a place/break loop can't farm mining rewards. Placement memory is boot-lifetime only; a restart forgets prior placements.falserewards every break.message-on-activate— a global chat line when an enchant fires, off by default. The two sides toggle separately:by-enabledmessages you (naming the victim),on-enabledmessages the other party (naming the attacker). Templates take{ENCHANT},{TIER_COLOR},{VICTIM}, and{ATTACKER};uppercaserenders the enchant name in caps. A non-combat activation, having no other party, sends nothing. A pack that opts in usually drops its per-enchant self-announceMESSAGEeffects to avoid doubling up.apply-cues— the universal sound and particles played when an enchant book is applied to gear: thesuccesscue on a successful apply, thefailcue on any failure (whether the gear shattered, a white scroll saved it, or it survived unharmed). Blank the sound or empty the particle list for silence.books.max-success— the ceiling (%) a book's success rate may reach through randomised minting (unopened books, the randomizer scroll), the black scroll's conversion roll, or Magic Dust. Dust that would push a book past it snaps to it instead.100is effectively no cap. Admin overrides —/se book, the admin browser, an explicit/se give book <success>— ignore it.crystals.max-merge— how many crystals may merge into one multi-crystal, and therefore into one gear entry. The default2means a crystal holds at most two combined effects. This is separate fromcrystals.slots, which is how many crystal entries an item has in the first place.
An annotated enchant
One enchant is one file under content/enchants/. Here is a real example —
content/enchants/frostbite.yml — annotated field by field:
tier: uncommon # rarity → lore color / glint / sort weight (see tiers.yml)
display: "&bFrostbite" # the name shown on gear lore ('&' color codes)
description: "Chill and slow the enemy you strike." # a string, or a list of lore lines
trigger: ATTACK # the event that fires it — one trigger, or a list [ATTACK, BOW]
applies-to: [SWORD, AXE] # which item kinds can carry this enchant
group: combat # shared cooldown / suppression bucket
levels:
1:
chance: 25 # percentage roll — fires ~1 swing in 4
effects: # the actions that run when it fires
- { POTION: { effect: SLOWNESS, level: 1, duration: 60, who: "@Victim" } }
- { PARTICLE: { particle: CLOUD, count: 6 } }
2:
chance: 35
effects:
- { POTION: { effect: SLOWNESS, level: 2, duration: 80, who: "@Victim" } }
- { POTION: { effect: WEAKNESS, level: 1, duration: 60, who: "@Victim" } }
3:
chance: 45
cooldown: 0 # ticks between firings (20 ticks = 1 second)
effects:
- { POTION: { effect: SLOWNESS, level: 2, duration: 100, who: "@Victim" } }
- { POTION: { effect: WEAKNESS, level: 1, duration: 80, who: "@Victim" } }
- { MESSAGE: { text: "&bFrost grips your foe!" } }
Root keys
| Key | Meaning |
|---|---|
display | the enchant's name in lore (& color codes) |
description | flavor text — a string or a list of lines |
tier | rarity id from tiers.yml |
trigger | the firing event — one trigger, or a list |
applies-to | item kinds that can carry it (SWORD, AXE, HELMET, PICKAXE, BOW, WEAPON, …) |
group | shared cooldown / suppression bucket |
repeat | period in ticks for a REPEATING enchant (e.g. 100 = pulse every 5s) |
disabled-worlds | a list of world names the enchant never fires in |
suppress-immune | true = this enchant can never be silenced (DISABLE_ENCHANT/GROUP/TYPE/KIND no-op against it), so a permanent buff survives while the wearer's other enchants are suppressed. Default false |
suppress-type | the key a SUPPRESS { scope: TYPE } window matches this by. Leave it out — by default an ability's type is its trigger's combat side (DEFENSE for DEFENSE/HURT/FALL/FIRE, ATTACK for ATTACK/BOW/TRIDENT/KILL, none for a neutral trigger like PASSIVE), which is what makes a Silence-style key: DEFENSE window park a victim's whole defensive kit. Setting it replaces that, since one ability carries one type |
requires / blacklist / removes-required | apply-relationship rules between enchants |
Per-level keys
Inside each levels: entry:
| Key | Meaning |
|---|---|
chance | percentage activation roll (0–100) |
cooldown | ticks before it can fire again (20 ticks = 1 second) |
cooldown-scope | none = this ability gets no cooldown bucket at all, so it neither waits on nor spends the one its sibling levels and abilities share. Leave the key out to keep that shared bucket |
cooldown-per-victim | true = the cooldown is tracked per target rather than once for mobs and once for players, so throttling a repeat strike on one enemy never blocks the next one. Set it beside cooldown at the top level to cover every rung. A trigger with no victim falls back to the shared bucket, so the cooldown still holds. Default false |
soul-cost | souls spent per activation (requires the player be in soul mode) |
soul-cost-carried | charge soul-cost against the player's carried gems even with no gem active — the gem becomes a wallet rather than a switch |
soul-cost-growth | multiplier the price compounds by on each successful charge — 2 doubles it every proc. Default 1 (a flat price) |
soul-cost-cap | ceiling the escalating price stops at. Default 0 (no ceiling) |
soul-cost-decay-period | ticks of quiet that shed one step of escalation, down to the base soul-cost. Default 0 (the price never comes back down) |
no-souls-message | line shown when a soul-cost activation can't pay (at most once every 15s per player) |
no-souls-sound | sound played with no-souls-message, on the same 15s throttle |
no-souls-particle | particle spawned with no-souls-message, on the same 15s throttle |
condition | a boolean test that gates the firing |
effects | the list of effects to run |
:::tip Set a key once at the root
Any per-level key may instead be set once at the root as the default for every level. If every
level shares a cooldown, write cooldown: 100 at the top level instead of repeating it.
:::
Several abilities on one level
A level usually does one thing, so effects: sits directly under it. When one level needs two
independent behaviours — different triggers, different chances, or separate cooldowns — replace
effects: with an abilities: list. Each entry is a complete ability in its own right:
levels:
3:
abilities:
- chance: 40 # a proc on the swing
cooldown: 60
effects:
- { IGNITE: { duration: 60, who: "@Victim" } }
- trigger: DEFENSE # …and a separate retaliation, on its own trigger
chance: 100
effects:
- { POTION: { effect: RESISTANCE, level: 1, duration: 40, who: "@Self" } }
Each block takes any per-level key plus its own trigger and repeat. Anything a block leaves out
falls back to the level, then to the root — so the shared knobs stay written once.
The blocks belong to the same enchant: they share its group, its cooldown bucket, and its
suppression key, so a DISABLE_ENCHANT silences all of them together.
:::caution One shape per level
A level uses either effects: or abilities:, never both — declaring both is a load error rather
than a silent guess about which one you meant. An empty abilities: [] is an error too.
:::
Writing effects
Each effect is a block map — { HEAD: { param: value } }:
effects:
- { IGNITE: { duration: 60 } }
- { POTION: { effect: REGENERATION, level: 1, duration: 60, who: "@Self" } }
Two parameter names are special:
who:chooses the selector — who the effect lands on (@Self,@Victim,@Attacker,@Aoe{r=3}, …). Every effect has a sensible default target if you omit it.wait:inserts a delay, in ticks, before that single effect runs.
Conditions
A condition: is a boolean expression over %scope.name% variables, combined with && || ! ( )
and the operators == != < <= > >=, contains, and matchesregex:
condition: "%victim.health% < 6 && %onground%"
condition: "%victim.helditem% contains \"SWORD\""
A condition may also end in a flow clause — <test> : <outcome> — whose outcome applies when the
test is true. There are five: : %continue% (proceed to the chance roll as normal — the bare-gate
pass), : %stop% (block this activation), : %force% (activate, skipping the chance roll),
: %allow% (activate regardless of the roll), and : +15 %chance% (nudge the roll by signed
percentage points). Without a clause it simply gates whether the enchant fires. See the full
conditions reference.
A richer level
A gated, cooled-down crit with a targeted effect, particle, and message (from
content/enchants/executioner.yml):
3:
chance: 50
cooldown: 0
condition: "%victim.health% < 6"
effects:
- { DAMAGE_MOD: { side: attack, mode: flat, amount: 8 } }
- { PARTICLE: { particle: CRIT, count: 18 } }
- { MESSAGE: { text: "&4&lExecuted!" } }
Rarity tiers — tiers.yml
Tiers are defined once, in content/tiers.yml:
default-tier: common
tiers:
<id>: { color: "&7", weight: 10, glint: false } # one entry per tier
Each tier id carries a lore color, a GUI sort weight, and whether items of that tier glint.
default-tier is used by any enchant that omits tier:. The tiers StarEnchants ships with:
| Tier | Colour | Weight | Glint |
|---|---|---|---|
| common (default) | &7 | 10 | — |
| uncommon | &a | 20 | — |
| rare | &b | 30 | — |
| epic | &d | 40 | Yes |
| legendary | &6 | 50 | Yes |
| mythic | &c&l | 60 | Yes |
See Rarity tiers for the concept.
Defining a set
A set lives in content/sets/. armor: and weapon: describe the look — the pieces, their lore,
the optional matched weapon — and a separate top-level bonuses: list describes the behaviour.
Each entry names the side it belongs to with on: armor or on: weapon, then reads exactly like an
enchant level: a trigger plus optional chance / cooldown / condition and its effects. You may
declare as many entries per side as you like. From content/sets/inferno.yml:
display: "&cInferno"
description: "Burn attackers and shrug off fire when the full set is worn."
complete: 4
armor:
lore:
- "&cInferno Set &7(4 pieces)"
- "&7Wear the full set to burn attackers."
pieces:
helmet: { material: DIAMOND_HELMET, name: "&cInferno Helm" }
chestplate: { material: DIAMOND_CHESTPLATE, name: "&cInferno Chestplate" }
leggings: { material: DIAMOND_LEGGINGS, name: "&cInferno Leggings" }
boots: { material: DIAMOND_BOOTS, name: "&cInferno Boots" }
weapon:
material: DIAMOND_SWORD
name: "&cInferno Blade"
lore:
- "&cInferno Set Weapon"
- "&7Wield with the full set to set foes alight."
# Behaviours: on:armor fires while the set is complete; on:weapon also requires the set weapon held.
bonuses:
- on: armor
trigger: DEFENSE
chance: 45
cooldown: 100
effects:
- { IGNITE: { duration: 80, who: "@Attacker" } }
- { POTION: { effect: FIRE_RESISTANCE, level: 1, duration: 100, who: "@Self" } }
- { PARTICLE: { particle: FLAME, count: 12 } }
- on: weapon
trigger: ATTACK
chance: 60
effects:
- { IGNITE: { duration: 60, who: "@Victim" } }
complete is how many armor pieces must be worn before any bonus is live. An on: armor entry
fires once that threshold is met; an on: weapon entry additionally requires the matched weapon to be
held, so a set can hand out a defensive aura and an offensive proc from the same file.
:::note Sets have no tier
Unlike enchants and crystals, an armor set carries no rarity tier. See
Armor sets.
:::
Defining a crystal
A crystal lives in content/crystals/. It is a levelless bonus block. Unlike a set, it carries no
item likeness of its own — every crystal is minted from the one global likeness in items/crystal.yml,
so the def only declares its styled name, its description lines, and what it does. display is the
crystal's own name (no "Crystal" suffix — the likeness supplies that), and description is a list
of lore lines. From content/crystals/ember-crystal.yml:
display: "&6Ember"
description:
- "&6&lEMBER CRYSTAL BONUS"
- "&6* 60% chance on hit to set your foe alight for 3 seconds."
tier: uncommon
applies-to: [SWORD, AXE]
trigger: ATTACK
chance: 60
effects:
- { IGNITE: { duration: 60 } }
- { PARTICLE: { particle: FLAME, count: 8 } }
That is the single-ability shorthand — one trigger + effects pair at the root. A crystal that
needs more than one ability writes an abilities: list instead, each entry its own trigger + effects.
Two more root keys are crystal-specific: stackable decides whether worn or merged copies of the same
crystal each count (a non-stackable crystal is deduplicated per wearer). From the signature pack's
content/crystals/bolt.yml:
display: "{#5eb3f6}&lBolt"
description:
- "{#5eb3f6}&lBOLT CRYSTAL BONUS"
- "{#5eb3f6}* Outgoing lightning strikes deal 10% more damage to all enemies"
- "{#5eb3f6}* Bolt Crystal is stackable"
tier: rare
applies-to: [ARMOR]
stackable: true
abilities:
- { trigger: PASSIVE, effects: [ { LIGHTNING_MOD: { amount: 10 } } ] }
Crystals can be merged into one gear entry — how many is capped by crystals.max-merge, and how
many sockets an item has by crystals.slots, both in config.yml. A merged crystal renders as a
"Multi Crystal". See Crystals.
Defining a use-item
A use-item lives in content/use-items/<key>.yml, and the filename stem is the key the minted item
stores. Its trigger is implicit: everything in the file fires on USE (a right-click), so you do
not write a trigger: — one that is declared anyway is warned about and forced to USE.
The shipped content/use-items/rage-crystal.yml doubles as the annotated template for the family:
name: "&c&lRage Crystal&r &7(Right Click)&r" # display name (colours inline); used verbatim + as {NAME} in messages
material: RED_DYE # resolved cross-version at mint (degrades to REDSTONE on the 1.8 lane)
consumable: true # true = one item is consumed on a successful use; false = a reusable tool
shiny: false # true = the minted item carries an enchant glint
lore:
- "&eConsume to gain a temporary strength buff, at the cost of movement speed."
- ""
- "&eCooldown: &f&n{TIME_FORMATTED}&r" # {TIME_FORMATTED} in LORE renders the a0 cooldown below, h/m/s
- "&7Right Click while holding this item to apply."
permission: "" # optional Bukkit permission checked at use time; empty = everyone
cooldown: 1200 # ticks (standard ability cooldown, gate 6) — 60s; also what {TIME_FORMATTED} shows
chance: 100 # activation chance percent (gate 8)
condition: "" # optional condition DSL, same grammar as enchants; failing it renders {CONDITION} in the fail message
effects: # Strength II + Slowness I on self for 12s (240 ticks)
- { POTION: { effect: "INCREASE_DAMAGE", level: 2, duration: 240, who: "@Self" } }
- { POTION: { effect: "SLOW", level: 1, duration: 240, who: "@Self" } }
commands: [] # strings (run as console) or { as: player|console, run: "..." }; {PLAYER}/{UUID}/{WORLD} substituted
That is the single-ability shorthand; a use-item that needs more than one ability writes an
abilities: list instead, each entry taking chance / cooldown / condition / effects. A
commands: entry is either a bare string (run as console) or a { as: player|console, run: "..." }
map, with {PLAYER}, {UUID}, and {WORLD} substituted for the user. features.use-items in
config.yml is the live master switch — turn it off and a held use-item goes inert.
For the minted item, the universal use-item.* lang keys, and the walkthrough, see
Use-items.
Defining a mask
A mask lives in content/masks/<key>.yml. It declares a display name, a color, the head texture
(a base64 skin value), a description list, and its abilities. The mask item's likeness comes
from the global items/mask.yml, so the def carries no material of its own. From
content/masks/blaze.yml:
display: "Blaze"
color: "&6"
head: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ=="
description:
- "&6* Immune to fire and lava damage"
abilities:
- { trigger: FIRE, effects: [ { CANCEL: {} } ] }
Unlike a use-item, every mask ability must declare its own trigger:. features.masks is the
live master switch. See Masks.
Defining a pet
A pet lives in content/pets/<key>.yml. Alongside display, color, type (ACTIVE or PASSIVE),
the head texture and the description lines, its abilities live under a sparse levels: map. Each
key is a level floor, and the highest floor at or below the head's stored level is the live
bracket — with floors 1, 25, 50, and 100, a level-30 pet runs the 25 bracket. A bracket sets
cooldown and duration (the armed window, in ticks; 0 = no window) and lists its abilities.
content/pets/shield.yml is the commented exemplar for the family:
display: "Shield"
color: "&7"
type: ACTIVE
head: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTdhODgwMTEzN2JkMjc0YjFhNWU4YzZkYjRkYWJmMjcwN2EwYjlmMzUxYjdmYTFjYmU4Y2U3NDM2MjFjNTE0NiJ9fX0="
description:
- "&7* Temporarily reduces all incoming damage"
levels:
1:
cooldown: 1800
duration: 60
abilities:
- { effects: [ { SOUND: { sound: "BLOCK_ANVIL_PLACE", volume: 0.6, pitch: 1.6 } } ] }
- { trigger: DEFENSE, effects: [ { DAMAGE_MOD: { side: defense, mode: add, amount: 15 } } ] }
On an ACTIVE pet an ability with no trigger: is the implicit right-click use; any other trigger is
an armed ability, live only for duration ticks after a successful click. The pet head's likeness
is items/pet.yml, the levelling and economy knobs are the pets: block in config.yml, and
features.pets is the live master switch. See Pets.
Defining a reforge
A reforge lives in content/reforges/<key>.yml and drag-applies onto a weapon, where its signature
ability fires on shift + right-click. It declares a display, a color (legacy & codes or a
{#RRGGBB} hex token), an icon material for menus, a description list, and its abilities. From
the signature pack's content/reforges/blink.yml:
display: "Quantum Blink"
color: "{#62baa2}"
icon: ENDER_PEARL
type: ACTIVE
description:
- "{#62baa2}* Instantly teleport up to five blocks in the direction you are facing, but does not pass through walls"
abilities:
- cooldown: 600
effects:
- { SOUND: { sound: "ENTITY_ENDERMAN_TELEPORT", volume: 0.7, pitch: 1.6 } }
- { SOUND: { sound: "BLOCK_AMETHYST_BLOCK_CHIME", volume: 0.5, pitch: 1.2 } }
- { BLINK: { distance: 5, particle: REDSTONE, r: 98, g: 186, b: 162, size: 1.0, count: 10 } }
What counts as a weapon is reforges.weapon-groups in config.yml, which defaults to
[SWORD, AXE] and takes item-group tokens (SWORD, AXE, TRIDENT, MACE, or the WEAPON
composite); tokens whose materials don't exist on the running server version are simply skipped.
features.reforges is the live master switch. The default content tree ships no reforges — the
shipped examples all live in the signature pack. See Reforges.
Customizing items
Every physical item is one file under items/, tagged by type:. These files describe each item's
look (material, name, lore) and its economy knobs — they never compile to an ability. Every
physical item StarEnchants ships, with its type:, default material, and default name:
| Item key | Type | Material | Name |
|---|---|---|---|
| black-scroll | black-scroll | INK_SAC | &8Black Scroll |
| blocktrak | blocktrak | SLIME_BALL | {#84c874}&lBlockTrak Gem |
| crystal | crystal | AMETHYST_SHARD | &d{CRYSTAL} &7Crystal |
| dust | dust | GLOWSTONE_DUST | &aSuccess Dust |
| enchant-book | enchant-book | ENCHANTED_BOOK | {TIER_COLOR}&l{ENCHANT} {LEVEL} |
| fishtrak | fishtrak | CLAY_BALL | {#b0b9d5}&lFishTrak Gem |
| godly-transmog | godly-transmog | NETHER_STAR | &5Godly Transmog |
| heroic | heroic | NETHERITE_SCRAP | &6&lHeroic Upgrade |
| holy-white-scroll | holy-white-scroll | TOTEM_OF_UNDYING | &fHoly White Scroll |
| mask | mask | — | {COLOR}&l{NAME} Mask |
| mobtrak | mobtrak | MAGMA_CREAM | {#e6cb2f}&lMobTrak Gem |
| nametag | nametag | NAME_TAG | &bItem Nametag |
| pet-food | pet-food | GOLDEN_CARROT | &e&lPet Food [&r&a&n+{AMOUNT}&r&e&l] |
| pet | pet | — | {COLOR}&l{NAME} Pet &7[Lvl. &f&n{LEVEL}&r&7]&r |
| randomizer-scroll | randomizer-scroll | SUGAR | &eRandomizer Scroll |
| reforge | reforge | — | &6&lWeapon Reforge ({COLOR}&l{NAME}&r&6&l) |
| slot-orb | slot-orb | — | — |
| soul-gem | soul-gem | EMERALD | &aSoul Gem |
| soultrak | soultrak | FIRE_CHARGE | {#e54f00}&lSoulTrak Gem |
| transmog-scroll | transmog-scroll | PAPER | &c&lTransmog Scroll |
| unopened-book | unopened-book | BOOK | &b{TIER} Mystery Book |
| white-scroll | white-scroll | PAPER | &fWhite Scroll |
For each item type's economy knobs and notable fields — success-lore and destroy-on-fail on
books, save-chance on the holy scroll, souls-per-kill on the gem, hard-cap on the orb, and so
on — see the Items & economy section, which covers each type in detail.
Reloading
/se reload rebuilds the entire content library — config.yml, lang.yml, content/,
items/, and menus/ — off-thread, then swaps it in atomically, and only if it compiles
clean. A broken edit keeps the running config live and reports diagnostics instead of taking the
server down.
/se reload # rebuild and hot-swap
/se reload --dry-run # validate and report — do NOT swap
:::tip Validate before you commit
Run /se reload --dry-run after a big edit to catch typos in effect names, missing required params,
or bad references before you swap them into the live config.
:::
Use config packs (/se pack export <name>) to snapshot your whole setup into a portable ZIP,
and /se pack apply <name> to swap one in transactionally. Two packs ship in the jar: the default
signature-pack, and cosmic-pack — the classic Cosmic experience, ported number-exact — which you
apply with /se pack apply cosmic-pack. Applying replaces the whole surface above, backing up your
current one first. See the commands page.
:::caution Two things to know before you apply a pack
signature-pack is modern-only. Its pack.yml declares min-server: "1.17.1". On the 1.8.9
build, /se pack apply signature-pack is refused with one clear message instead of a wall of
unknown-sound errors, and a server that boots with it already applied logs the same message. The
bundled defaults and cosmic-pack are legacy-capable and run on the whole supported range, 1.8.9
included.
cosmic-pack does not carry every item. It ships content/ in full plus thirteen item
likenesses — the crystal, the Heroic upgrade, masks, pets, enchant books, mystery books, dust, the
enchantment orb, and the white/black/transmog/randomization scrolls and pet food. Nine keep their
stock StarEnchants likeness, and all menus do too: the soul gem, the four trak gems, the item
nametag, the holy white scroll and the godly transmog were minted by other plugins on the original
server, so there is nothing of theirs to port, and weapon reforges are ours alone. Nothing breaks —
those items just look like stock StarEnchants.
:::