Skip to content

Latest commit

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Libb

A library for convenient and easy creation of Minecraft plugins.


Requirements:

Java: 21+
Paper
Minecraft version: 1.20 and higher

GUI

Example

publicclassGuiTestextendsAdvancedGui {
publicGuiTest() {
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():

newGuiTest().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_guititle: "<gold>My Shop"size: 54# must be a multiple of 9on_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: DIAMONDslot: 13# single slotdisplay_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 slotslots:
- '0-8'# range
- '45-53'# another range
- '27'# single inside a list

Opening from code

// From a FileConfiguration:FileConfigurationconfig = YamlConfiguration.loadConfiguration(file);
newParsedGui(player, config, myPlugin).open(player);
// From a pre-parsed Gui record (more efficient for many players):Guigui = ...; // parsed once at startupnewParsedGui(player, gui, myPlugin).open(player);

Runtime placeholders

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

ParsedGuigui = newParsedGui(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.

ParsedGuigui = newParsedGui(player, config, myPlugin);
gui.addClickHandler("my_item", event -> {
Playerclicker = (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) -> {
ParsedGuigui = ctx.get(ParsedGui.class);
if (gui == null) return;
// do something, then refreshgui.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_PANEslot: 13priority: 1display_name: "<red>Not enough money"view_requirements:
- "%vault_eco_balance% < 100"# shown when balance < 100buy_unlocked:
material: EMERALDslot: 13priority: 2# fallback — shown when locked item's requirement failsdisplay_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:

publicclassMyGuiextendsParsedGui {
privatefinalMyPluginplugin;
publicMyGui(Playerviewer, FileConfigurationconfig, MyPluginplugin) {
super(viewer, config, plugin);
this.plugin = plugin;
// your init here
}
@OverridepublicvoidbuildItems(List<Item> items) {
if (plugin == null) { // guard: called from super() before our fields existsuper.buildItems(items);
return;
}
// your custom logic, then:super.buildItems(items);
}
@Overridepublicvoidrefresh() {
// update your replacements before items are rebuiltsetReplace("%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.ymlactions:
- "[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)

@OverridepublicvoidonEnable() {
ActionRegistry.register("myplugin", "give_diamond", (ctx, text) -> {
Playerplayer = ctx.getPlayer();
if (player == null || text == null) return;
intamount = Integer.parseInt(text);
player.getInventory().addItem(newItemStack(Material.DIAMOND, amount));
player.sendMessage("You got " + amount + " diamonds!");
});
}
@OverridepublicvoidonDisable() {
ActionRegistry.unregisterAll("myplugin");
}

Class (recommended for complex logic)

Register in onEnable:

@OverridepublicvoidonEnable() {
ActionRegistry.register("myplugin", "give_diamond", newGiveDiamondAction());
}
@OverridepublicvoidonDisable() {
ActionRegistry.unregisterAll("myplugin");
}

Implement Action:

publicclassGiveDiamondActionimplementsAction {
@Overridepublicvoidexecute(@NotNullActionContextctx, @NullableStringtext) {
Playerplayer = ctx.getPlayer();
if (player == null || text == null) return;
// Parse text argumentintamount = Integer.parseInt(text);
player.getInventory().addItem(newItemStack(Material.DIAMOND, amount));
player.sendMessage("You got " + amount + " diamonds!");
// Retrieve a custom object from context — null if not providedEntityentity = 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 inActionContextctx = ActionContext.of(player)
.with(entity) // store by entity.getClass()
.with(myGui); // store by myGui.getClass()// Get objects out (inside a handler)Entityentity = ctx.get(Entity.class); // null if not providedEntityentity = 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>JetbyMC</id>
<url>https://api.jetby.org/</url>
</repository>
<dependency>
<groupId>org.jetby.libb</groupId>
<artifactId>api</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
GRADLE
repositories {
maven {
url "https://api.jetby.org/"
name "JetbyMC"
}
}
dependencies {
compileOnly "org.jetby.libb:api:1.2"
}

About

Easy util for Minecraft Gui, Command, Action

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages