Astral Realms Documentation Help

Shop Configuration

Every .yml/.yaml file under <plugin-data-folder>/shops/ is one shop. On enable, and again on /shop reload, PaperShopService#load() calls configurationManager().loadFolder(dataPath.resolve("shops"), ShopConfiguration.class), which walks the folder, deserializes each file into one ShopConfiguration, and indexes it by its own id field (not the filename) in an in-memory map. AstralShop ships one example, shops/wood.yml.

Example

id: "wood" title: "Wood shop" slots: - 10 - 11 - 12 - 13 - 14 - 15 - 16 items: oak_wood: buy-price: 5 sell-price: 5 display: material: "OAK_LOG" name: "&6Wood" lore: - "&7This is a piece of wood" buyable: true sellable: true give-item: false buy-actions: - "[console] give %player% oak_log 1" sell-actions: - "[message] not cool to sell."

Top-level fields

Field

Type

Description

id

String

The shop's identifier. Used as the map key shops are stored under and resolved by (e.g. /shop open's <shop> argument, via PaperShopService#findShopById), and read back into every one of its items as their category (see Category).

title

ComponentWrapper

The shop menu's title. A MiniMessage/legacy-formatted string, placeholder-aware like any other ComponentWrapper field.

slots

List<String>

The inventory slot indices this shop's items occupy. Exposed to the shop's menu blueprint as %shop_slots%; AstralShop itself does not consume it — it's the menu blueprint's job to lay items into these slots.

items

Map<String, ShopItem>

The shop's items, keyed by item id. See items entries.

ShopConfiguration also implements ComplexPlaceholder under the shop namespace, chaining id, title, slots, and items (the latter as an item-provider list). See Placeholders.

items entries

Each key under items: becomes one ShopItem; the YAML map key itself (oak_wood above) is captured as the item's id (ShopItemTypeSerializer reads node.key()). Fields, with their ShopItemTypeSerializer defaults:

Field

Type

Default

Description

buy-price

double

0.0

Price to buy one unit, before per-player modifiers. Charged as buy-price * amount.

sell-price

double

0.0

Payout for selling one unit, before modifiers. Paid as sell-price * amount.

display

ItemStack

— (required)

The item's appearance, and the exact ItemStack compared against a player's inventory/hand to detect what they're buying or selling (ItemStack#isSimilar). See display.

buyable

boolean

true

If false, /shop buy flows and the [buy-shop-item] action reject with ITEM_NOT_BUYABLE.

sellable

boolean

true

If false, sell flows (including sell-hand and sell-all) reject with ITEM_NOT_SELLABLE and skip the item in sell-all sweeps.

give-item

boolean

true

If true, buying adds a clone of display (amount set) to the buyer's inventory. If false, nothing is given — buy-actions runs instead. See buy-actions and sell-actions.

buy-actions

AstralCore action list

none

Run on a successful buy, in place of the item grant when give-item is false.

sell-actions

AstralCore action list

none

Run on a successful sell, in addition to the normal payout and item removal.

display

display is a standard Bukkit ItemStack — the shipped example only sets material, name, and lore:

Field

Description

material

A Material name (e.g. OAK_LOG).

name

Legacy &-code or MiniMessage display name.

lore

List of lore lines.

AstralCore's ItemStack deserializer also accepts amount, enchantments (Map<String, int>), unbreakable, max-stack-size, enchantment-glint-override, custom-model-data, and item-flags — none of which wood.yml uses. This item stack is resolved once at load time; it is not placeholder-aware the way a menu's item-stack block is (see Menu Items).

buy-actions and sell-actions

Both are AstralCore action lists — "[action-id] args" strings run through PaperActionFactory, exactly like any other action list in the ecosystem. See Actions for the full catalogue of action ids (e.g. [console], [message], [give-item]).

  • Buy: if give-item is true, buy-actions is never run — the configured item is granted directly instead. If give-item is false, the item is not granted and buy-actions runs in its place.

  • Sell: sell-actions always runs after a successful sale (payment deposited, items removed from the seller's inventory) — it isn't a substitute for anything and can be omitted entirely.

Category (shop id on items)

ShopItemTypeSerializer reads the enclosing shop's id back (node.parent().parent().node("id")) and stores it on every ShopItem as shopId. ModifierService uses this as the "category" a ShopCategoryModifier targets, letting a per-player price modifier apply to every item in a shop rather than one specific item. See Per-player price modifiers.

/shop open <player> <shop> (and the [buy-shop-item]/[sell-shop-item] action flows) render a shop through MenuService#openShopMenu, which opens AstralCore's MenuContainer menu id shop (container.computeAndOpen(player, "shop", Map.of("shop", configuration))) — the clicked-or-opened ShopConfiguration is handed to the menu blueprint as its shop parameter, resolvable via %shop_*%/%item_*% placeholders.

AstralShop's own menus/ folder ships empty — it does not include a menus/shop.yml blueprint. A menu blueprint with id shop must be authored under the server's menus/ folder (Menu YAML format, see Menu Items) for /shop open to render anything; without one, opening a shop fails with IllegalArgumentException: Menu blueprint with id 'shop' not found.

Reloading

/shop reload (permission shop.command.reload) calls AstralShop#loadConfiguration(), which re-runs, in order:

  1. shops.load() — reloads every file under shops/.

  2. menus.load() — reloads every menu blueprint under menus/.

  3. loadEnum("messages.yml", ShopMessages.class) — reloads messages.yml.

See Commands for the full /shop command reference.

No config.yml

AstralShop has no config.yml — the shop files under shops/ and messages.yml are the only shipped configuration.

Last modified: 25 July 2026