
XGamemode
You're not switching modes, you're switching dimensions.
Added
- API security control:
allow_to_use_apiconfig option (default: true) to prevent other plugins from accessing the API when set to false IllegalStateExceptionwith clear message when API access is disabled
Fixed
- None
Changed
- None
Removed
- None
- API security control:
Added
- Storage type change detection on reload - warns admin to restart server instead of loading mismatched data
Fixed
MAX_MAPPINGSlimit now trims oldest entries instead of only warning- YAML name fallback uses full UUID string instead of
substring(0, 8)to prevent potential boundary issues
Changed
lastStorageTypefield tracks storage type across reloads for change detection
Added
- Folia scheduler support with automatic fallback to Bukkit scheduler
- SQLite ON CONFLICT detection for better UPSERT performance
- UUID-based write locks for thread-safe player data operations
- Player save queue (
pendingSaves) to serialize async database writes per UUID - Offline player name caching to reduce I/O operations during batch processing
- YAML save debouncing with resettable timer (
scheduleYamlSave) - Atomic reference for
nameToUUIDsanduuidToNamemaps for safe reload - Legacy YAML format detection and migration support (
uuid: GAMEMODE) - Support for setting gamemode for players who have never joined the server
GamemodeChangeEventcustom event for API integration-all,-online,-offlinebatch operation flags- Database transaction support for batch offline player updates
- Automatic config.yml key merging with missing defaults preservation
- Connection retry mechanism with configurable attempts and delay
- Debug logging controlled by config option
Fixed
- NPE in
onDisable()whenstorageTypeis not"yaml"andyamlCacheis null - Race condition in
onPlayerJoinwhere async save could overwrite recently set gamemode - SQL operation silent failure - now logs error after max retry attempts
- Write lock timeout now logs debug message instead of failing silently
- Skipped offline players during batch operations now logged with warning count
- Config merge now properly adds missing keys without overwriting existing values
- Migration now handles both legacy (flat) and modern (nested) YAML formats
Changed
- Replaced
pendingSavesSet<String>withMap<UUID, CompletableFuture<Void>>for per-UUID queuing - Refactored
tryWriteLockpattern intowithWriteLockhelper method - Optimized
processOfflinePlayersDatawith name cache and early empty check - Cached UPSERT SQL generation to avoid repeated ON CONFLICT detection
- Message placeholder replacement now uses
Matcher.quoteReplacement()to escape$and\ - Folia reflection now uses
Consumer.classwith proper generic erasure handling savePlayerModeDirectnow updates memory cache immediately before async DB write- Batch migration now uses incremental
executeBatch()to avoid memory issues
Removed
- Legacy
yamlCache.set(uuid.toString(), mode.name())flat format write - Redundant
saveYamlCache()call when using database storage - Unused
SAVE_DELAYfield from earlier versions
Added
- Added database connection retry mechanism with
MAX_RETRY_ATTEMPTS(3) andRETRY_DELAY_MS(1000ms) for MySQL/SQLite. - Added
ensureConnection()andreconnect()methods for automatic database connection recovery. - Added
executeWithRetry(),executeUuidQueryWithRetry(), andexecuteVoidWithRetry()helper methods to wrap SQL operations with retry logic. - Added cross-server compatibility for offline player targeting: When a player name is not found in the local memory cache (
nameToUUIDs), the plugin now queries the database directly viaqueryUuidByName(). - Added
-offline,-online, and-allflags to batch target processing. - Added
PlayerQuitEventhandler to clean upplayerLockswhen a player disconnects, preventing potential memory leaks. - Added proper index creation handling (
createIndexSafe) with fallback checks for MySQL vs SQLite metadata differences. - Added
GamemodeChangeEventcustom event that is called when a player's gamemode is changed by the plugin.
Fixed
- Fixed database index creation to check for existing indexes before attempting
CREATE INDEXto prevent SQL errors on MySQL. - Fixed
onPlayerJoinevent to useOptionalforloadPlayerModeand properly handle null stored gamemodes without triggering unnecessary errors. - Fixed
savePlayerModeto ensure player name is correctly updated in the database when saving gamemode. - Fixed
setPlayerModeAPI method to handle exceptions and returnfalseon failure rather than always returningtrue. - Fixed YAML caching to properly wrap saves in
synchronizedblocks to prevent concurrent modification issues. - Fixed
loadDatato properly populatenameToUUIDsanduuidToNamemappings from both YAML and SQL storage. - Fixed
handleSinglePlayerto check for player name in database when local cache misses, improving cross-server or bungeecord network support. - Fixed
processOfflinePlayersDatato use database batch operations for SQL storage instead of locking each player individually, greatly improving performance.
Changed
- Refactored database initialization to use a dedicated
dbUrl,dbUser, anddbPassfields instead of constructing the connection string inline. - Updated
loadPlayerModeto useexecuteWithRetryfor robust SQL error handling andOptional<GameMode>return type. - Improved
setPlayerGamemodeLockedlogic to checkplayer.isOnline()before scheduling tasks. - Enhanced
handleGamemodeTargetto useasync()for both batch and single player operations to avoid blocking the main thread. - Replaced explicit
try-catchblocks withexecuteWithRetrywrappers in database operations for cleaner code. - Changed
handleBatchPlayersandhandleSinglePlayerto usesync()for sending messages to ensure thread safety. - Improved
migrateFromYamlIfNeededto handleON DUPLICATE KEY UPDATEproperly on MySQL. - Optimized
processOfflinePlayersDatato use batch SQL execution (executeBatch()) withBATCH_SIZEinstead of individual updates.
Removed
- Removed
tryReadLock(),unlockRead(), andwithReadLock()methods as they were unused in the new version. - Removed
saveAllSync()method as it was unused. - Removed direct
Statementusage ininitDatabase()in favor of try-with-resources and prepared statements. - Removed redundant player mode saving in
onPlayerJoin(no longer forces save if gamemode didn't change). - Removed manual thread sleeping in
processOfflinePlayersDatafor SQL storage, as batch processing handles this efficiently.
- Added database connection retry mechanism with
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)
Added
- Batch processing for offline player data with configurable
BATCH_SIZE(default: 100) to prevent memory overflow when handling large datasets - Centralized constant declarations (
SAVE_DELAY,MAX_MAPPINGS,BATCH_SIZE,LOCK_TIMEOUT,SHUTDOWN_TIMEOUT) for better maintainability
Fixed
- Potential performance issue where offline player data was processed without pagination, causing high memory usage
- Redundant
BatchResultinner class replaced with local variables for cleaner code structure
Changed
- Optimized
processOfflinePlayersDatamethod to process keys in batches instead of all at once - Simplified
handleBatchPlayersmethod by removing unnecessaryBatchResultwrapper class - Streamlined code formatting: compressed multi-line conditionals into single lines where appropriate
- Improved code readability with consistent constant usage across all methods
Removed
- Redundant
BatchResultinner class (functionality replaced with local variables) - Hardcoded thread pool size value (now using
THREAD_POOL_SIZEconstant)
- Batch processing for offline player data with configurable
Added
- Added debug logging for lock timeouts and interruptions
- Added
pendingSavesset to prevent multiple concurrent save operations
Changed
- Improved Folia scheduler fallback logic: sync tasks now use Bukkit scheduler instead of direct
run()to prevent main thread blocking - Enhanced version detection to properly handle 1.8.8 format
Fixed
- Fixed potential main thread blocking when Folia scheduling fails
- Fixed lock timeout handling with proper debug logging for easier troubleshooting
- Fixed duplicate data saving by implementing pending saves tracking with
ConcurrentHashMap.newKeySet() - Fixed version parsing for formats like 1.8.8
Added
- Added comprehensive thread-safe locking mechanism using ReentrantLock for player data
- Added support for Folia server software with unified scheduling API
- Added debug mode with detailed logging for troubleshooting
- Added maximum mappings limit (10,000) to prevent memory leaks
- Added delayed save system (20 ticks) to batch disk writes
- Added batch processing commands:
/gamemode -all,-online,-offline - Added server version detection for spectator mode compatibility
- Added configuration auto-merge to keep config.yml up-to-date
- Added proper error handling with stack traces in debug mode
- Added player quit event handling to clean up locks
Changed
- Complete architecture rewrite with modular design
- Migrated from coarse synchronized blocks to fine-grained ReentrantLock
- Improved thread management: replaced scattered async calls with centralized 4-thread pool
- Enhanced name-to-UUID mapping with bidirectional cache (uuidToName + nameToUUIDs)
- Optimized data saving: from immediate writes to delayed batch saving
- Unified task scheduling for Bukkit and Folia platforms
- Improved command tab completion with offline player suggestions
- Refactored permission system with granular control (xgamemode.admin, xgamemode.others.*)
- Enhanced logging with color-coded console messages
- Restructured message system with better fallback support
Fixed
- Fixed thread safety issues in name-to-UUID mappings
- Fixed memory leak where player data never got cleaned up
- Fixed data loss risk from frequent uncoordinated saves
- Fixed incorrect console sender usage in logo display
- Fixed spectator mode detection on older server versions
- Fixed race conditions in player join event handling
- Fixed improper synchronization in data file access
- Fixed tab completion showing duplicate entries
- Fixed permission checks for offline player modifications
Removed
- Removed excessive synchronized blocks causing performance bottlenecks
- Removed redundant saveData() calls after every player join
- Removed unsafe HashSet usage in concurrent mappings
- Removed mixed tab/space indentation (now using consistent spaces)
- Removed deprecated scheduler implementations
I won't be sad when the final JAR file is big anymore! Stable > Everything! Screw you, JAR size!
- Optimized the plugin.
[x] Fixed the bug that cause error when closing the server.
[+] Added 1.8.X mode
[x] Optimized Tab Completer
[+] Added
Supports to 1.9.X ~ 1.10.X.
[x] Optimized
Optimized Performance.
[+] Added
show_logo: true/falseShow logo or not when plugin enabled.
[x] Optimized
Optimized Performance.
Fixed the issue where lang settings could not be changed
I uploaded the Release version without checking the plugin functionality, which was my negligence. I hereby apologize to all users affected by the above issues. SORRY ABOUT THAT!
Optimized performance
Readded Invalid Playername Check
Supported 1.11+
Removed oii-aioA huge of performance improve
JAR size improve
Bug fixes
Fixed bug where XGamemode not working on Folia
Added Check Legal Player Name
Improved performance a lot!
Hope you enjoy it!
Fixed bug about Auto-Fix config
Optimized size and performance and data secure
Performance optimize and a HUGE size optimize
(I didn't use ProGuard this time!)
Optimized size and fixed bugs

