Menu API
The menu engine that backs every GUI in uxmEssentials is extensible. Through the public MenuApi you can teach the engine your own actions, requirements, placeholders, list sources, and icon providers โ so operators can then use them by name in their own menus/*.conf files, exactly like the built-in vocabulary.
MenuApi is registered in Bukkit's ServicesManager at ServicePriority.Normal, so you obtain it at runtime โ there is no compile dependency to add (see Overview).
Obtaining MenuApi¶
Fetch it in your onEnable, after uxmEssentials has loaded, and null-check:
import org.bukkit.plugin.ServicesManager;
// MenuApi lives in the uxmEssentials menu api package; resolved at runtime off the shared classpath.
import com.uxplima.uxmessentials.shared.gui.menu.api.MenuApi;
@Override
public void onEnable() {
ServicesManager services = getServer().getServicesManager();
MenuApi menuApi = services.load(MenuApi.class); // null if the plugin/service is absent
if (menuApi == null) {
getLogger().info("uxmEssentials MenuApi not present โ skipping menu extensions.");
return;
}
registerMenuExtensions(menuApi);
}
Confirm the exact import from the jar
The plugin is not published to Maven, so the MenuApi type is resolved at runtime from the shared classpath. Confirm the exact package against the version you build for (inspect the jar or the plugin's api package) rather than pinning a copied path.
What you can register¶
| Method | Registers | Referenced in a spec as |
|---|---|---|
registerAction |
A custom click/open action | an action id:value (for example myaddon-reward:5) |
registerRequirement |
A custom view/click condition | a requirement id:value (with ! to invert) |
registerPlaceholder |
A custom %โฆ% placeholder |
%your_token% in titles, names, and lore |
registerListSource |
A source for paginated list items | a list { source = "your-source" } block |
registerIconProvider |
A custom material prefix resolver |
material = "yourprefix:some-id" |
buildItem |
(not a registration) builds an ItemStack from an engine item spec |
โ |
buildItem is the inverse of the others: instead of extending the engine, it lets your code produce an icon that looks identical to one the engine would render from the same spec, so custom UIs stay visually consistent with the built-in menus.
Example¶
private void registerMenuExtensions(MenuApi menuApi) {
// A custom action operators can call as "myaddon-reward:<amount>".
menuApi.registerAction("myaddon-reward", (context, argument) -> {
int amount = Integer.parseInt(argument);
grantReward(context.player(), amount);
});
// A custom requirement, usable as "myaddon-vip" (or "!myaddon-vip" to invert).
menuApi.registerRequirement("myaddon-vip", (context, argument) ->
isVip(context.player()));
// A custom placeholder, usable as %myaddon_rank% in any title/name/lore.
menuApi.registerPlaceholder("myaddon_rank", context ->
rankOf(context.player()));
}
The lambdas above are illustrative โ check the current handler interfaces in the api package for the exact parameter shapes. Handlers receive the open context (the viewer and the resolved argument) and either perform the action, answer the condition, or return the placeholder string.
Register once, before menus load
Every registerโฆ call must happen once, during your onEnable, and before any menu that references it is loaded. Registering a duplicate id throws โ do not re-register on /menu reload or a plugin reload. Because operator menus and the built-in feature menus are loaded after plugins enable, extensions registered in your onEnable are already present when the engine reads a spec that names them; register late and the spec that uses your id fails to resolve.
Handlers run on the viewer's region thread (Folia)
Action, requirement, and placeholder handlers execute on the viewer's own region thread โ the same thread as MenuOpenEvent / MenuClickEvent (see Events). Keep them fast and region-safe; hand any I/O or cross-region work off to the appropriate scheduler instead of blocking.
Next Steps¶
- Custom Menu Engine โ the spec format, action/requirement vocabulary, and built-in placeholders your extensions sit alongside
- Overview โ soft-depend and the
ServicesManagerpattern - Events โ observe menu opens and clicks