Developer API
AstralScrolls exposes its state through two services hung off the main plugin instance (plugin.scrolls(), plugin.goals()), one custom Bukkit event, and an item-supplier registration under the scrolls namespace. There is no static ScrollsAPI façade.
Maven coordinates
<dependency>
<groupId>com.astralrealms</groupId>
<artifactId>scrolls</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
Repository: https://maven.astralrealms.fr/repository/maven-public/.
On onEnable, AstralScrolls registers itself with AstralCore's item-supplier registry under the name scrolls:
AstralPaperAPI.registerItemStackSupplier("scrolls", new ScrollItemSupplier(this));
ScrollItemSupplier implements AstralCore's ItemStackSupplier contract, resolving <id> as a rarity id (not a blueprint id):
Method | Behavior |
|---|
get(String id)
| plugin.configuration().findById(id) (a RarityBlueprint) then plugin.scrolls().build(blueprint) — throws IllegalArgumentException if id doesn't match a configured rarity.
|
get(Player player, Key key, int amount)
| Same lookup using key.value(), then sets the built stack's amount to amount. |
completions()
| Every configured rarity id, as Key.key("scrolls", id). |
keyOf(ItemStack itemStack)
| plugin.scrolls().fromItemStack(itemStack) mapped through Scroll::rarity → RarityBlueprint::id → Key.key("scrolls", id), or null if the stack isn't a scroll.
|
# anywhere an item-supplier key is accepted
actions:
- "[give-item] scrolls:legendary"
See Commands.
Accessed via AstralScrolls#scrolls().
import com.astralrealms.scrolls.AstralScrolls;
import com.astralrealms.scrolls.service.ScrollService;
ScrollService scrolls = AstralScrolls.getPlugin(AstralScrolls.class).scrolls();
Method | Returns | Behavior |
|---|
build(RarityBlueprint rarity)
| ItemStack
| Picks a random ScrollBlueprint weighted by that blueprint's chance entry for rarity, then delegates to the two-arg overload. Throws IllegalArgumentException if no loaded blueprint has a requirements entry for the rarity. |
build(ScrollBlueprint blueprint, RarityBlueprint rarity)
| ItemStack
| Rolls a target between blueprint's min/max for rarity, builds a fresh Scroll, renders config.yml's scroll-item template onto rarity's base ItemStackWrapper, tags the PDC, and forces maxStackSize to 1. Throws IllegalArgumentException if blueprint has no requirements entry for rarity. |
update(Player player, Class<T> goalType, E event)
| void
| Advances every incomplete scroll of goalType the player is holding (per the scroll cache) by calling that goal's handle, re-rendering the item, and — on completion — firing ScrollCompletedEvent and running completion-actions. This is what every GoalListener handler calls; see Blueprints & Goals. |
fromItemStack(ItemStack itemStack)
| Optional<Scroll>
| Reads the scroll off the stack's PDC via ScrollDataType, or Optional.empty() if the stack has no meta or no scroll tag. |
isScroll(ItemStack itemStack)
| boolean
| true if the stack's PDC carries a scroll tag at all (completed or not). false for a null /meta-less/empty stack.
|
findById(String id)
| Optional<ScrollBlueprint>
| First loaded blueprint whose id matches, across every blueprints/*.yml file. |
giveReward(Player player, Scroll scroll)
| void
| Draws one RarityBlueprint.RewardGroup from scroll.rarity().rewards() (weighted chance), runs its actions, then scans the player's inventory for the matching scroll (by uniqueId) and removes it. No-op if the reward pool is empty. |
cache(Player player)
| PlayerCache
| The player's memoized scroll-slot map, rebuilt if older than 10 seconds. |
invalidate(UUID playerId)
| void
| Drops the cached entry for a player, forcing a rebuild on next access. Called by CacheListener on quit/drop/pickup/inventory-click/inventory-drag. |
ItemStack scroll = scrolls.build(configuration.findById("common").orElseThrow());
player.getInventory().addItem(scroll);
GoalService
Accessed via AstralScrolls#goals(). A simple string→class registry, seeded in its constructor with the eight built-in goal types (see Blueprints & Goals).
Method | Returns | Behavior |
|---|
registerGoal(String type, Class<? extends ScrollGoal<?>> goalClass)
| void
| Registers (or overwrites) the ScrollGoal class used to deserialize a blueprint's goal.type: "<type>" value. |
findByType(String type)
| Optional<Class<? extends ScrollGoal<?>>>
| Looked up by ScrollBlueprintTypeSerializer while parsing a blueprint's goal: node; a miss throws SerializationException ("Unknown goal type: …") during blueprint loading. |
plugin.goals().registerGoal("custom-goal", CustomGoal.class);
Extends AstralCore's AbstractEvent (supports both sync and async firing). Fired by ScrollService#update the moment a scroll's value reaches its total, before completion-actions runs.
Field | Type | Description |
|---|
player
| Player
| The player whose scroll completed. |
itemStack
| ItemStack
| The scroll's ItemStack, already re-styled with completed-item and glinting. |
scroll
| Scroll
| The completed Scroll (rarity, blueprint, value == total). |
Async or sync depending on the completing thread (!Bukkit.isPrimaryThread()), since update can run from any of the eight goal-tracking listeners. Not cancellable.
@EventHandler
public void onScrollCompleted(ScrollCompletedEvent event) {
event.getPlayer().sendMessage("Scroll " + event.getScroll().rarity().id() + " ready to redeem!");
}
A Scroll is stored on its ItemStack's PersistentDataContainer via ScrollDataType (PersistentDataType<PersistentDataContainer, Scroll>), under the key astralscrolls:scroll. Five sub-keys back the five Scroll fields (astralscrolls:id, :blueprint, :rarity, :total, :value); reading back a stored scroll re-resolves blueprint/rarity against the currently loaded configuration (ScrollService#findById/MainConfiguration#findById) and throws IllegalArgumentException if either id no longer matches a loaded blueprint or rarity.
Last modified: 25 July 2026