Overview
AstralPlayerShops turns any un-blacklisted container into a player-run chest shop. A player sneak-right- clicks a container while holding the item they want to trade, sets a price and a direction (buy or sell) in a creation dialog, and the plugin auto-places a sign and a floating item hologram over the chest. Shops can only be created on land claimed by an AstralTown town — the plugin refuses creation outside a town regardless of whether the shop is town-shared or purely personal.
What it does
Two shop types (
ShopType): BUY — the owner stocks the chest and sells items to players; SELL — the owner buys items from players, paying them and depositing the items into the chest.Zero-command placement. Sneak-right-click a container holding the traded item; a creation dialog collects the price, type, and (if the block sits in a town) whether the shop is town-shared and whether its proceeds route through the town bank.
Visual presentation. An
OAK_WALL_SIGNis auto-placed on the container's facing side with configurable lines (config.yml: sign), refreshed on trade, inventory close, and a periodic chunk-tick sweep. A floating item is rendered above the chest as a packet-onlyPacketItem— no real entity is spawned.Persistence & caching. Shops and their transactions live in MariaDB (
shops,transactions); each shop row is tagged with the creating server'sserver_id. Shops are cached in memory (by UUID and by chunk key) once loaded, and transaction/recap/stats lookups are cached with Caffeine.Town integration. A shop can be marked town-shared (any town member with the
USE_PLAYER_SHOPSpermission may trade at it, not just the owner) and/or routed through the town's economy account (requiresBANK_WITHDRAW); creating in a town at all requiresBLOCK_PLACE.Away recaps. Trades gate an in-game chat ping to the owner on the owner's own recap preference (
PSPlayerData.recapEnabled, synced via AstralSync). Absent owners get an automatic recap prompt on login; anyone can pull one on demand with/ps recap.Custom-item aware. Stock counting, removal, and insertion (
ContainerUtils) understand AstralItems custom items, AstralPets items, and AstralScrolls scrolls, so a shop for a custom item only matches that exact item, not the base material.
Requirements
Dependency | Required | Notes |
|---|---|---|
Paper 1.21+ | Yes |
|
AstralCore | Yes | Dialogs, menus, actions, placeholders, configuration, database, mailbox, economy service. |
AstralTown | Yes | Town lookup/permissions gate shop creation, town-shared trading, and town-economy routing. |
AstralSync | Yes | Persists |
AstralItems | Yes | Custom-item identity used when matching stock in |
AstralPets | Yes | Pet items are matched by their custom type, not raw material. |
AstralScrolls | Yes | Scrolls are matched by their custom type, not raw material. |
MariaDB / PostgreSQL | Yes | Two tables: |
Architecture at a glance
Storage at a glance
ShopRepository loads every shop for the current server_id at startup into an in-memory map keyed by UUID plus a chunk-key index, refreshed as chunks load/unload; TransactionRepository and TransactionService layer Caffeine caches (5-minute access expiry) over per-shop transaction history, per-shop daily/weekly ShopStats, and per-player recap aggregates. A week-old transaction sweep runs every 12 hours.
Where to go next
Configuration —
config.ymlkeys: recap interval, shop limits, sign lines, blacklisted containers, ignored items, chunk-update tuning.Commands —
/pssubcommands.Shops — creation flow, trading, editing, deletion, sign/hologram mechanics in depth.
Activity Recaps — away recap and
/ps recapin depth.Actions — the seven registered AstralCore actions.
Placeholders —
%shop_*%,%entry_*%,%stats_*%,%transaction_*%,%playershops_*%.Developer API —
PlayerShopPreCreateEvent,PlayerShopCreateEvent,PlayerShopRemoveEvent, and the service getters exposed offAstralPlayerShops.