MarketManager
Listing, buy with transaction states, remove listings, refund, and reservations.
Based on GrzybcioRynek 1.0.3 and web 0.1.0 source.
MarketManager is the only class that mutates listings and money. MarketAPI.sellItem / removeListing delegate here and require the main thread.
Locks
globalLock—synchronizedaround buy, remove, force-expire, and refund.reservedListings(ConcurrentHashMap.newKeySet) — listing ID duringbuyItem.- Reload (
/market reload) is blocked whenhasReservedListings()istrue:Trwają aktywne transakcje — spróbuj ponownie za chwilę.
sellItem(Player, ItemStack, double)
Check order:
- Price is finite and within
settings.min-price…settings.max-price. - Listing cooldown (
anti-abuse.listing-cooldown-seconds, default 5 s). - Listing limit (
settings.max-listings-per-player, default 10). - Listing fee (
market-fee.listing-fee-percent) — player must have the money. - Item in main hand must be
isSimilarto the passed stack (not AIR).
Then: take from hand → withdraw fee (fail = return item) → StorageManager.createListing (fail = return item + deposit fee) → ListingCreatedEvent + AlertService.checkListing.
MarketAPI.sellItem and /market sell / /wystaw use the same path. The item must be in the main hand at call time.
buyItem(Player, int)
If the ID is already in reservedListings: message buy.listing-locked (Oferta jest właśnie kupowana przez kogoś innego.).
In synchronized (globalLock):
| Step | State | On error |
|---|---|---|
| Validation | — | no listing, own listing, anti-abuse, no money, AIR, full inventory |
| Create TX | CREATED | — |
removeListing | LISTING_RESERVED | LISTING_REMOVE_FAILED |
Buyer withdraw | MONEY_WITHDRAWN | restore listing, WITHDRAW_FAILED |
Seller deposit (UUID) | SELLER_PAID | refund buyer + restore, SELLER_DEPOSIT_FAILED |
Fee to sink-account (optional) | — | log warning only, purchase continues |
addItem / overflow → mailbox purchase-overflow | ITEM_DELIVERED | — |
| Persist TX, anti-abuse | COMPLETED | — |
On success: TransactionCompletedEvent and (when ratings.enabled) rating prompt.
Rollback (rollbackBuy)
Called from catch when the transaction was not committed.
| State at exception | Action |
|---|---|
ITEM_DELIVERED / COMPLETED | finalize — does not undo economy (avoid mint + item) |
SELLER_PAID | withdraw from seller; fail = ROLLBACK_SELLER_WITHDRAW_FAILED without refunding buyer |
MONEY_WITHDRAWN | deposit to buyer + restore listing → ROLLED_BACK |
LISTING_RESERVED | restore listing → ROLLED_BACK |
| other | EXCEPTION_AFTER_<STATE> |
| exception in rollback | ROLLBACK_FAILED:<msg> |
Remove and expire
removeListing(CommandSender, int):
- owner or
market.admin; - reserved listing →
buy.listing-locked; - owner: item to inventory / mailbox (
removed); - admin:
returnListingToSeller(..., "admin-removed"); - event:
ListingRemovedEventwith reason"removed"or"admin-removed".
forceExpire(int): removes listing, mailbox reason "expired", event "force-expire".
Refund
refundTransaction(sender, txId, reclaimItem) — only COMPLETED, does not repeat when error starts with REFUND.
- Withdraw
sellerReceivedfrom seller (if > 0). - Deposit that amount (or
pricewhensellerReceived == 0) to buyer. - Option
reclaim: tryremoveItemfrom online buyer + seller mailbox (admin-refund). error = "REFUND:" + timestamp, stateROLLED_BACK.
Commands: /market admin refund <tx-id> [reclaim].
TX logs
When transactions.logging: true:
[TX <uuid>] <STAGE> listing=#<id> buyer=... seller=... price=... fee=... item=... state=... error=...Search the console for [TX and the transaction ID.
Other methods
| Method | Role |
|---|---|
isListingReserved(int) | whether ID is mid-purchase |
hasReservedListings() | reload lock |
sendInvalidPriceMessage | sell.invalid-price with min/max |
sendPriceHint | min/avg/max from history (StatsManager.getPriceSummary) |
getItemName / getPlainItemName | display name or material |