- Java 21 required — Minimum Java version raised from 17 to 21. Server must run JDK 21+.
DKIConfigimmutable config snapshot — All ~60 config values cached in a single object at startup/reload. Hot-path methods (onPlayerDeath,isWorldEnabled, etc.) no longer callgetConfig().get*()on every death event.EconomyModeenum — Replaced string comparisons ("charge-to-keep","gui") with type-safe enumCHARGE_TO_KEEP / CHARGE_TO_BYPASS / GUIthroughoutDeathListener.- Stats TTL cache —
StatsManagernow evicts offline player stats after 5 minutes instead of holding them indefinitely in memory.
- WorldGuard hook — Region-based keep-inventory rules:
in-own-region— keep items/XP when dying in a region you own/are member ofin-other-region— keep items/XP when dying in someone else's regionwilderness— fallback rule for areas outside any region
- Towny hook — Town-based keep-inventory rules:
in-own-town— keep items/XP when dying in your own townin-other-town— keep items/XP when dying in another player's townwilderness— fallback rule for areas outside any town
- Grave fallback warning — When GravesX/AxGraves fails to create a grave, the plugin now logs a warning and optionally drops items naturally (configurable via
integrations.graves.fallback-on-fail) - MMOItems configurable tags —
hooks.mmoitems.protected-tagslist allows specifying which NBT tags count as soulbound (defaults toMMOITEMS_SOULBOUND)
- First Death Leniency (
rules.first-death) — Players keep items/XP on their very first death ever. Configurable keep-items and keep-xp separately. - Death Streak Protection (
rules.streak) — Players who die N times within a configurable time window (e.g., 3 deaths in 300 seconds) get keep-inventory protection. Prevents frustration during difficult content.
/dki test [player]— Diagnostic command that simulates the rule chain for a player and reports which rule would apply, what the result would be, and why. Useful for debugging configuration./dki status— Now shows the active rule chain with numbered rules in evaluation order.
- Config validation on startup/reload —
ConfigMigration.validateConfig()checks: time ranges (0–24000), day < night, trigger values, check-interval > 0, economy cost ≥ 0, GUI timeout/expire > 0, valid economy mode. - Safe reload —
/dki reloadnow runs config migration before reloading, preventing stale config from being loaded. - Broadcast permission — New
messages.broadcast.permissionconfig key to restrict death messages to players with a specific permission (empty = broadcast to all). RuleManager.getRuleNames()— Exposes ordered list of active rules for status display and debugging.
The full rule evaluation order is now:
BypassPermissionRule— permission-based bypassFirstDeathRule— first death leniency (if enabled)DeathStreakRule— death streak protection (if enabled)ProtectionRule— Lands / GriefPrevention / WorldGuard / Towny region checksDeathCauseRule— PvP vs PvE filteringWorldTimeRule— day/night cycle rules
messages:
broadcast:
permission: "" # empty = all players
integrations:
graves:
fallback-on-fail: true # drop items if grave creation fails
worldguard:
enabled: false
in-own-region:
keep-items: true
keep-xp: true
in-other-region:
keep-items: false
keep-xp: false
wilderness:
enabled: false
keep-items: false
keep-xp: false
towny:
enabled: false
in-own-town:
keep-items: true
keep-xp: true
in-other-town:
keep-items: false
keep-xp: false
wilderness:
enabled: false
keep-items: false
keep-xp: false
hooks:
mmoitems:
protected-tags: [] # empty = default MMOITEMS_SOULBOUND
rules:
first-death:
enabled: false
keep-items: true
keep-xp: true
streak:
enabled: false
threshold: 3
window-seconds: 300
keep-items: true
keep-xp: true- Added WorldGuard 7.0.11 (
worldguard-bukkit, scope: provided) - Added Towny 0.98.3.0 (scope: provided)
- Updated
plugin.ymlsoftdepend:[Vault, Lands, GriefPrevention, PlaceholderAPI, GravesX, AxGraves, WorldGuard, Towny, MMOItems]
DKIConfig.java— Immutable config snapshot classEconomyMode.java— Economy mode enumWorldGuardHook.java— WorldGuard region integrationTownyHook.java— Towny town integrationFirstDeathRule.java— First death leniency ruleDeathStreakRule.java— Death streak protection rule
- All 51 tests passing after upgrade
- Fixed test compatibility with
DKIConfigsnapshot pattern (refreshDKIConfig()after config mutations)
- Fixed
DeathGuiHolder.getInventory()returning null — Addedinventoryfield + setter;DeathConfirmGUInow callsholder.setInventory()afterBukkit.createInventory() - Fixed
StatsGUIusing null holder — NewStatsGuiHolderclass replaces the null holder; click/drag event handlers now useinstanceof StatsGuiHolderinstead of fragile title-string matching - Fixed language default
"vi"— Default language inDynamicKeepInvPlugincorrected to"en"to matchmessages.yml - Fixed misleading
volatileoneconomyRetryCount— Removedvolatilekeyword; all accesses are already inside asynchronizedblock - Fixed missing AxGraves path in
DeathListener— Added AxGraves fallback after GravesX, mirroring the logic already present inPendingDeathManager.performDrop()
RuleReasonsconstants class — All magic reason strings ("bypass","pvp","pve","time-day","time-night","lands-defer", etc.) replaced with typed constants inrules/RuleReasons.java- Imports cleanup in
DeathListener— All inline fully-qualified class names moved to proper top-of-file imports
BypassPermissionRuleTest— 4 Mockito unit testsDeathCauseRuleTest— 4 Mockito unit testsWorldTimeRuleTest— 4 Mockito unit testsRuleManagerTest— 6 Mockito unit testsEconomyManagerTest— 10 Mockito unit testsDeathListenerTest— 6 MockBukkit integration tests
- God class split —
DynamicKeepInvPlugin(893 → 639 lines) decomposed into:IntegrationManager— owns all hook setup/teardown and availability checksCommandDispatcher— owns all/dkicommand handling logic
- pom.xml — All 11 dependency versions extracted to named
<properties>;maven-enforcer-pluginadded (requires Java ≥ 17, Maven ≥ 3.6)
wiki/Basic-Configuration.md— Rewritten to match actualconfig.ymlstructure; removed stale keys (keep-inventory-day,keep-inventory-night,advanced.enabled,world-settings,gamerule-change)wiki/Advanced-Configuration.md— Removed staleadvanced.enabledrequirement; updated all config paths to match current structure; added AxGraves section
- Auto-Pay Option - Players can enable auto-pay to automatically keep items on death
- Toggle with
/dki autopaycommand or via GUI button - When enabled, automatically pays and keeps items without showing GUI
- Falls back to GUI if player doesn't have enough money
- Setting saved per-player in database
- Toggle with
- Fixed
/dki confirmand/dki autopayerror messages - Now properly checks if GUI mode is enabled before allowing commands
- Added
player_settingstable for storing auto-pay preferences - Added auto-pay toggle button in Death Confirmation GUI (slot 8)
- Death Confirmation GUI - New economy mode
guithat shows a GUI when player dies- Players can choose to pay to keep items or drop them
- Configurable timeout (default: 30 seconds)
- Persistent storage survives server restarts
- Handles disconnect/reconnect gracefully
- Protected against inventory duplication exploits
- Command
/dki confirmto reopen the GUI
- Pending Death Database - Separate SQLite database for pending deaths persistence
- New economy mode:
mode: "gui"(alongside existingcharge-to-keepandcharge-to-bypass) - New GUI settings under
advanced.economy.gui:timeout: 30- Seconds before auto-dropexpire-time: 300- Seconds to store pending death if player disconnects
- Fixed timestamp not restored from DB - Pending deaths loaded from database now use original timestamp instead of current time
- Fixed ConcurrentModificationException - Cleanup task now collects expired IDs before iterating
- Fixed duplicate event listeners on reload - Old DeathConfirmGUI listeners are now unregistered before creating new instance
- New classes:
PendingDeath,PendingDeathManager,DeathConfirmGUI - Added
EconomyManager.getBalance()method - Full Folia compatibility for GUI mode
- Fixed ResultSet resource leak - 6 database queries were not properly closing ResultSet objects, causing potential memory leaks
- Fixed async task race condition - Stats async tasks now check shutdown flag inside the task to prevent SQLException after connection close
- Fixed economy retry spam - Limited economy setup retries to 5 attempts (30s interval) instead of infinite retries
- Fixed PlaceholderAPI version - Now uses dynamic version from plugin instead of hardcoded "1.0.15"
- Economy retry counter resets on
/dki reload - Added debug logging for economy retry attempts
- Better shutdown safety for async database operations
- Fixed stats GUI title detection so inventory clicks/drags are always cancelled
- Fixed per-world keep-inventory resolution to use actual day/night state (not trigger window)
- Lands override now cleanly defers to Lands when
override-lands=false, avoiding double handling - Serialized all SQLite access to prevent concurrent connection use and potential locks
- Removed unnecessary deprecation suppression in stats command lookup
- Fixed economy payments not being tracked in stats database
- Fixed potential SQLite connection crashes on server lag
- Fixed
/dki stats <player>not working for offline players
- Added async database writes for better Paper/Folia performance
- Database operations no longer block main server thread
- Graceful shutdown with async task completion
- Added Player Stats GUI (
/dki stats [player]) - SQLite database for persistent death statistics
- Track deaths saved, deaths lost, economy paid, death reasons
- 45-slot inventory GUI with player head, progress bar, server stats
- Added 8 new PlaceholderAPI placeholders for stats
%dynamickeepinv_stats_deaths_saved%- Total deaths saved%dynamickeepinv_stats_deaths_lost%- Total deaths lost%dynamickeepinv_stats_total_deaths%- Total deaths%dynamickeepinv_stats_save_rate%- Save rate percentage%dynamickeepinv_stats_economy_paid%- Total economy paid%dynamickeepinv_stats_global_saved%- Server-wide deaths saved%dynamickeepinv_stats_global_lost%- Server-wide deaths lost%dynamickeepinv_stats_global_rate%- Server-wide save rate
- Config version updated to 5
- Added
stats.enabledoption
dynamickeepinv.stats- View own statsdynamickeepinv.stats.others- View other players' stats
- Added PlaceholderAPI support with 14 placeholders
- Placeholders:
%dynamickeepinv_enabled%,%dynamickeepinv_keepinventory%,%dynamickeepinv_time%,%dynamickeepinv_isday%,%dynamickeepinv_isnight%,%dynamickeepinv_period%, and more
- Added
use-death-causeoption for wilderness settings - When enabled, wilderness deaths use death-cause (PvP/PvE) instead of fixed values
- Allows Lands to control claimed areas while death-cause controls wilderness
- Fixed death messages showing during daytime when keepInventory gamerule is already true
- Plugin now skips advanced processing when gamerule handles everything
- Config version updated to 4
- Added
wilderness.use-death-causefor Lands and GriefPrevention
- Simplified config.yml (removed verbose comments)
- Added wiki documentation
- Config version updated to 3
- Fixed death-cause not overriding wilderness settings
- PvP/PvE now correctly overrides wilderness keep-items/keep-xp
- Claimed areas (in-own-land, in-other-land) still have highest priority
- Updated priority order documentation in config
- Clearer comments explaining how settings interact
- Added per-world settings (world-settings section)
- Added wilderness config for Lands/GriefPrevention
- Added death message notifications (chat/action-bar)
- Added custom gamerule change times (day-trigger/night-trigger)
- Advanced settings now disabled by default (safer for new users)
- Nerfed Lands integration to avoid conflicts with Lands' built-in keepInventory
- Added override-lands option for explicit control
- Improved config comments explaining priority order
- Fixed economy bypass death message reason
- Config version updated to 2 (auto-migration supported)
- Added gamerule-change section
- Added death-message section
- Added wilderness settings under protection plugins
- Fixed thread-safety issues with protection hooks on Folia
- Fixed item duplication bug when forcing inventory drops
- Improved reload command to reinitialize economy and protection hooks
- Fixed null gamerule handling that could crash the scheduler
- Add Lands plugin integration for land-based keep inventory
- Add GriefPrevention plugin integration for claim-based settings
- Separate settings for own/other land/claim
- Safe API version mismatch handling (auto-disable on incompatible)
- Downgrade to Java 17 for MC 1.20.4+ support
- Added economy mode option (charge-to-keep / charge-to-bypass)
- Fixed DeathListener event priority
- Improved debug logging
- Bug fixes
- Fixed bypass permission path to handle plugins that return null drops
- Advanced day/night item and XP defaults now respect the base keep-inventory settings
- Economy manager initialization is now thread-safe across Folia regions
- Hardened economy retry logic, event drop handling, and config wording for cleaner advanced flow
- Fixed Folia-safe player notification scheduling to avoid unsafe region access
- Added advanced configuration for inventory and XP control
- Added bypass permission for specific players
- Added Vault economy integration for paid keep inventory
- Added separate PvP and PvE death rules
- Added action bar and title notifications
- Added configurable sound effects
- Updated messages.yml with economy notifications
- Refactored broadcast to target specific worlds
- Added DeathListener for advanced logic with Folia support