▶️ ЗАБЕРИ СВОИ 8 ПОДАРКОВ 🎁 ПРИ СОЗДАНИИ СВОЕГО МАЙНКРАФТ СЕРВЕРА
Libb

Libb

Easy util for Minecraft Gui, Command, Action

2
0

Libb

A library for convenient and easy creation of Minecraft plugins.


Requirements:

Java: 17
Paper
Minecraft version: 1.20 and higher

GUI

Example

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():

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

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:

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

Opening from code

// 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.

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

In 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.

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:

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:

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.

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.

gui.refresh();

Typically called inside a click handler after state changes:

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:

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

KeyDescription
[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:

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

With extra objects in context:

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:

# 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)

@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:

@Override
public void onEnable() {
    ActionRegistry.register("myplugin", "give_diamond", new GiveDiamondAction());
}

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

Implement Action:

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.

// 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:

ctx.with(MyInterface.class, myObject);
// retrieve as:
ctx.get(MyInterface.class);

API

MAVEN
<repository>
  <id>jetby-repo</id>
  <url>https://api.jetby.org/</url>
</repository>
<dependency>
  <groupId>me.jetby</groupId>
  <artifactId>Libb</artifactId>
  <version>VERSION</version>
  <scope>provided</scope>
</dependency>
GRADLE
repositories {
    maven {
        url "https://api.jetby.org/"
        name "jetby-repo"
    }
}
dependencies {
    compileOnly "me.jetby:Libb:VERSION"
}

Совместимость

Minecraft: Java Edition

26.1.x1.21.x1.20.x

Платформы

Поддерживаемые окружения

Сервер

Детали

Лицензия:MIT
Опубликован:1 неделю назад
Обновлён:1 неделю назад
Главная