31 KiB
CustomNPC+ 1.11 Market Update - Implementation Plan
Overview
The 1.11 Market Update introduces a comprehensive economy system for CustomNPC+:
- Currency System - Built-in CNPC+ currency with optional Vault integration
- Trader Enhancements - Stock system, currency-based trades, reset timers
- Auction House - Global auction system with bidding, buyout, and claims
1. Currency System
Status: COMPLETE ✅
The currency system provides a unified economy for CNPC+ features.
Features
- Built-in CNPC+ Currency - Stored in PlayerData, persists across profile slots
- Vault Integration - Optional, when enabled all operations use Vault instead
- Scripting API - Full access via
IPlayermethods - Unified Usage - Both Trader and Auction systems use
PlayerCurrencyDatawhich auto-delegates to Vault
Vault Integration Flow
┌─────────────────────────────────────────────────────────────────┐
│ PlayerCurrencyData │
│ │
│ shouldUseVault() = ConfigMarket.UseVault && VaultUtil.isEnabled()│
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ All methods check shouldUseVault() first: │ │
│ │ - getBalance() → VaultUtil.getBalance() or local balance │ │
│ │ - withdraw() → VaultUtil.withdrawMoney() or local │ │
│ │ - deposit() → VaultUtil.addMoney() or local │ │
│ │ - canAfford() → VaultUtil.has() or local check │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ Used by: ContainerNPCTrader, AuctionController │
└─────────────────────────────────────────────────────────────────┘
Key Files
| File | Purpose |
|---|---|
PlayerTradeData.java |
Per-player trade data (currency + auction claims), Vault delegation |
IPlayerTradeData.java |
API interface for trade operations (currency + claims) |
ConfigMarket.java |
Currency configuration (UseVault, CurrencyName, StartingBalance, MaxBalance) |
VaultUtil.java |
Vault API integration via reflection |
Configuration (ConfigMarket.java)
Market.Currency:
- Use Vault: false
- Currency Name: "Coins"
- Starting Balance: 0
- Max Balance: 2147483647
Scripting API (IPlayer)
player.getCurrencyBalance() // Get balance
player.setCurrencyBalance(amount) // Set balance
player.depositCurrency(amount) // Add currency (returns success)
player.withdrawCurrency(amount) // Remove currency (returns success)
player.canAffordCurrency(amount) // Check if can afford
player.isUsingVaultCurrency() // Check if Vault is active
player.getFormattedCurrencyBalance() // Get formatted string
// Via IPlayerData
player.getData().getTradeData() // Get IPlayerTradeData interface
2. Trader Enhancements
Status: COMPLETE ✅
2.1 Stock System - COMPLETE ✅
Traders can have limited stock that resets on configurable schedules.
Stock Modes
| Mode | Description | Status |
|---|---|---|
| Global | All players share the same stock pool | ✅ Working |
| Per-Player | Each player has their own stock counts | ✅ Working |
Stock Reset Types (EnumStockReset)
| Type | Description | Status |
|---|---|---|
NONE |
Stock never resets | ✅ Working |
MCDAILY |
Resets every MC day (24000 ticks) | ✅ Working |
MCWEEKLY |
Resets every 7 MC days (168000 ticks) | ✅ Working |
MCCUSTOM |
Custom MC tick interval | ✅ Working |
RLDAILY |
Resets every 24 real-life hours | ✅ Working |
RLWEEKLY |
Resets every 7 real-life days | ✅ Working |
RLCUSTOM |
Custom real-time interval | ✅ Working |
Stock UI Features - COMPLETE ✅
| Feature | Status | Notes |
|---|---|---|
| Stock count per item | ✅ | Shows to right of output slot |
| Out of stock indicator | ✅ | Dark overlay + red count |
| Reset timer countdown | ✅ | Real-time client-side countdown in top-right |
| "Reopen Trader" message | ✅ | Shows when countdown reaches 0 |
| Admin stock configuration | ✅ | SubGuiNpcTraderStock |
| Per-slot stock limits | ✅ | SubGuiNpcTraderStockSlots |
| Reset stock button | ✅ | With confirmation dialog |
| Reset cooldown button | ✅ | With confirmation dialog |
2.2 Trader Currency Support - COMPLETE ✅
Trades can require BOTH items AND currency (additive costs). Uses PlayerCurrencyData which auto-delegates to Vault when enabled.
Trade Entry Structure
Each trade slot can have:
- Sold Item - What the player receives ✅
- Currency 1 - First item cost (existing) ✅
- Currency 2 - Second item cost (existing) ✅
- Currency Cost - CNPC+ Currency / Vault cost ✅ NEW
Implementation Details
- Currency cost stored as
long[] currencyCost[18]in RoleTrader - Uses
data.tradeData.getBalance()anddata.tradeData.withdraw() - Automatically uses Vault when
ConfigMarket.UseVaultis enabled - NBT serialization for persistence ✅
2.3 Player Trader GUI - COMPLETE ✅
Display Features
| Element | Position | Status |
|---|---|---|
| "Trader" label | Top-left | ✅ |
| Reset countdown | Top-right | ✅ Real-time ticking |
| Stock count | Right of each trade | ✅ Green/Red |
| Player balance | Bottom-right | ✅ |
| Status message | Bottom-left | ✅ On hover |
2.4 Multi-Player Sync - COMPLETE ✅
MarketRegistry provides linked market synchronization across all NPCs sharing the same market.
2.5 Scripting API - COMPLETE ✅
Full API available via IRoleTrader interface.
3. Auction House System
Status: COMPLETE ✅
3.1 Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ AuctionController │
│ - Manages auction listings with player indices │
│ - Handles listing/bidding/buyout logic │
│ - Uses ConcurrentHashMap for thread-safety (no locks) │
│ - Async saves on CNPC+ thread every 30 seconds │
│ - 30-second update cycle for processing ended auctions │
└─────────────────────────────────────────────────────────────────┘
│
Uses PlayerCurrencyData (Vault-aware)
│
┌─────────────────────────────────────────────────────────────────┐
│ PlayerTradeData │
│ - Combined currency + auction claims (shared across profiles) │
│ - Currency: Vault integration with local fallback │
│ - Claims: Thread-safe CopyOnWriteArrayList for async additions │
│ - Expired claims processed on login │
│ - Notifications sent immediately to online players │
└─────────────────────────────────────────────────────────────────┘
3.2 Vault Integration
The Auction system uses PlayerCurrencyData for all currency operations:
AuctionController.createListing()→currencyData.withdraw(fee)AuctionController.placeBid()→currencyData.withdraw(bidAmount)AuctionController.buyout()→currencyData.withdraw(buyoutPrice)AuctionController.claimCurrency()→currencyData.deposit(amount)
When Vault is enabled (ConfigMarket.UseVault = true):
- All operations automatically use Vault economy
- No code changes required -
PlayerCurrencyDatahandles delegation
3.3 GUI Structure
GuiAuctionInterface (Base GUI - opened via Auctioneer NPC)
│
├── GuiAuctionListing (Browse auctions - PAGE_LISTINGS)
│ - 9x5 grid of auction items
│ - Filter button with tooltip showing current settings
│ - Click item → Opens GuiAuctionBidding
│ - Pagination with up/down arrows
│
├── GuiAuctionSell (Create new listing - PAGE_SELL)
│ - Sell slot for item to auction (cloned from inventory)
│ - Click inventory: left=add stack, right=add 1
│ - Click sell slot: left=clear, right=remove 1
│ - Starting price + buyout price text fields
│ - Allow Buyout toggle button
│ - Listing fee display
│ - Confirm button with coin icon
│
├── GuiAuctionTrades (My Trades - PAGE_CLAIMS)
│ - 9x5 grid showing: active listings, active bids, claims
│ - Blue tint: active listings/bids
│ - Green tint: claimable items
│ - Red tint: refunds
│ - Confirmation system for cancel/claim operations
│
├── GuiAuctionBidding (View listing details)
│ - Item display slot
│ - Auction info (seller, price, time, bids)
│ - Bid button → SubGuiAuctionBid
│ - Buy Now button → SubGuiAuctionBuyNow
│ - Own listings: buttons hidden, view-only
│
├── SubGuiAuctionBid (Bid confirmation popup)
│ - Shows minimum bid, player balance
│ - Bid amount input field
│ - Place Bid / Cancel buttons
│
├── SubGuiAuctionBuyNow (Buyout confirmation popup)
│ - Shows buyout price, player balance
│ - Yes / Cancel buttons
│
└── SubGuiAuctionSearch (Filter popup)
- Search text input
- Apply/Cancel buttons
3.4 Client Config Sync
The client uses AuctionClientConfig to cache server settings:
- Synced via
LoginPacketon player join - Client never uses
ConfigMarketdirectly for display - Ensures server authority over fees, currency name, etc.
// Server sends config in LoginPacket
AuctionClientConfig.writeToNBT(compound); // Server side
// Client receives and caches
AuctionClientConfig.readFromNBT(compound); // Client side
// Client GUI uses cached values
AuctionClientConfig.getListingFee();
AuctionClientConfig.getCurrencyName();
AuctionClientConfig.getMinBidIncrement();
3.5 Data Structures
AuctionListing
public class AuctionListing {
String id; // Unique listing ID (UUID-based)
UUID sellerUUID; // Seller's UUID
String sellerName; // Seller's display name
ItemStack item; // Item being sold
long startingPrice; // Minimum starting bid
long buyoutPrice; // Instant buy price (0 = no buyout)
long currentBid; // Current highest bid
UUID highBidderUUID; // Current high bidder (null if no bids)
String highBidderName; // High bidder display name
int bidCount; // Number of bids placed
long createdTime; // When listing was created
long endTime; // When auction ends
EnumAuctionStatus status; // ACTIVE, ENDED, CANCELLED, CLAIMED
}
AuctionClaim
public class AuctionClaim {
String id; // Unique claim ID
UUID playerUUID; // Player who can claim
String listingId; // Related auction listing
EnumClaimType type; // ITEM, CURRENCY, REFUND
ItemStack item; // Item to claim (if type = ITEM)
long currency; // Currency to claim (if type = CURRENCY/REFUND)
long createdTime; // When claim was created
boolean claimed; // Whether claimed
}
3.6 Security Features
All actions are validated server-side:
| Check | Location | Description |
|---|---|---|
| Own item bid prevention | placeBid() |
listing.isSeller(playerUUID) check |
| Own item buyout prevention | buyout() |
listing.isSeller(playerUUID) check |
| Auction expiry check | placeBid()/buyout() |
Double-check inside write lock |
| Currency validation | All actions | Verify balance before operations |
| Claim ownership | claimItem()/claimCurrency() |
claim.isForPlayer(playerUUID) check |
| Blacklist check | createListing() |
AuctionBlacklist.isBlacklistedForPlayer() check |
| Bound item check | createListing() |
Auto-blocks Soulbound/Profile-Slotbound items |
3.7 Snipe Protection
When a bid is placed with less than SnipeProtectionMinutes remaining:
- Extend the auction end time TO
SnipeProtectionMinutesfrom now - Never extend beyond
SnipeProtectionMinutes - Default: 2 minutes
Example: Auction ends in 30 seconds, someone bids → Timer resets to 2:00
3.8 Item Blacklist System
Prevents specific items from being listed on the auction house.
Blacklist Types
| Type | Description | Example |
|---|---|---|
| Items | Block specific items by registry name | minecraft:diamond_sword |
| Wildcards | Block items matching pattern | minecraft:diamond* |
| Mods | Block all items from a mod | customnpcs |
| NBT Tags | Block items with specific NBT | ench (enchanted items) |
Auto-Blocked Items (Always Blocked)
These items are always blocked regardless of blacklist settings:
- Soulbound Items - Items with
cnpc_soulbindrequirement - Profile-Slotbound Items - Items with
cnpc_profile_slotrequirement
The system checks for these under RPGCore/Requirements in the item's NBT.
Bypass Permission
Players with OP status or the customnpcs.auction.blacklist.bypass permission can list blacklisted items.
Configuration
Market.Auction.Blacklist:
Enabled: true
BlacklistedItems: ["minecraft:barrier", "minecraft:command_block*"]
BlacklistedMods: []
BlacklistedNBTTags: []
Commands
| Command | Description |
|---|---|
/cnpc auction blacklist add <item|mod|nbt> <value> |
Add to blacklist (runtime only) |
/cnpc auction blacklist remove <item|mod|nbt> <value> |
Remove from blacklist (runtime only) |
/cnpc auction blacklist list [item|mod|nbt] |
List blacklisted entries |
/cnpc auction blacklist reload |
Reload blacklist from config |
/cnpc auction blacklist check |
Check if held item is blacklisted |
4. AuctionController Performance & Thread Safety
4.1 Threading Model
┌─────────────────────────────────────────────────────────────────┐
│ AuctionController │
│ │
│ ┌─────────────────────┐ ┌─────────────────┐ ┌───────────────┐ │
│ │ ConcurrentHashMap │ │ AtomicBoolean │ │ CNPC+ Thread │ │
│ │ (listings, indices) │ │ dirty, saving │ │ (async saves) │ │
│ └─────────────────────┘ └─────────────────┘ └───────────────┘ │
│ │
│ All operations use ConcurrentHashMap - no explicit locking │
│ Minecraft is single-threaded for gameplay - inherent safety │
│ Async saves snapshot data before writing to disk │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────┐
│ PlayerTradeData │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Currency: long balance (or Vault delegation) │ │
│ │ Claims: CopyOnWriteArrayList<AuctionClaim> │ │
│ │ - Thread-safe for concurrent read/write │ │
│ │ - Claims can be added from CNPC+ thread for offline players │ │
│ │ - Stored in PlayerData (persisted with player, not auctions) │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
4.2 Player Indices for O(1) Lookups
| Index | Type | Purpose |
|---|---|---|
playerListingIds |
Map<UUID, Set<String>> |
Active listings by seller |
playerBidIds |
Map<UUID, Set<String>> |
Listings where player has active bid |
Claims are now stored in PlayerData:
PlayerTradeData.claims- CopyOnWriteArrayList per player- Accessed via
PlayerData.get(player).tradeData - Shared across all profile slots (combined with currency)
Performance Impact:
getPlayerListingCount(): O(n) → O(1)getPlayerActiveListings(): O(n) → O(k) where k = player's listingsgetPlayerActiveBids(): O(n) → O(k)getPlayerClaims(): Direct access to player's claims list
4.3 Update Intervals
| Operation | Interval | Rationale |
|---|---|---|
| Process ended auctions | 30 seconds (600 ticks) | Reduces server load |
| Save auction data | 30 seconds (600 ticks) | Batches writes, reduces I/O |
| Process expired claims | On player login | Per-player, not global tick |
4.4 Data Safety
- Currency Deduction - Withdraw before updating listing
- Previous Bidder Refund - Store info before modification
- Concurrent Saves -
AtomicBooleanprevents duplicates - Offline Player Claims - Loaded async on CNPC+ thread, saved to PlayerData
- Claim Migration - Old claims in auction.dat migrated to PlayerData on load
4.5 Server Shutdown Handling
On FMLServerStoppedEvent:
AuctionController.save()called synchronously- Uses CNPC+ thread (single-threaded executor)
- All pending saves complete before shutdown
5. File Structure
New Files Created
constants/
EnumAuctionStatus.java ✅
EnumAuctionSort.java ✅
EnumClaimType.java ✅
EnumNotificationType.java ✅
controllers/
AuctionController.java ✅ (with threading, indices, Vault support)
AuctionConfigSync.java ✅ (server-side config sync utility)
controllers/data/
AuctionListing.java ✅
AuctionClaim.java ✅
AuctionFilter.java ✅
AuctionBlacklist.java ✅ (item blacklist checking + bypass)
PlayerTradeData.java ✅ (currency + claims storage per player)
roles/
RoleAuctioneer.java ✅
containers/
ContainerAuction.java ✅
ContainerAuctionListing.java ✅
ContainerAuctionBidding.java ✅
ContainerAuctionTrades.java ✅
ContainerAuctionSell.java ✅
InventoryAuctionDisplay.java ✅
SlotAuctionDisplay.java ✅
client/
AuctionClientConfig.java ✅ (client-side config cache)
client/gui/player/
GuiAuctionInterface.java ✅
GuiAuctionListing.java ✅
GuiAuctionSell.java ✅
GuiAuctionTrades.java ✅
GuiAuctionBidding.java ✅
SubGuiAuctionSearch.java ✅
SubGuiAuctionBid.java ✅
SubGuiAuctionBuyNow.java ✅
AuctionTooltipHandler.java ✅
client/gui/util/
GuiAuctionNavButton.java ✅
network/packets/player/
AuctionActionPacket.java ✅
New Commands
command/
AuctionCommand.java ✅ /cnpc auction with list, view, open, blacklist
command/auction/
BlacklistSubCommand.java ✅ /cnpc auction blacklist subcommands
Files Modified
CustomNpcs.java ✅ Initialize AuctionController, save on shutdown
EnumRoleType.java ✅ Added Auctioneer
EnumGuiType.java ✅ Added PlayerAuction, PlayerAuctionSell, PlayerAuctionTrades, PlayerAuctionBidding
EnumPlayerPacket.java ✅ Added AuctionData, AuctionAction
CommonProxy.java ✅ Handle auction container types
ClientProxy.java ✅ Handle auction GUI types
DataAdvanced.java ✅ Handle Auctioneer role
ConfigMarket.java ✅ Added Auction section
LoginPacket.java ✅ Sync auction config to client
PlayerData.java ✅ Added tradeData field (currency + claims, shared across profiles)
en_US.lang ✅ Added auction lang keys
6. Configuration
ConfigMarket.java Structure
// =========================================
// Currency (Market.Currency)
// =========================================
public static boolean UseVault = false; // Use Vault economy
public static String CurrencyName = "Coins"; // Display name
public static long StartingBalance = 0; // New player balance
public static long MaxBalance = Long.MAX_VALUE; // Balance cap
// =========================================
// Auction (Market.Auction)
// =========================================
public static final int MAX_TRADE_SLOTS = 45; // 9x5 grid maximum
public static final int MIN_TRADE_SLOTS = 1; // Minimum allowed
public static boolean AuctionEnabled = true;
public static int AuctionDurationHours = 24; // Auction length (hours)
public static long ListingFee = 10; // Fee to create listing
public static long MinimumListingPrice = 1; // Minimum starting price
public static double SalesTaxPercent = 0.05; // 5% tax on sales
public static int DefaultMaxTrades = 8; // Per player (listings + bids + claims)
public static int SnipeProtectionMinutes = 2; // Anti-snipe timer
public static int ClaimExpirationDays = 20; // Days before unclaimed deleted
public static double MinBidIncrementPercent = 0.05; // 5% minimum bid increase
// =========================================
// Auction Logging
// =========================================
public static boolean AuctionLoggingEnabled = false;
public static boolean LogAuctionCreated = true;
public static boolean LogAuctionBid = true;
public static boolean LogAuctionBuyout = true;
public static boolean LogAuctionSold = true;
public static boolean LogAuctionExpired = true;
public static boolean LogAuctionCancelled = true;
public static boolean LogAuctionClaimed = true;
// =========================================
// Auction Blacklist (Market.Auction.Blacklist)
// =========================================
public static boolean BlacklistEnabled = true;
public static String[] BlacklistedItems = {}; // Registry names (supports wildcards)
public static String[] BlacklistedMods = {}; // Mod IDs to block entirely
public static String[] BlacklistedNBTTags = {}; // NBT tag keys to block
Auction Permissions
| Permission | Description |
|---|---|
customnpcs.auction.trades.* |
Unlimited trade slots (up to 45) |
customnpcs.auction.trades.X |
Exactly X trade slots (where X is 1-45) |
customnpcs.auction.blacklist.bypass |
Bypass item blacklist restrictions |
Trade Slot Permissions:
- Default is 8 trade slots
- Permissions only increase the limit (permissions below 8 are ignored)
- Maximum is capped at 45 (9x5 grid)
- Trade slots = Active Listings + Active Bids + Pending Claims
Blacklist Bypass:
- OP players or those with
customnpcs.auction.blacklist.bypasscan list blacklisted items - Soulbound and Profile-Slotbound items are always blocked (no bypass)
7. Commands
/cnpc auction Command
Allows interaction with the Auction House without needing an Auctioneer NPC.
| Subcommand | Usage | Permission | Description |
|---|---|---|---|
list |
/cnpc auction list [page] |
OP | View active auctions in chat |
view |
/cnpc auction view <player> |
OP | View a player's auction activity |
open |
/cnpc auction open |
Any | Opens the Auction House GUI |
Examples:
/cnpc auction list - Show first page of active auctions
/cnpc auction list 2 - Show page 2 of auctions
/cnpc auction view Steve - Show Steve's listings, bids, and claims
/cnpc auction open - Open the full Auction House GUI
/cnpc auction blacklist Command
Manage the auction item blacklist (runtime changes, not persisted to config).
| Subcommand | Usage | Permission | Description |
|---|---|---|---|
add |
/cnpc auction blacklist add <item|mod|nbt> <value> |
OP | Add to blacklist |
remove |
/cnpc auction blacklist remove <item|mod|nbt> <value> |
OP | Remove from blacklist |
list |
/cnpc auction blacklist list [item|mod|nbt] |
OP | List blacklisted entries |
reload |
/cnpc auction blacklist reload |
OP | Reload from config |
check |
/cnpc auction blacklist check |
Any | Check if held item is blacklisted |
Examples:
/cnpc auction blacklist add item minecraft:diamond_sword
/cnpc auction blacklist add item minecraft:diamond* (wildcard)
/cnpc auction blacklist add mod industrialcraft2
/cnpc auction blacklist add nbt ench
/cnpc auction blacklist remove item minecraft:diamond_sword
/cnpc auction blacklist list item
/cnpc auction blacklist check (checks held item)
8. Implementation Status
Phase 1: Currency System - COMPLETE ✅
Phase 2: Trader Enhancements - COMPLETE ✅
Phase 3: Auction Core - COMPLETE ✅
Phase 4: Auction GUI - COMPLETE ✅
Phase 5: Auction Network - COMPLETE ✅
Phase 6: Performance & Safety - COMPLETE ✅
Threading model with ReentrantReadWriteLockPlayer indices for O(1) lookups20-second update cycleAsync saves on CNPC+ threadRace condition preventionServer shutdown handlingOwn listing view (buttons hidden)Server-side security checks
Remaining Work
- GuiManageAuction (Admin GUI) - Admin interface to view all auctions, cancel listings, manage claims
- Additional testing
Implemented Since Initial Plan
/auctionCommand - Console/player command with subcommands:/auction list [page]- View active auctions from command line/auction view <player>- View a player's auction activity (listings, bids, claims)/auction open- Open Auction House GUI without needing an Auctioneer NPC
- Permission system integration - Per-player trade slot limits via
customnpcs.auction.trades.Xpermissions- Default: 8 trade slots
- Maximum: 45 (9x5 grid)
- Synced to client when viewing My Trades
- Cached on login for performance
- Minimum Listing Price - Configurable minimum starting price (default: 1)
- Buyout enabled by default - Buyout toggle is ON by default when creating listings
- Search by seller - Filter can now search by item name OR seller name
- Rebid prevention - Players cannot rebid on auctions where they're already the highest bidder
- Buyout price difference - When buying out an auction you're bidding on, only pay the difference
- Immediate claim cleanup - Claims are removed from storage immediately when claimed
- Listing cleanup - Ended listings are removed when all related claims are processed
- Live notifications - Notifications sent immediately to online players instead of queued
- Login claim summary - Shows detailed claim summary on login (X items and Y currency to claim)
- PlayerTradeData - Merged currency + claims into single class (shared across profiles)
- No locking system - Pure ConcurrentHashMap for better performance
- 30-second intervals - Combined process/save cycle for simplicity
- Async offline player claims - Claims added to offline players via CNPC+ thread
- Claim migration - Old claims in auction.dat automatically migrated to PlayerData
- Item Blacklist System - Block items by registry name, mod, NBT tag, or wildcard pattern
- Auto-blocks Soulbound and Profile-Slotbound items (checks
RPGCore/Requirements) - Per-player bypass via
customnpcs.auction.blacklist.bypasspermission - Runtime add/remove commands (not persisted to config)
- Check command to test held item
- Auto-blocks Soulbound and Profile-Slotbound items (checks
9. Design Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Claims Storage | In PlayerData, not auction.dat | Claims persist with player, reduces auction.dat size, allows offline claim addition |
| Thread Safety | ConcurrentHashMap (no locks) | Minecraft is single-threaded for gameplay; locks add overhead without benefit |
| Vault Integration | Via PlayerCurrencyData | Single point of delegation, reused by Trader & Auction |
| Update Interval | 30 seconds | Performance vs responsiveness tradeoff |
| Player Indices | ConcurrentHashMap + Sets | O(1) lookups, thread-safe |
| Async Saves | CNPC+ Thread | Doesn't block server tick |
| Offline Claims | Load PlayerData async, add claim, save | Claims can be added to offline players without blocking |
| Config Sync | LoginPacket → AuctionClientConfig | Client never accesses server config directly |
| Item Blacklist | Static utility class | Simple, fast checks without instantiation; auto-blocks bound items |
| Bound Item Detection | Check RPGCore/Requirements NBT path |
Uses AttributeItemUtil constants for consistency |
10. Future Considerations (Not in 1.11)
- Category-based filtering (by item type, mod, etc.)
- Auction history/statistics tracking
- Auction house tax sink (currency removed from economy)
- Reserve prices (hidden minimum price)
- Private auctions (invite-only)
- Watchlist/favorites system
- Price history graphs