Developer API
AstralShop exposes buy/sell eligibility and pricing to other plugins through the AstralCore ShopService SPI, lets other plugins grant per-player price adjustments through the static ShopAPI façade, and fires cancellable Bukkit events around every purchase and sale.
Maven coordinates
Repository: https://maven.astralrealms.fr/repository/maven-public/.
ShopService
ShopService is an AstralCore SPI interface (com.astralrealms.core.paper.service.ShopService extends AstralService) implemented by PaperShopService and registered on AstralPaperAPI when AstralShop enables:
Other plugins resolve it without depending on any AstralShop class:
Method | Returns | Notes |
|---|---|---|
|
|
|
|
| Same check against |
|
|
|
|
|
|
|
| Same lookup, then runs the result through |
|
| Same, for |
All six methods scan every currently loaded shop's items and match by ItemStack#isSimilar, not by shop/item id — the same rule the /sellhand command uses to find what a held item sells as.
ShopAPI
ShopAPI (com.astralrealms.shop.ShopAPI) is a static utility, initialized in AstralShop#onEnable right after the services are constructed. It is the only supported way for another plugin to grant, revoke, or query a player's price modifiers.
Method | Returns | Notes |
|---|---|---|
|
| Stores the modifier under its own |
|
| No-op if the player has no modifier under that key. |
|
|
|
Modifiers
A ShopModifier (com.astralrealms.shop.model.modifier.ShopModifier) is a plain data class:
Two subclasses narrow which items a modifier applies to; a bare ShopModifier applies to everything matching its scope across every shop:
Class | Extra field | Applies to |
|---|---|---|
| — | Every item in every shop, subject only to |
|
| Every item within the shop whose |
|
| Only the item whose |
ShopModifierType
Value | Effect |
|---|---|
| Contributes to a summed scalar applied as |
| Added directly to the running total before the relative scalar is applied. |
ShopModifierScope
Value | Matches |
|---|---|
| Only sell-price computations. |
| Only buy-price computations. |
| Not itself matched against — |
Price formula
ModifierService#computePrice filters the player's stored modifiers to those that:
Have
scopeequal to the transaction's scope (BUYorSELL).Are not a
ShopCategoryModifierwith a differentcategoryIdthan the shop being bought/sold from.Are not a
ShopItemModifierwith a differentitemIdthan the item being bought/sold.
The surviving modifiers are then folded into the base price (item.buyPrice() or item.sellPrice(), already multiplied by the transaction amount) by ModifierService#computeModifiers:
ABSOLUTE values accumulate into the running total first; RELATIVE values accumulate into a separate scalar that scales the whole total (base plus absolutes) at the end. Order of modifier registration does not matter — only the final sums do.
Storage and lifecycle
Modifiers are held entirely in memory, in a ConcurrentHashMap<UUID, PlayerModifiers> inside ModifierService, keyed by player UUID and then by the modifier's own Key (so re-adding a modifier under the same Key overwrites the previous one). They are not persisted to disk or through AstralSync. ModifiersListener clears a player's entire modifier map on PlayerQuitEvent:
Any modifier granted by another plugin only lasts for the remainder of that play session unless the granting plugin re-applies it (e.g. on PlayerJoinEvent) every time the player reconnects.
Events
ShopEvent (com.astralrealms.shop.event.ShopEvent) is an abstract, cancellable Bukkit event (extends AbstractCancellableEvent implements Cancellable) that both concrete shop events extend:
Accessor | Type | Notes |
|---|---|---|
|
| The buyer/seller. |
|
| The shop the item belongs to. |
|
| The item being bought/sold. |
|
| The quantity involved. |
|
| The computed price (post-modifiers). Mutable — overriding it changes what's actually charged/paid. |
|
| Standard Bukkit |
ShopBuyEvent
Fired by PaperShopService#buy after the item/eligibility checks and price computation, but before the EconomyService#withdraw call and before the item (or buy-actions) is granted. Cancelling it stops the purchase entirely — no funds are withdrawn and nothing is given.
ShopSellEvent
Fired by PaperShopService#sell after eligibility/inventory checks and price computation, but before EconomyService#deposit, before the items are removed from the seller's inventory, and before sell-actions run. Cancelling it stops the sale entirely.
Both events construct with isAsync = false, so handlers always run on the main thread and are safe to touch other Bukkit API from.
ShopItem type serializer
ShopItem is registered as a Configurate TypeSerializer<ShopItem> (ShopItemTypeSerializer) via registerTypeSerializer in AstralShop#onEnable:
The serializer only implements deserialize — it reads an item's node key as its id, buy-price, sell-price, display, buyable, sellable, give-item, buy-actions, and sell-actions, and derives shopId by walking up to the enclosing shop file's id node (node.parent().parent().node("id")). serialize is unimplemented and throws UnsupportedOperationException("Serialization of ShopItem is not supported.") — ShopItem values can only be read from config, never written back out through Configurate. See Shop Configuration for the full YAML shape this serializer reads.
Where to go next
Overview — how shops, items, and modifiers fit together.
Shop Configuration — the
ShopConfiguration/ShopItemYAML shape.Commands —
/shop,/sellall,/sellhand.Actions —
[buy-shop-item],[sell-shop-item],[sell-all].Placeholders —
%shop_*%/%item_*%, including the modifier-aware%item_buyPrice%/%item_sellPrice%sub-keys.