Skip to content

feat(command): gates answer refused players with the plugin's line - #87

Merged
siracozmen01 merged 5 commits into
mainfrom
feat/command-gates
Nov 4, 2026
Merged

siracozmen01 merged 5 commits into
mainfrom
feat/command-gates

Conversation

@siracozmen01

Copy link
Copy Markdown
Member

A customer read Incorrect argument for command kits editor<--[HERE] and nothing in the console (2026-11-04). Brigadier's requires hides a word from the client's command list and from the parser at once, and the parser tries only the literal a typed word matches, so a sender without the node reads Brigadier's own text: not the plugin's line, not which node. The same happens to every @Permission branch the annotation layer renders, through Cmd.visibility.

This separates the two jobs.

  • Gate: who sees a node (shows) and who may use it (allows). As a requirement it always passes, so the parser accepts every word. Gate.permission, Gate.visibility (keeps the default: true meaning), Gate.shownTo (a word for some readers, usable by everyone), Gate.when (a feature that is off), Gate.open, joined with and/or; a plain predicate cannot be joined in, since it would always pass.
  • CommandGates.seal: rebuilds a tree so every executor and every suggestion below a gate asks the gates on its path first and answers a refusal with the plugin's Refusal. The gates are read at seal time, so a Paper alias that redirects to the root still passes the root's gate. A tree with a gate may not redirect anywhere.
  • GateVisibility: one listener per plugin; trims each player's command list and the completions the server sends of what a gate hides from them. Geyser translates the same list.
  • CommandRegistrar seals and listens; a new overload takes a Refusal, the old one answers with the server's permission message. AnnotatedCommands refuses with CommandMessages.noPermission. The executor of an annotated branch now checks the class node as well as its own.
  • Cmd.permission and Cmd.visibility keep their native meaning and are deprecated.

17 tests run the trees in a real CommandDispatcher: refusals, suggestions (custom and the argument type's own), pruning, words for some readers, redirects, joined gates, the class node. Checked on a Folia server through uxmEssentials built on this snapshot: a player typing /kits editor, /worlds create, /guard define or /npc create reads the catalog's no-permission line; the tree each player was sent, captured after the listener, lacked every staff word for the player and held all of them for an operator.

Goes with UXPLIMA/uxm-essentials feat/command-gates and UXPLIMA/.github#39.

@siracozmen01
siracozmen01 merged commit 0e726da into main Nov 4, 2026
5 checks passed
@siracozmen01
siracozmen01 deleted the feat/command-gates branch November 4, 2026 15:43
siracozmen01 added a commit that referenced this pull request Nov 4, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.8.0](uxm-lib-v0.7.0...uxm-lib-v0.8.0)
(2026-11-04)


### Features

* **command:** gates answer refused players with the plugin's line
([#87](#87))
([0e726da](0e726da))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Sirac Ozmen <siracozmen@protonmail.com>
siracozmen01 added a commit to UXPLIMA/uxm-essentials that referenced this pull request Nov 4, 2026
)

The customer report behind UXPLIMA/uxm-lib#87: `/kits editor` answered
`Incorrect argument for command` when the player lacked
`uxmessentials.kit.edit`.

- Every `requires(src -> src.getSender().hasPermission(X))` (356) and
the helpers built on it (`/worlds` `p()`, the NPC and hologram
capabilities, the either-node roots of `/skin`, `/invrestore`, `/ranks`,
`/poses`) are now `Gate`s. The `/pwarp sponsor` word is
`Gate.when(sponsor on)` joined with its node.
- `GateBinding` seals each published command right before the
`LocaleBinding`, so a refusal is the catalog line in the player's
language: `command.no-permission`, or the new `command.unavailable` (12
languages) for a feature that is off.
- One `GateVisibility` listener trims each player's command list and
completions; a command reload clears and refills it.

Checked on ess-folia (Folia) against a local uxmLib snapshot: a player
typing `/kits editor`, `/worlds create foo`, `/guard define test` or
`/npc create bob` read "you don't have permission."; the command tree
sent to that player lacked every staff word and `/npc`, an operator's
held all of them. `./gradlew build` green against the snapshot.

Builds against uxm-gradle 0.7.0, which pins uxmLib 0.8.0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant