Astral Realms Documentation Help

Actions

AstralPlayerShops#onEnable registers seven AstralCore actions — the [action-id] <argument> ... bracket syntax usable anywhere the configuration layer accepts an actions: list (menu items, dialog buttons, event hooks).

Six are registered with the plain, plugin-scoped registerAction:

Map.of( "create-playershop", CreateShopAction.class, "edit-playershop", EditShopAction.class, "open-playershops-transactions", OpenShopTransactionsAction.class, "open-playershops-container", OpenShopContainerAction.class, "buy-playershop-item", BuyShopItemAction.class, "sell-playershop-item", SellShopItemAction.class ).forEach(this::registerAction);

toggle-playershops-recap is registered separately with registerActionGlobally. AstralCore's action registry checks a plugin's own registrations first and falls back to the shared global registry, so the six registerAction entries only resolve inside menu/dialog configuration that AstralPlayerShops itself parses, while toggle-playershops-recap resolves from any plugin's action list — it can be wired into a cross-plugin settings menu alongside other AstralSync-backed notification toggles.

Every argument is declared as a PlaceholderWrapper record component and resolved with context.parseWrapper(...) (or the equivalent wrapper.get(context)) when the action runs. Simple types (Integer, Boolean, ShopType) accept a literal or a %placeholder%; object types (Location, ItemStack, PlayerShop, UUID) can only resolve through a %placeholder% that the caller's context already exposes as that object — e.g. %shop% (a PlayerShop, exposed wherever a shop object is placed in the menu/dialog context — see Placeholders), or %item%/%location%, which the shop-creation flow puts directly into the "playershops-creation" dialog's context. The action always acts on context.executor() — there is no separate "target player" argument.

create-playershop

Creates a shop on the container the executor is standing at, wrapping ShopService#create.

Arg

Type

Description

location

Location placeholder

The container's block location.

item

ItemStack placeholder

The item the shop trades. Cloned and reduced to a stack of 1 before creation.

type

ShopType placeholder

BUY (owner sells to players) or SELL (owner buys from players).

price

Integer placeholder

Price per unit.

town-shared

Boolean placeholder

Whether other town members with USE_PLAYER_SHOPS may trade at the shop.

town-economy

Boolean placeholder

Whether proceeds route through the town's bank account instead of the owner's own balance.

# wired into the "playershops-creation" dialog's confirm button — %location% and %item% come from # the block the player right-clicked and the item they were holding; the remaining four values are # supplied by the dialog's own price/type/toggle inputs (shown here as literals) - "[create-playershop] %location% %item% BUY 100 false false"

If town-economy is true, the action looks up the town at location and requires the executor to hold BANK_WITHDRAW there; if there is no town or the check fails, it sends NO_WITHDRAWAL_PERMISSION and stops — no shop is created, and ShopService#create is never called. If town-economy is false this check is skipped at the action level, but ShopService#create unconditionally requires the block to sit inside a town regardless of town-shared/town-economy (sends AstralTown's ERROR_OCCURRED otherwise) and separately re-validates the owner's shop limit, that no shop already exists at that location, and fires the cancellable PlayerShopCreateEvent — see Shops and Developer API. On success the action sends SHOP_CREATED with the item and %price% substituted; on an unexpected exception it logs the error and sends CREATION_FAILED. If ShopService#create itself rejects the shop (limit reached, duplicate location, cancelled event), it has already messaged the player and the action sends nothing further.

edit-playershop

Updates an existing shop's price, type, town-shared flag, and economy routing, wrapping ShopService#update.

Arg

Type

Description

shop

PlayerShop placeholder

The shop to edit, e.g. %shop%.

type

ShopType placeholder

New BUY/SELL type.

price

Integer placeholder

New price per unit.

town-shared

Boolean placeholder

New town-shared flag.

town-economy

Boolean placeholder

New economy-routing flag.

- "[edit-playershop] %shop% SELL 150 true true"

Requires shop.hasPermission(executor) — true for the shop's owner, for a playershops.admin holder, or (since the check is the same one interaction/edit/manage all share) for any town member holding USE_PLAYER_SHOPS if the shop is already town-shared. Failing that sends NOT_OWNER. If town-economy is true, it separately requires the executor to hold the town's BANK_WITHDRAW at the shop's location (NO_WITHDRAWAL_PERMISSION otherwise) — same guard as create-playershop. Passing both checks, the action applies an optimistic update: it writes the new price/type/town-shared directly onto the in-memory PlayerShop, and either resolves the shop's town UUID as the new economyAccount (when town-economy is true) or clears economyAccount to null (routing sales to the owner's own balance) — all before the database write completes. If ShopService#update fails, all four fields are rolled back to their pre-edit values, the error is logged, and SHOP_UPDATE_FAILED is sent. On success, ShopService#refreshShop runs (updates the sign/hologram) and SHOP_UPDATE_SUCCESS is sent with the shop placeholder.

buy-playershop-item

Buys amount units from shop, on behalf of the executor.

Arg

Type

Description

shop

PlayerShop placeholder

The shop to buy from, e.g. %shop%.

amount

Integer placeholder

Quantity to buy.

- "[buy-playershop-item] %shop% 1"

Calls ShopService#buy(player, shop, shop.location().getBlock(), amount) directly — the same overload InteractionListener drives when a non-owner right-clicks a BUY-type shop, which opens the "playershops-buy" menu that this action is typically wired into. The action performs no clamping itself: a non-positive amount is a silent no-op, and ShopService#buy re-validates the chest still holds at least amount, transfers price * amount from the buyer to shop.economyAccount(), re-checks stock again on the main thread, removes the items (custom-item aware via ContainerUtils), delivers them to the player (falling back to the mailbox if their inventory is full), refreshes the sign, sends PURCHASE_SUCCESS, notifies the owner with BUY_NOTIFICATION if their recap preference is enabled, and records the sale — see Shops and Activity Recaps.

sell-playershop-item

Sells up to amount units of shop's item, out of the executor's inventory, into shop.

Arg

Type

Description

shop

PlayerShop placeholder

The shop to sell into, e.g. %shop%.

amount

Integer placeholder

Quantity to sell.

- "[sell-playershop-item] %shop% 1"

Unlike buy-playershop-item, this action clamps before calling the service: it first caps amount down to how many matching items the executor's inventory actually holds, then — back on the main thread — checks the chest has enough empty capacity for that (already inventory-clamped) amount; if it doesn't, it sends CHEST_FULL and aborts entirely rather than selling a partial quantity. Only then does it call ShopService#sell(player, shop, chestBlock, finalAmount) — the same overload the "playershops-sell" menu uses — which independently re-validates chest space and inventory count before transferring funds and items.

open-playershops-container

Opens the shop's backing container inventory for the executor.

Arg

Type

Description

shop-id

UUID placeholder

The shop's %shop_id%.

- "[open-playershops-container] %shop_id%"

Looks up the shop by UUID via ShopService#findByUniqueId, resolves the block at the shop's stored coordinates in the executor's current world, and opens its inventory if that block is a Container (chest, barrel, shulker box, etc.). If the shop id doesn't resolve, or the block is no longer a container, sends UNEXPECTED_ERROR. There is no ownership check in the action itself — gate access through the menu button's own requirements (this action is the natural fit for a management button inside the "playershops-main" menu, which is only opened for players shop.hasPermission already approved — see InteractionListener).

open-playershops-transactions

Opens the shop's transaction history menu for the executor.

Arg

Type

Description

shop-id

UUID placeholder

The shop's %shop_id%.

- "[open-playershops-transactions] %shop_id%"

Looks up the shop by UUID via ShopService#findByUniqueId and, if found, calls MenuService#openTransactionHistoryMenu, which loads the shop's transactions and opens the "playershops-history" menu with shop and transactions in its context. If the shop id doesn't resolve, sends UNEXPECTED_ERROR. As with open-playershops-container, there is no permission check in the action itself.

toggle-playershops-recap

Toggles the executor's away-recap notification preference. No arguments.

- "[toggle-playershops-recap]"

Registered globally (see above), so this is callable from any plugin's menu/dialog configuration, not just AstralPlayerShops's own. Looks up the executor's PSPlayerData via SyncAPI#findData; if present, flips recapEnabled and sends RECAP_ENABLED or RECAP_DISABLED to match the new state. If the player's synced data isn't loaded, sends UNEXPECTED_ERROR instead. The resulting state is exposed back for rendering a toggle button via %playershops_recapNotification% — see Placeholders and Activity Recaps.

Action Summary Table

ID

Scope

Arguments

Effect

create-playershop

Local

location item type price town-shared town-economy

Creates a shop on the given container.

edit-playershop

Local

shop type price town-shared town-economy

Updates an existing shop's price/type/sharing/economy routing.

buy-playershop-item

Local

shop amount

Buys amount from shop for the executor.

sell-playershop-item

Local

shop amount

Sells up to amount of shop's item, from the executor's inventory.

open-playershops-container

Local

shop-id

Opens the shop's backing container inventory.

open-playershops-transactions

Local

shop-id

Opens the shop's "playershops-history" transaction menu.

toggle-playershops-recap

Global

(none)

Toggles the executor's recap notification preference.

See also

  • AstralCore Actions — the [action-id] <argument> <param=value> syntax and global delay/async parameters shared by every action on the network.

  • Shops — the creation, buy/sell, and editing mechanics these actions wrap.

  • Activity Recaps — the recap preference toggle-playershops-recap flips.

  • Placeholders%shop%/%shop_*%, %playershops_recapNotification%, and the other context placeholders these actions consume.

  • Developer APIPlayerShopCreateEvent and friends, fired underneath create-playershop.

  • Commandsplayershops.admin, which also bypasses the edit-playershop ownership check.

Last modified: 25 July 2026