Overview
AstralScrolls turns "scrolls" — single-stack ItemStacks tagged with a hidden goal — into a progress-to-reward item type. A player receives a scroll of a given rarity, carries out whatever in-game goal the scroll rolled (break N blocks, kill N mobs, travel N blocks, …), and once the goal is met, right-clicking the completed scroll consumes it and grants a weighted-random reward from that rarity's reward pool.
What it does
A scroll is one
ScrollBlueprint+ oneRarityBlueprint. When a scrollItemStackis built,ScrollService#buildpicks a randomScrollBlueprint(weighted by that blueprint'schancefor the target rarity), rolls a random requirement amount between that blueprint/rarity pair'smin/max, and stores the result — id, rarity, blueprint, target, current progress — directly on the item'sPersistentDataContainervia a customPersistentDataType(ScrollDataType). The item itself is the only place scroll state lives; there is no separate player-progress database.Progress is tracked by listening to the matching Bukkit event. Each
ScrollBlueprintcarries aScrollGoal<E>— one of eight goal types (see Blueprints & Goals) — which is itself a per-event handler.GoalListenerlistens to all eight underlying Bukkit events atMONITORpriority and asksScrollService#updateto advance every scroll the player is currently holding whose blueprint's goal matches that event type.A per-player cache avoids scanning every inventory slot on every event.
ScrollService#cachememoizes, per player, which inventory slots hold an active (incomplete) scroll and which goal classes are in play, rebuilding it after 10 seconds or wheneverCacheListenersees an inventory-changing event (quit, drop, pickup, inventory click/drag) that could have moved a scroll.Completion re-tags the item and fires an event. When a goal update brings a scroll's
valueto (or past) itstotal,ScrollService#updatere-styles theItemStackwithcompleted-item(fromconfig.yml), adds a fake enchant glint, callsScrollCompletedEvent, and — ifcompletion-actionsis configured — runs that action list.Redeeming is a right-click.
ItemListenerinterceptsPlayerInteractEventfor any held item that resolves to a completed scroll: it cancels the interaction and callsScrollService#giveReward, which rolls oneRarityBlueprint.RewardGroup(weighted bychance), runs its actions, and removes the scroll from the player's inventory.Scrolls can't be placed as blocks.
ItemListenercancelsBlockPlaceEventfor any item stack that resolves to a scroll (completed or not).
Requirements
Dependency | Required | Notes |
|---|---|---|
Paper 1.21+ | Yes |
|
AstralCore | Yes | Declared in |
Configuration & commands
config.yml holds the scroll-item/completed-item display templates, the rarities map (display name, color, base ItemStackWrapper, and reward pool per rarity), and an optional completion-actions list run whenever any scroll finishes. Scroll definitions — the goal + per-rarity requirement chances/ranges — live one-or-more-per-file under blueprints/ (the plugin ships example.yml). See Configuration and Blueprints & Goals.
The only command is /scrolls, with give, rewards, and reload subcommands. There is no dedicated "buy a scroll" flow — scrolls are handed out via /scrolls give, the [give-item] action, or any other AstralCore call site that accepts an item-supplier key, using the scrolls:<rarity-id> namespace the plugin registers on enable. See Commands and Developer API.
See also
Blueprints & Goals — the
blueprints/*.ymlschema and all eightScrollGoaltypes.Placeholders — the
%scroll_*%and%rarity_*%namespaces.Messages —
messages.yml, including the goal-type-name labels used in item lore.Developer API —
ScrollService,GoalService,ScrollCompletedEvent, and thescrolls:<id>item-supplier namespace.