Configuration
plugins/AstralPlayerShops/ holds config.yml (recap window, per-player shop limits, sign lines, the container/item restrictions, and the periodic sign-refresh task) and database.properties (the JDBC/HikariCP connection pool). Both are loaded into the PSConfiguration record on startup, and config.yml is re-parsed by /ps reload (playershops.reload) — but not every value takes effect immediately once re-parsed, and database.properties isn't re-read at all; see Reloading.
config.yml is parsed with Configurate: a camelCase Java field maps to a kebab-case YAML key (recapInterval → recap-interval, chunksPerTick → chunks-per-tick), and the Duration field accepts shorthand like 24h.
config.yml
Field | Type | Description |
|---|---|---|
| Duration | Lookback window for |
| object | Per-player concurrent shop cap. See Shop limits. |
| Component list (≤ 4 lines) | Lines rendered on a shop's sign. See Sign lines. |
|
| Container types that can never become a shop. See Container & item restrictions. |
|
| Item types that can never be used as shop stock. See Container & item restrictions. |
| object | Tuning for the periodic sign/stock refresh task. See Sign & stock refresh. |
Recap window
recap-interval (default 24h) is the lookback window for the on-demand /ps recap command (see Commands): it computes recap entries from System.currentTimeMillis() - recap-interval up to now. It only applies to that command — the automatic "while you were away" recap shown on login instead uses the player's last-logout timestamp, not recap-interval. See Activity Recaps for both flows.
Shop limits
Field | Type | Description |
|---|---|---|
| int | Floor limit applied to every player, regardless of permissions. Shipped as |
|
| Permission node → max concurrent shops. |
The effective limit for a player is the highest value among limits.default and every permission node in limits.permissions the player holds — lower-tier permissions don't cap a player who also holds a higher one:
ShopService.create checks this before creating a shop: if the player's current shop count (from the database) is >= the limit, creation is rejected with LIMIT_REACHED (placeholder %limit%) and no dialog opens.
Sign lines
sign is a list of up to 4 component-wrapper lines (MiniMessage/legacy strings, resolved through AstralCore's placeholder wrapper system) rendered onto the shop's wall sign. It refreshes on shop creation, after every buy/sell, and on the periodic sign-refresh tick (see Sign & stock refresh). A 5th line is rejected — a vanilla sign only has 4 lines — and the refresh throws instead of partially updating.
Placeholders resolve through a PlaceholderContainer scoped just to this render: the shop itself under the shop namespace, plus a stock value computed live from the backing container. The shipped file uses:
Placeholder | Description |
|---|---|
| Owner's player name, captured at shop creation (not live-updated on a later name change). |
| Price per item. |
| The |
| For a |
Any other shop-namespaced field also resolves here — %shop_id%, %shop_owner%, %shop_material%, %shop_type%, %shop_item%, %shop_location%, %shop_townShared%, %shop_townEconomy% — see Shops for what each one carries.
Container & item restrictions
Field | Type | Description |
|---|---|---|
|
| Container block types that can never be turned into a shop. |
|
| Item types that can never be used as a shop's stock item. |
blacklisted-containers is checked in two places:
Shop creation — sneak-right-clicking a container with an item in hand only opens the creation dialog if the container's type is not in this set.
Placement near a shop — placing a new container block normally triggers a check that cancels the placement (
NO_PERMISSION_PLACE_NEAR) if it's adjacent to a shop the placer doesn't have permission on. Blacklisted container types skip this check entirely — they can be placed next to someone else's shop freely, since they could never become a competing shop themselves.
ignored-items is checked only at creation time: if the item held while sneak-right-clicking a container is in this set, the creation dialog never opens. The shipped list blocks every placeable sign type (a shop can't be stocked with the signs it renders itself onto), chest/trapped_chest/hopper (containers as stock), and item_frame/painting/armor_stand (placeable entities, not stackable block/item stock).
Sign & stock refresh
Field | Type | Default | Description |
|---|---|---|---|
| int |
| Ticks between runs of the periodic refresh task, after a fixed 100-tick (5s) initial delay from startup. |
| int |
| Max chunks the task processes per run. |
|
|
| Worlds the refresh task (and chunk-load hologram spawning) operates in. |
|
|
| AstralCore server groups where the refresh task runs at all. |
updates drives ChunkTickTask, the repeating task that refreshes every shop's sign (stock counts, etc.) without waiting for a buy/sell to trigger it:
The task only exists on a server whose group (
AstralPaperAPI.serverInformation().group()) is inenabled-groups— otherwiseShopServicenever creates or schedules it, and that server gets no periodic refresh at all.When it runs, each pass round-robins through the currently loaded chunks of every world in
enabled-worlds, ticking up tochunks-per-tickchunks that haven't been processed in the current cycle (tracked per world); once every loaded chunk has been processed the cycle resets. A chunk that throws during processing is still marked processed, so one broken chunk can't stall the rotation. Chunks that unload are evicted from the processed set to avoid unbounded growth.enabled-worldsalso gates item-display (hologram) spawning on chunk load —ShopService.loadChunk(called fromChunkLoadEventand once per already-loaded chunk during startup) is a no-op for worlds outside this set. Shop creation, buying, and selling are not restricted toenabled-worlds— only the sign-refresh task and hologram spawning are.Fallbacks live in the
Updatesrecord's compact constructor: a non-positiveinterval-ticksorchunks-per-tick, or a missingenabled-worlds/enabled-groupskey, silently falls back to100/20/[world]/[build]. Omitting the wholeupdates:block does the same, applied one level up inPSConfiguration.
database.properties
A standard HikariCP/JDBC properties file, copied from the JAR the first time the plugin starts (an existing file on disk is never overwritten). For the connection keys (jdbcUrl, driverClassName, dataSource.user/password, poolName), see the AstralCore database docs — AstralPlayerShops reuses the same DatabaseService. The shipped file points at a playershops schema with pool name AstralPlayershops.
Reloading
/ps reload (playershops.reload) calls loadConfiguration(), the same method run on startup: it re-copies database.properties (a no-op once the file exists), reloads config.yml into a fresh PSConfiguration, reloads messages.yml, and reloads the menu/dialog definitions. It does not reconnect the database, and it does not reconstruct ShopService — both are only built once, in onEnable:
Applies immediately | Requires a full restart |
|---|---|
|
|
— |
|
See Commands for the command surface.