Requirements¶
A requirement decides whether somebody may see an icon or use it.
vip_button:
material: EMERALD
slot: 13
display_name: "&aVIP lounge"
view_requirement:
requirements:
rank:
type: has permission
permission: server.vip
left_click_commands:
- "[player] warp viplounge"
Anyone without server.vip sees an empty slot, not a locked one.
Where they go¶
view_requirement |
On an item. Decides whether it is drawn |
open_requirement |
On the menu. Decides whether it opens |
<click>_requirement |
On an item. Decides whether that click works |
A view requirement runs on every redraw, so it never fires a message. A click
requirement can, through deny_commands.
Two items, one slot¶
This is the pattern worth learning, because it replaces every branch you would otherwise want to write.
kit_ready:
material: CHEST
slot: 13
priority: 20
display_name: "&aStarter kit"
lore:
- "&aReady to claim"
view_requirement:
requirements:
ready:
type: string equals
input: "%essentials_kit_is_available_starter%"
output: "yes"
left_click_commands:
- "[player] kit starter"
- "[refresh]"
kit_cooldown:
material: GRAY_STAINED_GLASS
slot: 13
priority: 10
display_name: "&7Starter kit"
lore:
- "&cReady in &f%essentials_kit_time_until_available_formatted_starter%"
Same slot, different priorities. The highest priority whose view requirement passes is the one drawn. No scripting, and no third state to forget about: give the fallback no requirement and it always wins when the others do not.
Any of these, not all¶
view_requirement:
minimum_requirements: 1
requirements:
rank:
type: has permission
permission: server.vip
rich:
type: has money
amount: 10000
Without minimum_requirements, every requirement must pass. With it, that many
must. This is how you say "VIP or rich" without writing the item twice.
What happens on failure¶
left_click_requirement:
requirements:
rich:
type: has money
amount: 500
deny_commands:
- "[message] &cThat costs $500."
- "[sound] ENTITY_VILLAGER_NO"
success_commands:
- "[sound] ENTITY_EXPERIENCE_ORB_PICKUP"
Types¶
Permissions¶
type |
|
|---|---|
has permission |
Needs permission: |
has not permission |
The opposite |
is op |
Amounts¶
type |
|
|---|---|
has money |
Needs amount:, or an input: that resolves to a number |
has exp |
Experience points |
has level |
Experience levels |
has item |
Needs material: and optionally item_amount: |
Comparing¶
type |
|
|---|---|
== != > >= < <= |
input: against output: |
string equals |
Exact text |
string equals ignorecase |
|
string contains |
|
string does not contain |
|
regex |
output: is the pattern |
Comparisons are numeric when both sides are numbers and textual otherwise,
because "10" against "9" sorts the wrong way as text and numbers are
overwhelmingly what people mean.
Other¶
type |
|
|---|---|
is near |
input: is world,x,y,z, amount: is the distance |
expression |
An arithmetic condition, below |
Prefixing any type with ! inverts it.
Expressions instead of scripting¶
Supports + - * / % ^, brackets, > >= < <= == !=, and && ||.
There is deliberately no JavaScript type
Menu plugins have historically embedded a scripting engine so config authors could write conditions. That hands arbitrary code execution to anyone who can edit a YAML file, and the engine those plugins used, Nashorn, was removed from Java entirely in version 15, so those configs simply stop working on a modern server.
This evaluator understands numbers and operators. It cannot open a file, cannot reach the server, and cannot be made to.
A note on unknown types¶
A type we do not recognise passes, and the item stays visible. The
alternative is an invisible item and no explanation, which is a far worse
afternoon than an item that is showing when it should not be.