# 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