Links
Tags
Creators
Details
2.0.0
Compatibility
Changes
HimDungeons v2.0
Data storage refactor · Unified player lifecycle · WorldEdit fully removed · Relicensed to GPL v3
Compatibility change: HimDungeons v2.0 now requires Java 25+ and Bukkit 1.21+. Servers on Java 21 or older server versions will fail to load this build.
License
HimDungeons has been relicensed from "unlicensed / TBD" to GNU General Public License v3.0 (GPL-3.0).
This means:
- Anyone redistributing this plugin (binary or source), modified or unmodified, must release the source under GPL-3.0.
- Derivative works must also be GPL-3.0.
- The original author retains copyright and attribution rights.
If you were planning to fork or resell this plugin closed-source, this release makes that impossible. Review the full text at https://www.gnu.org/licenses/gpl-3.0.html.
Bug Fixes
Fixed: Restoring an inventory deleted the player's win count
In previous versions, win counts and inventory backups were stored in the same player_data.json player object. restoreBackup() called players.remove(uuid) after restoring the inventory, which deleted the entire player object — including wins. incrementWins() then found the entry missing and recreated it with wins = 1, making proper accumulation impossible.
v0.5 separates the two into physically distinct storage systems:
- Wins →
plugins/HimDungeons/<dungeon>/stats.yml(YAML, human-readable) - Inventory backups →
plugins/HimDungeons/backup.db(SQLite, WAL mode)
Restoring an inventory now only touches the SQLite table. Win counts are untouched.
Fixed: deepCloneInventory conditional was ineffective
The backup/restore logic was previously scattered across DungeonGenerator, HimDungeons, and DungeonLifecycleListener, each reading the global config at the time of execution. If the config was changed at runtime or cross-session leftovers existed, the plugin could restore an inventory even when deep clone was disabled.
v0.5 introduces DungeonInstance.deepCloneActive as the single source of truth. All backup and restore entry points now uniformly short-circuit with if (!instance.deepCloneActive) return;. Config drift and runtime config changes can no longer cause inconsistent state.
New Features
Split data storage
- Win counts are stored in
plugins/HimDungeons/<dungeon>/stats.yml— a plain YAML file you can open, inspect, and edit by hand. - Inventory backups are stored in
plugins/HimDungeons/backup.db— a SQLite database using WAL mode withsynchronous=NORMAL.
The two are completely independent. Restoring, deleting, or wiping one has no effect on the other.
Unified player lifecycle service
A new DungeonSessionService class routes every player transition — enter, finish, leave, quit, join — through a single state machine:
[Overworld] ──enter──► [In Dungeon] ──finish──► [Overworld] (restore inventory + rewards + wins++)
│
├── death ──► [In Dungeon] (respawn at checkpoint or spawn, no inventory op)
├── /dg leave ──► [Overworld] (restore inventory + 5-min cleanup timer)
├── quit ──► [Offline] (restore inventory immediately, 5-min rejoin window)
└── join ──► < 5 min: re-enter | ≥ 5 min: stay in overworld
Crash-safe inventory recovery
- On server startup,
DungeonSessionService.restorePendingOnEnable()scans everyACTIVErow in SQLite and marks itPENDING_RESTORE. - On player join, any pending row for that player is restored on the next tick and deleted.
- A
kill -9or hard power loss never loses committed backups, because SQLite guarantees WAL transaction durability. - For power-loss-grade durability, change
PRAGMA synchronous=NORMALtoPRAGMA synchronous=FULLinSqliteBackupStorage— a small performance cost that backup operations can easily absorb.
Offline and reconnect handling
- Quit — inventory is restored immediately (before the player's empty inventory can be persisted to playerdata), the offline timestamp is recorded, and if no online players remain in the world, a 5-minute cleanup countdown starts.
- Rejoin within 5 minutes — the player re-enters the dungeon, the inventory is re-backed up and cleared, and they are teleported to their last location.
- Rejoin after 5 minutes — the dungeon world has been deleted; the player stays in the overworld with a fully restored inventory.
Death handling
keepInventory = true— items do not drop inside the dungeon (vanilla gamerule).keepInventory = false— items drop on death (vanilla behavior).- Both modes: respawn location is
checkpoint > dungeon spawn, and death never triggers an inventory restore.
Dependency and Packaging
Added: SQLite JDBC (shaded)
org.xerial:sqlite-jdbc:3.46.1.3(Apache-2.0).- Merged via
ServicesResourceTransformerto registerjava.sql.Drivercorrectly.
Native library pruning
The raw sqlite-jdbc jar is ~12 MB and ships native binaries for 12 platforms. The shade plugin now excludes:
- Mac, FreeBSD, Android, Linux-Musl, Linux-Android
- Linux aarch64, armv7, arm, riscv64, ppc64
- Windows x86, aarch64, arm
Only Linux x86_64 and Windows x86_64 are kept. The final plugin jar is approximately 3.5 MB instead of ~10 MB.
If you need ARM or macOS support, remove the corresponding <exclude> entries in pom.xml and rebuild.
Removed
com.google.code.gson:gson— previously used by the deprecatedPlayerDataManager, no longer referenced.
Breaking Changes
- Java 25+ and Bukkit 1.21+ are now mandatory. The plugin refuses to load on Java 21 or older server versions.
- The old
player_data.jsonis not auto-migrated. Historical win counts must be manually imported intostats.yml. See the "Upgrade Notes" section below. PlayerDataManageris marked@Deprecatedand will be removed in a future release.- License changed from "unlicensed / TBD" to GPL-3.0. Redistributors must comply.
Test Results
Scenario: player inside a dungeon, server killed with kill -9
| Step | Result |
|---|---|
Player enters dungeon; SQLite row created with status=ACTIVE |
Pass |
Server hard-killed with kill -9 mid-play |
Pass |
| On restart, SQLite row preserved intact | Pass |
| Player joins; inventory restored with custom NBT names, enchantments, and metadata intact | Pass |
SQLite row deleted after restore; stats.yml win count unaffected |
Pass |
| Player placed safely in overworld (original dungeon world already deleted) | Pass |
Base64 + BukkitObjectStream serialization was verified to preserve custom item names, enchantments, and arbitrary NBT metadata across a hard crash.
Known Issues
getExtraContents()returns arrays of length 3 on some Paper forks. Functionally harmless; reported for future compatibility.- After a hard crash, world folders named
dungeon_<name>_<timestamp>remain on disk and must be cleaned manually. Automatic orphan-folder scanning is planned for the next release. - Bundled SQLite native libraries cover only Linux x86_64 and Windows x86_64.
- Running on Java 21 or any server version below 1.21 will throw
UnsupportedClassVersionErroror fail to load.
Upgrade Notes
- Back up your entire
plugins/HimDungeons/folder. - Upgrade your server to Java 25 and Bukkit 1.21+ before installing this build. Older Java versions will not run this jar.
- Replace the jar.
- Historical win counts from
player_data.jsonare not migrated automatically. To preserve them, read the old JSON once and callWinStorage.incrementWin(dungeonName, uuid, playerName)for each player's recorded win count. - Once you have confirmed there are no remaining references to
player_data.json, you may delete it.
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:gMUkJbNM:N3myUheB"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:gMUkJbNM:N3myUheB"
}

