Reusable VirtualMenu
Build contextual menus with the pattern used in production plugins.
VirtualMenu<T> is useful when a menu needs context such as a player, database object, filter string, or domain record. Override build(T context), fill the inherited menu, and return it.
import eu.xap3y.xagui.VirtualMenu;
import eu.xap3y.xagui.XaGui;
import eu.xap3y.xagui.interfaces.GuiMenuInterface;
import eu.xap3y.xagui.models.GuiButton;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class PlayerProfileMenu extends VirtualMenu<Player> {
public PlayerProfileMenu(XaGui xaGui) {
super("&8Player profile", 3, xaGui);
}
@Override
public @NotNull GuiMenuInterface build(@NotNull Player context) {
GuiMenuInterface menu = getGui();
// Clear dynamic content if this instance may be rebuilt.
menu.clearAllSlots();
menu.fillBorder();
menu.addCloseButton();
menu.setSlot(13, new GuiButton(Material.PLAYER_HEAD)
.setName("&e" + context.getName())
.setLore("&7Health: &f" + context.getHealth()));
return menu;
}
}Build and open in one call:
PlayerProfileMenu profiles = new PlayerProfileMenu(xaGui);
profiles.open(player, player);You may also call profiles.build(player).open(player). Do not call open(player) on VirtualMenu when contextual rebuilding is required; that overload opens the already-built backing menu.
Registry for named menus
GuiRegistry<K> maps your own key type—often an enum—to virtual menus.
enum MenuId { PROFILE }
GuiRegistry<MenuId> registry = new GuiRegistry<>();
registry.register(MenuId.PROFILE, new PlayerProfileMenu(xaGui), Player.class);
registry.invoke(MenuId.PROFILE, viewer, profilePlayer, Player.class);The context class passed to register, get, and invoke must match. For context-free menu keys, invoke(key, player) looks up a menu registered with Void.class and builds it with null; if your build contract is non-null, prefer a simple marker type or open the virtual menu directly.
Rebuild safety
A VirtualMenu owns one backing GuiMenuInterface. If the same instance is rebuilt, clear or overwrite old dynamic slots first. For truly player-specific menus opened concurrently, create a new VirtualMenu instance per opening so one player's build cannot overwrite another's state.