A high-performance hybrid storage system for Minecraft network servers, implementing a write-behind cache pattern with Redis/Dragonfly and PostgreSQL/CockroachDB.
- Submillisecond Performance: Player data loads from Redis cache during server switches
- Write-Behind Cache Pattern: Asynchronous data persistence to SQL database
- Data Locking Mechanism: Prevents race conditions during server transfers
- SOLID Architecture: Clean, extensible, and maintainable codebase
- Non-Blocking Operations: All database operations use CompletableFuture with virtual threads (Java 21)
- Dual Database Support: Compatible with both PostgreSQL and CockroachDB
- JSONB Storage: Efficient storage of complex player data structures
- Auto-Save System: Periodic background synchronization from Redis to SQL with configurable batch processing
- Comprehensive Sync Options: Synchronize inventory, ender chest, health, food, XP, effects, advancements, and statistics
- Fully Customizable Messages: All messages configurable in
messages.ymlwith color codes and placeholders - Performance Monitoring: Built-in performance tracking and warnings for slow operations
- Batch Processing: Efficient handling of multiple players with configurable batch sizes
- World Change Detection: Optional data saving when players change worlds
- SSL Support: Secure database connections with SSL/TLS
PlayerRepository (Interface)
├── SqlPlayerRepository (PostgreSQL/CockroachDB)
└── RedisPlayerRepository (Dragonfly/Redis)
- Player Join: Load from Redis → Fallback to SQL if cache miss → Update Redis
- Server Switch: Save to Redis with lock → Transfer player → Release lock
- Player Quit: Save to Redis → Asynchronously persist to SQL
- Auto-Save: Periodic batch write from Redis to SQL
- Java 21 or higher
- Gradle 8.x
- Paper/Spigot 1.21+
- Redis/Dragonfly instance
- PostgreSQL 12+ or CockroachDB
The plugin automatically generates config.yml and messages.yml on first run.
server:
id: "survival-01"
group: "survival"
database:
type: POSTGRESQL
host: localhost
port: 5432
name: network_data
user: admin
pass: 'password'
ssl: false
pool:
max_size: 15
connection_timeout: 5000
redis:
host: localhost
port: 6379
pass: ''
lock_timeout: 3
sync_settings:
inventory: true
ender_chest: true
health: true
food: true
xp: true
effects: true
advancements: true
statistics: true
automation:
sql_backup_interval: 15
save_on_quit: true
save_on_world_change: true
async_processing: true
performance:
batch_size: 50
use_compression: true
achievement_timeout_ms: 5000
logging:
level: INFO
monitor_performance: trueAll player-facing and console messages are fully customizable with color codes (&a, &b, etc.) and placeholders:
prefix: "&8[&bInventoryFlow&8]&r"
loading:
start: "{prefix} &7Loading your data..."
success: "{prefix} &aData loaded successfully!"
errors:
data_locked: "{prefix} &cYour data is currently being transferred."
# ... and many more configurable messagesid: Unique server identifier in the networkgroup: Server group for applying group-based configurations
type: Database type (POSTGRESQL for both PostgreSQL and CockroachDB)host: Database server hostnameport: Database server portname: Database nameuser: Database usernamepass: Database passwordssl: Enable SSL connectionpool.max_size: HikariCP maximum connectionspool.connection_timeout: Connection timeout in milliseconds
host: Redis/Dragonfly server hostnameport: Redis/Dragonfly server portpass: Redis authentication password (leave empty if not required)lock_timeout: Lock duration in seconds during server transfers
inventory: Synchronize player inventoryender_chest: Synchronize ender chest contentshealth: Synchronize player healthfood: Synchronize hunger and saturationxp: Synchronize experience and levelseffects: Synchronize potion effectsadvancements: Synchronize achievements/advancementsstatistics: Synchronize player statistics
sql_backup_interval: Minutes between automatic Redis-to-SQL savessave_on_quit: Save data when player disconnectssave_on_world_change: Save data when player changes worldsasync_processing: Process all operations asynchronously
batch_size: Number of players to process in each batch during auto-saveuse_compression: Compress JSON data before sending to Redis (saves bandwidth)achievement_timeout_ms: Timeout for achievement synchronization to prevent lag
level: Log level (INFO or DEBUG for verbose output)monitor_performance: Log performance metrics for operations
./gradlew buildThe compiled plugin will be available in build/libs/InventoryFlow-1.0.0.jar
- Build the plugin or download the JAR file
- Place
InventoryFlow-1.0.0.jarin your server'splugins/directory - Start the server to generate the default configuration
- Configure your database and Redis connection in
config.yml - Restart the server
CREATE DATABASE minecraft_network;
CREATE USER admin WITH PASSWORD 'securepassword123';
GRANT ALL PRIVILEGES ON DATABASE minecraft_network TO admin;CREATE DATABASE minecraft_network;
CREATE USER admin WITH PASSWORD 'securepassword123';
GRANT ALL ON DATABASE minecraft_network TO admin;The plugin automatically creates the required table schema on first run.
Player data is serialized to JSONB format containing:
- Inventory: Base64-encoded ItemStack array
- EnderChest: Base64-encoded ItemStack array
- Health: Player health points
- Food: Hunger level and saturation
- XP: Total experience, level, and experience progress
- Effects: Base64-encoded active potion effects
- Statistics: Custom key-value statistics
- Advancements: Achievement/advancement completion status
- LastUpdate: Timestamp of last modification
Uses HikariCP for optimal database connection management:
- Prepared statement caching
- Batch insert rewriting
- Connection leak detection
- Health checks
- Virtual threads (Java 21) for all async operations
- ConcurrentHashMap for local cache
- Redis-based distributed locking
- CompletableFuture for non-blocking database access
When a player switches servers:
- Acquire lock:
player:lock:<uuid>with TTL - Save data to Redis cache
- Player transfers to new server
- New server waits for lock release
- Load data from Redis cache
This prevents race conditions and data loss during transfers.
- Redis Read: < 1ms
- Redis Write: < 1ms
- SQL Read (cache miss): 5-20ms
- SQL Write (async): Non-blocking
- HikariCP: High-performance JDBC connection pool
- Jedis: Redis client for Java
- PostgreSQL JDBC: Database driver
- Gson: JSON serialization
- SnakeYAML: Configuration parsing
Under MIT license
Sebastian Cheikh
For issues or questions, please contact the development team.