All versions
4.5-alpha
Alpha
Major Change...6 months ago 21
Compatibility
Minecraft: Java Edition
26.1.x
1.21.x
1.20.x
1.19.x
1.18.x
1.17.x
1.16.x
1.15.x
1.14.x
1.13.x
1.12.x
1.11.x
1.10.x
1.9.x
1.8.x
1.7.10
Platforms
Bukkit
Folia
Paper
Purpur
Spigot
Changes
Added
- Multi-storage support with automatic migration (YAML, SQLite, MySQL)
- Database connection pooling preparation structure
- Automatic YAML to database migration on first load
- Fallback mechanism to YAML when database connection fails
- ReadWriteLock implementation for finer-grained concurrency control
- Separate read/write lock methods (
tryReadLock,tryWriteLock,unlockRead,unlockWrite) withReadLockandwithWriteLockhelper methods for cleaner lock management- Comprehensive API methods with
CompletableFuturereturn types (getPlayerMode,setPlayerMode) - Custom
GamemodeChangeEventfor third-party plugin integration - Static
Main.getInstance()API accessor - Dedicated
savePlayerModeandloadPlayerModemethods with storage abstraction saveAllSyncmethod for batch YAML persistencecloseStoragemethod for proper database connection cleanup- Storage type logging on startup when debug mode is enabled
- Player lock map initialization with
ReentrantReadWriteLock - Database index creation for player name lookups with fallback for SQLite compatibility
Fixed
- Lock ownership checking before unlocking to prevent
IllegalMonitorStateException - Thread interruption handling in lock timeout scenarios with proper flag restoration
- Concurrent modification safety in batch player processing
- Data consistency between online player state and persistent storage
- Proper thread interruption propagation during executor shutdown
- Offline player name resolution fallback chain
- UUID validation with proper exception handling for malformed entries
- Batch processing now includes invalid entry removal and reporting
- YAML cache synchronization issues with
synchronizedblocks - Pending save deduplication using
ConcurrentHashMap.newKeySet()
Changed
- Storage backend from single YAML file to pluggable architecture (YAML/SQLite/MySQL)
- Lock mechanism from
ReentrantLocktoReentrantReadWriteLockfor improved read concurrency - Database operations execute asynchronously with prepared statements
- Player mode saving now includes timestamp field for future audit capabilities
- Data file renamed from
data.ymlto structured format with separatenameandgamemodefields - Configuration now supports
storagesection with type, MySQL credentials, and connection parameters - Migration process creates
.bakbackup of original YAML file handleGamemodeTargetsplit intohandleBatchPlayersandhandleSinglePlayerfor clarityprocessOfflinePlayersDatanow returnsPlayerDataResultwith changed and removed counts- Lock acquisition timeout reduced from lock-per-operation to centralized timeout constant
saveDataAsyncandsaveDataSyncreplaced with storage-awaresavePlayerModeandsavePlayerModeLocked- Executor service now uses fixed thread pool of 4 instead of cached pool
detectServerVersionmethod removed as no longer needed for SPECTATOR detection- Database connection uses MySQL connection parameters (useSSL=false, serverTimezone=UTC, autoReconnect=true)
- YAML cache field renamed from
dataConfigtoyamlCachefor clarity
Removed
PlayerDataResultinner class (functionality merged into improved batch processing)serverMinorVersionfield and version-specific SPECTATOR availability checkingsaveDataSyncdirect public method (replaced bysaveYamlCache)updateMappingstandalone method (merged into player join event handling)processPlayerSethelper method (consolidated into main processing flow)- Direct
dataConfigfield exposure (now accessed through synchronizedyamlCache) - Inline database connection string building (moved to dedicated
initDatabasemethod) - Redundant gamemode name storage in YAML root level (now only stored in structured format)
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:J0B80Y0Q:MsXUQX9L"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:J0B80Y0Q:MsXUQX9L"
}

