-
Notifications
You must be signed in to change notification settings - Fork 11
Data Storage
EliteEssentials supports three storage backends, configurable via config.json. By default, all data is stored in JSON files. You can optionally switch to an embedded H2 database or an external MySQL/MariaDB server.
File-based storage in the mod's data folder. Zero setup, works out of the box. This is the original storage method and remains the default.
An embedded Java SQL database that runs in-process. No external software required. The database file is stored in the plugin data folder. Provides better performance and data integrity than JSON for larger servers.
To enable, set storage.storageType to "h2" in config.json:
"storage": {
"storageType": "h2"
}An external SQL database for multi-server networks. Player data is shared across all connected servers. When a player joins, data is loaded fresh from the database rather than relying on stale cache.
To enable, set storage.storageType to "mysql" and configure the connection:
"storage": {
"storageType": "mysql",
"mysql": {
"host": "localhost",
"port": 3306,
"database": "eliteessentials",
"username": "root",
"password": "",
"tablePrefix": "ee_",
"connectionPool": {
"maximumPoolSize": 10,
"minimumIdle": 2,
"connectionTimeout": 30000
}
}
}Use /eemigration sql [force] to copy all existing JSON data (players, warps, spawns, first-join spawn) into the configured SQL database. The command:
- Reports progress during migration
- Continues on individual record failures (logs the UUID/identifier)
- Reports a summary on completion (total migrated, failed, elapsed time)
- Refuses to run when
storageTypeis"json" - Checks if target tables are empty before migrating; use
forceto overwrite
Steps:
- Set
storage.storageTypeto"h2"or"mysql"inconfig.json - Restart the server (or
/ee reload) so the SQL backend initializes - Run
/eemigration sqlas an admin - Verify the migration summary
- Run
/eemigration cleanupto move old JSON files intobackup/
After migrating to SQL, run /eemigration cleanup to move the now-unused JSON files (players/, warps.json, spawn.json, firstjoinspawn.json, player_index.json) into a backup/ subfolder. This keeps your data folder clean and avoids confusion about which files are active.
The command only works when storageType is not "json". You can safely delete the backup/ folder once you've confirmed SQL is working correctly.
All SQL table names use the configured tablePrefix (default ee_). Tables are created automatically on first startup. Schema versioning is tracked in a {prefix}schema_version table for future migrations.
Tables created:
-
ee_players— core player data (uuid, name, nickname, timestamps, wallet, etc.) -
ee_homes— player home locations -
ee_back_history— back location history -
ee_kit_claims— one-time kit claims -
ee_kit_cooldowns— kit cooldown timestamps -
ee_playtime_claims— playtime reward claims -
ee_ignored_players— ignore list -
ee_mailbox— player mail -
ee_ip_history— IP address history -
ee_balance_notifications— pending balance change notifications -
ee_activity_log— admin action audit log (bans, kicks, mutes, economy, etc.) -
ee_warps— server warps -
ee_player_warps— player-created warps (public/private) -
ee_spawns— per-world spawn points -
ee_first_join_spawn— first-join spawn location -
ee_schema_version— schema version tracking
When using JSON storage (default), data is stored in files within the mod's data folder.
mods/
EliteEssentials/
config.json - Configuration settings
messages.json - Customizable messages (localization)
activity_log.json - Admin action audit log (bans, kicks, mutes, etc.)
mutes.json - Server-wide mute data
warns.json - Player warnings (for /warn, /warnings, /clearwarnings)
bans.json - Permanent ban data
tempbans.json - Temporary ban data (with expiration)
ipbans.json - IP-based ban data
warps.json - Server warp locations
player_warps.json - Player-created warp locations (public/private)
spawn.json - Per-world spawn locations
kits.json - Kit definitions
motd.json - Message of the Day content
rules.json - Server rules content
discord.json - Discord info content
autobroadcast.json - Auto broadcast configuration
groupchat.json - Group chat channel configuration
aliases.json - Command aliases
playtime_rewards.json - PlayTime reward definitions
playtime_claims.json - PlayTime reward claim tracking
players/ - Per-player data files
<uuid>.json - Individual player data
Each player has their own data file stored by UUID. This contains all player-specific data.
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "EliteScouter",
"firstJoin": 1704067200000,
"lastSeen": 1704153600000,
"wallet": 1500.0,
"playTime": 36000,
"homes": {
"base": {
"name": "base",
"world": "default",
"x": 100.5,
"y": 64.0,
"z": -200.5,
"yaw": 90.0,
"pitch": 0.0,
"createdAt": 1704067200000
}
},
"backLocations": [
{
"world": "default",
"x": 100.0,
"y": 64.0,
"z": -200.0,
"yaw": 0.0,
"pitch": 0.0
}
],
"kitClaims": {
"starter": 1704067200000,
"vip": 1704153600000
},
"mail": [
{
"id": "abc123",
"from": "Steve",
"fromUuid": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"message": "Hey, want to trade?",
"timestamp": 1704067200000,
"read": false
}
],
"playTimeRewardsClaimed": ["hourly_bonus", "100h_vip"],
"ignoredPlayers": [
"6ba7b810-9dad-11d1-80b4-00c04fd430c8"
],
"nickname": "CoolPlayer",
"defaultGroupChat": "trade"
}Structure:
-
uuid- Player's UUID -
name- Player's current username (updated on each login) -
firstJoin- Unix timestamp of first server join -
lastSeen- Unix timestamp of last logout -
wallet- Economy balance (requires economy enabled) -
playTime- Total play time in seconds -
homes- Map of home name to home object -
backLocations- Array of previous locations (most recent first) -
kitClaims- Map of kit ID to last claim timestamp -
mail- Array of mail messages -
playTimeRewardsClaimed- Array of claimed one-time reward IDs -
ignoredPlayers- Array of UUIDs of players being ignored -
nickname- Display nickname (null if not set) -
defaultGroupChat- Preferred group chat channel name (null if not set)
Stores all server warp locations.
{
"shop": {
"name": "shop",
"location": {
"world": "default",
"x": 0.0,
"y": 64.0,
"z": 0.0,
"yaw": 0.0,
"pitch": 0.0
},
"permission": "ALL",
"description": "Server shop - buy and sell items!",
"createdBy": "EliteScouter",
"createdAt": 1704067200000
}
}Structure:
- Top-level keys are warp names (lowercase)
-
permissionis eitherALLorOP -
descriptionis optional text shown in the warp GUI -
createdByis the player name who created the warp -
createdAtis Unix timestamp in milliseconds
Stores per-world spawn locations.
{
"default": {
"world": "default",
"x": 0.0,
"y": 64.0,
"z": 0.0,
"yaw": 0.0,
"pitch": 0.0
},
"explore": {
"world": "explore",
"x": 100.0,
"y": 80.0,
"z": -50.0,
"yaw": 90.0,
"pitch": 0.0
}
}Structure:
- Top-level keys are world names
- Each world can have its own spawn point set via
/setspawn -
yawandpitchcontrol the direction the player faces - Spawn protection is applied to each world that has a spawn set
Stores kit definitions.
[
{
"id": "starter",
"name": "Starter Kit",
"cooldownSeconds": 0,
"oneTime": true,
"items": [
{
"itemId": "hytale:wooden_sword",
"quantity": 1,
"slot": "hotbar"
},
{
"itemId": "hytale:bread",
"quantity": 16,
"slot": "storage"
}
],
"commands": []
},
{
"id": "vip",
"name": "VIP Kit",
"cooldownSeconds": 3600,
"oneTime": false,
"items": [
{
"itemId": "hytale:diamond_sword",
"quantity": 1,
"slot": "hotbar"
}
],
"commands": [
"eco add {player} 500",
"lp user {player} group add vip"
]
}
]Structure:
- Array of kit objects
-
id- Unique identifier (used in permissions) -
name- Display name -
cooldownSeconds- Time between claims (0 = no cooldown) -
oneTime- If true, can only be claimed once ever -
items- Array of items in the kit -
commands- Array of commands to execute on claim (optional, supports{player}and%player%placeholders, runs as console)
Stores custom command aliases.
{
"explore": {
"command": "warp explore",
"permission": "everyone",
"silent": true
},
"hub": {
"command": "warp spawn",
"permission": "everyone",
"silent": false
}
}Structure:
- Top-level keys are alias names (the command players type)
-
commandis the command to execute (without leading /) -
permissionis"everyone","op", or a custom permission node -
silentwhen true, suppresses teleport confirmation messages
Stores server-wide mute data. Managed by the /mute and /unmute commands.
{
"550e8400-e29b-41d4-a716-446655440000": {
"playerName": "Steve",
"reason": "Spamming in chat",
"mutedBy": "EliteScouter",
"mutedAt": 1704067200000
}
}Structure:
- Top-level keys are player UUIDs (the muted player)
-
playerName- The muted player's username -
reason- Optional reason for the mute (may be null) -
mutedBy- The admin who issued the mute -
mutedAt- Unix timestamp when the mute was applied
Stores player warnings. Managed by the /warn, /warnings, and /clearwarnings commands.
{
"550e8400-e29b-41d4-a716-446655440000": [
{
"reason": "Spamming in chat",
"warnedBy": "EliteScouter",
"warnedAt": 1704067200000
}
]
}Structure:
- Top-level keys are player UUIDs (the warned player)
- Each value is an array of warning entries
-
reason- Optional reason for the warning (may be null) -
warnedBy- The admin who issued the warning -
warnedAt- Unix timestamp when the warning was applied
When warn.autoPunishThreshold is reached, automatic punishment (ban or tempban) can be applied; see Configuration.
Stores permanent ban data. Managed by the /ban and /unban commands.
{
"550e8400-e29b-41d4-a716-446655440000": {
"playerName": "Steve",
"reason": "Griefing",
"bannedBy": "EliteScouter",
"bannedAt": 1704067200000
}
}Structure:
- Top-level keys are player UUIDs (the banned player)
-
playerName- The banned player's username -
reason- Optional reason for the ban (may be null) -
bannedBy- The admin who issued the ban -
bannedAt- Unix timestamp when the ban was applied
Stores temporary ban data with expiration. Managed by the /tempban command. Expired bans are cleaned up automatically.
{
"550e8400-e29b-41d4-a716-446655440000": {
"playerName": "Steve",
"reason": "Repeated rule violations",
"bannedBy": "EliteScouter",
"bannedAt": 1704067200000,
"expiresAt": 1704672000000
}
}Structure:
- Same as bans.json, plus:
-
expiresAt- Unix timestamp when the ban expires
Stores IP-based ban data. Managed by the /ipban and /unipban commands.
{
"192.168.1.100": {
"playerName": "Steve",
"reason": "Alt account abuse",
"bannedBy": "EliteScouter",
"bannedAt": 1704067200000
}
}Structure:
- Top-level keys are IP addresses
-
playerName- The player whose IP was banned -
reason- Optional reason for the ban -
bannedBy- The admin who issued the ban -
bannedAt- Unix timestamp when the ban was applied
Stores all customizable player-facing messages (localization).
{
"prefix": "[EliteEssentials] ",
"noPermission": "You don't have permission to use this command.",
"playerNotFound": "Player not found.",
"homeSet": "Home '{name}' has been set!",
"homeTeleported": "Teleported to home '{name}'."
}Structure:
- Key-value pairs where key is the message identifier
- Values support placeholders like
{player},{seconds},{name} - Supports color codes (
&a,&c,&l,&o,&r) - Supports hex colors (
&#RRGGBB) - See Placeholders for complete message reference
Stores the Message of the Day content with per-world support.
{
"lines": [
"&e&lWelcome to {server}, {player}!",
"&7There are &a{playercount}&7 players online."
],
"worldMotds": {
"explore": {
"enabled": true,
"showAlways": false,
"lines": [
"&a=== Welcome to Explore! ===",
"&7This is the exploration world."
]
}
}
}Structure:
-
lines- Global MOTD shown on first join -
worldMotds- Per-world MOTDs-
enabled- Enable/disable this world's MOTD -
showAlways- Show every time (true) or once per session (false) -
lines- Array of message lines
-
Stores the server rules content.
{
"lines": [
"&c&l========================================",
"&e&l SERVER RULES",
"&c&l========================================",
"&a1. &7Be Respectful to others",
"&a2. &7No Cheating / Hacking"
]
}Stores the server discord information.
{
"lines": [
"&b&l========================================",
"&e&l JOIN OUR DISCORD!",
"&b&l========================================",
"&bhttps://discord.gg/YourInvite"
]
}URLs are automatically made clickable.
Stores group chat channel configurations.
[
{
"groupName": "admin",
"displayName": "Admin Chat",
"prefix": "[ADMIN]",
"color": "#f85149",
"enabled": true,
"requiresGroup": true
},
{
"groupName": "trade",
"displayName": "Trade Chat",
"prefix": "[TRADE]",
"color": "#f0c674",
"enabled": true,
"requiresGroup": false
},
{
"groupName": "local",
"displayName": "Local Chat",
"prefix": "[LOCAL]",
"color": "#8b949e",
"enabled": true,
"requiresGroup": false,
"range": 50
}
]Structure:
-
groupName- Chat identifier (case-insensitive) -
displayName- Friendly name shown in messages -
prefix- Prefix shown before messages -
color- Hex color for the prefix -
enabled- Whether this chat is active -
requiresGroup-truefor LuckPerms group-based,falsefor permission-based -
range- Block range limit for proximity chat (null or 0 = unlimited, positive = limited)
Stores automatic broadcast configurations.
{
"broadcasts": [
{
"id": "discord",
"enabled": true,
"intervalSeconds": 600,
"prefix": "",
"random": false,
"requirePlayers": true,
"messages": [
"&5&l[Discord]&7 - Join us!\n&bhttps://discord.gg/YourInvite"
]
}
]
}Structure:
-
id- Unique identifier -
enabled- Whether this broadcast is active -
intervalSeconds- Time between broadcasts -
prefix- Optional prefix (supports color codes) -
random- If true, picks random message; if false, cycles sequentially -
requirePlayers- Only broadcast when players are online -
messages- Array of messages (use\nfor multi-line)
Stores the admin action audit log. Used by the Admin UI Activity tab. Maximum 200 entries are kept (oldest are removed when the limit is reached).
[
{
"type": "BAN",
"admin": "EliteScouter",
"target": "Steve",
"detail": "Griefing",
"timestamp": 1704067200000
},
{
"type": "KICK",
"admin": "EliteScouter",
"target": "Alex",
"detail": "kicked from admin UI",
"timestamp": 1704067100000
}
]Structure:
- Array of log entries (most recent first)
-
type- Action type (BAN, TEMPBAN, IPBAN, UNBAN, MUTE, UNMUTE, WARN, CLEARWARNINGS, KICK, FREEZE, UNFREEZE, ECONOMY, DELWARP, DELSPAWN, CLEARBACK, RESETKITS, DELHOME) -
admin- Username of the admin who performed the action -
target- Username of the affected player -
detail- Additional details about the action -
timestamp- Unix timestamp in milliseconds
When using SQL storage, this data is stored in the ee_activity_log table instead.
Stores playtime reward definitions.
[
{
"id": "hourly_bonus",
"name": "Hourly Bonus",
"minutesRequired": 60,
"repeatable": true,
"enabled": true,
"message": "&a[Reward] &fYou received your hourly bonus!",
"commands": ["eco add {player} 100"]
},
{
"id": "100h_vip",
"name": "100 Hour VIP",
"minutesRequired": 6000,
"repeatable": false,
"enabled": true,
"message": "&d[Milestone] &f100 hours played! VIP unlocked!",
"commands": [
"lp user {player} group set vip",
"eco add {player} 5000"
]
}
]Structure:
-
id- Unique identifier for tracking claims -
name- Display name -
minutesRequired- Minutes of playtime required -
repeatable- If true, triggers every X minutes; if false, one-time -
enabled- Enable/disable this reward -
message- Message sent when reward is granted -
commands- Commands to execute (supports{player}placeholder)
All location objects share the same structure:
{
"world": "default",
"x": 100.5,
"y": 64.0,
"z": -200.5,
"yaw": 0.0,
"pitch": 0.0
}| Field | Type | Description |
|---|---|---|
world |
string | World/dimension name |
x |
double | X coordinate |
y |
double | Y coordinate (height) |
z |
double | Z coordinate |
yaw |
float | Horizontal rotation (0-360) |
pitch |
float | Vertical rotation (-90 to 90) |
- Player Data - Saved immediately after changes (homes, kit claims, mail)
- Warps - Saved immediately after each create/delete
-
Spawn - Saved immediately after
/setspawn -
Config Files - Loaded on startup and when
/ee reloadis used - All Data - Saved on server shutdown
EliteEssentials automatically saves all data when:
- The server shuts down gracefully
- A home, warp, or other data is created/deleted
- The
/eliteessentials reloadcommand is run
- Data files use atomic writes to prevent corruption
- Existing data is preserved during mod updates
- Invalid JSON entries are logged and skipped (not deleted)
- Thread-safe file operations using synchronized blocks
EliteEssentials automatically migrates data from older formats:
-
homes.json(legacy) ->players/<uuid>.json -
back.json(legacy) ->players/<uuid>.json -
kit_claims.json(legacy) ->players/<uuid>.json -
first_join.json(legacy) ->players/<uuid>.json -
players.json(legacy) ->players/<uuid>.json
Migration happens automatically on first startup after updating.
It is recommended to regularly backup the mods/EliteEssentials/ folder, especially:
- Before updating EliteEssentials
- Before making major configuration changes
- As part of your regular server backup routine
# Linux/Mac
cp -r mods/EliteEssentials/ backups/EliteEssentials-$(date +%Y%m%d)/
# Windows
xcopy mods\EliteEssentials backups\EliteEssentials-%date:~-4,4%%date:~-10,2%%date:~-7,2% /E /IYou can manually edit the JSON files while the server is stopped. Be careful to:
- Stop the server first - Editing while running may cause data loss
- Validate JSON syntax - Use a JSON validator before saving
- Maintain structure - Keep the same field names and types
- Use valid UUIDs - Player UUIDs must be valid format
Player UUIDs can be found:
- In server logs when players join
- Using online UUID lookup tools with player names
- In the existing data files
EliteEssentials supports migration from other essentials plugins:
-
EssentialsCore - Use
/eemigration essentialscore -
EssentialsPlus - Use
/eemigration essentialsplus -
HomesPlus - Use
/eemigration homesplus -
Hyssentials - Use
/eemigration hyssentials
Migration imports homes, warps, and player data where applicable.
- Check file permissions on the data folder
- Ensure the server has write access
- Check server logs for error messages
- Verify disk space is available
If a data file becomes corrupted:
- Stop the server
- Check the file for JSON syntax errors
- Fix the syntax or restore from backup
- Start the server
- Check if the data folder location changed
- Look for data in both old and new locations
- Manually copy data files if needed
- Check for migration logs in server console
- Per-player data files reduce memory usage for large servers
- Data files are loaded on-demand when players join
- Consider periodic cleanup of inactive player data for very large servers
- Use the debug mode to monitor file I/O if experiencing issues
EliteEssentials by EliteScouter | GitHub | Report Issues