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
- Remove server-side check for setAIMoveSpeed to fix client prediction desync on ground mounts
- Increase air strafe factor for flying mounts to match ground speed feel