
XGamemode
You're not switching modes, you're switching dimensions.
- Загрузки
- 2K
- Подписчики
- 4
- Обновлён
- 29 апреля 2026 г.
- Лицензия
- CC-BY-NC-SA-4.0
Опубликован 23 января 2025 г.

“You're not switching modes, you're switching dimensions.”
2000 Downloads?! Thanks!
1 Feature
1.1 Offline Player
You can change the gamemode of a player, even he (or she) was offline.
1.2 Permissions
Allow permission group plugins (like Luckperms) to manage which gamemodes can be switched to and which gamemodes cannot be switched to.
e.g. Allow to switch to survival mode but not to any other mode.
1.3 Alias
/gamemode is simplified to /gm and /g.
(of course you can still use /gamemode)
1.4 Cross-Server Storage
Support MySQL and SQLite storage backends. Player gamemodes are saved and synchronized across multiple servers in a network.
1.5 Folia Support
Fully compatible with Folia servers — using region-based scheduling for optimal performance.
1.6 Lightweight
The Plugin size is only ~25 KB and has almost no impact on server performance!
2 Caution
2.1 Shortcut Keys
If you need to use shortcut keys such as F3+F4, please install another plugin F3NPerm.
2.2 Versions
1.8.X +
All Bukkit based server (Paper, Spigot, Purpur, Folia, etc.)
3 Commands
- /xgamemode
- /xgamemode reload
- /gm <mode>
- /gm <mode> <player>
- /gm <mode> -all
- /gm <mode> -online
- /gm <mode> -offline
/g = /gm = /gamemode
/xg = /xgm = /xgamemode
4 Permission Node
- xgamemode.survival
- xgamemode.creative
- xgamemode.adventure
- xgamemode.spectator
- xgamemode.others.survival
- xgamemode.others.creative
- xgamemode.others.adventure
- xgamemode.others.spectator
- xgamemode.reload
- xgamemode.admin
5 Custom Config
5.1 Basic Settings
lang: en-US
Language setting
default_gamemode: survival
If a new player joined your server, which gamemode should he (she) be?
survival, creative, adventure, spectator
show_logo: true
Show logo or not when plugin enabled.
true, false
debug: false
Enable debug logging for troubleshooting.
true, false
5.2 Storage Configuration
storage:
type: yaml
Storage backend type: yaml, sqlite, mysql
SQLite Example
storage:
type: sqlite
# No additional config needed — data.db will be created automatically
MySQL Example
storage:
type: mysql
mysql:
host: localhost
port: 3306
database: minecraft
username: root
password: your_password
5.3 Custom Messages
messages:
en-US: # Original en-US Language by Wind_Blood
reloaded: "&aXGamemode Reloaded!"
# ......
custom_lang: # Add Your Custom Language!
reloaded: "Thank you for using XGamemode!"
# ......
Customizable Messages. You can add your own new language here!
5.4 An Example config.yml
lang: msgForMyServer
default_gamemode: survival
show_logo: false
debug: false
storage:
type: yaml
messages:
msgForMyServer:
reloaded: "很明显作者是中国人 会说中文很正常 然后我也不知道为什么我要在一堆英文里写一段中文 挺好笑的 哈哈哈 对了 看到我就是缘分 XGamemode 官方 QQ 反馈交流群:点击链接加入群聊【XGamemode 反馈群】:https://qm.qq.com/q/rpTk5LK7w4 欢迎加"
usage: "&cUsage: /gm <mode> [player/-all/-online/-offline]"
console_usage: "&cUsage: /gm <mode> <player/-all/-online/-offline>"
invalid_gamemode: "&cInvalid Gamemode!"
invalid_player: "&cInvalid Player!"
gamemode_self: "&aYour Gamemode Changed to {mode}!"
gamemode_all: "&aChanged All Player's Gamemode to {mode}!"
gamemode_online: "&aAll Online Player's Gamemode Changed to {mode}!"
gamemode_offline: "&aAll Offline Player's Gamemode Changed to {mode}!"
no_permission: "&cYOU ARE NOT ALLOWED TO DO THAT!"
gamemode_other: "&a{player}'s Gamemode Changed to {mode}!"
gamemode_other_offline: "&a{player} (Offline)'s Gamemode Changed to {mode}!"
6 Developer API (Async)
Get Instance
Main plugin = Main.getInstance();
Get Player Gamemode
plugin.getPlayerMode(playerUUID).thenAccept(mode -> {
if (mode != null) {
// mode is GameMode.SURVIVAL, CREATIVE, ADVENTURE, or SPECTATOR
// Player is online or has saved data
} else {
// Player not found or no saved gamemode yet
}
});
Set Player Gamemode
plugin.setPlayerMode(playerUUID, GameMode.SURVIVAL).thenAccept(success -> {
if (success) {
// Gamemode changed and saved successfully
// Works for both online and offline players
} else {
// Failed to save (database error, etc.)
}
});
Listen to Gamemode Changes
@EventHandler
public void onGamemodeChange(GamemodeChangeEvent event) {
Player player = event.getPlayer(); // Online player only
GameMode oldMode = event.getOldMode();
GameMode newMode = event.getNewMode();
}
Note: All APIs are fully async and thread-safe. The
GamemodeChangeEventis only fired for online players when their mode is actually changed. ThegetPlayerMode()method returnsnullif the player has no saved gamemode data.
7 Reprint Post
www.minebbs.com/resources/xgamemode.11041
hangar.papermc.io/Wind_Blood/XGamemode
modrinth.com/plugin/xgamemode
8 Feedback
Just e-mail me with [email protected]. Thanks!
Ченджлог
4.6-betaБета26.1, 26.1.1, 26.1.2 · 29 апреля 2026 г.
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
4.6-alphaАльфа26.1, 26.1.1, 26.1.2 · 24 апреля 2026 г.
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
4.5-rlsРелиз26.1, 26.1.1, 26.1.2 · 23 апреля 2026 г.
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
4.5-betaБета26.1, 26.1.1, 26.1.2 · 20 апреля 2026 г.
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.
4.5-alphaАльфа26.1, 26.1.1, 26.1.2 · 18 апреля 2026 г.
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)
4.4-rlsРелиз1.21.9, 1.21.10, 1.21.11 · 22 марта 2026 г.
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)
4.4-betaБета1.21.9, 1.21.10, 1.21.11 · 27 февраля 2026 г.
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
4.4-alphaАльфа1.21.9, 1.21.10, 1.21.11 · 26 февраля 2026 г.
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!
Комментарии
Загружаем…