GrzybcioRynek

MarketManager

Listing, buy with transaction states, remove listings, refund, and reservations.

Compatible with: GrzybcioRynek 1.0.3Minecraft 26.2Web 0.1.0

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

  • globalLocksynchronized around buy, remove, force-expire, and refund.
  • reservedListings (ConcurrentHashMap.newKeySet) — listing ID during buyItem.
  • Reload (/market reload) is blocked when hasReservedListings() is true: Trwają aktywne transakcje — spróbuj ponownie za chwilę.

sellItem(Player, ItemStack, double)

Check order:

  1. Price is finite and within settings.min-pricesettings.max-price.
  2. Listing cooldown (anti-abuse.listing-cooldown-seconds, default 5 s).
  3. Listing limit (settings.max-listings-per-player, default 10).
  4. Listing fee (market-fee.listing-fee-percent) — player must have the money.
  5. Item in main hand must be isSimilar to the passed stack (not AIR).

Then: take from hand → withdraw fee (fail = return item) → StorageManager.createListing (fail = return item + deposit fee) → ListingCreatedEvent + AlertService.checkListing.

Tip

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):

StepStateOn error
Validationno listing, own listing, anti-abuse, no money, AIR, full inventory
Create TXCREATED
removeListingLISTING_RESERVEDLISTING_REMOVE_FAILED
Buyer withdrawMONEY_WITHDRAWNrestore listing, WITHDRAW_FAILED
Seller deposit (UUID)SELLER_PAIDrefund buyer + restore, SELLER_DEPOSIT_FAILED
Fee to sink-account (optional)log warning only, purchase continues
addItem / overflow → mailbox purchase-overflowITEM_DELIVERED
Persist TX, anti-abuseCOMPLETED

On success: TransactionCompletedEvent and (when ratings.enabled) rating prompt.

Rollback (rollbackBuy)

Called from catch when the transaction was not committed.

State at exceptionAction
ITEM_DELIVERED / COMPLETEDfinalize — does not undo economy (avoid mint + item)
SELLER_PAIDwithdraw from seller; fail = ROLLBACK_SELLER_WITHDRAW_FAILED without refunding buyer
MONEY_WITHDRAWNdeposit to buyer + restore listing → ROLLED_BACK
LISTING_RESERVEDrestore listing → ROLLED_BACK
otherEXCEPTION_AFTER_<STATE>
exception in rollbackROLLBACK_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: ListingRemovedEvent with 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.

  1. Withdraw sellerReceived from seller (if > 0).
  2. Deposit that amount (or price when sellerReceived == 0) to buyer.
  3. Option reclaim: try removeItem from online buyer + seller mailbox (admin-refund).
  4. error = "REFUND:" + timestamp, state ROLLED_BACK.

Commands: /market admin refund <tx-id> [reclaim].

TX logs

When transactions.logging: true:

text
[TX <uuid>] <STAGE> listing=#<id> buyer=... seller=... price=... fee=... item=... state=... error=...

Search the console for [TX and the transaction ID.

Other methods

MethodRole
isListingReserved(int)whether ID is mid-purchase
hasReservedListings()reload lock
sendInvalidPriceMessagesell.invalid-price with min/max
sendPriceHintmin/avg/max from history (StatsManager.getPriceSummary)
getItemName / getPlainItemNamedisplay name or material