Issue: Module configuration files (ban.yml, mutes.yml, etc.) were being auto-formatted by the plugin, causing line breaks in long strings and breaking the YAML syntax.
Problem: The plugin was loading module configs into a global map and then saving them during saveAllConfigs(), which triggered Bukkit's YAML formatter to add unwanted line breaks for strings longer than ~80 characters.
Fix:
config.yml and messages.yml are saved by the pluginImpact: Your module configuration files will no longer be modified by the plugin, preserving their original formatting and structure.
Issue: Staff notifications for muted players showed "Unknown" as duration instead of the actual remaining mute time.
Problem: The code was using blocking .get() calls and only checking for "MUTE" punishment type, missing "IP_MUTE" entries.
Fix:
thenAcceptAsync() handlersImpact: Staff will now see correct mute durations in chat attempt notifications for both regular and IP mutes.
Issue: Discord slash commands were timing out with "Unknown interaction" errors after 3 seconds.
Problem: The /getinfo command was using blocking .get() calls on database queries, preventing Discord from receiving an immediate acknowledgment.
Fix:
CompletableFuture chainsgetPlayerDataAsync() method that returns CompletableFuture<PlayerData>.get() calls from Discord command handlersImpact: Discord commands will no longer timeout, providing a smoother experience for staff members using the Discord bot.
Issue: History dropdown interactions in Discord were timing out with "zip file closed" errors.
Problem: The HistoryDropdownHandler was using .thenAccept() instead of .thenAcceptAsync(), which could cause thread blocking during database operations.
Fix:
.thenAccept() to .thenAcceptAsync() in both outer and inner chainsImpact: Discord dropdown menus for history entries will no longer timeout or cause errors, providing a seamless experience for staff.
Issue: Staff notifications for muted players showed "0 seconds" instead of the actual remaining mute time.
Problem: The code was checking for "expiryTime" in JSON data, but the database stores it as "expiry_time" (with underscore).
Fix:
"expiry_time" and "expiryTime" for backward compatibilityImpact: Staff will see correct mute durations like "2 hours, 15 minutes" instead of "0 seconds".
Issue: Vanished players still received knockback when hit, making their vanished status obvious to others.
Solution: Implemented knockback prevention using Paper's native EntityKnockbackEvent API.
Features:
Impact: Vanished players remain completely invisible, making staff investigations undetectable.
Issue: Using ban/mute templates without proper configuration caused crashes with NullPointerException.
Problem: Templates could be missing escalation or durations fields in configuration, causing crashes when the code tried to access them.
Fix:
escalation configuration before accessing itdurations list before accessing itImpact: The plugin will no longer crash when using templates with incomplete configuration, improving stability.
Issue: IP ban entries in database had incomplete JSON in additional_data field (missing closing brace).
Problem: When creating IP ban history entries for offline players, the JSON string was incomplete, causing parsing errors.
Fix:
"ip" field to IP ban JSON for offline playersImpact: IP ban data is now properly stored and can be correctly parsed for duration calculations and case management.
Issue: Staff notifications for banned players trying to join showed "Permanent" even for temporary bans.
Problem: The code was not calculating the remaining ban duration correctly from the expiry time stored in additional_data JSON.
Fix:
expiry_time in JSONImpact: Staff will now see accurate ban durations in join attempt notifications, making it easier to track when players can return.
Issue: Template bans showed incorrect escalation levels and disconnect screen showed "Permanent" instead of actual duration.
Problem:
Fix:
%(% in reason fieldImpact: Template bans now properly escalate (1st offense → 2nd offense) and show correct duration on disconnect screen.
Issue: Vanish module caused "Thread ForkJoinPool.commonPool-worker-5 failed main thread check" errors when applying vanish effects during player join.
Problem: The handlePlayerJoin() method in VanishModule was applying vanish effects (hiding players) from an async thread, but Bukkit's hidePlayer() operation must run on the main thread.
Fix:
Bukkit.getScheduler().runTask() to ensure it runs on main threadImpact: Vanish module no longer causes thread errors, providing a smoother experience for staff members using vanish.
Issue: Discord /unban command incorrectly reported "Player is not banned" for IP-banned players, even when they were clearly banned in the database.
Problem: The command was only checking playerData.isBanned() (regular ban status) and not checking playerData.isIpBanned() (IP ban status), causing IP-banned players to be rejected.
Fix:
isBanned() and isIpBanned()/unban command which checks both ban typesImpact: Staff can now unban IP-banned players via Discord without receiving false "not banned" errors.
Issue: Disconnect screen showed the original ban duration (e.g., "Unbanned in: 3 hours") instead of the actual remaining time (e.g., "Unbanned in: 20 minutes").
Problem: The code was using durationSeconds (original duration) instead of remainingDuration when creating the disconnect screen message.
Fix:
expiry_time in additional_data JSONdurationDisplay and untilMessageImpact: Banned players now see accurate remaining ban time on disconnect screen. For example, if they were banned for 3 hours 40 minutes ago, they'll see "Unbanned in: 20 minutes" instead of "Unbanned in: 3 hours". This fix applies to all bans, including existing ones in your database.
Issue: When a normal player joins the server while a staff member is vanished, the normal player could see the vanished staff member in both the world and the tab list.
Problem: The handlePlayerJoin() method wasn't properly hiding already-vanished players from new joiners. It only handled the case when the joining player was vanished, not when other players were already vanished.
Fix:
playerListName(Component.empty())Impact: Vanished staff members are now completely invisible to normal players, both in the world and in the tab list. This applies to both newly vanished players and already-vanished players.
Issue: Not all ban and unban operations were being logged to Discord channels.
Problem: The banOfflinePlayerWithCaseId() and ipBanOfflinePlayerWithCaseId() methods were missing Discord logging calls, causing offline bans to not appear in Discord.
Fix:
banOfflinePlayerWithCaseId() for offline player bansipBanOfflinePlayerWithCaseId() for offline IP bansImpact: All ban and unban operations are now consistently logged to Discord channels, providing complete audit trails for staff.
Issue: Sometimes "IPBAN" was stored instead of "IP_BAN", causing inconsistencies in database queries.
Problem:
Fix:
getActiveBanOrMuteCaseId() to support both formatsdeactivateIpBans() to support both formatsImpact: All IP ban queries now work correctly regardless of whether old entries use "IPBAN" or new entries use "IP_BAN".
modules/*.yml filesVersion: 1.1.9

Advanced moderation plugin with ban/mute systems, escalation templates, offline support, and Web-API integration for professional server management.