> For the complete documentation index, see [llms.txt](https://edseries-plugins.gitbook.io/p/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://edseries-plugins.gitbook.io/p/pinnablockselector/reference/api.md).

# Developer API

Add the jar as a `provided` dependency and `softdepend: [PinnaBlockSelector]` (or `depend`) in your plugin.yml.

Only the `es.edwardbelt.pinnablockselector.api` package is public API. Every other class of the plugin may be renamed or changed between versions (and is obfuscated in released jars), so never import or reflect into them.

## PinnaBlockSelectorAPI

All methods are static and safe to call while the plugin is off (reads return false / empty / null / 0, changes do nothing). Reads work from any thread; methods that change something must run on the main thread and throw `IllegalStateException` otherwise.

| Method                                                   | What it does                                                                                                                                                                                                |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `available()`                                            | PinnaBlockSelector runs                                                                                                                                                                                     |
| `hasUnlocked(OfflinePlayer)`                             | has the Block Selector (bought, given or the rank permission; offline: as of their last join)                                                                                                               |
| `hasPurchased(UUID)`                                     | bought or given for good                                                                                                                                                                                    |
| `getSelectedBlocks(UUID)`                                | the blocks applied to their mine, in slot order (empty = tier blocks); works offline                                                                                                                        |
| `getMineBlockWeights(UUID)`                              | the weighted `block-types` map their mine uses (chosen blocks + extra blocks), or null                                                                                                                      |
| `getChoosableBlocks()`                                   | every block that can be chosen                                                                                                                                                                              |
| `getAvailableBlocks(Player)`                             | the blocks this player may choose (without locked categories they lack)                                                                                                                                     |
| `isChoosable(Material)`, `canChoose(Player, Material)`   | block checks                                                                                                                                                                                                |
| `getMaxBlocks()`                                         | `max-blocks`                                                                                                                                                                                                |
| `getCategories()`, `getCategory(id)`                     | the categories (`SelectorCategory`: `id()`, `name()`, `icon()`, `blocks()`, `permission()`, `locked()`)                                                                                                     |
| `getApplyCooldown(Player)`                               | milliseconds until they may apply again in the menu                                                                                                                                                         |
| `unlock(OfflinePlayer)`                                  | unlock for good (works offline); false when they already bought it                                                                                                                                          |
| `revoke(OfflinePlayer)`                                  | take a bought / given unlock away (the rank permission still counts)                                                                                                                                        |
| `setSelectedBlocks(OfflinePlayer, Collection<Material>)` | set their blocks (no cooldown, no category permissions; invalid blocks and duplicates dropped, cut at `max-blocks`); refills an online player's mine. False when they don't have it or a listener cancelled |
| `clearSelectedBlocks(OfflinePlayer)`                     | back to the tier blocks                                                                                                                                                                                     |
| `openMenu(Player)`, `openMenu(Player, categoryId)`       | open the selector (or the purchase menu while locked)                                                                                                                                                       |

```java
if (Bukkit.getPluginManager().isPluginEnabled("PinnaBlockSelector")) {
    List<Material> blocks = PinnaBlockSelectorAPI.getSelectedBlocks(player.getUniqueId());
    if (!PinnaBlockSelectorAPI.hasUnlocked(player)) PinnaBlockSelectorAPI.unlock(player);
    PinnaBlockSelectorAPI.setSelectedBlocks(player, List.of(Material.STONE, Material.DIAMOND_ORE));
}
```

## Events

All in `es.edwardbelt.pinnablockselector.api`.

| Event                        | When                                                                                                                                                                                                                                                                                                                  |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BlockSelectionChangeEvent`  | a player's applied blocks are about to change. `getPlayerId()`, `getPlayer()` (null offline), `getPreviousBlocks()`, `getNewBlocks()`, `getCause()` (`MENU`, `COMMAND`, `API`, `REVOKED`, `RESET`). Cancellable, except `REVOKED` and `RESET` (`isCancellable()`). Main thread, except a `RESET` of an offline player |
| `BlockSelectorPurchaseEvent` | a player confirmed the in-game purchase, before their balance is checked. `getCurrency()`, `getPrice()`, `setPrice(BigDecimal)` (discounts, `ZERO` = free). Cancellable (send your own message)                                                                                                                       |
| `BlockSelectorUnlockEvent`   | the Block Selector was unlocked for good. `getPlayerId()`, `getPlayer()` (null offline), `getSource()` (`PURCHASE`, `COMMAND`, `API`). Not fired for the rank permission                                                                                                                                              |

## Without the API

Stores, crates and votes don't need code: run `blockselector give <player> -s` from the console, and check `%pinnablockselector_owned%`.
