Libb

Easy util for Minecraft Gui, Command, Action

49

Libb

Libb

A library for convenient and easy creation of Minecraft plugins.

---

<div align="center"> <a href="https://wiki.jetby.space/plugins/treexbuyer"><img src="https://cdn.modrinth.com/data/cached_images/31b63c1cc08964f616ae35ec874741870f4c8bb4.png" /></a><a href="https://dsc.gg/jmdev"><img src="https://cdn.modrinth.com/data/cached_images/60fcf5a0b12f3cff46b065aea871b3f08629f94e.png" /></a><a href="https://ko-fi.com/jetby"><img src="https://cdn.modrinth.com/data/cached_images/4a1b54c640e2f990880107e8bf3cd6c573a9201a.png" /></a> </div>

---

| Dependencies| |:-| | Dependencies | Java 17 or higher | Paper or forks | Minecraft Version 1.20 or higher

---

GUI

Example

```java public class GuiTest extends AdvancedGui { public GuiTest() { super("Gui title"); setItem("example", ItemWrapper.builder(Material.STONE) .slots(1, 5, 7) .displayName(Component.text("This is the name dude")) .onClick(event -> { event.setCancelled(true); player.sendMessage("Clicked on slot: " + event.getSlot()); }) .build()); } } ```

To open a GUI for a player, call `open()`:

```java new GuiTest().open(player); ```

---

ParsedGui — Config-driven GUIs

`ParsedGui` lets you define an entire inventory GUI in a YAML config file — items, slots, click actions, open/close hooks, and placeholders — with no boilerplate code.

---

YAML structure

```yaml id: my_gui title: "<gold>My Shop" size: 54 # must be a multiple of 9

on_open: # optional — action list to run when GUI opens - "[sound] UI_BUTTON_CLICK;1;1"

on_close: # optional — action list to run when GUI closes - "[message] <gray>Closed the shop."

Items: my_item: material: DIAMOND slot: 13 # single slot display_name: "<aqua>Buy Diamond" lore: - "" - " <gray>Click to purchase" - "" on_click: any: # fires on every click type - "[sound] UI_BUTTON_CLICK;1;1" - "[player] buy diamond" left: # fires only on left click - "[message] <green>Left clicked!" shift_left: - "[message] <yellow>Shift+Left!" ```

Supported click types: `any`, `left`, `shift_left`, `right`, `shift_right`, `middle`, `drop`, `control_drop`, `double`

Slot formats:

```yaml slot: 13 # single slot slots: - '0-8' # range - '45-53' # another range - '27' # single inside a list ```

---

Opening from code

```java // From a FileConfiguration: FileConfiguration config = YamlConfiguration.loadConfiguration(file); new ParsedGui(player, config, myPlugin).open(player);

// From a pre-parsed Gui record (more efficient for many players): Gui gui = ...; // parsed once at startup new ParsedGui(player, gui, myPlugin).open(player); ```

---

Runtime placeholders

Use `setReplace()` to inject values into display names, lore, and action lines at runtime. Call it before `open()` — items are built on open.

```java ParsedGui gui = new ParsedGui(player, config, myPlugin); gui.setReplace("%price%", "500") .setReplace("%item_name%", "Diamond Sword"); gui.open(player); ```

In YAML: ```yaml display_name: "<white>Price: <green>$%price%" lore: - " <gray>Item: <white>%item_name%" ```

PlaceholderAPI placeholders (`%papi_placeholder%`) are applied automatically — no extra setup needed.

---

Click handlers from code

Register Java-side click logic for items by their YAML section key. Runs in addition to whatever `on_click` is defined in YAML.

```java ParsedGui gui = new ParsedGui(player, config, myPlugin);

gui.addClickHandler("my_item", event -> { Player clicker = (Player) event.getWhoClicked(); clicker.sendMessage("You clicked my_item!"); gui.refresh(); });

gui.open(player); ```

---

Passing the GUI into actions via ActionContext

When a player clicks an item, `ParsedGui` puts itself into the `ActionContext` automatically. Inside a custom action you can retrieve it:

```java ActionRegistry.register("myplugin", "my_action", (ctx, text) -> { ParsedGui gui = ctx.get(ParsedGui.class); if (gui == null) return;

// do something, then refresh gui.refresh(); }); ```

In config: ```yaml on_click: any: - "[myplugin:my_action]" ```

---

Slot priority & view_requirements

Multiple items can target the same slot. The one with the lowest `priority` value whose `view_requirements` all pass wins. This is useful for conditional items — e.g. show a locked version until the player has enough money.

```yaml Items: buy_locked: material: RED_STAINED_GLASS_PANE slot: 13 priority: 1 display_name: "<red>Not enough money" view_requirements: - "%vault_eco_balance% < 100" # shown when balance < 100

buy_unlocked: material: EMERALD slot: 13 priority: 2 # fallback — shown when locked item's requirement fails display_name: "<green>Buy" ```

`view_requirements` supports `==`, `!=`, `>=`, `<=`, `>`, `<` with both numbers and strings. PlaceholderAPI placeholders are resolved before comparison.

---

Refreshing the GUI

Call `refresh()` to clear and rebuild all items — re-evaluates `view_requirements` and re-applies all placeholders.

```java gui.refresh(); ```

Typically called inside a click handler after state changes: ```java gui.addClickHandler("toggle", event -> { toggleSomething(player); gui.refresh(); }); ```

---

Extending ParsedGui

You can subclass `ParsedGui` to add custom inventory slots, override rendering logic, etc.

> ⚠️ `super(viewer, config, plugin)` calls `buildItems()` internally during construction — before your subclass fields are initialized. Override `buildItems()` with a null-check guard:

```java public class MyGui extends ParsedGui {

private final MyPlugin plugin;

public MyGui(Player viewer, FileConfiguration config, MyPlugin plugin) { super(viewer, config, plugin); this.plugin = plugin; // your init here }

@Override public void buildItems(List<Item> items) { if (plugin == null) { // guard: called from super() before our fields exist super.buildItems(items); return; } // your custom logic, then: super.buildItems(items); }

@Override public void refresh() { // update your replacements before items are rebuilt setReplace("%score%", String.valueOf(getScore())); super.refresh(); } } ```

---

Actions

Actions are config-driven commands executed on a player. Each action is a string in the format `[key] text`.

Built-in actions

| Key | Description | |-----|-------------| | `[message]` | Send a message to the player | | `[broadcast_message]` | Broadcast a message to all players | | `[console]` | Run a command from console | | `[player]` | Run a command as the player | | `[effect]` | Apply a potion effect | | `[action_bar]` | Send an action bar message | | `[broadcast_action_bar]` | Broadcast an action bar to all players | | `[title]` | Send a title to the player | | `[broadcast_title]` | Broadcast a title to all players | | `[sound]` | Play a sound for the player | | `[broadcast_sound]` | Play a sound for all players | | `[open]` | Open a GUI |

Usage

Simple run: ```java ActionExecute.run(ActionContext.of(player), "[message] Hello!"); ```

With extra objects in context: ```java ActionExecute.run( ActionContext.of(player).with(entity), "[myplugin:give_diamond] 64" ); ```

> Extra objects added via `.with()` can be retrieved inside the handler using `ctx.get(YourClass.class)`.

---

Registering a custom action

Custom actions are registered in `onEnable` and unregistered in `onDisable`.

Actions from different plugins can share the same key without conflict — the full key is `namespace:command`:

```yaml

config.yml

actions: - "[plugina:spawn] text" # resolves plugina's spawn - "[pluginb:spawn] text" # resolves pluginb's spawn — no conflict - "[spawn] text" # resolves whichever was registered first ```

Lambda (simple cases)

```java @Override public void onEnable() { ActionRegistry.register("myplugin", "give_diamond", (ctx, text) -> { Player player = ctx.getPlayer(); if (player == null || text == null) return;

int amount = Integer.parseInt(text); player.getInventory().addItem(new ItemStack(Material.DIAMOND, amount)); player.sendMessage("You got " + amount + " diamonds!"); }); }

@Override public void onDisable() { ActionRegistry.unregisterAll("myplugin"); } ```

Class (recommended for complex logic)

Register in `onEnable`: ```java @Override public void onEnable() { ActionRegistry.register("myplugin", "give_diamond", new GiveDiamondAction()); }

@Override public void onDisable() { ActionRegistry.unregisterAll("myplugin"); } ```

Implement `Action`: ```java public class GiveDiamondAction implements Action {

@Override public void execute(@NotNull ActionContext ctx, @Nullable String text) { Player player = ctx.getPlayer(); if (player == null || text == null) return;

// Parse text argument int amount = Integer.parseInt(text); player.getInventory().addItem(new ItemStack(Material.DIAMOND, amount)); player.sendMessage("You got " + amount + " diamonds!");

// Retrieve a custom object from context — null if not provided Entity entity = ctx.get(Entity.class); if (entity == null) return;

entity.teleport(player.getLocation()); ActionExecute.run( ActionContext.of(player), "[message] <red>Entity has been teleported to you" ); } } ```

ActionContext

`ActionContext` is a type-safe container for objects passed into an action. Objects are stored and retrieved by class — no string keys needed.

```java // Put objects in ActionContext ctx = ActionContext.of(player) .with(entity) // store by entity.getClass() .with(myGui); // store by myGui.getClass()

// Get objects out (inside a handler) Entity entity = ctx.get(Entity.class); // null if not provided Entity entity = ctx.require(Entity.class); // throws if not provided ```

If you want to store an object under an interface rather than its concrete class: ```java ctx.with(MyInterface.class, myObject); // retrieve as: ctx.get(MyInterface.class); ```

API

MAVEN

```xml <repository> <id>jetby-repo</id> <url>https://api.jetby.org/</url> </repository> ```

```xml <dependency> <groupId>me.jetby</groupId> <artifactId>Libb</artifactId> <version>VERSION</version> <scope>provided</scope> </dependency> ```

GRADLE

```gradle repositories { maven { url "https://api.jetby.org/" name "jetby-repo" } } ```

```gradle dependencies { compileOnly "me.jetby:Libb:VERSION" } ```

ADS