# API Reference
Bookshelf-API provides the public interfaces, utilities, and abstractions that other Lodestone plugins use. The API can be consumed either by depending on the Bookshelf plugin at runtime or by shading it directly into your plugin.
---
## Accessing the API
The `BookshelfAPI` class is the static entry point for all API access.
### With Bookshelf Plugin Installed
When the Bookshelf plugin is present on the server, the API is initialized automatically. Access it after your plugin enables:
```java
IBookshelfAPI api = BookshelfAPI.getApi();
IMenuManager menuManager = api.getMenuManager();
ICooldownManager cooldownManager = api.getCooldownManager();
```
### Standalone (Shaded)
If you shade Bookshelf-API into your plugin, initialize it during `onEnable()`. Remember to relocate the package to avoid conflicts.
```java
// Initialize with all managers enabled
BookshelfAPI.init(this);
// Initialize with selective managers
BookshelfAPI.init(this, BookshelfAPI.Builder.create()
.useMenuManager(true)
.useCooldownManager(true)
.useItemManager(false)
.useScoreboardManager(false)
);
```
**Note:** When running standalone, the following managers are only available with the full Bookshelf plugin installed:
- `IChatManager`
- `IGameManager`
- `IPlayerManager`
- `IVanishManager`
Calling these without the plugin throws `UnsupportedOperationException`.
---
## Manager Interfaces
### IMenuManager
Manages player menu registration and retrieval.
```java
IMenuManager menuManager = BookshelfAPI.getApi().getMenuManager();
// Register and open a menu
menuManager.registerAndOpen(player, myMenu);
// Get active menu for a player
Menu activeMenu = menuManager.getActiveMenu(player);
```
| Method | Description |
|---|---|
| `register(Player, Menu)` | Registers a menu for a player. |
| `register(UUID, Menu)` | Registers a menu by UUID. |
| `registerAndOpen(Player, Menu)` | Registers and immediately opens a menu. |
| `getActiveMenu(Player)` | Returns the player's currently active menu. |
| `getActiveMenu(UUID)` | Returns the active menu by UUID. |
### ICooldownManager
Manages timed cooldowns per player or globally.
```java
ICooldownManager cooldowns = BookshelfAPI.getApi().getCooldownManager();
// Set a 5-second cooldown
cooldowns.setCooldown(player, "ability.fireball", 5000);
// Check before executing
if (cooldowns.hasCooldown(player, "ability.fireball")) {
// Player is on cooldown
return;
}
// Set with callback when cooldown expires
cooldowns.setCooldown(player, "ability.fireball", 5000, p -> {
p.sendMessage("Fireball is ready!");
});
// Notify with message if on cooldown (returns true if on cooldown)
cooldowns.notifyPlayerWithCooldown(player, "ability.fireball",
"<red>Fireball is on cooldown!");
```
| Method | Description |
|---|---|
| `setCooldown(Player, String, long)` | Sets a player cooldown in milliseconds. |
| `setCooldown(String, long)` | Sets a global cooldown. |
| `setCooldown(Player, String, long, Consumer<Player>)` | Sets a cooldown with an expiry callback. |
| `hasCooldown(Player, String)` | Checks if a player has an active cooldown. |
| `hasCooldown(String)` | Checks if a global cooldown is active. |
| `getCooldown(Player, String)` | Returns remaining cooldown time in ms. |
| `notifyPlayerWithCooldown(Player, String, Component)` | Sends a message if on cooldown. Returns `true` if on cooldown. |
### ICustomItemManager
Registers and manages custom items.
```java
ICustomItemManager items = BookshelfAPI.getApi().getItemManager();
// Register custom items
items.register(new MyCustomSword(), new MyCustomBow());
// Check if an ItemStack is a specific custom item
boolean isCustom = items.isCustomItem(itemStack, MyCustomSword.class);
boolean isById = items.isCustomItem(itemStack, "my_custom_sword");
// Get an ItemStack from a custom item
ItemStack stack = items.getItemStackById("my_custom_sword");
ItemStack stackByClass = items.getItemStackByClass(MyCustomSword.class);
```
### IScoreboardManager
Manages per-player scoreboards.
```java
IScoreboardManager scoreboards = BookshelfAPI.getApi().getScoreboardManager();
// Add a scoreboard to a player
scoreboards.addPlayer(player, myBoard);
// Start automatic updates (every 20 ticks)
scoreboards.startScoreboard(plugin, 20);
// Change name color for a player
scoreboards.changeColor(viewer, target, NamedTextColor.RED);
```
### IVanishManager (Plugin Only)
Controls player visibility. Requires the full Bookshelf plugin.
```java
IVanishManager vanish = BookshelfAPI.getApi().getVanishManager();
vanish.vanishPlayer(player);
vanish.unvanishPlayer(player);
boolean hidden = vanish.isVanished(player);
```
### IChatManager (Plugin Only)
Controls global chat state. Requires the full Bookshelf plugin.
```java
IChatManager chat = BookshelfAPI.getApi().getChatManager();
chat.setChatMuted(true);
boolean muted = chat.isChatMuted();
boolean canBypass = chat.canPlayerBypassChat(player.getUniqueId());
```
### IGameManager (Plugin Only)
Controls game state. Requires the full Bookshelf plugin.
```java
IGameManager game = BookshelfAPI.getApi().getGameManager();
game.setPVPEnabled(false);
boolean pvp = game.isPVPEnabled();
```
### IPlayerManager (Plugin Only)
Queries player state. Requires the full Bookshelf plugin.
```java
IPlayerManager players = BookshelfAPI.getApi().getPlayerManager();
boolean god = players.hasGodMode(player);
String channel = players.getCurrentChatChannel(player);
```
---
## Menu System
Bookshelf provides a builder-based menu system. Extend `Menu` (which implements `InventoryHolder`) to create interactive inventory GUIs.
### Creating a Menu
```java
public class MyMenu extends Menu {
public MyMenu(Player player) {
super(player);
}
@Override
protected @NotNull TopMenuBuilder getTopMenuBuilder(TopMenuBuilder builder) {
ItemStack background = new ItemBuilder(Material.GRAY_STAINED_GLASS_PANE)
.title(" ")
.build();
return builder
.setTitle("My Custom Menu")
.setRows(3)
.fill(background)
.insertInRow(1, 4, new ItemBuilder(Material.DIAMOND)
.title("<aqua>Click Me")
.build(), event -> {
event.setCancelled(true);
player.sendMessage("You clicked the diamond!");
})
.addCloseAction(event -> {
// Runs when the menu is closed
})
.addOpenAction(() -> {
// Runs when the menu is opened
});
}
@Override
protected @Nullable MenuBuilder getBottomMenuBuilder(MenuBuilder builder) {
return null; // No bottom inventory modification
}
}
```
### Opening a Menu
```java
MyMenu menu = new MyMenu(player);
menu.open();
```
### TopMenuBuilder Methods
| Method | Description |
|---|---|
| `setTitle(String)` | Sets the menu title (supports MiniMessage). |
| `setTitle(Component)` | Sets the menu title as a Component. |
| `setRows(int)` | Sets row count (1-6). |
| `fill(ItemStack)` | Fills all slots with an item. |
| `outline(ItemStack)` | Fills only border slots. |
| `insertInRow(int, int, ItemStack)` | Places an item at a specific row and slot. |
| `insertInRow(int, int, ItemStack, Consumer<InventoryClickEvent>)` | Places an item with a click handler. |
| `buildRow(int, Consumer<RowBuilder>)` | Configures a specific row. |
| `editRow(int, Consumer<RowBuilder>)` | Modifies an existing row. |
| `addOpenAction(Runnable)` | Adds a callback for when the menu opens. |
| `addCloseAction(Consumer<InventoryCloseEvent>)` | Adds a callback for when the menu closes. |
| `addClickAction(Consumer<InventoryClickEvent>)` | Adds a global click callback. |
---
## Configuration Utility
The `Configuration` class wraps `YamlConfiguration` for simplified file access.
```java
Configuration config = new Configuration(plugin, "config.yml");
config.initialize(); // Reads or creates the file
// Read values
String value = config.getString("path.to.value", "default");
int number = config.getInt("path.to.value", 0);
boolean flag = config.getBoolean("path.to.flag", false);
double decimal = config.getDouble("path.to.value", 0.0);
// Write values
config.set("path.to.value", "new value");
config.save();
```
---
## ItemBuilder
A fluent builder for creating `ItemStack` instances.
```java
ItemStack item = new ItemBuilder(Material.DIAMOND_SWORD)
.title("<red>Flame Sword")
.lore("<gray>A burning blade", "<yellow>+10 Fire Damage")
.enchantment(Enchantment.FIRE_ASPECT, 2)
.unbreakable(true)
.modelData(1001)
.flags()
.build();
```
Key methods: `title(String)`, `lore(String...)`, `enchantment(Enchantment, int)`, `amount(int)`, `type(Material)`, `skull(Player)`, `skull(String base64)`, `tag(NamespacedKey)`, `unbreakable(boolean)`, `modelData(int)`, `itemModel(NamespacedKey)`, `maxStackSize(int)`, `trimPattern(TrimPattern)`, `trimMaterial(TrimMaterial)`, `leatherColor(String)`, `potionData(PotionData)`, `glider(boolean)`, `rarity(Object)`.
---
## CustomItem
Extend `CustomItem` to create items with event-driven behavior.
```java
public class FlameSword extends CustomItem {
@Override
public String id() {
return "flame_sword";
}
@Override
public void builder(ItemBuilder builder) {
builder.type(Material.DIAMOND_SWORD)
.title("<red>Flame Sword")
.enchantment(Enchantment.FIRE_ASPECT, 3);
}
@Override
public void onInteract(Player player, PlayerInteractEvent event, ItemStack item) {
player.sendMessage("The blade burns!");
}
@Override
public void onKill(Player player, EntityDeathEvent event, ItemStack item) {
player.sendMessage("Vanquished by fire!");
}
}
```
Available event hooks: `onHeld`, `onUnheld`, `onShift`, `onInteract`, `onRightInteract`, `onLeftInteract`, `onBlockBreak`, `onBlockPlace`, `onFish`, `onHurt`, `onKill`, `onHarvest`, `onShoot`, `onInventoryClick`, `onInventoryPlace`, `onInventoryHotbar`, `onDrop`, `onOffhand`.
---
## Utility Classes
| Class | Description |
|---|---|
| `MiniMessageHelper` | Deserialize/serialize MiniMessage strings, center text, convert legacy codes. |
| `VariableContext` | Template variable replacement. Supports `<var>` and `<<var>>` syntax with formatters. |
| `StringHelper` | String manipulation utilities. |
| `LocationHelper` | Location serialization and math. |
| `EntityHelper` | Entity lookup and manipulation. |
| `InventoryHelper` | Inventory utilities. |
| `ArrayHelper` | Array manipulation. |
| `ByteHelper` | Byte conversion utilities. |
| `EnumHelper` | Enum parsing utilities. |
| `WorldHelper` | World lookup and management. |
| `PlayerLookupHelper` | Online/offline player resolution. |
| `ReflectionHelper` | Reflection utilities. |
| `PackHelper` | Resource pack utilities. |
| `TrueDamageHelper` | Armor-and-enchantment-scaled true damage via `setHealth`. Calibrated against a configurable baseline (default: full Prot III diamond). |
| `PaperCapabilities` | Version-safe access to 1.21.4+ item meta features. |
### MiniMessageHelper Examples
```java
// Deserialize MiniMessage strings
Component msg = MiniMessageHelper.deserialize("<red>Hello <bold>World!");
// With variables
VariableContext ctx = VariableContext.of("player", player.getName());
Component msg = MiniMessageHelper.deserialize("Welcome, <player>!", ctx);
// Center text in chat
MiniMessageHelper.centerAndSend(player, "<gold>Welcome!", new VariableContext());
// Convert legacy formatting
String modern = MiniMessageHelper.convertAmpersandToMiniMessage("&cHello &lWorld");
// Result: "<red>Hello <bold>World"
```
---
## Scoreboard System
Extend `AbstractBoard` to create per-player scoreboards.
```java
public class MyBoard extends AbstractBoard {
public MyBoard(Player player) {
super(player, Component.text("My Server"));
}
@Override
public void update() {
setLineFromList(List.of(
"<gray>Welcome!",
"",
"<aqua>Players: <white>" + Bukkit.getOnlinePlayers().size(),
"<aqua>World: <white>" + player.getWorld().getName(),
"",
"<yellow>lode.gg"
));
}
}
// Register and start
IScoreboardManager scoreboards = BookshelfAPI.getApi().getScoreboardManager();
scoreboards.addPlayer(player, new MyBoard(player));
scoreboards.startScoreboard(plugin, 20); // Update every 20 ticks
```
---
## Related Pages
- [[Bookshelf/Developers/Overview]] - Architecture and module structure
- [[Events]] - Custom event system
- [[Command System]] - Command creation