BS-BanHammer
4.2.0The most feature-rich ban hammer for Paper & Folia. Strike players with lightning effects while maintaining a complete punishment database, Discord integration, and preset system.
4.2.0latestBS-BanHammer 4.2.04 weeks ago [4.2.0] - 2026-09-28
One JAR for 1.21.x and 26.xAdded
-/bh ban <player> [duration] [reason](permissionbanhammer.ban). - Punishing offline players who have been on the server bevore (/bh ban,/mute,/jail,/warn). Offline jails are applied on the next join. - Jail time only counts down while the player is online.Bug fixes
-Expiring temporary bans no longer remove other bans on the same player. - Approving an appeal now lifts the appealed punishment (also mutes and jails). - Jail state is perstistedinjails.yml: return locations survive restarts, offlineunjailworks with Essentials. - Folia: scheduled tasks are cancelled again; ban list and inventory access on the correct thread. - The hammer works fully without a database (events, audit log, Discord, IP bans). - Mutes also covers command aliases and legacy chat listeners. - Various smaller fixes to IP unbans, appeals, the word filter, the database layer and translations.4.1.0BS-BanHammer 4.1.0Aug 9, 2026 [4.1.0] - 2026-08-08
Result of a full audit of the code base. Nothing in this release adds a new feature for its own sake; it makes the existing ones behave as documented.
- MiniMessage injection through player input. Every message was built by string substitution and then parsed as MiniMessage, so an appeal text such asSecurity
<click:run_command:'/op me'>…</click>became a real clickable component in staff chat - and/appealis available to every player by default. Substituted values are now escaped. - Statistics GUI could be opened without permission. The GUI was recognised by its window title, so renaming a shulker box to "Leaderboard" and putting an item called "Zurück" inside it opened the staff leaderboard. Menus are now identified by anInventoryHolderand every screen re-checksbanhammer.stats. This also stops BanHammer from cancelling clicks in unrelated inventories that happen to share a word in their title. - `banhammer.bypass` was ignored by all commands. Only the hammer honoured it, so a moderator withbanhammer.mutecould mute or jail a protected player. There is now a singlecanPunishcheck used by every path, including self-punishment protection. - `banhammer.ipban` was never checked. It existed inplugin.ymlbut appeared nowhere in the code; anyone withbanhammer.usecould issue IP bans via a preset. - Webhook token written to the log. A webhook URL that failed the format check was logged in full - including a validcanary.discord.comlink. The URL is no longer logged. - Discord markdown injection. Appeal texts and reasons went unescaped into embed fields, which render markdown, allowing masked links in the staff channel.
- An unreadable duration no longer means "permanent".Bug fixes
/mute Steve 1w,/mute Steve 5or any typo silently produced a permanent punishment. Parsing now distinguishes "explicitly permanent" from "not understood" and reports the latter. Weeks, months and years are supported, negative and absurd values are rejected, and the duplicate parser inPunishmentCommands(which the actual commands used) is gone. - Auto-ban repeated forever. The warning count had noactivefilter and no time window, and was never reset, so every warning past the threshold triggered another ban. Warnings are now consumed by the ban they trigger and can expire (warnings.expireAfterDays). - `/unmute` did nothing without a database. The cache was only cleared in the database branch, making mutes unliftable on servers running without one. - IP-ban records had no IP. The address was read after the player was kicked, by which timegetAddress()returns null. - A failed jail was reported as success. If jailing failed, an active JAIL record was still written and staff were told it worked, while the player walked around free. - `BanList` was modified from async threads by the unban scheduler and the appeal-approval path.banned-players.jsonis not thread-safe, and on Folia these calls throw outright - auto-unban was simply broken there. - Expired punishments could be processed forever. A failing database write left the record active, so the same expiry was re-announced to Discord every 60 seconds. Deactivation is now a compare-and-set that runs first; only the winner performs the visible side effects. - Releasing from an unloaded world threw.Location#getWorld()throws rather than returning null once the world is gone, aborting the release after the tracking maps had already been cleared - leaving the player stuck in jail. - MySQL was likely unusable. The driver was never registered (SQLite did it, MySQL did not), and the shade plugin had noServicesResourceTransformer, so the two drivers' service files overwrote each other in the jar. - No schema migration existed.CREATE TABLE IF NOT EXISTSsilently does nothing on an existing table, so a column added by an update only surfaced as "no such column" after a punishment had been applied. There is now a schema version and column reconciliation. - MySQL rejected long names.VARCHAR(16)made Geyser/Bedrock names fail with "data too long" while SQLite accepted the identical punishment. Name columns are widened on upgrade. - Staff statistics split on a name change. Grouping includedstaff_name, so a rename produced two rows for one UUID - the single-staff query then reported only the first. - Errors vanished. Roughly a dozen database chains had no error handler: with the database down, a ban was applied in-game, the record was lost, and staff got no message at all. - A jailed player could escape during relog. The enforcement cache was rebuilt only after an async lookup returned; players are now blocked first and released if the lookup says so. - Effects ran before the permission check. Lightning, sound and knockback were applied and then the action was refused - a grief tool for anyone holding a hammer. - Reload was half-applied. The mute and jail listeners were registered only if enabled at startup, and the blocked-command list, jail location and Essentials toggle needed a full restart. Listeners are always registered and read their configuration per event. - Further fixes: doubleUnbanSchedulerafter a fast double reload; leaked HikariCP pool on initialization timeout; a closed database left wired into the punishment manager;/bh givereporting success with a full inventory;/bh historyloading 1000 rows to show ten; N+1 queries when restoring jails; items lost by dragging into the GUI;AIRasitem.materialthrowing on every/bh give.
- Console replies are delivered. Command output produced by a database query used to be scheduled for the next tick; RCON closes its connection as soon as the command returns, so those replies were lost without a trace. Replies now go out synchronously when already on the main thread, and an RCON caller's deferred replies are mirrored to the server log. - Console and RCON can punish. All punishment methods take aChanged
CommandSender; console actions are attributed to a reserved UUID. API change:getStaff()on the three BanHammer events now returnsCommandSender; usegetStaffPlayer()for aPlayer. - `/appeal` works against any active punishment (mute, jail, warning, ban), not only bans. Restricted to bans it was unreachable: a banned player cannot log in to type it. - Bans are keyed on the account, not the name. A name ban is shed by simply renaming, and whoever later claims the freed name inherits it. Bans now go through Paper's profile ban list (UUID + name). Both views write the samebanned-players.json, so no migration is needed, and pardoning still clears legacy name-only entries left by older versions or vanilla/ban. - Download links are clickable labels. Update and resource-pack notices now readDownload here: [Modrinth] [CurseForge]instead of printing a raw URL that wraps across lines. Providers are configurable underdownloadLinksandresourcePackHint.links; an entry with an empty URL is hidden. - Message files are kept up to date. Keys added by a plugin update are now written into the server'smessages_*.yml(after a one-time.backup) and logged, instead of only resolving invisibly against the bundled defaults. Existing values are never overwritten. - The `/banhammer` usage line is generated. Its subcommands were maintained by hand in three places - dispatch, tab completion and the message text - which is how the usage line kept advertising apacksubcommand that no longer exists, forever, on any server whose message file predated its removal. There is now oneSubcommandlist feeding all three, and the usage text only supplies the sentence around a{commands}placeholder. It also lists just the4.0.1BS-BanHammer 4.0.1Jun 3, 2026 [4.0.1] - 2026-06-03
#### Jail System - Fixed jail escape via relogging — jailed players are now re-enforced on join (Bug Fixes
JailListener#onJoin→JailManager#restoreJailOnJoin): the enforcement cache is rebuilt on every join (even within the offline-cleanup window) and restoration also works without a database (the periodic cleanup keeps active jails in memory when no DB is configured). Previously the cache was cleared on quit and never restored, so a player could leave jail simply by reconnecting. - Fixed jails not surviving server restarts —loadJailedPlayers()now runs ininitializeDatabaseDependentComponents()after the (asynchronous) database is ready, instead of duringonEnablewhen it was stillnull. - `/unjail` now works for offline players — the database record is released even when the target is not online (previously rejected outright). - Fixed jail enforcement being blocked by the plugin's own teleports —JailListener#onTeleportnow exemptsPLUGIN-cause teleports. Previously the plugin's own "teleport back into jail" (and, on Folia, the initial jailing teleport) was cancelled by the very teleport-prevention handler, so a jailed player could leave the jail radius and never be pulled back. - Temporary jails now auto-release without a database —JailManagertracks an in-memory expiry as a fallback when no database is configured. With a database theUnbanSchedulerremains the sole authority, so there is no duplicate handling or leaked entry. - Fixed return-location being clobbered on re-jail — the pre-jail location is now saved withputIfAbsent, so restoring a jail (relog/restart) no longer overwrites the player's real return location with the jail spot. #### Essentials Integration - Essentials is now always preferred when hooked — when Essentials is present, jails are created and managed in Essentials; the built-in jail system is no longer used as a fallback in that case. - Auto-creates an Essentials jail when none exists — if Essentials is hooked but no jail has been configured, BanHammer registers its configured jail location as an Essentials jail (viasetJail) instead of falling back to the built-in system. An existing, admin-configured Essentials jail is preferred when present. - Cell selection for `/jail` — new syntax/jail <player> <duration> [cell] [reason]. The optionalcelltargets a specific Essentials jail; when omitted, the configurable default cell is used. Tab-completion suggests existing cells, and a non-existent cell is rejected with the list of available ones. The hammer and reason-only commands use the default cell. Case-insensitive cell matching. - `/jail` no longer requires a built-in jail location when Essentials is hooked — the location now comes from Essentials. #### Configuration - New `punishmentTypes.jail.useEssentials` toggle — enable/disable the Essentials jail hook from the config (defaulttrue). Whenfalse, BanHammer always uses its built-in jail even if Essentials is installed. Applies on (re)start. - New `punishmentTypes.jail.essentialsDefaultJail` (default"1") — the Essentials cell used by the hammer and by/jailwhen no cell is specified. #### Punishments / IP Bans - Fixed IP-ban removal with anonymization enabled —/unbanno longer attempts to pardon an anonymized IP. The real IP is only pardoned whenprivacy.ipAnonymization: NONE; otherwise a hint to use the vanilla/pardon-ipis logged. Applied to both manual unban and the auto-unban scheduler. - Muted players can no longer bypass chat blocking via namespaced commands (e.g./minecraft:msg). #### Presets - Fixed memory leak — per-player preset selections are now cleared on quit. - Thread-safety — preset lists are immutable snapshots swapped atomically on reload, preventing a possibleArithmeticException(modulo by zero) if a player cycled presets during/bh reload. - Modernized sound resolution — new registry-basedSoundsutility resolves both namespaced keys (block.note_block.pling) and legacy constants (BLOCK_NOTE_BLOCK_PLING), removing the deprecatedSound.valueOfwarnings. #### Stability / Logging - Removed noisyINFO-level debug logging from the jail, hammer-use, ban and Discord code paths (nowdebug). -ModrinthUpdateCheckershared fields (latestVersion,downloadUrl,changelogUrl,lastCheck) are nowvolatilefor correct visibility between the async check and the main thread. -GUIListenerno longer risks aNullPointerExceptionon inventory items without a display name.3.1.2BS-BanHammer 3.1.2Jun 3, 2026 [3.1.2] - 2026-06-03
#### Jail System - Fixed jail escape via relogging — jailed players are now re-enforced on join (Bug Fixes
JailListener#onJoin→JailManager#restoreJailOnJoin): the enforcement cache is rebuilt on every join (even within the offline-cleanup window) and restoration also works without a database (the periodic cleanup keeps active jails in memory when no DB is configured). Previously the cache was cleared on quit and never restored, so a relog escaped the jail. - Fixed jails not surviving server restarts —loadJailedPlayers()now runs ininitializeDatabaseDependentComponents()after the (asynchronous) database is ready, instead of duringonEnablewhen it was stillnull. - `/unjail` now works for offline players — the database record is released even when the target is not online. - Fixed jail enforcement being blocked by the plugin's own teleports —JailListener#onTeleportnow exemptsPLUGIN-cause teleports. Previously the plugin's own "teleport back into jail" (and, on Folia, the initial jailing teleport) was cancelled by the very teleport-prevention handler, so a jailed player could leave the jail radius and never be pulled back. - Temporary jails now auto-release without a database —JailManagertracks an in-memory expiry as a fallback when no database is configured. With a database theUnbanSchedulerremains the sole authority, so there is no duplicate handling or leaked entry. - Fixed return-location being clobbered on re-jail — the pre-jail location is now saved withputIfAbsent, so restoring a jail (relog/restart) no longer overwrites the player's real return location with the jail spot. #### Essentials Integration - Essentials is now always preferred when hooked — when Essentials is present, jails are created and managed in Essentials; the built-in jail system is no longer used as a fallback in that case. - Auto-creates an Essentials jail when none exists — if Essentials is hooked but no jail has been configured, BanHammer registers its configured jail location as an Essentials jail (viasetJail) instead of falling back to the built-in system. An existing, admin-configured Essentials jail is preferred when present. - Cell selection for `/jail` — new syntax/jail <player> <duration> [cell] [reason]. The optionalcelltargets a specific Essentials jail; when omitted, the configurable default cell is used. Tab-completion suggests existing cells, and a non-existent cell is rejected with the list of available ones. The hammer and reason-only commands use the default cell. Case-insensitive cell matching. - `/jail` no longer requires a built-in jail location when Essentials is hooked — the location now comes from Essentials. #### Messages - Hammer feedback now renders MiniMessage —HammerListenerdeserializes MiniMessage tags (e.g.<green>…</green>) instead of sending them literally. #### Configuration - Resource pack is now disabled by default —resourcePack.enabledships asfalsewith emptyurl/hash(andSettingsdefaults tofalse). The texture pack is no longer bundled/sent by the plugin; host it yourself and opt in explicitly. Previously a freshly generated config re-enabled it with a hardcoded URL. - New `punishmentTypes.jail.useEssentials` toggle — enable/disable the Essentials jail hook from the config (defaulttrue). Whenfalse, BanHammer always uses its built-in jail even if Essentials is installed. Applies on (re)start. - New `punishmentTypes.jail.essentialsDefaultJail` (default"1") — the Essentials cell used by the hammer and by/jailwhen no cell is specified. #### Punishments / IP Bans - Fixed IP-ban removal with anonymization enabled —/unbanno longer attempts to pardon an anonymized IP. The real IP is only pardoned whenprivacy.ipAnonymization: NONE; otherwise a hint to use the vanilla/pardon-ipis logged. Applied to both manual unban and the auto-unban scheduler. - Muted players can no longer bypass chat blocking via namespaced commands (e.g./minecraft:msg). #### Presets - Fixed memory leak — per-player preset selections are now cleared on quit. - Thread-safety — preset lists are immutable snapshots swapped atomically on reload, preventing a possibleArithmeticException(modulo by zero) if a player cycled presets during/bh reload. - Modernized sound resolution — new registry-basedSoundsutility resolves both namespaced keys (block.note_block.pling) and legacy constants (BLOCK_NOTE_BLOCK_PLING). #### Stability / Logging - Removed noisyINFO-level debug logging from the jail, hammer-use, ban and Discord code paths (nowdebug). -ModrinthUpdateCheckershared fields are nowvolatilefor correct visibility between the async check and the main thread. -GUIListenerno longer risks aNullPointerExceptionon inventory items without a display name.4.0.0BS-BanHammer 4.0.0May 3, 2026 [4.0.0] - 2026-05-02
#### Breaking Changes - Minimum Java version: 25 (up from 21) - Minimum Minecraft version: 26.1.x (Paper 26.1.2+) - api-version:Major Release - Paper 26.1.x Support
26.1in plugin.yml - Not compatible with 1.21.x servers (use v3.1.1 for 1.21.x) #### Modernized API Usage - Removed all deprecated `kickPlayer(String)` calls — now usesPlayer.kick(Component)everywhere - Removed `Bukkit.broadcastMessage(String)` — now usesBukkit.broadcast(Component)- Removed legacy `§` color codes — Update Checker now uses Adventure Component API with clickable links - Removed deprecated `setResourcePack()` fallbacks — now uses AdventureResourcePackRequestAPI exclusively - Removed deprecated `Server.getResourcePack()` fallback — usesServer.getServerResourcePack()only - Removed reflection-based ResourcePack sending — direct API calls now that Paper 26.x provides them natively - Improved `getOfflinePlayer(String)` usage — usesgetOfflinePlayerIfCached()first, deprecated call only as last resort - Replaced `Material.CHAIN` (removed in 26.1) withMaterial.IRON_BARSin Statistics GUI #### Build System Updates - Updatedmaven-compiler-pluginto 3.14.0 (Java 25 support) - Updatedmaven-shade-pluginto 3.6.1 (class file version 69 / Java 25 support) - Paper API dependency uses new version format:[26.1.2.build,)#### Resource Pack - Removed built-in resource pack sending — pack is now a separate download on [Modrinth](https://modrinth.com/resourcepack/bs-banhammer-resource-p… - RemovedResourcePackSender,ResourcePackListener, and allresourcePack.*config options - Added clickable join hint for staff (resourcePackHint.enabled: truein config, disable if not needed) #### Metrics - Added [bStats](https://bstats.org) integration (Plugin ID: 31076) #### Update Checker - Game version filter (from v3.1.1) ensures 1.21.x users don't see 4.0.0 updates3.1.1BS-BanHammer 3.1.1May 3, 2026 [3.1.1] - 2026-05-02
#### Update Checker - Game Version Filter - Update notifications are now filtered by Minecraft version — servers only see updates compatible with their game version - UsesImprovement
Bukkit.getMinecraftVersion()to detect the running server version - Passesgame_versionsparameter to Modrinth API to filter releases - Why: Prepares for Paper 26.x support — 1.21.x users won't receive update notifications for incompatible 26.x releases (and vice versa)3.1.0BS-BanHammer 3.1.0Apr 24, 2026 [3.1.0] - 2026-04-24
#### Folia Support (Dual-Compatibility) - Paper + Folia from a single JAR — automatically detects the platform at startup - NewNew Feature
FoliaSchedulerutility class abstracts all scheduler, teleport and kick operations -plugin.ymldeclaresfolia-supported: trueMigrated APIs: - AllBukkit.getScheduler().runTask()calls →FoliaScheduler.runGlobal()/runOnEntity()- AllrunTaskTimerAsynchronously()calls →FoliaScheduler.runAsyncRepeating()- Allplayer.teleport()calls →FoliaScheduler.teleportAsync()(usesteleportAsync()on Folia) - AllBukkitTaskfields →ObjectwithFoliaScheduler.cancelTask()- GUIopenInventory()calls run on entity scheduler for correct thread ownership - Resource pack sending uses entity-delayed scheduler Files changed: -BanHammerPlugin.java— Folia detection on startup -PunishmentManager.java— 13 scheduler replacements -UnbanScheduler.java— async scheduler, entity scheduler for jail release -JailManager.java— 4 teleport migrations, scheduler migration -ModrinthUpdateChecker.java— async scheduler, global scheduler for notifications -StatisticsGUI.java— entity scheduler for inventory operations -ResourcePackListener.java— entity-delayed scheduler -EssentialsJailIntegration.java— async teleport No changes needed:HammerListener.java,AppealCommand.java,BanHammerCommand.java— events already fire on correct regional threads.3.0.1BS-BanHammer 3.0.1Apr 18, 2026 [3.0.1] - 2026-04-18
#### Critical - Unjail Teleport nicht funktioniert: Spieler wurden beim Release aus dem Jail nicht an ihren ursprünglichen Ort zurückteleportiert - Ursache: JailListener hat den Release-Teleport gecancelt, weil der Spieler noch im Jail-Cache war - Fix: Cache-Entfernung erfolgt jetzt VOR dem Teleport inBug Fixes
JailManager.releasePlayer()- Gilt sowohl für/unjailBefehl als auch automatischen Ablauf - SimpleDateFormat nicht thread-safe:BanHammerCommandnutzte statischesSimpleDateFormataus async CompletableFuture-Callbacks - Fix: Ersetzt durch thread-sicherenDateTimeFormatter- loadActiveMutes() doppelte DB-Queries:CompletableFuture.allOf()wurde aufgerufen und ignoriert, dann die gleichen 2 Queries nochmal einzeln - Fix: Sinnlosen allOf-Block entfernt (4 Queries → 2) - Discord Shutdown Hook Leak: Bei jedem/bh reloadwurde ein neuerRuntime.addShutdownHook()registriert ohne den alten zu entfernen - Fix: Hook-Referenz wird gespeichert und beishutdown()entfernt #### High Priority - getDatabase() NullPointerException:handleAppeals()undreviewAppeal()riefenplugin.getDatabase()ohne Null-Check auf - Fix: Null-Checks vor allen direktengetDatabase()-Aufrufen in BanHammerCommand - unbanPlayer() findet nur BAN-Typ: Temp-Bans und IP-Bans konnten per/bh unbannicht entfernt werden - Fix: Sucht jetzt nach allen Ban-Typen (BAN, TEMP_BAN, IP_BAN) und entfernt auch IP-Bans aus der IP-Banliste - unmutePlayer() findet nur MUTE-Typ: Temp-Mutes konnten per/unmutenicht entfernt werden - Fix: Sucht jetzt nach allen Mute-Typen (MUTE, TEMP_MUTE) - IPv6-Validation immer true:isValidIP()in UnbanScheduler gab für jede IPv6-Adresse true zurück, auch gehashte IPs - Fix: Gehashte IPs werden erkannt (kein./:→ sofort false) - HttpURLConnection Leak: ModrinthUpdateChecker hatconnection.disconnect()nie aufgerufen - Fix:disconnect()im finally-Block; zusätzlich Null-Checks für JSON-Response-Felder #### Medium Priority - PunishmentManager Race Condition: Manager wurde mit null-Database erstellt und bei DB-Init komplett neu erstellt — Listener behielten alte Referenz - Fix: DB/Discord-Referenzen sind jetztvolatileund updatebar viaupdateDatabase()/updateDiscord()- Cooldown Maps Memory Leak:cooldowns,switchCooldowns,switchKickJailCooldownsin HammerListener wuchsen unbegrenzt - Fix: Cleanup beiPlayerQuitEvent- Auto-Unjail ohne Teleport: UnbanScheduler nutztereleasePlayerByUUID()für abgelaufene Jails, was keinen Teleport zurück auslöst - Fix: Online-Spieler werden jetzt perreleasePlayer()(mit Teleport) auf dem Main-Thread freigelassen - Essentials Jail Release ohne Rück-Teleport: Bei Essentials-Release wurde der Spieler nicht zum Original-Ort zurückteleportiert - Fix: Return-Location wird auch bei Essentials-Release verwendet
- Modrinth API Response: Robustere JSON-Parsing mit Null-Checks fürImprovements
version_number,urlundfiles- DoppelterreleasePlayer()-Aufruf inunjailPlayer()entfernt (Caller ist verantwortlich)3.0.0BS-BanHammer 3.0.0Jan 8, 2026 [3.0.0] - 2026-01-08
#### Ban Presets System (NEW!) - Shift + Right-Click to switch between predefined ban presets - Actionbar feedback shows current preset when switching - Sound feedback individually configurable per preset - Unlimited presets definable in config.yml - Each preset with own duration, reason, IP-ban flag and sound - Per-player tracking of active preset - Configurable switch cooldown (250ms default) - Works everywhere: on players, blocks or in the air #### Kick/Jail Presets System (NEW!) - Shift + Left-Click to switch between predefined kick/jail presets - Mix kicks and jails in one preset list (no duration = kick, with duration = jail) - Actionbar feedback shows current preset when switching - Sound feedback individually configurable per preset - Unlimited presets definable in config.yml - Per-player tracking of active kick/jail preset - Same configurable cooldown as ban presets - Left-Click on Player executes kick or jail with active preset #### Modrinth Update Checker (NEW!) - Automatic update checking on server startup - Periodic checks with configurable interval (default: 6 hours) - Admin notifications on login (permission:Main Features
banhammer.updatenotify) - Semantic version comparison - Download URLs and changelog links - Rate limiting (max 1 check per hour) - Fully configurable in config.yml #### Database System - SQLite support for single-server (no setup required) - MySQL support for multi-server networks - Complete ban history with detailed tracking - Automatic schema creation and migrations - Connection pooling with HikariCP for optimal performance - WAL mode for SQLite (better concurrency) - Optimized indexes for fast queries #### Auto-Unban System - Automatic unbanning when temporary bans expire - Configurable check intervals (default: 60 seconds) - Asynchronous processing (doesn't block main thread) - Event triggers for external plugins - Discord notifications on auto-unbans - Supports temp-bans, temp-mutes and jail times #### Discord Integration - Webhook-based notifications - Color-coded embeds for different actions: -Bans (Red) -
Kicks (Orange) -
Unbans (Green) -
Mutes (Yellow) - Staff names, player names, duration and reason in embeds - Server names for multi-server setups - Configurable which events are sent - NEW: Discord now works independently of database (no database required) - NEW: Discord webhook reinitializes on
/bh reloadwithout server restart #### Essentials Jail Integration (NEW!) - Soft Dependency: Optional Essentials plugin integration viasoftdependin plugin.yml - Reflection-Based: No hard dependency - uses reflection to access Essentials API - Smart Preference System: Automatically uses Essentials jail if available, falls back to built-in - Automatic Detection: Checks for Essentials on startup and enables integration - Built-in Fallback: Own jail system continues to work if Essentials not installed - Seamless Integration: Works with existing Essentials jail configurations - Debug Logging: Comprehensive DEBUG TELEPORT logs for troubleshooting
#### Extended Punishment Types - Mute System: Blocks chat and commands - Permanent and temporary - Cache-based for performance - Shows remaining time - Jail System: Locks players in place - Configurable jail location viaNew Features
/setjail- Prevents teleportation and movement - Optional: Prevents damage and commands - Warning System: Warnings with auto-ban - Counts warnings per player - Auto-ban after X warnings (configurable) - Non-active punishment (only tracking) #### Ban Appeals System - Players can submit appeals via/appeal <text>- Cooldown system (default: 24 hours) - Maximum appeals per punishment (default: 3) - Staff can approve/deny appeals - Discord notifications for new appeals - Appeal status tracking (PENDING, APPROVED, DENIED) #### Statistics & Leaderboards - Tracking of all punishments per staff member - Total counts: Bans, kicks, mutes, warnings - Leaderboard system - GUI view via/bh stats- Exportable via REST API #### GDPR & Privacy Features - IP anonymization with 4 levels: -NONE: Full IP storage -PARTIAL: Last octet removed (192.168.1.0) -HASH: One-way hash with server salt -FULL: Complete masking - Automatic salt generation - Salt validation (min. 16 characters, 3 character types) - Configurable data retention
#### Performance Optimizations - Asynchronous database initialization (no longer blocks server start) -Improvements
loadActiveMutes()loads mutes into cache on startup - Optimized warning count viaSELECT COUNT(*)instead of N+1 query - SQLite connection pool set to 1 (single-writer) - Race condition ingetActiveMute()fixed viacomputeIfPresent()- Composite indexes for common query patterns #### Error Handling & Robustness - Separate try-catch blocks in ban flow (prevents partial state) - Improved Discord webhook validation - URL format check - Clear error messages - Graceful degradation - Robust duration parsing - Supports: "7d", "1h30m", "PT24H", "permanent" - Case-insensitive - Warnings for invalid format - Improved IPv6 validation viaInetAddress#### Thread-Safety - Mute cache removes expired entries atomically - Switch cooldown via ConcurrentHashMap - Database operations fully async - Events fired on main thread
New commands: -Commands
/bh appeals- Shows pending appeals -/bh approve <id> [response]- Approves appeal -/bh deny <id> [response]- Denies appeal -/bh stats [player]- Shows statistics -/bh reload- IMPROVED: Now reinitializes Discord webhook and Database connection -/appeal <text>- Submits appeal -/mute <player> <duration> [reason]- Mutes player -/unmute <player> [reason]- Unmutes player -/jail <player> <duration> [reason]- Jails player (uses Essentials if available) -/unjail <player> [reason]- Releases from jail (works without database) -/setjail- Sets jail location (only needed for built-in jail) -/warn <player> [reason]- Warns player
New permissions: -Permissions
banhammer.appeals- Can view appeals -banhammer.appeals.review- Can review appeals -banhammer.appeal- Can submit appeals (default: true) -banhammer.mute- Can mute players -banhammer.jail- Can jail players -banhammer.warn- Can warn players -banhammer.stats- Can view statistics -banhammer.updatenotify- Receive update notifications
#### Custom Events -API
PlayerPunishEvent- Fired BEFORE punishment (cancellable) -PlayerPunishedEvent- Fired AFTER successful punishment -PlayerUnpunishedEvent- Fired when punishment removed #### PunishmentManager API
#### Database Interface - Abstract interface for SQLite/MySQL - All operations via CompletableFuture - Prepared statements against SQL injection// Fully async with CompletableFuture pm.banPlayer(staff, victim, reason, duration, ipBan) pm.mutePlayer(staff, victim, reason, duration) pm.jailPlayer(staff, victim, reason, duration) pm.warnPlayer(staff, victim, reason) pm.getHistory(playerUuid, limit) pm.getWarningCount(playerUuid)
#### Critical Bug Fixes -Bug Fixes
Expired Punishment Spam (CRITICAL): Fixed infinite "Found 1 expired punishment(s), processing..." spam - Root Cause: NULL UUID handling in
deactivatePunishment()caused NullPointerException - Fix: Added null check for staffUuid in SQLiteDatabase.java:396 and MySQLDatabase.java:406 - Impact: Prevented database corruption and console spam -Jail Auto-Release Not Working (CRITICAL): Players weren't automatically released after jail time expired - Root Cause: Missing JAIL case in UnbanScheduler switch statement - Fix: Added JAIL case to UnbanScheduler.java:110-114 - Impact: Jail time now properly expires and releases players automatically -
**Unjail Required D
2.2.0BS-BanHammer 2.2.0Nov 28, 2025 [2.2.0] - 2025-11-29
Added
- Automatic resource pack delivery when players join, with configurable delay. - Prioritization of existing server resource packs over the BanHammer pack. - Shared ResourcePackSender, which is also used by the /banhammer pack command. - Feedback for /banhammer pack, which shows which pack was sent.2.1.1BS-BanHammer 2.1.1Nov 18, 2025 Update to 1.21.102.1.0BS-BanHammer 2.1.0Oct 13, 2025
Similar projects
Plugin →VeinMiner
Mine the whole vein on mining a single ore/block. Make the tedious mining experience to something satisfying and fun! FTB Ultimine alternative
99.3MSueta
Simple Voice Chat
A working voice chat in Minecraft!
76.8MSueta
Chunky
Pre-generates chunks, quickly and efficiently
18.4MSueta
VeinMiner Enchantment
Veinminer Addon - Adds vineminer enchantment to enchanting tables. Only tools with the enchantment can veinmine
18MSueta
JourneyMap
Real-time map used for mapping in-game or your browser as you explore.
14.7MSueta
WorldEdit
A Minecraft Map Editor... that runs in-game! With selections, schematics, copy and paste, brushes, and scripting. Use it in creative, or use it temporarily in survival.
11.6MSueta