Permissions
MagicUtils commands generate and evaluate permission nodes automatically. The registry prefix controls namespacing, while annotations control explicit nodes, defaults, and conditional argument checks.
Permission Prefix
Every command registry has a permission prefix. You set it either directly on the registry:
or through the bootstrap helper:
MagicUtils prepends that prefix to all generated nodes.
Generated Nodes
When annotations omit explicit permission strings, MagicUtils builds defaults:
- Command:
commands.<command> - Subcommand:
commands.<command>.subcommand.<path> - Argument:
commands.<command>.subcommand.<path>.argument.<name>
With prefix donatemenu:
donatemenu.commands.donatedonatemenu.commands.donate.subcommand.givedonatemenu.commands.donate.subcommand.give.argument.player
Default Access
MagicPermissionDefault controls what happens when the permission node is not
granted explicitly:
TRUE-> everyoneOP-> operators or elevated sendersNOT_OP-> non-operators / non-elevated sendersFALSE-> nobody
Platform behaviour differs slightly:
- Bukkit registers permission nodes with Bukkit's permission manager and uses Bukkit permission defaults.
- Fabric checks
fabric-permissions-api-v0when available and falls back to op-level checks. - NeoForge falls back to command-source permission level checks.
- Velocity relies on the proxy's permission checks and uses the default policy only when the node itself is absent.
Wildcards
On Bukkit, MagicUtils also registers wildcard nodes:
...commands.<command>.*...commands.<command>.subcommand.*
Velocity also honours prefix-style wildcard checks such as prefix.* and
prefix<node>.* when the proxy reports them as granted.
Explicit Permission Annotations
Use explicit nodes when you want stable names independent of the generated shape:
Subcommands support the same fields:
Argument Permissions
Use @Permission on parameters to gate argument usage:
You can override the generated node segment:
@Permission Members
@Permission supports both a string DSL (when) and structured members:
| Member | Default | Purpose |
|---|---|---|
value | "" | Explicit permission node; empty means use the generated node. |
when | "" | Condition DSL string, for example other(player) (see keywords below). |
condition | ALWAYS | PermissionConditionType when set structurally instead of via when. |
conditionArgs | {} | Argument names the condition applies to. |
node | "" | Override the generated node segment. |
includeArgumentSegment | true | Include the .argument. segment before the node. |
compare | AUTO | CompareMode (AUTO, UUID, NAME, EQUALS) for value comparisons. |
defaultValue | OP | MagicPermissionDefault for this argument node. |
message | magicutils.noPermission | Language key used when the check fails. |
PermissionConditionType values: ALWAYS, NOT_NULL, SELF, OTHER,
ANY_OTHER, DISTINCT, ALL_DISTINCT, EQUALS, NOT_EQUALS, EXISTS. The
when DSL keywords below map onto these types, so use whichever style reads
better for your command.
Conditional Permission Keywords
self(arg)/other(arg)/anyother(arg)not_null(arg)/exists(arg)distinct(a,b)/all_distinct(a,b)equals(a,b)/not_equals(a,b)
Use compare = CompareMode.UUID/NAME/EQUALS/AUTO to control how values are
compared.
Manual Checks
MagicSender exposes direct permission checks when you need custom logic
outside annotation processing:
When the platform adapter uses op-level fallback semantics, the two-argument form keeps the adapter default, while the three-argument form overrides it for that one check:
This matters most on Fabric and NeoForge, where permission backends may fall back to command-source op levels when a node is unknown or no backend responds.
You can also use the registry prefix when building related manual nodes so the manual and generated permissions stay in the same namespace.