- Add Auctioneer to role dropdown in GuiNpcAdvanced
- Create GuiNpcAuctioneer setup GUI for configuring:
- Tab visibility (browse, my listings, my bids, claims)
- Player actions (create, bid, buyout)
- Custom welcome/disabled messages
- Add PlayerAuction container handler in CommonProxy
- Add PlayerAuction GUI handler in ClientProxy
- Add all role.auctioneer lang keys to en_US.lang
- Consolidate AuctionLogger and AuctionNotificationController into AuctionController
- Add inline logging and notification methods to AuctionController
- Add comprehensive LANG keys for all auction GUI strings
- Update EnumAuctionSort and EnumAuctionDuration to use lang keys
- Remove category filtering system (EnumAuctionCategory deleted)
- Update AuctionFilter to remove category references
- Update GuiAuction and all sub-GUIs to use StatCollector.translateToLocal()
- Update AuctionListing to remove category field and NBT serialization
New files:
- EnumAuctionSort: Sorting options (price, time, name, bids, etc.)
- AuctionFilter: Search/filter criteria with builder pattern
- AuctionDataPacket: Large packet for server->client listing data
AuctionController changes:
- getFilteredListings(): Main filtering/pagination method
- sortListings(): Comprehensive sorting by various criteria
- quickSearch(): Convenience method for simple searches
- FilterResult: Pagination result container
AuctionListing changes:
- Added bidCount field with NBT persistence
- Added creationTime alias methods
AuctionActionPacket changes:
- QueryListings: Filter-based search
- QueryMyListings: Player's own listings
- QueryMyBids: Player's active bids
- QueryClaimable: Items ready to claim
NoppesUtil changes:
- Auction data storage and IAuctionData interface
- Client-side data handling for GUI integration
- Add ItemTradeAttribute.java for trade restriction utilities
- TAG_UNTRADEABLE for items that cannot be traded
- Check existing TAG_PROFILE_SLOT and TAG_SOULBIND tags
- canTrade() checks all three restriction types
- getTradeBlockReason() returns localization key for UI
- Utility methods for setting/getting each restriction type
- clearAllRestrictions() and getRestrictionSummary() helpers
- Add AuctionBlacklist.java controller
- Blacklist items by registry name (e.g., "minecraft:diamond_sword")
- Blacklist entire mods by mod ID (e.g., "minecraft")
- Blacklist items with specific NBT tags (supports dot notation)
- isBlacklisted() and getBlacklistReason() for checking
- Persistence via auction_blacklist.dat
- Add/remove methods for each blacklist type
- Initialize AuctionBlacklist in CustomNpcs.java
- Add scripting API methods to ScriptItemStack.java
- canTrade() - check if item can be traded
- getTradeBlockReason() - get block reason
- isUntradeable() / setUntradeable() - manage untradeable flag
- isProfileSlotBound() / getProfileSlot() / setProfileSlotBound()
- isSoulbound() / getSoulbindOwner() / removeSoulbind()
- clearTradeRestrictions() - remove all restrictions
- getRestrictionSummary() - human-readable summary
- Currency now stored in main player save file, not separate file
- Currency excluded from getNBT/setNBT (slot-specific data)
- Currency saved in save() after getNBT(), loaded before setNBT()
- This ensures currency is preserved during profile slot changes
- Removed loadCurrency() and saveCurrency() separate file methods
- Updated VaultHelper to call save() instead of saveCurrency()
Configuration now uses the main config file with nested categories:
- market (main category)
- market.currency (currency system settings)
- market.auction (auction house settings)
- market.trader (trader stock settings)
This keeps all market/economy settings in one place within the
existing main configuration file.
This plan covers three major features:
- Auction House: New Auctioneer NPC role with global auction system
- Currency System: VaultAPI integration for Bukkit hybrid servers
- Trader Enhancements: Stock/inventory system with reset timers
Includes detailed architecture, data structures, and implementation order.
When users modified biomes, dimensions, or spawning options through the
sub-GUI dialogs, changes were only stored in client memory and never sent
to the server. This caused spawn configurations to appear correct in the
UI but fail to work after server restarts.
The closeSubGui() method now calls save() when SubGuiNpcBiomes,
SubGuiNpcDimensions, or SubGuiSpawningOptions dialogs close, ensuring
changes are immediately sent to the server via NaturalSpawnSavePacket.
Added @Override annotation for consistency with other GUI classes.
The canQuestBeAccepted() method was missing cases for MCCUSTOM and
RLCUSTOM repeat types, causing quests with custom cooldowns to become
permanently inaccessible after first completion. Added the missing
checks using quest.customCooldown for both MC ticks and real-life
milliseconds.
Two issues were causing the bug:
1. GuiDialogInteract.close() called stopAllSounds() unconditionally,
which stopped Bard music even when the dialog had no sound or
when a different Bard was playing nearby.
2. MusicController.stopMusic() didn't set playDelay, allowing Bards
to immediately restart their music after dialog close.
Changes:
- MusicController.stopMusic() now sets playDelay=20 and clears entity
reference to prevent immediate music restart
- Added MusicController.stopSound(key) to stop specific sounds
- Dialog GUIs now track their dialog sound and only stop that on close,
preserving Bard music and other sounds
The LivingAttackEvent handler was firing too late for NPCs because
EntityNPCInterface.attackEntityFrom() has its own immunity check that
runs BEFORE calling super (which fires LivingAttackEvent).
Now the attack speed bypass is checked directly in the NPC's
attackEntityFrom() method, before the immunity check at line 658.
Instead of blindly resetting hurtResistantTime for fast weapons, now
checks if enough time has elapsed based on the weapon's attackSpeed:
- timeElapsed = maxHurtResistantTime - hurtResistantTime
- Allow attack when: hurtResistantTime <= maxHurtResistantTime - attackSpeed
Example: attackSpeed=10, maxHurtResistantTime=20
- Allows attack when hurtResistantTime <= 10 (10 ticks elapsed)
- Remove legacy attack speed handling from ServerEventsHandler.LivingHurtEvent
(was setting hurtResistantTime AFTER immunity check, too late)
- Add proper handling in ScriptPlayerEventHandler.LivingAttackEvent
(sets hurtResistantTime=0 BEFORE immunity check for fast weapons)
- For weapons with attackSpeed < 20, bypass invincibility frames to allow
rapid attacks to land
- Player logout: Dismount from NPC mount before logout to prevent
orphaned mount state (ServerTickHandler)
- Teleportation: Dismount before cross-dimension teleport to prevent
mount being left behind in old dimension (NoppesUtilPlayer)
- Dead rider: Validate rider is alive, dismount dead/invalid riders
to prevent stuck mount state (NPCMountUtil)
- Role disable: Dismount rider when mount role is disabled to prevent
mounted player on non-mount NPC (RoleMount)
- Remove all velocityChanged=true flags from mount movement code
(NPCMountUtil, EntityNPCInterface, EntityNPCFlying)
- Make performMountedMovement physics server-side only like vanilla horse
- Remove syncMountedRiderVelocity method that forced rider velocity packets
- Fix ground movement to not reset motionY every tick
- Let Minecraft's entity tracker handle position sync naturally
The jitter was caused by S12PacketEntityVelocity being sent every tick,
which constantly reset client interpolation. Vanilla horses/boats never
set velocityChanged and rely on the entity tracker for smooth sync.
- Fix category search logic for Quest/Dialog/Transport tabs that was
incorrectly checking selectedCategory.isEmpty() before filtering,
which cleared the category list instead of filtering it
- Add resetScroll() calls to all search methods so scroll position
resets when search results change