OreoEssentials — Shop Module

Everything in plugins/OreoEssentials/shop/ — explained for beginners, step by step

GUI Shop Buy & Sell Dynamic Pricing Token Shop Daily Rotation Anti-Dupe Price Modifiers ItemsAdder / Nexo
🛒

Shop Module

A full GUI shop system — players buy and sell items, admins control prices, economy uses Vault or custom currencies (tokens), with dynamic pricing that reacts to player demand.

The shop module gives your server a clean, icon-based store. Players open it with /shop, browse categories, click items to buy or sell, and use an amount-selection screen to pick exactly how many they want. As an admin, you can set up as many shops as you like, wire them up to different currencies, and let prices drift with demand automatically.

Where are the files? All shop config lives in plugins/OreoEssentials/shop/. The main settings are in config.yml, text messages in messages.yml, and each shop is a separate YAML file inside the shops/ sub-folder.

15 Built-in Shops

Ores, weapons, armor, tools, food, potions, enchanted books, building blocks, farming, nether, redstone, mob drops, end items, token shop, and a daily rotating shop — all pre-configured.

Dual Economy

Each shop can use Vault (server money) or a custom currency (e.g. tokens). The token shop is a separate store where everything costs tokens instead of coins.

Dynamic Pricing

When players buy a lot of an item, its price goes up automatically. When nobody buys it for a while, the price drifts back down. This prevents market flooding.

Price Modifiers

Admins can give individual players discounts or markups — globally, per-shop, or per-item. Great for VIP ranks or punishments.

Daily Rotation

A special shop shows only 4 random items from a pool each day. The selection resets at midnight (configurable). Creates excitement and trading opportunities.

Anti-Dupe Protection

Built-in cooldowns, rate limits, transaction locking, and an auto-kick system for suspicious activity prevent item or money duplication exploits.


Quick Start

Get the shop working in under 5 minutes:

Install Vault and an economy plugin (e.g. EssentialsX, CMI, or any Vault-compatible economy). The shop needs Vault to handle money unless you're using only custom currencies.

Restart your server. OreoEssentials will automatically create the plugins/OreoEssentials/shop/ folder with all default files — 15 shop YAMLs, config.yml, and messages.yml.

Give players the oshopgui.shop permission (or put it in your default group). Without this they can't open the shop at all.

Give players sell permissions: oshopgui.sell.hand, oshopgui.sell.hand.all, oshopgui.sell.all — or all three at once.

Test in-game: type /shop to open the main menu. Click any category icon to browse items. Left-click an item to buy, right-click to sell.

Customize prices by editing the files in plugins/OreoEssentials/shop/shops/, then run /shop reload in-game to apply changes instantly.

No Vault installed? The shop will still work for shops that use a custom currency (like the token shop), but money-based shops will show errors. Always install Vault + an economy plugin for a full experience.

⚙️

config.yml — Main Settings

Controls whether the shop is on, which language to use, anti-dupe safety, and how the main menu looks.

Enabling the Shop

enabled: true                      # Set to false to disable the whole shop
auto-deploy-missing-shops: true   # Automatically copy any missing default shop files on startup
language: en                       # Message language: "en" or "fr"

Economy

economy:
  currency-symbol: "$"   # Symbol shown when Vault isn't installed. With Vault, it uses Vault's format.

Anti-Dupe Protection

These settings stop players from exploiting the shop to duplicate items or money.

anti-dupe:
  enabled: true                   # Master switch for anti-dupe
  cooldown-ms: 500               # Minimum milliseconds between transactions (500 = 0.5 seconds)
  verify-inventory: true         # Double-check player has items before selling
  log-suspicious: true           # Log suspicious activity to console/file
  max-transactions-per-second: 5 # Rate limit: more than 5 transactions/sec = suspicious
  lock-during-transaction: true  # Prevent a player from opening two transactions at once
How the rate limit works: The plugin tracks timestamps of the last transactions. If a player completes more than max-transactions-per-second transactions in a rolling 1-second window, a "flag" is recorded. At 10 flags the player is automatically kicked. Flags reset on disconnect.

Main Menu Layout

main-menu:
  title: "&6&lShop"              # Title shown at the top of the main menu GUI
  rows: 4                        # How many rows the main menu has (1–6)
  fill-empty-slots: true        # Fill unused slots with a decorative glass pane
  fill-material: BLACK_STAINED_GLASS_PANE  # Material for the filler
  close-slot: 49               # Slot number for the close/back button (0 = top-left)

Category Buttons (main-menu-items)

Each entry in main-menu-items is one icon in the main menu. Players click these icons to open a specific shop. The shop value must match the shop-id in the corresponding shop YAML file.

main-menu-items:
  ores:
    slot: 0                        # Position in the GUI (counting left-to-right, top-to-bottom from 0)
    material: DIAMOND              # The icon material
    name: "&b&lOres & Minerals"    # Display name (supports & color codes)
    lore:
      - "&7Buy and sell ores"       # Tooltip lines
    shop: ores_minerals           # Must match shop-id in ores_minerals.yml

Amount Selection GUI

amount-selection:
  enabled: true   # When true, clicking an item opens an amount-picker screen instead of buying x1 instantly

Navigation Button Slots

gui:
  previous-page-slot: 45   # Slot for the "previous page" arrow in shop GUIs
  next-page-slot: 53       # Slot for the "next page" arrow
  back-button-slot: 49    # Slot for the "back to main menu" button

Transaction Logging

logging:
  enabled: true
  log-file: "shop/transactions.log"                  # Relative to plugins/OreoEssentials/
  log-format: "{date} | {player} | {action} | x{amount} {item} | {price} ({economy})"

Dynamic Pricing

dynamic-pricing:
  enabled: false                # Set to true to enable demand-based price changes
  demand-scale: 500             # How many purchases = maximum pressure (500 = prices max out at 500 buys)
  max-buy-multiplier: 3.0       # Maximum buy price = base price × 3.0
  min-sell-multiplier: 0.2      # Minimum sell price = base price × 0.2 (80% drop at max demand)
  decay-interval-minutes: 60   # How often prices decay back towards normal
  decay-rate: 0.05              # Fraction of pressure removed each decay tick (5%)
  save-interval-minutes: 5     # How often buy-counts are saved to disk
  show-trend-in-lore: true     # Show ↑ / ↓ trend indicator in item lore

💬

messages.yml — All Player Messages

Every message players see is defined here. Supports both &color codes and MiniMessage <gradient> tags.

Messages are organized by language under en: and fr: keys. The language used is controlled by the language: setting in config.yml. If a message key is missing in your chosen language, it automatically falls back to en.

Available Placeholders

PlaceholderReplaced withUsed in
{prefix}The shop's colored prefix (e.g. [Shop])Most messages
{amount}Number of items bought/soldbuy-success, sell-success, sell-all-success
{item}Item display namebuy-success, sell-success
{price}Formatted price (e.g. $1,250.00)buy-success, sell-success, errors
{shop}Shop IDshop-not-found, modifier messages
{player}Player namemodifier messages
{material}Bukkit material name (e.g. DIAMOND)check-item messages
{buy}Buy pricecheck-item-buy
{sell}Sell pricecheck-item-sell
{type}Modifier type (global/shop/item)modifier-added, modifier-reset
{value}Modifier valuemodifier-added
{page} / {total}Current / total page numbersGUI navigation buttons

Common Message Keys

KeyWhen it shows
buy-successPlayer successfully buys an item
buy-not-enough-moneyPlayer can't afford the item
buy-inventory-fullNo room in player's inventory
buy-invalid-amountNon-numeric amount typed in /sell hand <qty>
sell-successPlayer successfully sells an item
sell-not-enoughPlayer doesn't have enough of the item
sell-no-priceItem has no sell price (sell-price: -1)
sell-hand-emptyPlayer runs /sell hand with nothing in hand
sell-hand-not-sellableHeld item isn't in any shop
sell-all-successSuccessful /sell all or /sell handall
sell-all-nothing/sell all finds nothing sellable in inventory
no-permissionPlayer lacks permission
reload-successAdmin runs /shop reload successfully
shop-not-foundSpecified shop ID doesn't exist
player-not-foundTarget player is offline

Example Customization

en:
  buy-success: "<gradient:green:aqua>✔ Bought</gradient> &f{amount}x {item} &7for &a{price}&7."
  sell-success: "&a✔ Sold &f{amount}x {item} &7for &2{price}&7."
  buy-not-enough-money: "&cNot enough money! This costs &e{price}&c."

📁

Shop Files — shops/ folder

Each YAML file in shops/ defines one (or more) shops. 15 shops are included by default.

Default Shops Overview

FileShop IDDescriptionEconomy
ores_minerals.ymlores_minerals44 ores and minerals (coal → netherrack)Vault
weapons_armor.ymlweapons_armorFull set of swords, bows, armor, horse armorVault
tools.ymltoolsPickaxes, axes, shovels, hoes, fishing rod, shearsVault
food.ymlfoodAll food itemsVault
farming_nature.ymlfarming_natureSeeds, crops, saplings, flowersVault
building_blocks.ymlbuilding_blocksStone, wood, sand, gravel, concrete and moreVault
mob_drops.ymlmob_dropsDrops from hostile and passive mobsVault
nether.ymlnetherNether-specific blocks and itemsVault
end_misc.ymlend_miscEnd items + miscellaneousVault
redstone.ymlredstoneRedstone components, pistons, hoppers, etc.Vault
brewing.ymlbrewingBrewing ingredientsVault
potions.ymlpotionsAll drinkable and splash potions by typeVault
enchanted_books.ymlenchanted_books39 enchanted books (Protection IV → Mending)Vault
token_shop.ymltoken_shopPremium items bought with tokens (custom currency)Custom: token
daily_rotating_shop.ymldaily_shop4 random items from a pool, resets dailyVault

Shop File Structure

Every shop file starts with a header section, then an items: list:

shop-id: my_shop             # Unique ID — used in /shop my_shop and config menu
title: "&6&lMy Shop"         # GUI title (supports & color codes)
rows: 6                      # GUI rows (1–6). 6 rows = 54 slots total
pages: 1                     # Number of pages. With rows:6, each page has 45 item slots
currency: vault             # "vault" (default) OR a custom currency ID like "token"

items:
  # ... item entries go here (see Item Format section)
How are item slots calculated? The bottom row of any shop is the navigation bar (filler panes, back button, page arrows). With rows: 6, the navigation bar is row 6 (slots 45–53). That leaves slots 0–44 for items — 45 slots per page.

Optional: Per-Shop GUI Layout

You can override the navigation bar buttons in any specific shop by adding a gui: section. If you leave it out, the global defaults from config.yml are used.

gui:
  filler:
    material: GRAY_STAINED_GLASS_PANE
    name: " "
  back-button:
    enabled: true
    slot: 49
    material: ARROW
    name: "&6&l← Back to Menu"
    lore: ["&7Return to main shop menu"]
  prev-page:
    slot: 45
    material: ARROW
    name: "&e← Previous"
    lore: ["&7Go to page {page}"]
  next-page:
    slot: 53
    material: ARROW
    name: "&eNext →"
    lore: ["&7Go to page {page}"]
  page-indicator:
    slot: 48
    material: PAPER
    name: "&fPage {page} &7of &f{total}"

📦

Item Format — How to Define Shop Items

Every item in a shop file follows the same YAML structure. Here's every possible field explained.

Full Item Example

items:
  diamond_sword_p1s4:          # Unique ID for this item — can be anything, no spaces
    material: DIAMOND_SWORD      # Bukkit material name (must be ALL_CAPS)
    name: "&bDiamond Sword"      # Optional custom display name. Leave out to use default.
    lore:                        # Optional tooltip lines
      - "&7A sharp blade"
      - "&7Made of diamond"
    slot: 4                       # Slot position (0 = top-left). Bottom row = navigation bar!
    page: 1                       # Which page this item appears on
    amount: 1                     # How many items per "unit" (e.g. 64 = sell by the stack)
    buy-price: 120000            # Cost for players to buy. Use -1 to disable buying.
    sell-price: 19200.0          # Money players receive when selling. Use -1 to disable selling.
    permission: "vip.shop"      # Optional: only players with this permission see/use this item
    custom-model-data: 0        # Optional: custom model data for resource packs

Item ID Naming Convention

The ID format used in default shops is materialname_pPAGEsSLOT — for example diamond_sword_p1s4 means Diamond Sword, page 1, slot 4. This is just a convention to keep IDs unique and readable; you can use any ID you like as long as there are no duplicates within the same shop.

Adding Enchantments

Works for enchanted books (ENCHANTED_BOOK) and any other item. Use the Bukkit enchantment key (lowercase with underscores).

ebook_fortune_1s32:
  material: ENCHANTED_BOOK
  name: "&6Fortune III"
  slot: 32
  page: 1
  amount: 1
  buy-price: 500000
  sell-price: 50000
  enchantments:
    fortune: 3       # enchantment_name: level
    unbreaking: 3   # Multiple enchantments are supported
Enchanted books work correctly. When material: ENCHANTED_BOOK, enchantments are stored as stored enchants inside the book (as they should be). This lets players use an anvil to apply them to equipment.

Potions

strength_potion_p1s0:
  material: POTION          # or SPLASH_POTION, LINGERING_POTION
  name: "&cStrength II"
  slot: 0
  page: 1
  amount: 1
  buy-price: 3000
  sell-price: 500
  potion-type: STRENGTH    # Bukkit PotionType enum name (uppercase)

Custom Items (ItemsAdder / Nexo)

If you have ItemsAdder or Nexo installed, you can sell their custom items directly from the shop.

custom_gem_p1s0:
  material: DIAMOND                  # Fallback material if the hook is unavailable
  name: "&dMystic Gem"
  slot: 0
  page: 1
  amount: 1
  buy-price: 50000
  sell-price: 8000
  itemsadder-id: "mypack:mystic_gem"  # ItemsAdder namespaced ID
  # OR for Nexo:
  nexo-id: "mystic_gem"               # Nexo item ID

Buy-Only and Sell-Only Items

# Buy-only (players cannot sell this item back)
buy-price: 1000
sell-price: -1   # -1 disables selling

# Sell-only (players cannot buy this from the shop)
buy-price: -1   # -1 disables buying
sell-price: 500

Selling by the Stack

# "amount: 64" means the price shown is for 64 items at once
coal_p1s0:
  material: COAL
  slot: 0
  page: 1
  amount: 64         # Price listed = cost/value of a full stack (64 items)
  buy-price: 640     # = $10 per coal (640 ÷ 64)
  sell-price: 320   # = $5 per coal

📈

Dynamic Pricing — Demand-Based Prices

Prices automatically rise when an item is bought often, and fall back when demand drops. This makes the economy feel alive.

Enable it in config.yml with dynamic-pricing.enabled: true. Once enabled, every time a player buys an item, an internal buy-count increments. This count drives a "pressure" value between 0.0 and 1.0.

Buy Price Formula

price × (1 + pressure × (maxMult − 1))
With default settings: at max pressure a $1,000 item costs $3,000.

Sell Price Formula

price × max(1 − pressure × (1 − minMult), minMult)
At max demand you only get 20% of the base sell price.

Pressure Decay

Every decay-interval-minutes (default 60min), each item's pressure is reduced by 5% of its current value. Low-demand items slowly return to base price.

How Pressure Is Calculated

# pressure = min(buy_count / demand_scale, 1.0)
# Example: 250 purchases of diamond, demand_scale=500
# pressure = 250/500 = 0.5  (50% of max pressure)
# Buy multiplier  = 1 + 0.5 × (3.0 - 1) = 2.0  → diamond costs 2× base price
# Sell multiplier = max(1 - 0.5 × (1 - 0.2), 0.2) = 0.6  → sell for 60% of base

Trend Lore Indicator

With show-trend-in-lore: true, items show a trend arrow in the shop GUI:
↑ High demand means buy price is elevated. ↓ Low demand means sell price is better than usual.

Tip: Set demand-scale based on your server size. A small server with 20 players should use a lower value (50–100). A large server with 200+ players can go up to 1000+. If demand-scale is too low, prices spike from just a few purchases.

🏷️

Price Modifiers — Per-Player Discounts

Give specific players custom buy/sell prices — globally, for a specific shop, or for a specific item.

Price modifiers are applied on top of dynamic pricing. Three levels exist, applied in priority order:

  1. Item modifier — highest priority: affects one item in one shop for one player
  2. Shop modifier — affects all items in one specific shop for one player
  3. Global modifier — lowest priority: affects all shops for one player

Modifier values are percentages. 100 = normal price. 90 = 10% discount. 110 = 10% markup.

Commands

CommandDescriptionExample
/shop addmodifier global <player> <value> [buy|sell] Set a global buy or sell modifier for a player /shop addmodifier global Steve 90 buy → Steve gets 10% off all buys
/shop addmodifier shop <player> <shop> <value> [buy|sell] Set a modifier for one shop /shop addmodifier shop Alex ores_minerals 80 sell → Alex sells ores for 20% less
/shop addmodifier item <player> <shop> <item> <value> [buy|sell] Set a modifier for one specific item /shop addmodifier item Notch enchanted_books mending_1s35 50 buy → Notch buys Mending at 50% off
/shop resetmodifier global <player> Remove global modifier from player /shop resetmodifier global Steve
/shop resetmodifier shop <player> <shop> Remove shop modifier from player /shop resetmodifier shop Alex ores_minerals
/shop resetmodifier item <player> <shop> <item> Remove item modifier from player
/shop checkmodifiers <player> Show all active modifiers for a player /shop checkmodifiers Steve
Note: Modifiers are stored in memory and reset when the server restarts. They are intended for temporary discounts (sales events, VIP bonuses during a session). For permanent discounts, consider setting per-item prices in the shop YAML.

🔄

Daily Rotation Shop

A special shop that shows only a random subset of its item pool each day — creating scarcity and excitement.

The rotating shop is defined in shops/daily_rotating_shop.yml. By default, 4 items are randomly chosen from a pool of 8 each day at midnight. The selection is saved to disk so a server restart doesn't change today's rotation.

Rotation Configuration

shop-id: daily_shop

rotating:
  enabled: true              # Must be true for rotation to work
  display-count: 4          # How many items to show from the pool each day
  reset-time: "00:00"       # Time of day when the rotation resets (24-hour HH:mm format)
  timezone: "Europe/Paris"  # IANA timezone ID. See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

items:                       # ALL items in the pool (8 defined, only 4 shown per day)
  diamond_sword:
    material: DIAMOND_SWORD
    slot: 0
    page: 1
    amount: 1
    buy-price: 120000
    sell-price: -1
  # ... more items in pool ...

How the Rotation Works

When the shop is first opened after the reset time, it checks if the saved rotation has expired.

If expired (or no rotation saved), it shuffles all items in the pool using a Fisher-Yates algorithm and picks the first display-count items.

The chosen item IDs are saved to disk so the selection persists across restarts.

The next reset time is computed: if the configured reset time has already passed today, the next reset is tomorrow at that time.

Admin Force-Reroll

Admins can immediately reroll the daily shop with:

/shop reroll daily_shop   # Forces a new random selection right now
Timezone matters! Make sure the timezone field matches your server's expected reset timezone. If left blank or wrong, the reset time may be off by hours. Use a standard IANA zone like Europe/Paris, America/New_York, or UTC.

🪙

Token Shop — Custom Currency

A separate shop where everything costs a custom currency (tokens) instead of server money.

The token shop is defined in shops/token_shop.yml. The key difference is the currency: token line — this tells the shop to use the custom currency system instead of Vault.

shop-id: token_shop
title: "&6&lToken Shop"
rows: 6
pages: 1
currency: token   # Must match the currency ID created with /currency create token

items:
  diamond_p1s0:
    material: DIAMOND
    name: "&b&lDiamond"
    slot: 0
    page: 1
    amount: 1
    buy-price: 10    # 10 tokens
    sell-price: -1  # -1 = cannot sell this item back
Setup required: Before the token shop works, you must create the currency with /currency create token Token Tokens T 0 (or whatever values you prefer). The currency ID must exactly match the currency: field in the shop file.

Default Token Shop Items

ItemToken Cost
Diamond10
Emerald5
Netherite Ingot50
Golden Apple15
Enchanted Golden Apple (God Apple)200
Experience Bottle3
Elytra500
Totem of Undying100

🛡️

Anti-Dupe Protection

Multiple layers of protection prevent item and money duplication exploits.

Transaction Lock

While a player's transaction is processing, a lock prevents them from starting another. This stops double-click or lag exploits from triggering two purchases at once.

Cooldown

After each transaction, a configurable cooldown (default 500ms) blocks any new transaction. Prevents rapid-fire clicking from triggering dozens of purchases.

Rate Limiting

Tracks transaction timestamps in a 1-second window. More than max-transactions-per-second transactions in 1 second increments a flag counter. At 10 flags → auto-kick.

Inventory Verify

Before accepting a sell, the plugin counts the player's actual inventory to confirm they have enough items. Prevents selling items they no longer have due to lag.

Space Verify (Buy)

Before a buy, confirms the player's inventory has room. If not, the buy is rejected and money is not charged — prevents losing money to a full inventory.

Auto-Cleanup

When a player disconnects or is kicked, all their locks, cooldowns, and rate-limit data are cleared. No stuck state remains after a player leaves.

Custom currency sell order: When selling with a custom currency (tokens), items are only removed from the player's inventory after the deposit succeeds. This means if the currency system is down, the player keeps their items. No money-without-items exploit is possible.

💻

Commands

All shop commands, what they do, and who can use them.

/shop — The Main Command

UsageDescriptionPermission
/shopOpen the main shop menu GUIoshopgui.shop
/shop <shopId>Open a specific shop directly by its IDoshopgui.shop
/shop <player> <shopId>Open a shop for another player (admin)oshopgui.others
/shop reloadReload all shop configs without restartoshopgui.reload
/shop reroll <shopId>Force-reroll a rotating shop's selectionoshopgui.reroll
/shop checkCheck the buy/sell price of the item in your handoshopgui.check
/shop addmodifier global <player> <value> [buy|sell]Add a global price modifier to a playeroshopgui.shop.addmodifier
/shop addmodifier shop <player> <shop> <value> [buy|sell]Add a shop-specific modifieroshopgui.shop.addmodifier
/shop addmodifier item <player> <shop> <item> <value> [buy|sell]Add an item-specific modifieroshopgui.shop.addmodifier
/shop resetmodifier global <player>Remove global modifier from a playeroshopgui.shop.resetmodifier
/shop resetmodifier shop <player> <shop>Remove shop modifieroshopgui.shop.resetmodifier
/shop resetmodifier item <player> <shop> <item>Remove item modifieroshopgui.shop.resetmodifier
/shop checkmodifiers <player>See all price modifiers on a playeroshopgui.shop.checkmodifiers

/sell — Selling From Chat

UsageDescriptionPermission
/sell hand [quantity]Sell the item in your main hand (specific quantity)oshopgui.sell.hand
/sell handallSell ALL items matching what's in your handoshopgui.sell.hand.all
/sell allSell every sellable item in your entire inventoryoshopgui.sell.all

🔑

Permissions

All permissions required for the shop module.

PermissionWhat it allowsWho needs it
oshopgui.shopOpen the shop GUI with /shopAll players
oshopgui.sell.handUse /sell hand [qty]All players
oshopgui.sell.hand.allUse /sell handallAll players
oshopgui.sell.allUse /sell allAll players (optional)
oshopgui.checkUse /shop check (price check on held item)All players (optional)
oshopgui.reloadUse /shop reloadAdmins only
oshopgui.rerollUse /shop rerollAdmins only
oshopgui.othersOpen a shop for another playerAdmins only
oshopgui.shop.addmodifierAdd price modifiers to playersAdmins only
oshopgui.shop.resetmodifierRemove price modifiers from playersAdmins only
oshopgui.shop.checkmodifiersView a player's active price modifiersAdmins only
Per-item permissions: You can restrict individual shop items to players with a specific permission by setting the permission: field on any item in the shop YAML. Players without that permission won't see or be able to interact with that item.

Player Examples — Real Scenarios

Step-by-step walkthroughs of common player interactions.

Buying an Item

Steve — New player, first time buying

Steve wants a diamond sword. He types /shop, clicks the "Weapons & Armor" icon, and sees the GUI. He hovers over Diamond Sword and reads the price ($120,000). He left-clicks it.

Since amount-selection.enabled: true, a confirmation screen opens. Steve sees buttons to increase/decrease quantity (+1, +16, +32, +64). He clicks "Max Affordable" — it calculates he can afford 3 swords. He clicks Confirm Purchase.

✔ Bought 3x Diamond Sword for $360,000.
Alex — Selling ores quickly

Alex has a full inventory of iron ore after mining. She holds the iron ore and types /sell handall. The plugin scans her inventory, finds all iron ore stacks, and sells them all at once.

✔ Sold 324x items for $8,748.00.

She then types /sell all to sell everything else sellable in her inventory (coal, gravel, etc.) in one command.

Notch — Checking prices before selling

Notch has a stack of diamonds and wants to know if today's price is good. He holds the diamonds and types /shop check. The server replies with the current buy and sell prices, including any active dynamic pricing modifier.

> [Shop] Diamond — Buy: $50,000 | Sell: $30,000 (High demand: ↑)

Notch notices the high demand indicator. He decides to wait until demand drops before selling, knowing the price will return to its normal $40,000.

Herobrine — Using the Token Shop

Herobrine has earned 600 tokens through gameplay. He types /shop token_shop to open the token shop directly. He sees an Elytra listed for 500 tokens. He left-clicks it, confirms on the amount screen, and gets the elytra in his inventory.

✔ Bought 1x Elytra for 500T.

Notice: the currency shows as T (tokens) instead of $ (money) — because this shop uses the custom token currency.

Daily Rotation

Alex — Checking today's daily shop

Alex types /shop daily_shop every morning to see what's on sale. Today she finds a Trident and a Beacon in the 4 rotating items. She buys the Beacon before someone else does.

✔ Bought 1x Beacon for $800,000.

Tomorrow at midnight the selection resets — the Beacon might not be available again for days.

Admin Actions

Admin — Setting a VIP discount

A player achieves VIP rank. The admin types:

/shop addmodifier global Steve 90 buy

Steve now gets a 10% discount on every buy in every shop. The admin can check it with:

/shop checkmodifiers Steve

If Steve's VIP expires, the admin removes it with:

/shop resetmodifier global Steve
Admin — Reloading after editing prices

The admin edits plugins/OreoEssentials/shop/shops/ores_minerals.yml to change the diamond price, then runs:

/shop reload
[Shop] Shop reloaded successfully.

No restart needed. Players currently in the shop GUI will see updated prices when they next open it.


Frequently Asked Questions

Players can't open the shop — what's wrong?

Make sure players have the oshopgui.shop permission. Also check that enabled: true is set in config.yml. If using LuckPerms: lp group default permission set oshopgui.shop true.

The shop says "Vault not found" or transactions fail.

You need both Vault (the API plugin) AND an economy plugin (EssentialsX, CMI, etc.) installed. Vault alone is just an API — it doesn't provide any economy by itself. Install both, restart, and the error should disappear.

I added an item to a shop YAML but it doesn't appear in-game.

Run /shop reload after editing any shop file. Also check:

  • The page field matches the page you're viewing
  • The slot is within bounds (not in the navigation row)
  • The material name is valid (use ALL_CAPS exactly as Bukkit defines it)
  • If you set a permission field, the player has that permission
Enchanted books in the shop aren't working — the enchantment doesn't apply to tools.

This was a bug that has been fixed. When you buy an enchanted book from the shop, the enchantment is now correctly stored inside the book as a stored enchantment. To apply it to a tool, use an anvil. If you're on an older version where this was broken, update to get the fix.

How do I create a new shop?

Create a new file in plugins/OreoEssentials/shop/shops/, e.g. my_custom_shop.yml. Give it a unique shop-id, add items following the item format. Then add a button for it in config.yml under main-menu-items with shop: my_custom_shop. Run /shop reload.

How do I disable buying or selling for a specific item?

Set the price to -1: buy-price: -1 disables buying, sell-price: -1 disables selling. An item with both set to -1 won't appear in the shop at all (no interactable action).

How do I add a second page to a shop?

Set pages: 2 (or however many you need) in the shop header. Then set page: 2 on the items you want on the second page. Make sure those items have slot values within the valid range (0 to rows×9 - 10, avoiding the navigation bar).

The token shop prices show in $ instead of tokens.

Check that the currency: field in token_shop.yml exactly matches the currency ID you created. Open your currency configuration and verify the ID. Remember: it's case-sensitive and must match exactly (e.g. if you created it as token, the field must say currency: token).

Dynamic pricing is making items too expensive — how do I tune it?

Increase demand-scale so it takes more purchases to reach max pressure. For example, if 50 buys are spiking prices, try demand-scale: 500 so prices don't hit maximum until 500 purchases. You can also lower max-buy-multiplier — setting it to 1.5 caps the buy price increase at 50% above base instead of 200%.

The daily rotation didn't change at midnight.

Check the timezone in daily_rotating_shop.yml. If your server runs in UTC but you set Europe/Paris, the reset happens at midnight Paris time (1am UTC in winter, 2am in summer). Also confirm that the rotation file is being written correctly — check logs/latest.log for any errors from the shop module on startup.

A player is stuck and can't use the shop — locked out.

The anti-dupe lock releases automatically when the transaction completes or when the player disconnects. If a player is permanently stuck (very rare edge case), have them reconnect — the onQuit event always clears all locks. If they're still stuck after reconnecting, use /shop reload which reinitializes the transaction processor.

Can I have shops accessible only from specific NPCs?

Yes. Open the shop programmatically from your NPC plugin using the command /shop <player> <shopId> via player.performCommand() or dispatch a command. You can also set hide-back-button: true in the shop YAML to hide the "Back to Main Menu" button, making the shop feel self-contained.